diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b2af6d..aba88dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,6 +95,8 @@ set(codepointer_sources src/widgets/bannerwidget.h src/widgets/HistoryLineEdit.cpp src/widgets/HistoryLineEdit.h + src/widgets/BoldItemDelegate.cpp + src/widgets/BoldItemDelegate.hpp src/widgets/gotolineform.ui src/widgets/bannermessage.ui src/widgets/replaceform.ui diff --git a/src/GlobalCommands.hpp b/src/GlobalCommands.hpp index 88bb651..74e2f78 100644 --- a/src/GlobalCommands.hpp +++ b/src/GlobalCommands.hpp @@ -15,6 +15,9 @@ inline constexpr const char *OpenFile = "OpenFile"; // Broadcast - a new file has been loaded. The payload will contain the filename inline constexpr const char *LoadedFile = "LoadedFile"; +// Broadcast - a file has been saved. The payload will contain the filename +inline constexpr const char *SavedFile = "SavedFile"; + // Broadcast - a file has been closed inline constexpr const char *ClosedFile = "ClosedFile"; diff --git a/src/plugins/ProjectManager/ProjectManagerPlg.cpp b/src/plugins/ProjectManager/ProjectManagerPlg.cpp index b8fb10c..cec2316 100644 --- a/src/plugins/ProjectManager/ProjectManagerPlg.cpp +++ b/src/plugins/ProjectManager/ProjectManagerPlg.cpp @@ -1,18 +1,23 @@ -#include "qmdipluginconfig.h" +#include #include #include #include +#include #include +#include #include #include #include #include #include #include +#include +#include #include #include #include #include +#include #include #include #include @@ -33,6 +38,7 @@ #include #include #include +#include #include #include @@ -148,6 +154,13 @@ auto static setupPty(QProcess &process, int &masterFd) -> bool { #endif } +auto static isClangFormatSupported(const QString &fileName) -> bool { + auto static supported = + QSet{"c", "cc", "cpp", "cxx", "h", "hh", "hpp", "hxx", "m", "mm", "cu", "cuh"}; + auto ext = QFileInfo(fileName).suffix().toLower(); + return supported.contains(ext); +} + void ProjectBuildModel::addConfig(std::shared_ptr config) { int row = configs.size(); beginInsertRows(QModelIndex(), row, row); @@ -233,7 +246,7 @@ QStringList ProjectBuildModel::getAllOpenDirs() const { } ProjectManagerPlugin::ProjectManagerPlugin() { - name = tr("Project manager"); + name = "ProjectManager"; author = tr("Diego Iastrubni "); iVersion = 0; sVersion = "0.0.1"; @@ -241,6 +254,14 @@ ProjectManagerPlugin::ProjectManagerPlugin() { alwaysEnabled = true; auto monospacedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); + auto values = QStringList() << tr("Never") << tr("Always") << tr("Loaded projects"); + +#if defined(Q_OS_LINUX) + clangFormatExe = "/usr/bin/clang-format"; +#else + clangFormatExe = R"(C:\Program Files\llvm\bin\ctags.exe)"; +#endif + config.pluginName = tr("Project manager"); config.description = tr("Add support for building using CMake/Cargo/Go"); config.configItems.push_back( @@ -266,6 +287,22 @@ ProjectManagerPlugin::ProjectManagerPlugin() { .setDefaultValue(monospacedFont) .setValue(monospacedFont) .build()); + config.configItems.push_back(qmdiConfigItem::Builder() + .setDisplayName(tr("clang-format exe")) + .setDescription(tr("Where do you have LLVM tools installed")) + .setKey(Config::ClangFormatExeKey) + .setType(qmdiConfigItem::Path) + .setDefaultValue(clangFormatExe) + .setPossibleValue(true) // Must be an existing file + .build()); + config.configItems.push_back(qmdiConfigItem::Builder() + .setDisplayName(tr("Clang-format behaviour")) + .setDescription(tr("When to run clang-format")) + .setKey(Config::ClangFormatBehaviourKey) + .setType(qmdiConfigItem::OneOf) + .setPossibleValue(values) + .setDefaultValue(ClangFormatOnSave::InProjects) + .build()); /* config.configItems.push_back(qmdiConfigItem::Builder() @@ -807,19 +844,15 @@ int ProjectManagerPlugin::canHandleCommand(const QString &command, const Command if (command == GlobalCommands::LoadedFile) { return true; } + if (command == GlobalCommands::SavedFile) { + return true; + } if (command == GlobalCommands::ClosedFile) { return true; } return false; } -#include -#include -#include -#include -#include -#include - #ifdef Q_OS_WIN #include #endif @@ -861,73 +894,15 @@ auto verifyRunnable(const QString &fileName) -> bool { CommandArgs ProjectManagerPlugin::handleCommand(const QString &command, const CommandArgs &args) { if (command == GlobalCommands::LoadedFile) { auto client = args.value(GlobalArguments::Client).value(); - if (!client) { - return {}; - } - - auto filename = args[GlobalArguments::FileName]; - auto action = client->contextMenu.findActionNamed("runScript"); - auto isScript = verifyRunnable(client->mdiClientFileName()); - if (isScript) { - if (!action) { - auto shortcut = QKeySequence(Qt::ControlModifier | Qt::ShiftModifier | Qt::Key_R); - action = new QAction(tr("Run script")); - action->setObjectName("runScript"); - action->setShortcut(shortcut); - action->setData(QVariant::fromValue(client)); - client->contextMenu.addAction(action); - client->menus[tr("&Project")]->addAction(action); - - connect(action, &QAction::triggered, action, [action, this]() { - auto client = action->data().value(); - if (!client->canCloseClient(CloseReason::CloseTab)) { - return; - } - auto fi = QFileInfo(client->mdiClientFileName()); - auto workingDir = fi.dir().absolutePath(); - auto scriptName = fi.absoluteFilePath(); - auto arguments = QStringList(); - auto env = QProcessEnvironment(); - auto capture = - outputPanel ? outputPanel->captureTasksOutput->isChecked() : true; - this->runCommand(workingDir, scriptName, arguments, env, capture); - }); - if (client == mdiServer->getCurrentClient()) { - this->mdiServer->mdiHost->unmergeClient(client); - this->mdiServer->mdiHost->mergeClient(client); - this->mdiServer->mdiHost->updateGUI(); - } - } - } else { - client->contextMenu.removeAction(action); - client->menus[tr("&Project")]->removeAction(action); - if (client == mdiServer->getCurrentClient()) { - this->mdiServer->mdiHost->unmergeClient(client); - this->mdiServer->mdiHost->mergeClient(client); - this->mdiServer->mdiHost->updateGUI(); - } - } - - auto widget = dynamic_cast(client); - auto actionCopyFilePath = new QAction(tr("Copy path relative to project"), widget); - connect(actionCopyFilePath, &QAction::triggered, actionCopyFilePath, [client, this]() { - auto c = QApplication::clipboard(); - auto fileName = client->mdiClientFileName(); - auto project = projectModel->findProjectForFile(fileName); - if (!project || !fileName.startsWith(project->sourceDir)) { - c->setText(fileName); - return; - } - auto fixed = fileName; - auto l = project->sourceDir.length(); - if (!project->sourceDir.endsWith('\\') && !project->sourceDir.endsWith('/')) { - l++; - } - fixed.remove(0, l); - c->setText(fixed); - }); - client->contextMenu.addAction(actionCopyFilePath); - + auto filename = args[GlobalArguments::FileName].toString(); + fixClientsMenu(client, filename); + return {}; + } + if (command == GlobalCommands::SavedFile) { + auto client = args.value(GlobalArguments::Client).value(); + auto filename = args[GlobalArguments::FileName].toString(); + fixClientsMenu(client, filename); + saveFileExternalActions(client); return {}; } if (command == GlobalCommands::ClosedFile) { @@ -1666,3 +1641,103 @@ auto ProjectManagerPlugin::tryScrollOutput(int line) -> bool { vScrollBar->setValue(centerScrollValue); return true; } + +auto ProjectManagerPlugin::fixClientsMenu(qmdiClient *client, const QString &fileName) -> void { + if (!client) { + return; + } + + // TODO - do we even need this argument? + if (fileName.isEmpty()) { + return; + } + + auto action = client->contextMenu.findActionNamed("runScript"); + auto isScript = verifyRunnable(client->mdiClientFileName()); + if (isScript) { + if (!action) { + auto shortcut = QKeySequence(Qt::ControlModifier | Qt::ShiftModifier | Qt::Key_R); + action = new QAction(tr("Run script")); + action->setObjectName("runScript"); + action->setShortcut(shortcut); + action->setData(QVariant::fromValue(client)); + client->contextMenu.addAction(action); + client->menus[tr("&Project")]->addAction(action); + + connect(action, &QAction::triggered, action, [action, this]() { + auto client = action->data().value(); + if (!client->canCloseClient(CloseReason::CloseTab)) { + return; + } + auto fi = QFileInfo(client->mdiClientFileName()); + auto workingDir = fi.dir().absolutePath(); + auto scriptName = fi.absoluteFilePath(); + auto arguments = QStringList(); + auto env = QProcessEnvironment(); + auto capture = outputPanel ? outputPanel->captureTasksOutput->isChecked() : true; + this->runCommand(workingDir, scriptName, arguments, env, capture); + }); + this->mdiServer->mdiHost->unmergeClient(client); + this->mdiServer->mdiHost->mergeClient(client); + this->mdiServer->mdiHost->updateGUI(); + } + } else { + client->contextMenu.removeAction(action); + client->menus[tr("&Project")]->removeAction(action); + this->mdiServer->mdiHost->unmergeClient(client); + this->mdiServer->mdiHost->mergeClient(client); + this->mdiServer->mdiHost->updateGUI(); + } + + auto widget = dynamic_cast(client); + auto actionCopyFilePath = new QAction(tr("Copy path relative to project"), widget); + connect(actionCopyFilePath, &QAction::triggered, actionCopyFilePath, [client, this]() { + auto c = QApplication::clipboard(); + auto fileName = client->mdiClientFileName(); + auto project = projectModel->findProjectForFile(fileName); + if (!project || !fileName.startsWith(project->sourceDir)) { + c->setText(fileName); + return; + } + auto fixed = fileName; + auto l = project->sourceDir.length(); + if (!project->sourceDir.endsWith('\\') && !project->sourceDir.endsWith('/')) { + l++; + } + fixed.remove(0, l); + c->setText(fixed); + }); + client->contextMenu.addAction(actionCopyFilePath); +} + +auto ProjectManagerPlugin::saveFileExternalActions(qmdiClient *client) -> void { + // TODO how can we notify of errors? + if (getConfig().getClangFormatBehaviour() == ClangFormatOnSave::Never) { + return; + } + + auto fileName = client->mdiClientFileName(); + if (!isClangFormatSupported(fileName)) { + qDebug() << "saveFileExternalActions: not supported by clang-format" << fileName; + return; + } + if (getConfig().getClangFormatBehaviour() == ClangFormatOnSave::InProjects) { + auto project = projectModel->findProjectForFile(fileName); + if (!project || !fileName.startsWith(project->sourceDir)) { + qDebug() << "saveFileExternalActions: will not autoformat file" << fileName; + return; + } + } + + auto clangFormat = getConfig().getClangFormatExe(); + auto args = QStringList{"-style=file", "-fallback-style=none", "-i", fileName}; + auto p = QProcess(); + p.start(clangFormat, args); + p.waitForFinished(); + auto exitCode = p.exitCode(); + if (p.exitStatus() != QProcess::NormalExit || exitCode != 0) { + auto output = QString::fromUtf8(p.readAllStandardOutput()).trimmed(); + qDebug() << "Running clang-format failed, exit=" << exitCode << output; + qDebug() << QString("clang ") + args.join(" "); + } +} diff --git a/src/plugins/ProjectManager/ProjectManagerPlg.h b/src/plugins/ProjectManager/ProjectManagerPlg.h index 5589bb0..d61665e 100644 --- a/src/plugins/ProjectManager/ProjectManagerPlg.h +++ b/src/plugins/ProjectManager/ProjectManagerPlg.h @@ -42,12 +42,16 @@ class ProjectBuildModel : public QAbstractListModel { QStringList getAllOpenDirs() const; }; +enum class ClangFormatOnSave { Never, Always, InProjects }; + class ProjectManagerPlugin : public IPlugin { struct Config { CONFIG_DEFINE(SaveBeforeTask, bool); CONFIG_DEFINE(BlackConsole, bool); CONFIG_DEFINE(ConsoleFont, QString) + CONFIG_DEFINE(ClangFormatExe, QString); + CONFIG_DEFINE(ClangFormatBehaviour, ClangFormatOnSave) CONFIG_DEFINE(ExtraPath, QStringList); CONFIG_DEFINE(OpenDirs, QStringList); CONFIG_DEFINE(SelectedDirectory, QString); @@ -113,6 +117,8 @@ class ProjectManagerPlugin : public IPlugin { auto updateExecutablesUI(std::shared_ptr buildConfig) -> void; auto tryOpenProject(const QString &filename, const QString &dir) -> bool; auto tryScrollOutput(int line) -> bool; + auto fixClientsMenu(qmdiClient *client, const QString &filename) -> void; + auto saveFileExternalActions(qmdiClient *client) -> void; int panelIndex = -1; Ui::ProjectManagerGUI *gui = nullptr; @@ -132,6 +138,7 @@ class ProjectManagerPlugin : public IPlugin { ProjectBuildModel *projectModel = nullptr; CommandPalette *commandPalette = nullptr; ProjectSearch *searchPanelUI = nullptr; + QString clangFormatExe; QAction *runAction = nullptr; QAction *buildAction = nullptr; diff --git a/src/plugins/git/GitPlugin.cpp b/src/plugins/git/GitPlugin.cpp index 0f7003e..eb9cc24 100644 --- a/src/plugins/git/GitPlugin.cpp +++ b/src/plugins/git/GitPlugin.cpp @@ -23,6 +23,7 @@ #include "ui_GitCommands.h" #include "ui_GitCommit.h" #include "widgets/AutoShrinkLabel.hpp" +#include "widgets/BoldItemDelegate.hpp" #include "widgets/qmdieditor.h" QString shortGitSha1(const QString &fullSha1, int length = 7) { diff --git a/src/widgets/BoldItemDelegate.cpp b/src/widgets/BoldItemDelegate.cpp new file mode 100644 index 0000000..276a19a --- /dev/null +++ b/src/widgets/BoldItemDelegate.cpp @@ -0,0 +1,37 @@ +/** + * \file BoldItemDelegate.cpp + * \brief Implementation of the bold item delegate + * \author Diego Iastrubni diegoiast@gmail.com + */ + +// SPDX-License-Identifier: MIT + +#include + +#include "widgets/BoldItemDelegate.hpp" + +void BoldItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const { + QString text = index.data(Qt::DisplayRole).toString(); + painter->save(); + + bool isSelected = option.state & QStyle::State_Selected; + if (isSelected) { + painter->fillRect(option.rect, option.palette.highlight()); + painter->setPen(option.palette.highlightedText().color()); + } else { + painter->setPen(option.palette.text().color()); + } + + QFont font = painter->font(); + if (text == boldItemStr) { + font.setBold(true); + } + painter->setFont(font); + + // I honestly don't remember why I needed to adjust 4 pixels, but it looks + // better this way. + QRect textRect = option.rect.adjusted(4, 0, -4, 0); + painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text); + painter->restore(); +} diff --git a/src/widgets/BoldItemDelegate.hpp b/src/widgets/BoldItemDelegate.hpp new file mode 100644 index 0000000..3295829 --- /dev/null +++ b/src/widgets/BoldItemDelegate.hpp @@ -0,0 +1,30 @@ +/** + * \file BoldItemDelegate.hpp + * \brief Definition of the bold item delegate + * \author Diego Iastrubni diegoiast@gmail.com + */ + +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +/** + * \class Bold + * \brief item delegate used for highlighting a specific value + * + * This is a quick and dirty delegate to strap into a QListView or QComboBox + * (or anything supported) that will display a specific item, at the same font + * color as the default - but also bold. + * + * Can be used to mark the current item. + */ +class BoldItemDelegate : public QStyledItemDelegate { + public: + QString boldItemStr = ""; + explicit BoldItemDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) {} + + void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const override; +}; diff --git a/src/widgets/qmdieditor.cpp b/src/widgets/qmdieditor.cpp index a664e87..a72978f 100644 --- a/src/widgets/qmdieditor.cpp +++ b/src/widgets/qmdieditor.cpp @@ -50,6 +50,7 @@ #include "GlobalCommands.hpp" #include "plugins/texteditor/thememanager.h" #include "qmdieditor.h" +#include "widgets/BoldItemDelegate.hpp" #include "widgets/textoperationswidget.h" #include "widgets/textpreview.h" #include "widgets/ui_bannermessage.h" @@ -171,30 +172,6 @@ static auto createSubFollowSymbolSubmenu(const CommandArgs &data, QMenu *menu, } } -void BoldItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index) const { - QString text = index.data(Qt::DisplayRole).toString(); - painter->save(); - - bool isSelected = option.state & QStyle::State_Selected; - if (isSelected) { - painter->fillRect(option.rect, option.palette.highlight()); - painter->setPen(option.palette.highlightedText().color()); - } else { - painter->setPen(option.palette.text().color()); - } - - QFont font = painter->font(); - if (text == boldItemStr) { - font.setBold(true); - } - painter->setFont(font); - QRect textRect = option.rect.adjusted(4, 0, -4, 0); - // painter->drawText(option.rect, Qt::AlignLeft | Qt::AlignVCenter, text); - painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text); - painter->restore(); -} - namespace Qutepart { QStringList getAvailableHighlihters() { extern QMap languageNameToXmlFileName; @@ -819,44 +796,7 @@ void qmdiEditor::on_fileChanged(const QString &filename) { auto isModified = textEditor->document()->isModified(); if (!isModified) { - auto oldCursor = textEditor->textCursor(); - auto line = oldCursor.blockNumber(); - auto column = oldCursor.positionInBlock(); - auto anchorLine = oldCursor.anchor() >= oldCursor.position() - ? oldCursor.blockNumber() - : textEditor->document() - ->findBlock(oldCursor.anchor()) - .blockNumber(); - auto anchorColumn = oldCursor.anchor() >= oldCursor.position() - ? oldCursor.positionInBlock() - : oldCursor.anchor() - - textEditor->document()->findBlock(oldCursor.anchor()).position(); - - documentHasBeenLoaded = false; - loadContent(false); - - auto doc = textEditor->document(); - auto newCursor = QTextCursor (doc); - auto maxLine = doc->blockCount() - 1; - auto caretLine = std::min(line, maxLine); - auto caretBlock = doc->findBlockByNumber(caretLine); - newCursor.setPosition(caretBlock.position()); - - auto caretMaxColumn = caretBlock.length() - 1; - newCursor.movePosition( - QTextCursor::Right, - QTextCursor::MoveAnchor, - std::min(column, caretMaxColumn) - ); - auto anchorMaxLine = doc->blockCount() - 1; - auto selLine = std::min(anchorLine, anchorMaxLine); - auto anchorBlock = doc->findBlockByNumber(selLine); - auto anchorMaxColumn = anchorBlock.length() - 1; - auto anchorPos = - anchorBlock.position() + - std::min(anchorColumn, anchorMaxColumn); - newCursor.setPosition(anchorPos, QTextCursor::KeepAnchor); - textEditor->setTextCursor(newCursor); + reload(); return; } @@ -873,6 +813,40 @@ void qmdiEditor::on_fileChanged(const QString &filename) { displayBannerMessage(message, -1); } +void qmdiEditor::reload() { + auto oldCursor = textEditor->textCursor(); + auto line = oldCursor.blockNumber(); + auto column = oldCursor.positionInBlock(); + auto anchorLine = oldCursor.anchor() >= oldCursor.position() + ? oldCursor.blockNumber() + : textEditor->document()->findBlock(oldCursor.anchor()).blockNumber(); + auto anchorColumn = oldCursor.anchor() >= oldCursor.position() + ? oldCursor.positionInBlock() + : oldCursor.anchor() - + textEditor->document()->findBlock(oldCursor.anchor()).position(); + + documentHasBeenLoaded = false; + loadContent(false); + + auto doc = textEditor->document(); + auto newCursor = QTextCursor(doc); + auto maxLine = doc->blockCount() - 1; + auto caretLine = std::min(line, maxLine); + auto caretBlock = doc->findBlockByNumber(caretLine); + newCursor.setPosition(caretBlock.position()); + + auto caretMaxColumn = caretBlock.length() - 1; + newCursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, + std::min(column, caretMaxColumn)); + auto anchorMaxLine = doc->blockCount() - 1; + auto selLine = std::min(anchorLine, anchorMaxLine); + auto anchorBlock = doc->findBlockByNumber(selLine); + auto anchorMaxColumn = anchorBlock.length() - 1; + auto anchorPos = anchorBlock.position() + std::min(anchorColumn, anchorMaxColumn); + newCursor.setPosition(anchorPos, QTextCursor::KeepAnchor); + textEditor->setTextCursor(newCursor); +} + void qmdiEditor::hideTimer_timeout() { if (m_timerHideout != 0) { QString s; @@ -1271,7 +1245,7 @@ bool qmdiEditor::saveFile(const QString &newFileName, bool makeExecutable) { auto pluginManager = dynamic_cast(mdiServer->mdiHost); pluginManager->handleCommand( - GlobalCommands::LoadedFile, + GlobalCommands::SavedFile, { {GlobalArguments::FileName, mdiClientFileName()}, {GlobalArguments::Client, QVariant::fromValue(static_cast(this))}, @@ -1355,8 +1329,7 @@ void qmdiEditor::transformBlockCase() { void qmdiEditor::fileMessage_clicked(const QString &s) { if (s == ":reload") { - documentHasBeenLoaded = false; - loadContent(false); + reload(); hideBannerMessage(); } else if (s == ":forcerw") { hideBannerMessage(); @@ -1421,9 +1394,28 @@ void qmdiEditor::loadContent(bool useBackup) { // When loading, (setPlainText()) a signal is emitted, which triggers the system to believe // that the content has been modified. Just don't do this. It will also save some time // on loading, since really, signals emitted a this stage are not meaningful. - textEditor->blockSignals(true); - textEditor->setPlainText(textStream.readAll()); - file.close(); + { + auto doc = textEditor->document(); + auto oldCursor = textEditor->textCursor(); + auto selStart = oldCursor.selectionStart(); + auto selEnd = oldCursor.selectionEnd(); + auto cursor = QTextCursor (doc); + + cursor.beginEditBlock(); + cursor.select(QTextCursor::Document); + cursor.removeSelectedText(); + cursor.insertText(textStream.readAll()); + cursor.endEditBlock(); + + auto docLength = doc->characterCount() - 1; + selStart = qMin(selStart, docLength); + selEnd = qMin(selEnd, docLength); + + auto newCursor = QTextCursor (doc); + newCursor.setPosition(selStart); + newCursor.setPosition(selEnd, QTextCursor::KeepAnchor); + textEditor->setTextCursor(newCursor); + } QFileInfo fileInfo(fileName); auto elapsed = timer.elapsed(); diff --git a/src/widgets/qmdieditor.h b/src/widgets/qmdieditor.h index 5dfb7d7..12bd195 100644 --- a/src/widgets/qmdieditor.h +++ b/src/widgets/qmdieditor.h @@ -36,15 +36,6 @@ namespace Qutepart { class ThemeManager; } -class BoldItemDelegate : public QStyledItemDelegate { - public: - QString boldItemStr = ""; - explicit BoldItemDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) {} - - void paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index) const override; -}; - /** A source editor with MDI interface. This class will be a very rich text editor which will also have a set of toolbars and menus @@ -107,6 +98,7 @@ class qmdiEditor : public QWidget, public qmdiClient { void newDocument(); void setPlainText(const QString &plainText); + void reload(); bool doSave(); bool doSaveAs(); bool loadFile(const QString &fileName);