diff --git a/krusader/FileSystem/defaultfilesystem.cpp b/krusader/FileSystem/defaultfilesystem.cpp index 12d4560c..6af35acc 100644 --- a/krusader/FileSystem/defaultfilesystem.cpp +++ b/krusader/FileSystem/defaultfilesystem.cpp @@ -1,412 +1,412 @@ /***************************************************************************** * Copyright (C) 2000 Rafi Yanai * * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 2 of the License, or * * (at your option) any later version. * * * * Krusader is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #include "defaultfilesystem.h" // QtCore #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fileitem.h" #include "../defaults.h" #include "../krglobal.h" #include "../krservices.h" #include "../JobMan/krjob.h" DefaultFileSystem::DefaultFileSystem(): FileSystem(), _watcher() { _type = FS_DEFAULT; } void DefaultFileSystem::copyFiles(const QList &urls, const QUrl &destination, KIO::CopyJob::CopyMode mode, bool showProgressInfo, JobMan::StartMode startMode) { // resolve relative path before resolving symlinks const QUrl dest = resolveRelativePath(destination); KIO::JobFlags flags = showProgressInfo ? KIO::DefaultFlags : KIO::HideProgressInfo; KrJob *krJob = KrJob::createCopyJob(mode, urls, dest, flags); // destination can be a full path with filename when copying/moving a single file const QUrl destDir = dest.adjusted(QUrl::RemoveFilename); connect(krJob, &KrJob::started, this, [=](KIO::Job *job) { connectJobToDestination(job, destDir); }); if (mode == KIO::CopyJob::Move) { // notify source about removed files connect(krJob, &KrJob::started, this, [=](KIO::Job *job) { connectJobToSources(job, urls); }); } krJobMan->manageJob(krJob, startMode); } void DefaultFileSystem::dropFiles(const QUrl &destination, QDropEvent *event) { qDebug() << "destination=" << destination; // resolve relative path before resolving symlinks const QUrl dest = resolveRelativePath(destination); KIO::DropJob *job = KIO::drop(event, dest); #if KIO_VERSION >= QT_VERSION_CHECK(5, 30, 0) // NOTE: a DropJob "starts" with showing a menu. If the operation is chosen (copy/move/link) // the actual CopyJob starts automatically - we cannot manage the start of the CopyJob (see // documentation for KrJob) connect(job, &KIO::DropJob::copyJobStarted, this, [=](KIO::CopyJob *kJob) { connectJobToDestination(job, dest); // now we have to refresh the destination KrJob *krJob = KrJob::createDropJob(job, kJob); krJobMan->manageStartedJob(krJob, kJob); if (kJob->operationMode() == KIO::CopyJob::Move) { // notify source about removed files connectJobToSources(kJob, kJob->srcUrls()); } }); #else // NOTE: DropJob does not provide information about the actual user choice // (move/copy/link/abort). We have to assume the worst (move) connectJobToDestination(job, dest); connectJobToSources(job, KUrlMimeData::urlsFromMimeData(event->mimeData())); #endif } void DefaultFileSystem::addFiles(const QList &fileUrls, KIO::CopyJob::CopyMode mode, const QString &dir) { QUrl destination(_currentDirectory); if (!dir.isEmpty()) { destination.setPath(QDir::cleanPath(destination.path() + '/' + dir)); const QString scheme = destination.scheme(); if (scheme == "tar" || scheme == "zip" || scheme == "krarc") { if (QDir(destination.path()).exists()) // if we get out from the archive change the protocol destination.setScheme("file"); } } destination = ensureTrailingSlash(destination); // destination is always a directory copyFiles(fileUrls, destination, mode); } void DefaultFileSystem::mkDir(const QString &name) { KJob *job; if (name.contains('/')) { job = KIO::mkpath(getUrl(name)); } else { job = KIO::mkdir(getUrl(name)); } connectJobToDestination(job, currentDirectory()); } void DefaultFileSystem::rename(const QString &oldName, const QString &newName) { const QUrl oldUrl = getUrl(oldName); const QUrl newUrl = getUrl(newName); KIO::Job *job = KIO::moveAs(oldUrl, newUrl, KIO::HideProgressInfo); connectJobToDestination(job, currentDirectory()); KIO::FileUndoManager::self()->recordJob(KIO::FileUndoManager::Rename, {oldUrl}, newUrl, job); } QUrl DefaultFileSystem::getUrl(const QString& name) const { // NOTE: on non-local fs file URL does not have to be path + name! FileItem *fileItem = getFileItem(name); if (fileItem) return fileItem->getUrl(); QUrl absoluteUrl(_currentDirectory); if (name.startsWith('/')) { absoluteUrl.setPath(name); } else { absoluteUrl.setPath(absoluteUrl.path() + '/' + name); } return absoluteUrl; } void DefaultFileSystem::updateFilesystemInfo() { if (!KConfigGroup(krConfig, "Look&Feel").readEntry("ShowSpaceInformation", true)) { _mountPoint = ""; emit fileSystemInfoChanged(i18n("Space information disabled"), "", 0, 0); return; } // TODO get space info for trash:/ with KIO spaceInfo job if (!_currentDirectory.isLocalFile()) { _mountPoint = ""; emit fileSystemInfoChanged(i18n("No space information on non-local filesystems"), "", 0, 0); return; } const QString path = _currentDirectory.path(); const KDiskFreeSpaceInfo info = KDiskFreeSpaceInfo::freeSpaceInfo(path); if (!info.isValid()) { _mountPoint = ""; emit fileSystemInfoChanged(i18n("Space information unavailable"), "", 0, 0); return; } _mountPoint = info.mountPoint(); const KMountPoint::Ptr mountPoint = KMountPoint::currentMountPoints().findByPath(path); const QString fsType = mountPoint ? mountPoint->mountType() : ""; emit fileSystemInfoChanged("", fsType, info.size(), info.available()); } // ==== protected ==== bool DefaultFileSystem::refreshInternal(const QUrl &directory, bool onlyScan) { qDebug() << "refresh internal to URL=" << directory.toDisplayString(); if (!KProtocolManager::supportsListing(directory)) { emit error(i18n("Protocol not supported by Krusader:\n%1", directory.url())); return false; } delete _watcher; // stop watching the old dir if (directory.isLocalFile()) { qDebug() << "start local refresh to URL=" << directory.toDisplayString(); // we could read local directories with KIO but using Qt is a lot faster! return refreshLocal(directory, onlyScan); } _currentDirectory = cleanUrl(directory); // start the listing job KIO::ListJob *job = KIO::listDir(_currentDirectory, KIO::HideProgressInfo, showHiddenFiles()); connect(job, &KIO::ListJob::entries, this, &DefaultFileSystem::slotAddFiles); connect(job, &KIO::ListJob::redirection, this, &DefaultFileSystem::slotRedirection); connect(job, &KIO::ListJob::permanentRedirection, this, &DefaultFileSystem::slotRedirection); connect(job, &KIO::Job::result, this, &DefaultFileSystem::slotListResult); // ensure connection credentials are asked only once if(!parentWindow.isNull()) { KIO::JobUiDelegate *ui = static_cast(job->uiDelegate()); ui->setWindow(parentWindow); } emit refreshJobStarted(job); _listError = false; // ugly: we have to wait here until the list job is finished QEventLoop eventLoop; connect(job, &KJob::finished, &eventLoop, &QEventLoop::quit); eventLoop.exec(); // blocking until quit() return !_listError; } // ==== protected slots ==== void DefaultFileSystem::slotListResult(KJob *job) { qDebug() << "got list result"; if (job && job->error()) { // we failed to refresh _listError = true; qDebug() << "error=" << job->errorString() << "; text=" << job->errorText(); emit error(job->errorString()); // display error message (in panel) } } void DefaultFileSystem::slotAddFiles(KIO::Job *, const KIO::UDSEntryList& entries) { for (const KIO::UDSEntry entry : entries) { FileItem *fileItem = FileSystem::createFileItemFromKIO(entry, _currentDirectory); if (fileItem) { addFileItem(fileItem); } } } void DefaultFileSystem::slotRedirection(KIO::Job *job, const QUrl &url) { qDebug() << "redirection to URL=" << url.toDisplayString(); // some protocols (zip, tar) send redirect to local URL without scheme const QUrl newUrl = preferLocalUrl(url); if (newUrl.scheme() != _currentDirectory.scheme()) { // abort and start over again, // some protocols (iso, zip, tar) do this on transition to local fs job->kill(); _isRefreshing = false; refresh(newUrl); return; } _currentDirectory = cleanUrl(newUrl); } void DefaultFileSystem::slotWatcherCreated(const QString& path) { qDebug() << "path created (doing nothing): " << path; } void DefaultFileSystem::slotWatcherDirty(const QString& path) { qDebug() << "path dirty: " << path; if (path == realPath()) { // this happens // 1. if a directory was created/deleted/renamed inside this directory. // 2. during and after a file operation (create/delete/rename/touch) inside this directory // KDirWatcher doesn't reveal the name of changed directories and we have to refresh. // (QFileSystemWatcher in Qt5.7 can't help here either) refresh(); return; } const QString name = QUrl::fromLocalFile(path).fileName(); FileItem *fileItem = getFileItem(name); if (!fileItem) { qWarning() << "file not found (unexpected), path=" << path; // this happens at least for cifs mounted filesystems: when a new file is created, a dirty // signal with its file path but no other signals are sent (buggy behaviour of KDirWatch) refresh(); return; } // we have an updated file.. FileItem *newFileItem = createLocalFileItem(name); addFileItem(newFileItem); emit updatedFileItem(newFileItem); delete fileItem; } void DefaultFileSystem::slotWatcherDeleted(const QString& path) { qDebug() << "path deleted: " << path; if (path != _currentDirectory.toLocalFile()) { // ignore deletion of files here, a 'dirty' signal will be send anyway return; } // the current directory was deleted. Try a refresh, which will fail. An error message will // be emitted and the empty (non-existing) directory remains. refresh(); } bool DefaultFileSystem::refreshLocal(const QUrl &directory, bool onlyScan) { const QString path = KrServices::urlToLocalPath(directory); #ifdef Q_WS_WIN if (!path.contains("/")) { // change C: to C:/ path = path + QString("/"); } #endif // check if the new directory exists if (!QDir(path).exists()) { emit error(i18n("The folder %1 does not exist.", path)); return false; } // mount if needed emit aboutToOpenDir(path); // set the current directory... _currentDirectory = directory; _currentDirectory.setPath(QDir::cleanPath(_currentDirectory.path())); // Note: we are using low-level Qt functions here. // It's around twice as fast as using the QDir class. QT_DIR* dir = QT_OPENDIR(path.toLocal8Bit()); if (!dir) { emit error(i18n("Cannot open the folder %1.", path)); return false; } // change directory to the new directory const QString savedDir = QDir::currentPath(); if (!QDir::setCurrent(path)) { emit error(i18nc("%1=folder path", "Access to %1 denied", path)); QT_CLOSEDIR(dir); return false; } QT_DIRENT* dirEnt; QString name; const bool showHidden = showHiddenFiles(); while ((dirEnt = QT_READDIR(dir)) != NULL) { name = QString::fromLocal8Bit(dirEnt->d_name); // show hidden files? if (!showHidden && name.left(1) == ".") continue; // we don't need the "." and ".." entries if (name == "." || name == "..") continue; FileItem* temp = createLocalFileItem(name); addFileItem(temp); } // clean up QT_CLOSEDIR(dir); QDir::setCurrent(savedDir); if (!onlyScan) { // start watching the new dir for file changes _watcher = new KDirWatch(this); // if the current dir is a link path the watcher needs to watch the real path - and signal // parameters will be the real path _watcher->addDir(realPath(), KDirWatch::WatchFiles); connect(_watcher.data(), &KDirWatch::dirty, this, &DefaultFileSystem::slotWatcherDirty); // NOTE: not connecting 'created' signal. A 'dirty' is send after that anyway //connect(_watcher.data(), &KDirWatch::created, this, &DefaultFileSystem::slotWatcherCreated); connect(_watcher.data(), &KDirWatch::deleted, this, &DefaultFileSystem::slotWatcherDeleted); _watcher->startScan(false); } return true; } FileItem *DefaultFileSystem::createLocalFileItem(const QString &name) { return FileSystem::createLocalFileItem(name, _currentDirectory.path()); } -QString DefaultFileSystem::DefaultFileSystem::realPath() +QString DefaultFileSystem::realPath() { // NOTE: current dir must exist return QDir(_currentDirectory.toLocalFile()).canonicalPath(); } QUrl DefaultFileSystem::resolveRelativePath(const QUrl &url) { // if e.g. "/tmp/bin" is a link to "/bin", // resolve "/tmp/bin/.." to "/tmp" and not "/" return url.adjusted(QUrl::NormalizePathSegments); } diff --git a/krusader/Konfigurator/konfiguratorpage.h b/krusader/Konfigurator/konfiguratorpage.h index 8f643b65..03535574 100644 --- a/krusader/Konfigurator/konfiguratorpage.h +++ b/krusader/Konfigurator/konfiguratorpage.h @@ -1,513 +1,513 @@ /***************************************************************************** * Copyright (C) 2003 Csaba Karai * * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 2 of the License, or * * (at your option) any later version. * * * * Krusader is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #ifndef KONFIGURATORPAGE_H #define KONFIGURATORPAGE_H // QtWidgets #include #include #include #include #include #include "konfiguratoritems.h" struct KONFIGURATOR_CHECKBOX_PARAM; /** * KonfiguratorPage is responsible for handling pages in Konfigurator. * It provides simple methods for create and manage Konfigurator pages. * * @short The base class of a page in Konfigurator */ class KonfiguratorPage : public QScrollArea { Q_OBJECT public: /** * The constructor of the KonfiguratorPage class. * * @param firstTime this parameter is true if it is the first call of Konfigurator * @param parent reference to the parent widget */ KonfiguratorPage(bool firstTime, QWidget *parent); /** * Applies the changes in the Konfigurator page. * * Writes out all relevant information to the configuration object and synchronizes * it with the file storage (hard disk, krusaderrc file). This function calls the apply() * method of each konfigurator item and finally performs the synchronization. * * @return a boolean value indicates that Krusader restart is needed for the correct change */ virtual bool apply(); /** * Sets every konfigurator item to its default value on the page. * * This method calls the setDefaults() method of each konfigurator item. This function * doesn't modify the current configuration, only the values of the GUI items. The * apply() method must be called for finalizing the changes. */ virtual void setDefaults(); /** * Reloads the original value of each konfigurator item from the configuration object. * * This function calls the loadInitialValue() method of each konfigurator item. * Used to rollback the changes on the konfigurator page. Called if the user * responds 'No' to the "Apply changes" question. */ virtual void loadInitialValues(); /** * Checks whether the page was changed. * * This function calls the isChanged() method of each konfigurator item and * performs logical OR operation on them. Actually, this function returns true * if any of the konfigurator items was changed. * * @return true if at least one of the konfigurator items was changed */ virtual bool isChanged(); /** * Flag, indicates the first call of Konfigurator * @return true if konfigurator was started at the first time */ inline bool isFirst() { return firstCall; } /** * This method is used to query the active subpage from the Konfigurator * @return the active page (by default the first page) */ virtual int activeSubPage() { return FIRST_PAGE; } /** * Adds a new checkbox item to the page. *
The checkbox widget's name is QString(configGroup + "/" + name).ascii()
* * Sample:

* KonfiguratorCheckBox *myCheckBox = createCheckBox( "class", "name", false, parentWidget);
* myLayout->addWidget( myCheckBox, 0, 0 ); * * @param configGroup The class name used in KConfig (ex. "Archives") * @param name The item name used in KConfig (ex. "Do Tar") * @param defaultValue The default value of the checkbox * @param text The text field of the checkbox * @param parent Reference to the parent widget * @param restart The change of this parameter requires Krusader restart * @param toolTip Tooltip used for this checkbox * @param page The subpage of a Konfigurator page (because of setDefaults) * * @return reference to the newly created checkbox */ KonfiguratorCheckBox *createCheckBox(QString configGroup, QString name, bool defaultValue, QString text, QWidget *parent = 0, bool restart = false, QString toolTip = QString(), int page = FIRST_PAGE); /** * Adds a new spinbox item to the page. *
The spinbox widget's name is QString(configGroup + "/" + name).ascii()
* * Sample:

* KonfiguratorSpinBox *mySpinBox = createSpinBox( "class", "name", 10, 1, 100, parentWidget);
* myLayout->addWidget( mySpinBox, 0, 0 ); * * @param configGroup The class name used in KConfig (ex. "Archives") * @param configName The item name used in KConfig (ex. "Do Tar") * @param defaultValue The default value of the spinbox * @param min The minimum value of the spinbox * @param max The maximum value of the spinbox * @param parent Reference to the parent widget * @param restart The change of this parameter requires Krusader restart * @param page The subpage of a Konfigurator page (because of setDefaults) * * @return reference to the newly created spinbox */ KonfiguratorSpinBox *createSpinBox(QString configGroup, QString configName, int defaultValue, int min, int max, QWidget *parent = 0, bool restart = false, int page = FIRST_PAGE); /** * Adds a new editbox item to the page. *
The editbox widget's name is QString(configGroup + "/" + name).ascii()
* * Sample:

* KonfiguratorEditBox *myEditBox = createEditBox( "class", "name", "default", parentWidget);
* myLayout->addWidget( myEditBox, 0, 0 ); * * @param configGroup The class name used in KConfig (ex. "Archives") * @param name The itemname used in KConfig (ex. "Do Tar") * @param defaultValue The default value of the editbox * @param parent Reference to the parent widget * @param restart The change of this parameter requires Krusader restart * @param page The subpage of a Konfigurator page (because of setDefaults) * * @return reference to the newly created editbox */ KonfiguratorEditBox *createEditBox(QString configGroup, QString name, QString defaultValue, QWidget *parent = 0, bool restart = false, int page = FIRST_PAGE); /** * Adds a new listbox item to the page. *
The listbox widget's name is QString(configGroup + "/" + name).ascii()
* * Sample:

* QStringList valueList;
* valueList += "item";
* KonfiguratorListBox *myListBox = createListBox( "class", "name", valueList, parentWidget);
* myLayout->addWidget( myListBox, 0, 0 ); * * @param configGroup The class name used in KConfig (ex. "Archives") * @param name The itemname used in KConfig (ex. "Do Tar") * @param defaultValue The default value of the listbox * @param parent Reference to the parent widget * @param restart The change of this parameter requires Krusader restart * @param page The subpage of a Konfigurator page (because of setDefaults) * * @return reference to the newly created editbox */ KonfiguratorListBox *createListBox(QString configGroup, QString name, QStringList defaultValue, QWidget *parent = 0, bool restart = false, int page = FIRST_PAGE); /** * Adds a new URL requester item to the page. *
The URL requester widget's name is QString(configGroup + "/" + name).ascii()
* * Sample:

* KonfiguratorURLRequester *myURLRequester = createURLRequester( "class", "name", "default", parentWidget );
* myLayout->addWidget( myURLRequester, 0, 0 ); * * @param configGroup The class name used in KConfig (ex. "Archives") * @param name The itemname used in KConfig (ex. "Do Tar") * @param defaultValue The default value of the URL requester * @param parent Reference to the parent widget * @param restart The change of this parameter requires Krusader restart * @param page The subpage of a Konfigurator page (because of setDefaults) * @param expansion Whether to perform url expansion * * @return reference to the newly created URL requester */ KonfiguratorURLRequester *createURLRequester(QString configGroup, QString name, QString defaultValue, QWidget *parent, bool restart, int page = FIRST_PAGE, bool expansion = true); /** * Adds a new font chooser item to the page. *
The font chooser widget's name is QString(configGroup + "/" + name).ascii()
* * Sample:

* KonfiguratorFontChooser *myFontChooser = createFontChooser( "class", "name", QFont(), parentWidget );
* myLayout->addWidget( myFontChooser, 0, 0 ); * * @param configGroup The class name used in KConfig (ex. "Archives") * @param name The item name used in KConfig (ex. "Do Tar") * @param defaultValue The default value of the font chooser * @param parent Reference to the parent widget * @param restart The change of this parameter requires Krusader restart * @param page The subpage of a Konfigurator page (because of setDefaults) * * @return reference to the newly created font chooser */ KonfiguratorFontChooser *createFontChooser(QString configGroup, QString name, QFont defaultValue, QWidget *parent = 0, bool restart = false, int page = FIRST_PAGE); /** * Adds a new combobox item to the page. *
The combobox widget's name is QString(configGroup + "/" + name).ascii()
* * Sample:

* KONFIGURATOR_NAME_VALUE_PAIR comboInfo[] =
*  {{ i18n( "combo text1" ), "value1" },
*   { i18n( "combo text2" ), "value2" },
*   { i18n( "combo text3" ), "value3" }};

* KonfiguratorComboBox *myComboBox = createComboBox( "class", "name", "value2", comboInfo, 3, parentWidget );
* myLayout->addWidget( myComboBox, 0, 0 ); * * @param configGroup The class name used in KConfig (ex. "Archives") * @param name The item name used in KConfig (ex. "Do Tar") * @param defaultValue The default value of the combobox * @param params Pointer to the name-value pair array (combo elements) * @param paramNum Number of the combobox elements * @param parent Reference to the parent widget * @param restart The change of this parameter requires Krusader restart * @param editable Flag indicates that the combo can be edited * @param page The subpage of a Konfigurator page (because of setDefaults) * * @return reference to the newly created combobox */ KonfiguratorComboBox *createComboBox(QString configGroup, QString name, QString defaultValue, KONFIGURATOR_NAME_VALUE_PAIR *params, int paramNum, QWidget *parent = 0, bool restart = false, bool editable = false, int page = FIRST_PAGE); /** * Creates a frame on the page. * * Sample:

* QGroupBox *myGroup = createFrame( i18n( "MyFrameName" ), parentWidget, "frameName" );
* myLayout->addWidget( myGroup, 0, 0 ); * * @param text The text written out onto the frame * @param parent Reference to the parent widget * * @return reference to the newly created frame */ QGroupBox *createFrame(QString text = QString(), QWidget *parent = 0); /** * Creates a new QGridLayout element and sets its margins. * * Sample:

* QGroupBox *myGroup = createFrame( i18n( "MyFrameName" ), parentWidget, "frameName" );
* QGridLayout *myLayout = createGridLayout( myGroup ) );
* myLayout->addWidget( myGroup, 0, 0 ); * * @param parent Reference to the parent layout * * @return reference to the newly created QGridLayout */ QGridLayout *createGridLayout(QWidget *parent); /** * Adds a new label to a grid layout. * * Sample:

* QGroupBox *myGroup = createFrame( i18n( "MyFrameName" ), parentWidget, "frameName" );
* QGridLayout *myLayout = createGridLayout( myGroup->layout() );
* addLabel( myLayout, 0, 0, i18n( "Hello world!" ), myGroup, "myLabel" );
* mainLayout->addWidget( myGroup, 0, 0 ); * * @param layout The grid layout on which the item will be placed * @param x the column to which the label will be placed * @param y the row to which the label will be placed * @param label the text of the label * @param parent Reference to the parent widget * * @return reference to the newly created label */ QLabel *addLabel(QGridLayout *layout, int x, int y, QString label, QWidget *parent = 0); /** * Creates a spacer object (for justifying in QHBox). * * Sample:

* QHBox *hbox = new QHBox( myParent, "hbox" );
* createSpinBox( "class", "spin", 5, 1, 10, hbox );
* createSpacer( hbox );
* myLayout->addWidget( hbox, 0, 0 ); * * @param parent Reference to the parent widget * * @return reference to the newly created spacer widget */ QWidget *createSpacer(QWidget *parent = 0); /** * Creates a separator line. * * Sample:

* QFrame *myLine = createLine( myParent, "myLine" );
* myLayout->addWidget( myLine, 1, 0 );
* * @param parent Reference to the parent widget * @param vertical Means vertical line * * @return reference to the newly created spacer widget */ QFrame *createLine(QWidget *parent = 0, bool vertical = false); /** * Creates a checkbox group. A checkbox group contains a lot of checkboxes. * The grouped checkboxes are embedded into one widget, which can be placed anywhere * on the GUI. The placing of the elements can be horizontal or vertical in the group. * At horizontal placing the sizex integer defines the maximum element number in * one row, sizey is 0. At vertical placing sizex is 0, and sizey defines the * maximum row number in one column.
* * One specific element can be reached by its name or index with the find methods. * The first element is checkBoxGroup->find( 0 ), "myCb" element is checkBoxGroup->find( "myCb") ... * * Sample:

* KONFIGURATOR_CHECKBOX_PARAM myCBArray[] =
*  {{"CbClass","CbName1", false, i18n( "name1" ), false, "tooltip1"},
*   {"CbClass","CbName2", true, i18n( "name2" ), false, "tooltip2"},
*   {"CbClass","CbName3", true, i18n( "name3" ), false, "tooltip3"}};

* KonfiguratorCheckBoxGroup *myCheckBoxGroup = createCheckBoxGroup( 1, 0, myCBArray, 3, myParent, "myCheckboxGroup" );
* myCheckBoxGroup->find( 0 )->setEnabled( false );

* myLayout->addWidget( myCheckBoxGroup, 0, 0 );
* * @param sizex the maximum column number at horizontal placing * @param sizey the maximum row number at vertical placing * @param params pointer to the checkbox array * @param paramNum number of the checkbox elements * @param parent Reference to the parent widget * @param page The subpage of a Konfigurator page (because of setDefaults) * * @return reference to the newly created checkbox group widget */ KonfiguratorCheckBoxGroup *createCheckBoxGroup(int sizex, int sizey, KONFIGURATOR_CHECKBOX_PARAM *params, int paramNum, QWidget *parent = 0, int page = FIRST_PAGE); /** * Creates a radio button group. A radio button group contains a lot of radio buttons. * The grouped buttons are embedded into one widget, which can be placed anywhere * on the GUI. The placing of the elements can be horizontal or vertical in the group. * At horizontal placing the sizex integer defines the maximum element number in * one row, sizey is 0. At vertical placing sizex is 0, and sizey defines the * maximum row number in one column.
* * The references of the buttons can be accessed by the find methods of KonfiguratorRadioButtons. * The first element is myRadioGrp->find( 0 ), "myRadio" element is myRadioGrp->find( "myRadio") ... * * Sample:

* KONFIGURATOR_NAME_VALUE_TIP radioInfo[] =
*  {{ i18n( "radio text1" ), "value1", i18n( "tooltip1" ) },
*   { i18n( "radio text2" ), "value2", i18n( "tooltip2" ) },
*   { i18n( "radio text3" ), "value3", i18n( "tooltip3" ) }};

* KonfiguratorRadioButtons *myRadioGroup = createRadioButtonGroup( "class", "name", "value1", * 1, 0, radioInfo, 3, myParent, "myRadioGroup" );
* myRadioGroup->find( i18n( "radio text1" ) )->setEnabled( false );
* myLayout->addWidget( myRadioGroup, 0, 0 );
* * @param configGroup The class name used in KConfig (ex. "Archives") * @param name The item name used in KConfig (ex. "Do Tar") * @param defaultValue The default value of the radio buttons * @param sizex the maximum column number at horizontal placing * @param sizey the maximum row number at vertical placing * @param params pointer to the checkbox array * @param paramNum number of the checkbox elements * @param parent Reference to the parent widget * @param restart The change of this parameter requires Krusader restart * @param page The subpage of a Konfigurator page (because of setDefaults) * * @return reference to the newly created radio button group widget */ KonfiguratorRadioButtons *createRadioButtonGroup(QString configGroup, QString name, QString defaultValue, int sizex, int sizey, KONFIGURATOR_NAME_VALUE_TIP *params, int paramNum, QWidget *parent = 0, bool restart = false, int page = FIRST_PAGE); /** * This function is used to insert new, unknown items into KonfiguratorPage. The * item must be derived from KonfiguratorExtension class, which have * isChanged(), apply(), setDefaults, loadInitialValue() methods. After that, the * object is properly handled by Konfigurator page. * * * @param item The item to be added to KonfiguratorPage */ void registerObject(KonfiguratorExtension *item); /** * This function is used to remove elements from KonfiguratorPage. * * Sample:

* KonfiguratorEditBox *myEditBox = createEditBox( "class", "name", "default", parentWidget);
* myLayout->addWidget( myEditBox, 0, 0 );
* removeObject( myEditBox->extension() ); * * After the removeObject myEditBox will be untouched at apply(), setDefaults(), isChanged(), * loadInitialValues() methods of the KonfiguratorPage. * * @param item The item to be removed from KonfiguratorPage */ void removeObject(KonfiguratorExtension *item); /** * Adds a new color chooser combobox item to the page. *
The chooser's widget's name is QString(configGroup + "/" + name).ascii()
* * Sample:

* KonfiguratorColorChooser *myColorChooser = createColorChooser( "class", "name", QColor( 255, 0, 255 ), parentWidget );
* myLayout->addWidget( myColorChooser, 0, 0 ); * * @param configGroup The class name used in KConfig (ex. "Archives") * @param name The item name used in KConfig (ex. "Do Tar") * @param defaultValue The default value of the color chooser * @param parent Reference to the parent widget * @param restart The change of this parameter requires Krusader restart * @param addColPtr The additional color values - * @param restart Number of additional colors + * @param addColNum Number of additional colors * @param page The subpage of a Konfigurator page (because of setDefaults) * * @return reference to the newly created combobox */ KonfiguratorColorChooser *createColorChooser(QString configGroup, QString name, QColor defaultValue, QWidget *parent = 0, bool restart = false, ADDITIONAL_COLOR *addColPtr = 0, int addColNum = 0, int page = FIRST_PAGE); signals: /** * The signal is emitted if the changed flag was modified in any konfigurator item. * Used for enabling/disabling the apply button. */ void sigChanged(); protected: QList itemList; private: bool firstCall; }; /** * KONFIGURATOR_CHECKBOX_PARAM is the basic item of checkbox arrays. It contains * every information related to a checkbox. */ struct KONFIGURATOR_CHECKBOX_PARAM { /** * The class used in KConfig (ex. "Archives") */ QString configClass; /** * The item name used in KConfig (ex. "Do Tar") */ QString configName; /** * The default value of the checkbox */ bool defaultValue; /** * The text field of the checkbox */ QString text; /** * The change of this parameter requires Krusader restart */ bool restart; /** * The checkbox's tooltip */ QString toolTip; }; #endif /* __KONFIGURATOR_PAGE_H__ */ diff --git a/krusader/UserAction/expander.h b/krusader/UserAction/expander.h index 732c9b8b..2c4a685f 100644 --- a/krusader/UserAction/expander.h +++ b/krusader/UserAction/expander.h @@ -1,285 +1,285 @@ /***************************************************************************** * Copyright (C) 2004 Jonas Bähr * * Copyright (C) 2004 Shie Erlich * * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * * * * This file is part of Krusader [https://krusader.org]. * * * * Krusader is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 2 of the License, or * * (at your option) any later version. * * * * Krusader is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with Krusader. If not, see [http://www.gnu.org/licenses/]. * *****************************************************************************/ #ifndef EXPANDER_H #define EXPANDER_H // QtCore #include #include #include # include "tstring.h" class KrPanel; class Expander; class Error; typedef TagString_t TagString; typedef QList TagStringList; /** * This holds the information about each parameter */ class exp_parameter { public: exp_parameter() {} inline exp_parameter(QString desc, QString pre, bool ness) { _description = desc; _preset = pre; _necessary = ness; } inline QString description() const { ///< A description of the parameter return _description; } inline QString preset() const { ///< the default of the parameter return _preset; } inline bool necessary() const { ///< false if the parameter is optional return _necessary; } private: QString _description; QString _preset; bool _necessary; }; #define EXP_FUNC virtual TagString expFunc ( const KrPanel*, const TagStringList&, const bool&, Expander& ) const #define SIMPLE_EXP_FUNC virtual TagString expFunc ( const KrPanel*, const QStringList&, const bool&, Expander& ) const /** * Abstract baseclass for all expander-functions (which replace placeholder). * A Placeholder is an entry containing the expression, * its expanding function and Parameter. * * Not to be created on the heap */ class exp_placeholder { public: inline QString expression() const { ///< The placeholder (without '%' or panel-prefix) return _expression; } inline QString description() const { ///< A description of the placeholder return _description; } inline bool needPanel() const { ///< true if the placeholder needs a panel to operate on return _needPanel; } inline void addParameter(exp_parameter parameter) { ///< adds parameter to the placeholder _parameter.append(parameter); } inline int parameterCount() const { ///< returns the number of placeholders return _parameter.count(); } inline const exp_parameter& parameter(int id) const { ///< returns a specific parameter return _parameter[ id ]; } EXP_FUNC = 0; protected: static void setError(Expander& exp, const Error& e); static void panelMissingError(const QString &s, Expander& exp); static QStringList splitEach(const TagString& s); static QStringList fileList(const KrPanel* const panel, const QString& type, const QString& mask, const bool omitPath, const bool useUrl, Expander&, const QString&); exp_placeholder(); exp_placeholder(const exp_placeholder& p); virtual ~exp_placeholder() { } QString _expression; QString _description; QList _parameter; bool _needPanel; }; class Error { public: enum Cause { exp_C_USER, exp_C_SYNTAX, exp_C_WORLD, exp_C_ARGUMENT }; enum Severity { exp_S_OK, exp_S_WARNING, exp_S_ERROR, exp_S_FATAL }; Error() : m_severity(exp_S_OK) {} Error(Severity severity, Cause cause) : m_severity(severity), m_cause(cause), m_description() {} Error(Severity severity, Cause cause, QString description) : m_severity(severity), m_cause(cause), m_description(description) {} operator bool() const { return m_severity != exp_S_OK; } Cause cause() const { return m_cause; } const QString &description() const { return m_description; } private: Severity m_severity; Cause m_cause; QString m_description; }; /** * The Expander expands the command of an UserAction by replacing all * placeholders by their current values.@n * Each placeholder begins with a '%'-sign, followed by one char indicating * the panel, followed by a command which may have some parameter enclosed * in brackets and also ends with a '%'-sign. * Examples are %aPath% or %rBookmark("/home/jonas/src/krusader_kde3", "yes")%.@n * The panel-indicator has to be either * 'a' for the active * 'o' for the other * 'r' for the right * 'l' for the left * '_' for panel-independence. * * Currently supported are these commands can be ordered in three groups * (children are the parameter in the right order): * - Placeholders for Krusaders panel-data (panel-indicator has to be 'a', 'o', 'r' or 'l') * - @em Path is replaced by the panel's path * - @em Count is replaced by a nomber of * -# Either "All", "Files", "Dirs", "Selected" * . * - @em Filter is preplaced by the panels filter-mask (ex: "*.cpp *.h") * - @em Current is replaced by the current item or, in case of onmultiple="call_each", by each selected item. * -# If "yes", only the filename (without path) is returned * . * - @em List isreplaced by a list of * -# Either "All", "Files", "Dirs", "Selected" * -# A separator between the items (default: " " [one space]) * -# If "yes", only the filename (without path) is returned * -# (for all but "Selected") a filter-mask (default: "*") * . * . * - Access to panel-dependent, krusader-internal, parameter-needed functions * (panel-indicator has to be 'a', 'o', 'r' or 'l') * - @em Select manipulates the selection of the panel * -# A filter-mask (necessary) * -# Either "Add", "Remove", "Set" (default) * . * - @em Bookmark manipulates the selection of the panel * -# A path or URL (necessary) * -# If "yes", the location is opened in a new tab * . * . * - Access to panel-independent, krusader-internal, parameter-needed functions * (panel-indicator doesn't matter but should be set to '_') * - @em Ask displays a lineedit and is replaced by its return * -# The question (necessary) * -# A default answer * -# A cation for the popup * . * - @em Clipboard manipulates the system-wide clipboard * -# The string copied to clip (ex: "%aCurrent%") (necessary) * -# A separator. If set, parameter1 is append with this to the current clipboard content * . * . * . * Since all placeholders are expanded in the order they appear in the command, * little one-line-scripts are possible */ class Expander { public: inline static int placeholderCount() { ///< returns the number of placeholders return _placeholder().count(); } inline static const exp_placeholder* placeholder(int id) { return _placeholder()[ id ]; } /** * This expands a whole commandline * * @param stringToExpand the commandline with the placeholder * @param useUrl true iff the path's should be expanded to an URL instead of an local path * @return a list of all commands */ void expand(const QString& stringToExpand, bool useUrl); /** * Returns the list of all commands to be executed, provided that #expand was called - * before, and there was no error (see #error). Otherwise, calls #abort + * before, and there was no error (see #error). * * @return The list of commands to be executed */ const QStringList& result() const { assert(!error()); return resultList; } /** * Returns the error object of this Expander. You can test whether there was * any error by * \code * if(exp.error()) * error behaviour... * else * no error... * \endcode * * @return The error object */ const Error& error() const { return _err; } protected: /** * This expands a whole commandline by calling for each Placeholder the corresponding expander * * @param stringToExpand the commandline with the placeholder * @param useUrl true if the path's should be expanded to an URL instead of an local path * @return the expanded commanline for the current item */ TagString expandCurrent(const QString& stringToExpand, bool useUrl); /** * This function searches for "\@EACH"-marks to split the string in a list for each %_Each%-item * * @param stringToSplit the string which should be split * @return the split list */ static QStringList splitEach(TagString stringToSplit); /** * @param panelIndicator either '_' for panel-independent placeholders, 'a', 'o', 'r', or 'l' for the active, other (inactive), right or left panel * @param pl placeholder * @param exp expander * @return a pointer to the right panel or NULL if no panel is needed. */ static KrPanel* getPanel(const char panelIndicator , const exp_placeholder*, Expander&); /** * This splits the parameter-string into separate parameter and expands each * @param exp the string holding all parameter * @param useUrl true if the path's should be expanded to an URL instead of an local path * @return a list of all parameter */ TagStringList separateParameter(QString* const exp, bool useUrl); /** * This finds the end of a placeholder, taking care of the parameter * @return the position where the placeholder ends */ int findEnd(const QString& str, int start); void setError(const Error &e) { _err = e; } friend class exp_placeholder; private: static QList & _placeholder(); Error _err; QStringList resultList; }; #endif // ifndef EXPANDER_H