diff --git a/krusader/ActionMan/actionproperty.cpp b/krusader/ActionMan/actionproperty.cpp index ee0b2281..2338b384 100644 --- a/krusader/ActionMan/actionproperty.cpp +++ b/krusader/ActionMan/actionproperty.cpp @@ -1,520 +1,518 @@ /***************************************************************************** * Copyright (C) 2004-2007 Jonas Bähr * * 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 "actionproperty.h" #include "addplaceholderpopup.h" #include "../UserAction/useraction.h" #include "../UserAction/kraction.h" #include "../krusader.h" #include "../krglobal.h" +#include "../icon.h" // QtWidgets #include #include #include -#include #include #include -#define ICON(N) KIconLoader::global()->loadIcon(N, KIconLoader::Small) - ActionProperty::ActionProperty(QWidget *parent, KrAction *action) : QWidget(parent), _modified(false) { setupUi(this); if (action) { _action = action; updateGUI(_action); } - ButtonAddPlaceholder->setIcon(ICON("list-add")); - ButtonAddStartpath->setIcon(ICON("document-open")); + ButtonAddPlaceholder->setIcon(Icon("list-add")); + ButtonAddStartpath->setIcon(Icon("document-open")); // fill with all existing categories cbCategory->addItems(krUserAction->allCategories()); connect(ButtonAddPlaceholder, SIGNAL(clicked()), this, SLOT(addPlaceholder())); connect(ButtonAddStartpath, SIGNAL(clicked()), this, SLOT(addStartpath())); connect(ButtonNewProtocol, SIGNAL(clicked()), this, SLOT(newProtocol())); connect(ButtonEditProtocol, SIGNAL(clicked()), this, SLOT(editProtocol())); connect(ButtonRemoveProtocol, SIGNAL(clicked()), this, SLOT(removeProtocol())); connect(ButtonAddPath, SIGNAL(clicked()), this, SLOT(addPath())); connect(ButtonEditPath, SIGNAL(clicked()), this, SLOT(editPath())); connect(ButtonRemovePath, SIGNAL(clicked()), this, SLOT(removePath())); connect(ButtonAddMime, SIGNAL(clicked()), this, SLOT(addMime())); connect(ButtonEditMime, SIGNAL(clicked()), this, SLOT(editMime())); connect(ButtonRemoveMime, SIGNAL(clicked()), this, SLOT(removeMime())); connect(ButtonNewFile, SIGNAL(clicked()), this, SLOT(newFile())); connect(ButtonEditFile, SIGNAL(clicked()), this, SLOT(editFile())); connect(ButtonRemoveFile, SIGNAL(clicked()), this, SLOT(removeFile())); connect(KeyButtonShortcut, SIGNAL(keySequenceChanged(QKeySequence)), this, SLOT(changedShortcut(QKeySequence))); // track modifications: connect(leDistinctName, SIGNAL(textChanged(QString)), SLOT(setModified())); connect(leTitle, SIGNAL(textChanged(QString)), SLOT(setModified())); connect(ButtonIcon, SIGNAL(iconChanged(QString)), SLOT(setModified())); connect(cbCategory, SIGNAL(currentTextChanged(QString)), SLOT(setModified())); connect(leTooltip, SIGNAL(textChanged(QString)), SLOT(setModified())); connect(textDescription, SIGNAL(textChanged()), SLOT(setModified())); connect(leCommandline, SIGNAL(textChanged(QString)), SLOT(setModified())); connect(leStartpath, SIGNAL(textChanged(QString)), SLOT(setModified())); connect(chkSeparateStdError, SIGNAL(clicked()), SLOT(setModified())); connect(radioCollectOutput, SIGNAL(clicked()), SLOT(setModified())); connect(radioNormal, SIGNAL(clicked()), SLOT(setModified())); connect(radioTE, SIGNAL(clicked()), SLOT(setModified())); connect(radioTerminal, SIGNAL(clicked()), SLOT(setModified())); connect(radioLocal, SIGNAL(clicked()), SLOT(setModified())); connect(radioUrl, SIGNAL(clicked()), SLOT(setModified())); connect(KeyButtonShortcut, SIGNAL(keySequenceChanged(QKeySequence)), SLOT(setModified())); connect(chkEnabled, SIGNAL(clicked()), SLOT(setModified())); connect(leDifferentUser, SIGNAL(textChanged(QString)), SLOT(setModified())); connect(chkDifferentUser, SIGNAL(clicked()), SLOT(setModified())); connect(chkConfirmExecution, SIGNAL(clicked()), SLOT(setModified())); connect(chkSeparateStdError, SIGNAL(clicked()), SLOT(setModified())); // The modified-state of the ShowOnly-lists is tracked in the access-functions below } ActionProperty::~ActionProperty() { } void ActionProperty::changedShortcut(const QKeySequence& shortcut) { KeyButtonShortcut->setKeySequence(shortcut); } void ActionProperty::clear() { _action = 0; // This prevents the changed-signal from being emitted during the GUI-update _modified = true; // The real state is set at the end of this function. leDistinctName->clear(); cbCategory->clearEditText(); leTitle->clear(); leTooltip->clear(); textDescription->clear(); leCommandline->clear(); leStartpath->clear(); KeyButtonShortcut->clearKeySequence(); lbShowonlyProtocol->clear(); lbShowonlyPath->clear(); lbShowonlyMime->clear(); lbShowonlyFile->clear(); chkSeparateStdError->setChecked(false); radioNormal->setChecked(true); radioLocal->setChecked(true); chkEnabled->setChecked(true); chkConfirmExecution->setChecked(false); ButtonIcon->resetIcon(); leDifferentUser->clear(); chkDifferentUser->setChecked(false); setModified(false); } void ActionProperty::updateGUI(KrAction *action) { if (action) _action = action; if (! _action) return; // This prevents the changed-signal from being emitted during the GUI-update. _modified = true; // The real state is set at the end of this function. leDistinctName->setText(_action->objectName()); cbCategory->lineEdit()->setText(_action->category()); leTitle->setText(_action->text()); leTooltip->setText(_action->toolTip()); textDescription->setText(_action->whatsThis()); leCommandline->setText(_action->command()); leCommandline->home(false); leStartpath->setText(_action->startpath()); KeyButtonShortcut->setKeySequence(_action->shortcut()); lbShowonlyProtocol->clear(); lbShowonlyProtocol->addItems(_action->showonlyProtocol()); lbShowonlyPath->clear(); lbShowonlyPath->addItems(_action->showonlyPath()); lbShowonlyMime->clear(); lbShowonlyMime->addItems(_action->showonlyMime()); lbShowonlyFile->clear(); lbShowonlyFile->addItems(_action->showonlyFile()); chkSeparateStdError->setChecked(false); switch (_action->execType()) { case KrAction::CollectOutputSeparateStderr: chkSeparateStdError->setChecked(true); radioCollectOutput->setChecked(true); break; case KrAction::CollectOutput: radioCollectOutput->setChecked(true); break; case KrAction::Terminal: radioTerminal->setChecked(true); break; case KrAction::RunInTE: radioTE->setChecked(true); break; default: // case KrAction::Normal: radioNormal->setChecked(true); break; } if (_action->acceptURLs()) radioUrl->setChecked(true); else radioLocal->setChecked(true); chkEnabled->setChecked(_action->isVisible()); chkConfirmExecution->setChecked(_action->confirmExecution()); if (! _action->icon().isNull()) ButtonIcon->setIcon(_action->icon()); else ButtonIcon->resetIcon(); leDifferentUser->setText(_action->user()); if (_action->user().isEmpty()) chkDifferentUser->setChecked(false); else chkDifferentUser->setChecked(true); setModified(false); } void ActionProperty::updateAction(KrAction *action) { if (action) _action = action; if (! _action) return; if (_action->category() != cbCategory->currentText()) { _action->setCategory(cbCategory->currentText()); // Update the category-list cbCategory->clear(); cbCategory->addItems(krUserAction->allCategories()); cbCategory->lineEdit()->setText(_action->category()); } _action->setObjectName(leDistinctName->text()); _action->setText(leTitle->text()); _action->setToolTip(leTooltip->text()); _action->setWhatsThis(textDescription->toPlainText()); _action->setCommand(leCommandline->text()); _action->setStartpath(leStartpath->text()); _action->setShortcut(KeyButtonShortcut->keySequence()); QStringList list; for (int i1 = 0; i1 != lbShowonlyProtocol->count(); i1++) { QListWidgetItem* lbi = lbShowonlyProtocol->item(i1); list << lbi->text(); } _action->setShowonlyProtocol(list); list = QStringList(); for (int i1 = 0; i1 != lbShowonlyPath->count(); i1++) { QListWidgetItem* lbi = lbShowonlyPath->item(i1); list << lbi->text(); } _action->setShowonlyPath(list); list = QStringList(); for (int i1 = 0; i1 != lbShowonlyMime->count(); i1++) { QListWidgetItem* lbi = lbShowonlyMime->item(i1); list << lbi->text(); } _action->setShowonlyMime(list); list = QStringList(); for (int i1 = 0; i1 != lbShowonlyFile->count(); i1++) { QListWidgetItem* lbi = lbShowonlyFile->item(i1); list << lbi->text(); } _action->setShowonlyFile(list); if (radioCollectOutput->isChecked() && chkSeparateStdError->isChecked()) _action->setExecType(KrAction::CollectOutputSeparateStderr); else if (radioCollectOutput->isChecked() && ! chkSeparateStdError->isChecked()) _action->setExecType(KrAction::CollectOutput); else if (radioTerminal->isChecked()) _action->setExecType(KrAction::Terminal); else if (radioTE->isChecked()) _action->setExecType(KrAction::RunInTE); else _action->setExecType(KrAction::Normal); if (radioUrl->isChecked()) _action->setAcceptURLs(true); else _action->setAcceptURLs(false); _action->setEnabled(chkEnabled->isChecked()); _action->setVisible(chkEnabled->isChecked()); _action->setConfirmExecution(chkConfirmExecution->isChecked()); - _action->setIcon(QIcon::fromTheme(ButtonIcon->icon())); + _action->setIcon(Icon(ButtonIcon->icon())); _action->setIconName(ButtonIcon->icon()); _action->setUser(leDifferentUser->text()); setModified(false); } void ActionProperty::addPlaceholder() { AddPlaceholderPopup popup(this); QString exp = popup.getPlaceholder(mapToGlobal( QPoint( ButtonAddPlaceholder->pos().x() + ButtonAddPlaceholder->width() + 6, // 6 is the default margin ButtonAddPlaceholder->pos().y() ) )); leCommandline->insert(exp); } void ActionProperty::addStartpath() { QString folder = QFileDialog::getExistingDirectory(this); if (!folder.isEmpty()) { leStartpath->setText(folder); } } void ActionProperty::newProtocol() { bool ok; QString currentText; if (lbShowonlyProtocol->currentItem()) currentText = lbShowonlyProtocol->currentItem()->text(); QString text = QInputDialog::getText(this, i18n("New protocol"), i18n("Set a protocol:"), QLineEdit::Normal, currentText, &ok); if (ok && !text.isEmpty()) { lbShowonlyProtocol->addItems(text.split(';')); setModified(); } } void ActionProperty::editProtocol() { if (lbShowonlyProtocol->currentItem() == 0) return; bool ok; QString currentText = lbShowonlyProtocol->currentItem()->text(); QString text = QInputDialog::getText(this, i18n("Edit Protocol"), i18n("Set another protocol:"), QLineEdit::Normal, currentText, &ok); if (ok && !text.isEmpty()) { lbShowonlyProtocol->currentItem()->setText(text); setModified(); } } void ActionProperty::removeProtocol() { if (lbShowonlyProtocol->currentItem() != 0) { delete lbShowonlyProtocol->currentItem(); setModified(); } } void ActionProperty::addPath() { QString folder = QFileDialog::getExistingDirectory(this); if (!folder.isEmpty()) { lbShowonlyPath->addItem(folder); setModified(); } } void ActionProperty::editPath() { if (lbShowonlyPath->currentItem() == 0) return; bool ok; QString currentText = lbShowonlyPath->currentItem()->text(); QString text = QInputDialog::getText(this, i18n("Edit Path"), i18n("Set another path:"), QLineEdit::Normal, currentText, &ok); if (ok && !text.isEmpty()) { lbShowonlyPath->currentItem()->setText(text); setModified(); } } void ActionProperty::removePath() { if (lbShowonlyPath->currentItem() != 0) { delete lbShowonlyPath->currentItem(); setModified(); } } void ActionProperty::addMime() { bool ok; QString currentText; if (lbShowonlyMime->currentItem()) currentText = lbShowonlyMime->currentItem()->text(); QString text = QInputDialog::getText(this, i18n("New MIME Type"), i18n("Set a MIME type:"), QLineEdit::Normal, currentText, &ok); if (ok && !text.isEmpty()) { lbShowonlyMime->addItems(text.split(';')); setModified(); } } void ActionProperty::editMime() { if (lbShowonlyMime->currentItem() == 0) return; bool ok; QString currentText = lbShowonlyMime->currentItem()->text(); QString text = QInputDialog::getText(this, i18n("Edit MIME Type"), i18n("Set another MIME type:"), QLineEdit::Normal, currentText, &ok); if (ok && !text.isEmpty()) { lbShowonlyMime->currentItem()->setText(text); setModified(); } } void ActionProperty::removeMime() { if (lbShowonlyMime->currentItem() != 0) { delete lbShowonlyMime->currentItem(); setModified(); } } void ActionProperty::newFile() { bool ok; QString currentText; if (lbShowonlyFile->currentItem()) currentText = lbShowonlyFile->currentItem()->text(); QString text = QInputDialog::getText(this, i18n("New File Name"), i18n("Set a file name:"), QLineEdit::Normal, currentText, &ok); if (ok && !text.isEmpty()) { lbShowonlyFile->addItems(text.split(';')); setModified(); } } void ActionProperty::editFile() { if (lbShowonlyFile->currentItem() == 0) return; bool ok; QString currentText = lbShowonlyFile->currentItem()->text(); QString text = QInputDialog::getText(this, i18n("Edit File Name"), i18n("Set another file name:"), QLineEdit::Normal, currentText, &ok); if (ok && !text.isEmpty()) { lbShowonlyFile->currentItem()->setText(text); setModified(); } } void ActionProperty::removeFile() { if (lbShowonlyFile->currentItem() != 0) { delete lbShowonlyFile->currentItem(); setModified(); } } bool ActionProperty::validProperties() { if (leDistinctName->text().simplified().isEmpty()) { KMessageBox::error(this, i18n("Please set a unique name for the useraction")); leDistinctName->setFocus(); return false; } if (leTitle->text().simplified().isEmpty()) { KMessageBox::error(this, i18n("Please set a title for the menu entry")); leTitle->setFocus(); return false; } if (leCommandline->text().simplified().isEmpty()) { KMessageBox::error(this, i18n("Command line is empty")); leCommandline->setFocus(); return false; } if (leDistinctName->isEnabled()) if (krApp->actionCollection()->action(leDistinctName->text())) { KMessageBox::error(this, i18n("There already is an action with this name.\n" "If you do not have such a useraction the name is used by Krusader for an internal action.") ); leDistinctName->setFocus(); return false; } return true; } void ActionProperty::setModified(bool m) { if (m && !_modified) { // emit only when the state _changes_to_true_, emit changed(); } _modified = m; } diff --git a/krusader/ActionMan/addplaceholderpopup.cpp b/krusader/ActionMan/addplaceholderpopup.cpp index ac86d03d..d9008f35 100644 --- a/krusader/ActionMan/addplaceholderpopup.cpp +++ b/krusader/ActionMan/addplaceholderpopup.cpp @@ -1,702 +1,703 @@ /***************************************************************************** * Copyright (C) 2004 Shie Erlich * * Copyright (C) 2004 Rafi Yanai * * Copyright (C) 2004 Jonas Bähr * * 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 "addplaceholderpopup.h" // for ParameterDialog #include "../krglobal.h" // for konfig-access +#include "../icon.h" #include "../BookMan/krbookmarkbutton.h" #include "../GUI/profilemanager.h" // QtWidgets #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define ACTIVE_MASK 0x0100 #define OTHER_MASK 0x0200 #define LEFT_MASK 0x0400 #define RIGHT_MASK 0x0800 #define INDEPENDENT_MASK 0x1000 #define EXECUTABLE_ID 0xFFFF AddPlaceholderPopup::AddPlaceholderPopup(QWidget *parent) : QMenu(parent) { _activeSub = new QMenu(i18n("Active panel"), this); _otherSub = new QMenu(i18n("Other panel"), this); _leftSub = new QMenu(i18n("Left panel"), this); _rightSub = new QMenu(i18n("Right panel"), this); _independentSub = new QMenu(i18n("Panel independent"), this); addMenu(_activeSub); addMenu(_otherSub); addMenu(_leftSub); addMenu(_rightSub); addMenu(_independentSub); QAction *chooseExecAct = _independentSub->addAction(i18n("Choose executable...")); chooseExecAct->setData(QVariant(EXECUTABLE_ID)); _independentSub->addSeparator(); // read the expressions array from the user menu and populate menus Expander expander; for (int i = 0; i < expander.placeholderCount(); ++i) { if (expander.placeholder(i)->expression().isEmpty()) { if (expander.placeholder(i)->needPanel()) { _activeSub->addSeparator(); _otherSub->addSeparator(); _leftSub->addSeparator(); _rightSub->addSeparator(); } else _independentSub->addSeparator(); } else { QAction * action; if (expander.placeholder(i)->needPanel()) { action = _activeSub->addAction(i18n(expander.placeholder(i)->description().toUtf8())); action->setData(QVariant(i | ACTIVE_MASK)); action = _otherSub->addAction(i18n(expander.placeholder(i)->description().toUtf8())); action->setData(QVariant(i | OTHER_MASK)); action = _leftSub->addAction(i18n(expander.placeholder(i)->description().toUtf8())); action->setData(QVariant(i | LEFT_MASK)); action = _rightSub->addAction(i18n(expander.placeholder(i)->description().toUtf8())); action->setData(QVariant(i | RIGHT_MASK)); } else { action = _independentSub->addAction(i18n(expander.placeholder(i)->description().toUtf8())); action->setData(QVariant(i | INDEPENDENT_MASK)); } } } } QString AddPlaceholderPopup::getPlaceholder(const QPoint& pos) { QAction *res = exec(pos); if (res == 0) return QString(); // add the selected flag to the command line if (res->data().toInt() == EXECUTABLE_ID) { // did the user need an executable ? // select an executable QString filename = QFileDialog::getOpenFileName(this); if (!filename.isEmpty()) { return filename + ' '; // with extra space // return filename; // without extra space } } else { // user selected something from the menus Expander expander; const exp_placeholder* currentPlaceholder = expander.placeholder(res->data().toInt() & ~(ACTIVE_MASK | OTHER_MASK | LEFT_MASK | RIGHT_MASK | INDEPENDENT_MASK)); // if ( ¤tPlaceholder->expFunc == 0 ) { // KMessageBox::sorry( this, "BOFH Excuse #93:\nFeature not yet implemented" ); // return QString(); // } ParameterDialog* parameterDialog = new ParameterDialog(currentPlaceholder, this); QString panel, parameter = parameterDialog->getParameter(); delete parameterDialog; // indicate the panel with 'a' 'o', 'l', 'r' or '_'. if (res->data().toInt() & ACTIVE_MASK) panel = 'a'; else if (res->data().toInt() & OTHER_MASK) panel = 'o'; else if (res->data().toInt() & LEFT_MASK) panel = 'l'; else if (res->data().toInt() & RIGHT_MASK) panel = 'r'; else if (res->data().toInt() & INDEPENDENT_MASK) panel = '_'; //return '%' + panel + currentPlaceholder->expression() + parameter + "% "; // with extra space return '%' + panel + currentPlaceholder->expression() + parameter + '%'; // without extra space } return QString(); } //////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////// ParameterDialog //////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////// ParameterDialog::ParameterDialog(const exp_placeholder* currentPlaceholder, QWidget *parent) : QDialog(parent) { setWindowTitle(i18n("User Action Parameter Dialog")); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); _parameter.clear(); _parameterCount = currentPlaceholder->parameterCount(); QWidget *page = new QWidget(this); mainLayout->addWidget(page); QVBoxLayout* layout = new QVBoxLayout(page); layout->setSpacing(11); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(new QLabel(i18n("This placeholder allows some parameter:"), page)); for (int i = 0; i < _parameterCount; ++i) { if (currentPlaceholder->parameter(i).preset() == "__placeholder") _parameter.append(new ParameterPlaceholder(currentPlaceholder->parameter(i), page)); else if (currentPlaceholder->parameter(i).preset() == "__yes") _parameter.append(new ParameterYes(currentPlaceholder->parameter(i), page)); else if (currentPlaceholder->parameter(i).preset() == "__no") _parameter.append(new ParameterNo(currentPlaceholder->parameter(i), page)); else if (currentPlaceholder->parameter(i).preset() == "__file") _parameter.append(new ParameterFile(currentPlaceholder->parameter(i), page)); else if (currentPlaceholder->parameter(i).preset().indexOf("__choose") != -1) _parameter.append(new ParameterChoose(currentPlaceholder->parameter(i), page)); else if (currentPlaceholder->parameter(i).preset() == "__select") _parameter.append(new ParameterSelect(currentPlaceholder->parameter(i), page)); else if (currentPlaceholder->parameter(i).preset() == "__goto") _parameter.append(new ParameterGoto(currentPlaceholder->parameter(i), page)); else if (currentPlaceholder->parameter(i).preset() == "__syncprofile") _parameter.append(new ParameterSyncprofile(currentPlaceholder->parameter(i), page)); else if (currentPlaceholder->parameter(i).preset() == "__searchprofile") _parameter.append(new ParameterSearch(currentPlaceholder->parameter(i), page)); else if (currentPlaceholder->parameter(i).preset() == "__panelprofile") _parameter.append(new ParameterPanelprofile(currentPlaceholder->parameter(i), page)); else if (currentPlaceholder->parameter(i).preset().indexOf("__int") != -1) _parameter.append(new ParameterInt(currentPlaceholder->parameter(i), page)); else _parameter.append(new ParameterText(currentPlaceholder->parameter(i), page)); layout->addWidget(_parameter.last()); } QFrame * line = new QFrame(page); line->setFrameShape(QFrame::HLine); line->setFrameShadow(QFrame::Sunken); layout->addWidget(line); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::RestoreDefaults); mainLayout->addWidget(buttonBox); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(okButton, SIGNAL(clicked()), this, SLOT(slotOk())); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); connect(buttonBox->button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked()), this, SLOT(reset())); } QString ParameterDialog::getParameter() { if (_parameterCount == 0) // meaning no parameters return QString(); if (exec() == -1) return QString(); int lastParameter = _parameterCount; while (--lastParameter > -1) { if (_parameter[ lastParameter ]->text() != _parameter[ lastParameter ]->preset() || _parameter[ lastParameter ]->necessary()) break; } if (lastParameter < 0) // all parameters have default-values return QString(); QString parameter; for (int i = 0; i <= lastParameter; ++i) { if (i > 0) parameter += ", "; parameter += '\"' + _parameter[ i ]->text().replace('\"', "\\\"") + '\"'; } return '(' + parameter + ')'; } void ParameterDialog::reset() { for (int i = 0; i < _parameterCount; ++i) _parameter[ i ]->reset(); } void ParameterDialog::slotOk() { bool valid = true; for (int i = 0; i < _parameterCount; ++i) { if (_parameter[ i ]->necessary() && ! _parameter[ i ]->valid()) valid = false; } if (valid) accept(); } ///////////// ParameterText ParameterText::ParameterText(const exp_parameter& parameter, QWidget* parent) : ParameterBase(parameter, parent) { QVBoxLayout* layout = new QVBoxLayout(this); layout->setSpacing(6); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(new QLabel(i18n(parameter.description().toUtf8()), this)); layout->addWidget(_lineEdit = new KLineEdit(parameter.preset(), this)); _preset = parameter.preset(); } QString ParameterText::text() { return _lineEdit->text(); } QString ParameterText::preset() { return _preset; } void ParameterText::reset() { _lineEdit->setText(_preset); } bool ParameterText::valid() { if (_lineEdit->text().isEmpty()) return false; else return true; } ///////////// ParameterPlaceholder ParameterPlaceholder::ParameterPlaceholder(const exp_parameter& parameter, QWidget* parent) : ParameterBase(parameter, parent) { QVBoxLayout* layout = new QVBoxLayout(this); layout->setSpacing(6); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(new QLabel(i18n(parameter.description().toUtf8()), this)); QWidget * hboxWidget = new QWidget(this); layout->addWidget(hboxWidget); QHBoxLayout * hbox = new QHBoxLayout(hboxWidget); hbox->setContentsMargins(0, 0, 0, 0); hbox->setSpacing(6); _lineEdit = new KLineEdit(hboxWidget); hbox->addWidget(_lineEdit); _button = new QToolButton(hboxWidget); - _button->setIcon(QIcon::fromTheme("list-add")); + _button->setIcon(Icon("list-add")); hbox->addWidget(_button); connect(_button, SIGNAL(clicked()), this, SLOT(addPlaceholder())); } QString ParameterPlaceholder::text() { return _lineEdit->text(); } QString ParameterPlaceholder::preset() { return QString(); } void ParameterPlaceholder::reset() { _lineEdit->setText(QString()); } bool ParameterPlaceholder::valid() { if (_lineEdit->text().isEmpty()) return false; else return true; } void ParameterPlaceholder::addPlaceholder() { AddPlaceholderPopup* popup = new AddPlaceholderPopup(this); QString exp = popup->getPlaceholder(mapToGlobal(QPoint(_button->pos().x() + _button->width() + 6, _button->pos().y() + _button->height() / 2))); _lineEdit->insert(exp); delete popup; } ///////////// ParameterYes ParameterYes::ParameterYes(const exp_parameter& parameter, QWidget* parent) : ParameterBase(parameter, parent) { QVBoxLayout* layout = new QVBoxLayout(this); layout->setSpacing(6); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(_checkBox = new QCheckBox(i18n(parameter.description().toUtf8()), this)); _checkBox->setChecked(true); } QString ParameterYes::text() { if (_checkBox->isChecked()) return QString(); else return "No"; } QString ParameterYes::preset() { return QString(); } void ParameterYes::reset() { _checkBox->setChecked(true); } bool ParameterYes::valid() { return true; } ///////////// ParameterNo ParameterNo::ParameterNo(const exp_parameter& parameter, QWidget* parent) : ParameterBase(parameter, parent) { QVBoxLayout* layout = new QVBoxLayout(this); layout->setSpacing(6); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(_checkBox = new QCheckBox(i18n(parameter.description().toUtf8()), this)); _checkBox->setChecked(false); } QString ParameterNo::text() { if (_checkBox->isChecked()) return "Yes"; else return QString(); } QString ParameterNo::preset() { return QString(); } void ParameterNo::reset() { _checkBox->setChecked(false); } bool ParameterNo::valid() { return true; } ///////////// ParameterFile ParameterFile::ParameterFile(const exp_parameter& parameter, QWidget* parent) : ParameterBase(parameter, parent) { QVBoxLayout* layout = new QVBoxLayout(this); layout->setSpacing(6); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(new QLabel(i18n(parameter.description().toUtf8()), this)); QWidget * hboxWidget = new QWidget(this); layout->addWidget(hboxWidget); QHBoxLayout * hbox = new QHBoxLayout(hboxWidget); hbox->setContentsMargins(0, 0, 0, 0); hbox->setSpacing(6); _lineEdit = new KLineEdit(hboxWidget); hbox->addWidget(_lineEdit); _button = new QToolButton(hboxWidget); hbox->addWidget(_button); - _button->setIcon(QIcon::fromTheme("document-open")); + _button->setIcon(Icon("document-open")); connect(_button, SIGNAL(clicked()), this, SLOT(addFile())); } QString ParameterFile::text() { return _lineEdit->text(); } QString ParameterFile::preset() { return QString(); } void ParameterFile::reset() { _lineEdit->setText(QString()); } bool ParameterFile::valid() { if (_lineEdit->text().isEmpty()) return false; else return true; } void ParameterFile::addFile() { QString filename = QFileDialog::getOpenFileName(this); _lineEdit->insert(filename); } ///////////// ParameterChoose ParameterChoose::ParameterChoose(const exp_parameter& parameter, QWidget* parent) : ParameterBase(parameter, parent) { QVBoxLayout* layout = new QVBoxLayout(this); layout->setSpacing(6); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(new QLabel(i18n(parameter.description().toUtf8()), this)); layout->addWidget(_combobox = new KComboBox(this)); _combobox->addItems(parameter.preset().section(':', 1).split(';')); } QString ParameterChoose::text() { return _combobox->currentText(); } QString ParameterChoose::preset() { return _combobox->itemText(0); } void ParameterChoose::reset() { _combobox->setCurrentIndex(0); } bool ParameterChoose::valid() { return true; } ///////////// ParameterSelect ParameterSelect::ParameterSelect(const exp_parameter& parameter, QWidget* parent) : ParameterBase(parameter, parent) { QVBoxLayout* layout = new QVBoxLayout(this); layout->setSpacing(6); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(new QLabel(i18n(parameter.description().toUtf8()), this)); layout->addWidget(_combobox = new KComboBox(this)); _combobox->setEditable(true); KConfigGroup group(krConfig, "Private"); QStringList lst = group.readEntry("Predefined Selections", QStringList()); if (lst.size() > 0) _combobox->addItems(lst); _combobox->lineEdit()->setText("*"); } QString ParameterSelect::text() { return _combobox->currentText(); } QString ParameterSelect::preset() { return "*"; } void ParameterSelect::reset() { _combobox->lineEdit()->setText("*"); } bool ParameterSelect::valid() { return true; } ///////////// ParameterGoto ParameterGoto::ParameterGoto(const exp_parameter& parameter, QWidget* parent) : ParameterBase(parameter, parent) { QVBoxLayout* layout = new QVBoxLayout(this); layout->setSpacing(6); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(new QLabel(i18n(parameter.description().toUtf8()), this)); QWidget * hboxWidget = new QWidget(this); QHBoxLayout * hbox = new QHBoxLayout(hboxWidget); hbox->setContentsMargins(0, 0, 0, 0); hbox->setSpacing(6); _lineEdit = new KLineEdit(hboxWidget); _lineEdit->setCompletionObject(new KUrlCompletion(KUrlCompletion::DirCompletion)); hbox->addWidget(_lineEdit); _dirButton = new QToolButton(hboxWidget); hbox->addWidget(_dirButton); - _dirButton->setIcon(QIcon::fromTheme("document-open")); + _dirButton->setIcon(Icon("document-open")); connect(_dirButton, SIGNAL(clicked()), this, SLOT(setDir())); _placeholderButton = new QToolButton(hboxWidget); - _placeholderButton->setIcon(QIcon::fromTheme("list-add")); + _placeholderButton->setIcon(Icon("list-add")); hbox->addWidget(_placeholderButton); connect(_placeholderButton, SIGNAL(clicked()), this, SLOT(addPlaceholder())); layout->addWidget(hboxWidget); } QString ParameterGoto::text() { return _lineEdit->text(); } QString ParameterGoto::preset() { return QString(); } void ParameterGoto::reset() { _lineEdit->setText(QString()); } bool ParameterGoto::valid() { if (_lineEdit->text().isEmpty()) return false; else return true; } void ParameterGoto::setDir() { QString folder = QFileDialog::getExistingDirectory(this); _lineEdit->setText(folder); } void ParameterGoto::addPlaceholder() { AddPlaceholderPopup* popup = new AddPlaceholderPopup(this); QString exp = popup->getPlaceholder(mapToGlobal(QPoint(_placeholderButton->pos().x() + _placeholderButton->width() + 6, _placeholderButton->pos().y() + _placeholderButton->height() / 2))); _lineEdit->insert(exp); delete popup; } ///////////// ParameterSyncprofile ParameterSyncprofile::ParameterSyncprofile(const exp_parameter& parameter, QWidget* parent) : ParameterBase(parameter, parent) { QVBoxLayout* layout = new QVBoxLayout(this); layout->setSpacing(6); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(new QLabel(i18n(parameter.description().toUtf8()), this)); layout->addWidget(_combobox = new KComboBox(this)); _combobox->addItems(ProfileManager::availableProfiles("SynchronizerProfile")); } QString ParameterSyncprofile::text() { return _combobox->currentText(); } QString ParameterSyncprofile::preset() { return _combobox->itemText(0); } void ParameterSyncprofile::reset() { _combobox->setCurrentIndex(0); } bool ParameterSyncprofile::valid() { return true; } ///////////// ParameterSearch ParameterSearch::ParameterSearch(const exp_parameter& parameter, QWidget* parent) : ParameterBase(parameter, parent) { QVBoxLayout* layout = new QVBoxLayout(this); layout->setSpacing(6); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(new QLabel(i18n(parameter.description().toUtf8()), this)); layout->addWidget(_combobox = new KComboBox(this)); _combobox->addItems(ProfileManager::availableProfiles("SearcherProfile")); } QString ParameterSearch::text() { return _combobox->currentText(); } QString ParameterSearch::preset() { return _combobox->itemText(0); } void ParameterSearch::reset() { _combobox->setCurrentIndex(0); } bool ParameterSearch::valid() { return true; } ///////////// ParameterPanelprofile ParameterPanelprofile::ParameterPanelprofile(const exp_parameter& parameter, QWidget* parent) : ParameterBase(parameter, parent) { QVBoxLayout* layout = new QVBoxLayout(this); layout->setSpacing(6); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(new QLabel(i18n(parameter.description().toUtf8()), this)); layout->addWidget(_combobox = new KComboBox(this)); _combobox->addItems(ProfileManager::availableProfiles("Panel")); } QString ParameterPanelprofile::text() { return _combobox->currentText(); } QString ParameterPanelprofile::preset() { return _combobox->itemText(0); } void ParameterPanelprofile::reset() { _combobox->setCurrentIndex(0); } bool ParameterPanelprofile::valid() { return true; } ///////////// ParameterInt ParameterInt::ParameterInt(const exp_parameter& parameter, QWidget* parent) : ParameterBase(parameter, parent) { QHBoxLayout* layout = new QHBoxLayout(this); layout->setSpacing(6); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(new QLabel(i18n(parameter.description().toUtf8()), this)); layout->addWidget(_spinbox = new QSpinBox(this)); QStringList para = parameter.preset().section(':', 1).split(';'); _spinbox->setMinimum(para[0].toInt()); _spinbox->setMaximum(para[1].toInt()); _spinbox->setSingleStep(para[2].toInt()); _spinbox->setValue(para[3].toInt()); _default = _spinbox->value(); } QString ParameterInt::text() { return _spinbox->text(); } QString ParameterInt::preset() { return QString("%1").arg(_default); } void ParameterInt::reset() { return _spinbox->setValue(_default); } bool ParameterInt::valid() { return true; } diff --git a/krusader/ActionMan/useractionlistview.cpp b/krusader/ActionMan/useractionlistview.cpp index 568cc635..d89a2ec3 100644 --- a/krusader/ActionMan/useractionlistview.cpp +++ b/krusader/ActionMan/useractionlistview.cpp @@ -1,255 +1,255 @@ /***************************************************************************** * Copyright (C) 2006 Jonas Bähr * * Copyright (C) 2006-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 "useractionlistview.h" // QtCore #include // QtXml #include #include -#include #include "../krglobal.h" +#include "../icon.h" #include "../UserAction/kraction.h" #include "../UserAction/useraction.h" #define COL_TITLE 0 // UserActionListView UserActionListView::UserActionListView(QWidget * parent) : KrTreeWidget(parent) { setHeaderLabel(i18n("Title")); setRootIsDecorated(true); setSelectionMode(QAbstractItemView::ExtendedSelection); // normaly select single items but one may use Ctrl or Shift to select multiple setSortingEnabled(true); sortItems(COL_TITLE, Qt::AscendingOrder); connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), SLOT(slotCurrentItemChanged(QTreeWidgetItem*))); update(); } UserActionListView::~UserActionListView() { } QSize UserActionListView::sizeHint() const { return QSize(200, 400); } void UserActionListView::update() { clear(); UserAction::KrActionList list = krUserAction->actionList(); QListIterator it(list); while (it.hasNext()) insertAction(it.next()); } void UserActionListView::update(KrAction* action) { UserActionListViewItem* item = findActionItem(action); if (item) { // deleting & re-inserting is _much_easyer then tracking all possible cases of category changes! bool current = (item == currentItem()); bool selected = item->isSelected(); delete item; item = insertAction(action); if (current) setCurrentItem(item); if (selected) item->setSelected(true); } } UserActionListViewItem* UserActionListView::insertAction(KrAction* action) { if (! action) return 0; UserActionListViewItem* item; if (action->category().isEmpty()) item = new UserActionListViewItem(this, action); else { QTreeWidgetItem* categoryItem = findCategoryItem(action->category()); if (! categoryItem) { categoryItem = new QTreeWidgetItem(this); // create the new category item it not already present categoryItem->setText(0, action->category()); categoryItem->setFlags(Qt::ItemIsEnabled); } item = new UserActionListViewItem(categoryItem, action); } item->setAction(action); return item; } QTreeWidgetItem* UserActionListView::findCategoryItem(const QString& category) { QTreeWidgetItemIterator it(this); while (*it) { if ((*it)->text(COL_TITLE) == category && !((*it)->flags() & Qt::ItemIsSelectable)) return *it; it++; } return 0; } UserActionListViewItem* UserActionListView::findActionItem(const KrAction* action) { QTreeWidgetItemIterator it(this); while (*it) { if (UserActionListViewItem* item = dynamic_cast(*it)) { if (item->action() == action) return item; } it++; } return 0; } KrAction * UserActionListView::currentAction() const { if (UserActionListViewItem* item = dynamic_cast(currentItem())) return item->action(); else return 0; } void UserActionListView::setCurrentAction(const KrAction* action) { UserActionListViewItem* item = findActionItem(action); if (item) { setCurrentItem(item); } } void UserActionListView::setFirstActionCurrent() { QTreeWidgetItemIterator it(this); while (*it) { if (UserActionListViewItem* item = dynamic_cast(*it)) { setCurrentItem(item); break; } it++; } } void UserActionListView::slotCurrentItemChanged(QTreeWidgetItem* item) { if (! item) return; scrollTo(indexOf(item)); } QDomDocument UserActionListView::dumpSelectedActions(QDomDocument* mergeDoc) const { QList list = selectedItems(); QDomDocument doc; if (mergeDoc) doc = *mergeDoc; else doc = UserAction::createEmptyDoc(); QDomElement root = doc.documentElement(); for (int i = 0; i < list.size(); ++i) { QTreeWidgetItem* item = list.at(i); if (UserActionListViewItem* actionItem = dynamic_cast(item)) root.appendChild(actionItem->action()->xmlDump(doc)); } return doc; } void UserActionListView::removeSelectedActions() { QList list = selectedItems(); for (int i = 0; i < list.size(); ++i) { QTreeWidgetItem* item = list.at(i); if (UserActionListViewItem* actionItem = dynamic_cast(item)) { delete actionItem->action(); // remove the action itself delete actionItem; // remove the action from the list } // if } } // UserActionListViewItem UserActionListViewItem::UserActionListViewItem(QTreeWidget* view, KrAction* action) : QTreeWidgetItem(view) { setAction(action); } UserActionListViewItem::UserActionListViewItem(QTreeWidgetItem* item, KrAction * action) : QTreeWidgetItem(item) { setAction(action); } UserActionListViewItem::~UserActionListViewItem() { } void UserActionListViewItem::setAction(KrAction * action) { if (! action) return; _action = action; update(); } KrAction * UserActionListViewItem::action() const { return _action; } void UserActionListViewItem::update() { if (! _action) return; if (! _action->icon().isNull()) - setIcon(COL_TITLE, KIconLoader::global()->loadIcon(_action->iconName(), KIconLoader::Small)); + setIcon(COL_TITLE, Icon(_action->iconName())); setText(COL_TITLE, _action->text()); } bool UserActionListViewItem::operator<(const QTreeWidgetItem &other) const { // FIXME some how this only produces bullshit :-/ // if ( i->text( COL_NAME ).isEmpty() ) { // categories only have titles // //qDebug() << "this->title: " << text(COL_TITLE) << " |=| i->title: " << i->text(COL_TITLE); // return ( ascending ? -1 : 1 ); // <0 means this is smaller then i // } // else return QTreeWidgetItem::operator<(other); } diff --git a/krusader/ActionMan/useractionpage.cpp b/krusader/ActionMan/useractionpage.cpp index d2691443..fb064e68 100644 --- a/krusader/ActionMan/useractionpage.cpp +++ b/krusader/ActionMan/useractionpage.cpp @@ -1,356 +1,356 @@ /***************************************************************************** * Copyright (C) 2006 Shie Erlich * * Copyright (C) 2006 Rafi Yanai * * Copyright (C) 2006-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 "useractionpage.h" // QtWidgets #include #include #include #include #include #include // QtGui #include // QtXml #include #include #include #include #include -#include #include "actionproperty.h" #include "useractionlistview.h" #include "../UserAction/useraction.h" #include "../UserAction/kraction.h" #include "../krusader.h" #include "../krglobal.h" +#include "../icon.h" + -#define ICON(N) KIconLoader::global()->loadIcon(N, KIconLoader::Toolbar) //This is the filter in the QFileDialog of Import/Export: static const char* FILE_FILTER = I18N_NOOP("*.xml|XML files\n*|All files"); UserActionPage::UserActionPage(QWidget* parent) : QWidget(parent) { QVBoxLayout* layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(6); // 0px margin, 6px item-spacing // ======== pseudo-toolbar start ======== QHBoxLayout* toolbarLayout = new QHBoxLayout; // neither margin nor spacing for the toolbar with autoRaise toolbarLayout->setSpacing(0); toolbarLayout->setContentsMargins(0, 0, 0, 0); newButton = new QToolButton(this); - newButton->setIcon(ICON("document-new")); + newButton->setIcon(Icon("document-new")); newButton->setAutoRaise(true); newButton->setToolTip(i18n("Create new useraction")); importButton = new QToolButton(this); - importButton->setIcon(ICON("document-import")); + importButton->setIcon(Icon("document-import")); importButton->setAutoRaise(true); importButton->setToolTip(i18n("Import useractions")); exportButton = new QToolButton(this); - exportButton->setIcon(ICON("document-export")); + exportButton->setIcon(Icon("document-export")); exportButton->setAutoRaise(true); exportButton->setToolTip(i18n("Export useractions")); copyButton = new QToolButton(this); - copyButton->setIcon(ICON("edit-copy")); + copyButton->setIcon(Icon("edit-copy")); copyButton->setAutoRaise(true); copyButton->setToolTip(i18n("Copy useractions to clipboard")); pasteButton = new QToolButton(this); - pasteButton->setIcon(ICON("edit-paste")); + pasteButton->setIcon(Icon("edit-paste")); pasteButton->setAutoRaise(true); pasteButton->setToolTip(i18n("Paste useractions from clipboard")); removeButton = new QToolButton(this); - removeButton->setIcon(ICON("edit-delete")); + removeButton->setIcon(Icon("edit-delete")); removeButton->setAutoRaise(true); removeButton->setToolTip(i18n("Delete selected useractions")); toolbarLayout->addWidget(newButton); toolbarLayout->addWidget(importButton); toolbarLayout->addWidget(exportButton); toolbarLayout->addWidget(copyButton); toolbarLayout->addWidget(pasteButton); toolbarLayout->addSpacing(6); // 6 pixel nothing toolbarLayout->addWidget(removeButton); toolbarLayout->addStretch(1000); // some very large stretch-factor // ======== pseudo-toolbar end ======== /* This seems obsolete now! // Display some help KMessageBox::information( this, // parent i18n( "When you apply changes to an action, the modifications " "become available in the current session immediately.\n" "When closing ActionMan, you will be asked to save the changes permanently." ), QString(), // caption "show UserAction help" //dontShowAgainName for the config ); */ layout->addLayout(toolbarLayout); QSplitter *split = new QSplitter(this); layout->addWidget(split, 1000); // again a very large stretch-factor to fix the height of the toolbar actionTree = new UserActionListView(split); actionTree->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); actionProperties = new ActionProperty(split); actionProperties->setEnabled(false); // if there are any actions in the list, the first is displayed and this widget is enabled connect(actionTree, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), SLOT(slotChangeCurrent())); connect(newButton, SIGNAL(clicked()), SLOT(slotNewAction())); connect(removeButton, SIGNAL(clicked()), SLOT(slotRemoveAction())); connect(importButton, SIGNAL(clicked()), SLOT(slotImport())); connect(exportButton, SIGNAL(clicked()), SLOT(slotExport())); connect(copyButton, SIGNAL(clicked()), SLOT(slotToClip())); connect(pasteButton, SIGNAL(clicked()), SLOT(slotFromClip())); // forwards the changed signal of the properties connect(actionProperties, SIGNAL(changed()), SIGNAL(changed())); actionTree->setFirstActionCurrent(); actionTree->setFocus(); } UserActionPage::~UserActionPage() { } bool UserActionPage::continueInSpiteOfChanges() { if (! actionProperties->isModified()) return true; int answer = KMessageBox::questionYesNoCancel(this, i18n("The current action has been modified. Do you want to apply these changes?") ); if (answer == KMessageBox::Cancel) { disconnect(actionTree, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(slotChangeCurrent())); actionTree->setCurrentAction(actionProperties->action()); connect(actionTree, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), SLOT(slotChangeCurrent())); return false; } if (answer == KMessageBox::Yes) { if (! actionProperties->validProperties()) { disconnect(actionTree, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(slotChangeCurrent())); actionTree->setCurrentAction(actionProperties->action()); connect(actionTree, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), SLOT(slotChangeCurrent())); return false; } slotUpdateAction(); } // if Yes return true; } void UserActionPage::slotChangeCurrent() { if (! continueInSpiteOfChanges()) return; KrAction* action = actionTree->currentAction(); if (action) { actionProperties->setEnabled(true); // the discinct name is used as ID it is not allowd to change it afterwards because it is may referenced anywhere else actionProperties->leDistinctName->setEnabled(false); actionProperties->updateGUI(action); } else { // If the current item in the tree is no action (i.e. a cathegory), disable the properties actionProperties->clear(); actionProperties->setEnabled(false); } emit applied(); // to disable the apply-button } void UserActionPage::slotUpdateAction() { // check that we have a command line, title and a name if (! actionProperties->validProperties()) return; if (actionProperties->leDistinctName->isEnabled()) { // := new entry KrAction* action = new KrAction(krApp->actionCollection(), actionProperties->leDistinctName->text()); krUserAction->addKrAction(action); actionProperties->updateAction(action); UserActionListViewItem* item = actionTree->insertAction(action); actionTree->setCurrentItem(item); } else { // := edit an existing actionProperties->updateAction(); actionTree->update(actionProperties->action()); // update the listviewitem as well... } apply(); } void UserActionPage::slotNewAction() { if (continueInSpiteOfChanges()) { actionTree->clearSelection(); // else the user may think that he is overwriting the selected action actionProperties->clear(); actionProperties->setEnabled(true); // it may be disabled because the tree has the focus on a category actionProperties->leDistinctName->setEnabled(true); actionProperties->leDistinctName->setFocus(); } } void UserActionPage::slotRemoveAction() { if (! dynamic_cast(actionTree->currentItem())) return; int messageDelete = KMessageBox::warningContinueCancel(this, //parent i18n("Are you sure that you want to remove all selected actions?"), //text i18n("Remove Selected Actions?"), //caption KStandardGuiItem::remove(), //Label for the continue-button KStandardGuiItem::cancel(), "Confirm Remove UserAction", //dontAskAgainName (for the config-file) KMessageBox::Dangerous | KMessageBox::Notify); if (messageDelete != KMessageBox::Continue) return; actionProperties->clear(); actionProperties->setEnabled(false); actionTree->removeSelectedActions(); apply(); } void UserActionPage::slotImport() { QString filename = QFileDialog::getOpenFileName(this, QString(), QString(), i18n(FILE_FILTER)); if (filename.isEmpty()) return; UserAction::KrActionList newActions; krUserAction->readFromFile(filename, UserAction::renameDoublicated, &newActions); QListIterator it(newActions); while (it.hasNext()) actionTree->insertAction(it.next()); if (newActions.count() > 0) { apply(); } } void UserActionPage::slotExport() { if (! dynamic_cast(actionTree->currentItem())) return; QString filename = QFileDialog::getSaveFileName(this, QString(), QString(), i18n(FILE_FILTER)); if (filename.isEmpty()) return; QDomDocument doc = QDomDocument(ACTION_DOCTYPE); QFile file(filename); int answer = 0; if (file.open(QIODevice::ReadOnly)) { // getting here, means the file already exists an can be read if (doc.setContent(&file)) // getting here means the file exists and already contains an UserAction-XML-tree answer = KMessageBox::warningYesNoCancel(this, //parent i18n("This file already contains some useractions.\nDo you want to overwrite it or should it be merged with the selected actions?"), //text i18n("Overwrite or Merge?"), //caption KStandardGuiItem::overwrite(), //label for Yes-Button KGuiItem(i18n("Merge")) //label for No-Button ); file.close(); } if (answer == 0 && file.exists()) answer = KMessageBox::warningContinueCancel(this, //parent i18n("This file already exists. Do you want to overwrite it?"), //text i18n("Overwrite Existing File?"), //caption KStandardGuiItem::overwrite() //label for Continue-Button ); if (answer == KMessageBox::Cancel) return; if (answer == KMessageBox::No) // that means the merge-button doc = actionTree->dumpSelectedActions(&doc); // merge else // Yes or Continue means overwrite doc = actionTree->dumpSelectedActions(); bool success = UserAction::writeToFile(doc, filename); if (! success) KMessageBox::error(this, i18n("Cannot open %1 for writing.\nNothing exported.", filename), i18n("Export Failed") ); } void UserActionPage::slotToClip() { if (! dynamic_cast(actionTree->currentItem())) return; QDomDocument doc = actionTree->dumpSelectedActions(); QApplication::clipboard()->setText(doc.toString()); } void UserActionPage::slotFromClip() { QDomDocument doc(ACTION_DOCTYPE); if (doc.setContent(QApplication::clipboard()->text())) { QDomElement root = doc.documentElement(); UserAction::KrActionList newActions; krUserAction->readFromElement(root, UserAction::renameDoublicated, &newActions); QListIterator it(newActions); while (it.hasNext()) actionTree->insertAction(it.next()); if (newActions.count() > 0) { apply(); } } // if ( doc.setContent ) } bool UserActionPage::readyToQuit() { // Check if the current UserAction has changed if (! continueInSpiteOfChanges()) return false; krUserAction->writeActionFile(); return true; } void UserActionPage::apply() { krUserAction->writeActionFile(); emit applied(); } void UserActionPage::applyChanges() { slotUpdateAction(); } diff --git a/krusader/BookMan/kraddbookmarkdlg.cpp b/krusader/BookMan/kraddbookmarkdlg.cpp index 20ad36c0..4b5905af 100644 --- a/krusader/BookMan/kraddbookmarkdlg.cpp +++ b/krusader/BookMan/kraddbookmarkdlg.cpp @@ -1,185 +1,186 @@ /***************************************************************************** * Copyright (C) 2002 Shie Erlich * * Copyright (C) 2002 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 "kraddbookmarkdlg.h" #include "../krglobal.h" +#include "../icon.h" #include "krbookmarkhandler.h" // QtWidgets #include #include #include #include #include #include #include -#include + KrAddBookmarkDlg::KrAddBookmarkDlg(QWidget *parent, QUrl url): QDialog(parent) { setWindowModality(Qt::WindowModal); setWindowTitle(i18n("Add Bookmark")); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); QGridLayout *layout = new QGridLayout; // expanding // name and url QLabel *lb1 = new QLabel(i18n("Name:"), this); _name = new KLineEdit(this); _name->setText(url.toDisplayString()); // default name is the url _name->selectAll(); // make the text selected layout->addWidget(lb1, 0, 0); layout->addWidget(_name, 0, 1); QLabel *lb2 = new QLabel(i18n("URL:"), this); _url = new KLineEdit(this); layout->addWidget(lb2, 1, 0); layout->addWidget(_url, 1, 1); _url->setText(url.toDisplayString()); // set the url in the field // create in linedit and button QLabel *lb3 = new QLabel(i18n("Create in:"), this); _folder = new KLineEdit(this); layout->addWidget(lb3, 2, 0); layout->addWidget(_folder, 2, 1); _folder->setReadOnly(true); _createInBtn = new QToolButton(this); - _createInBtn->setIcon(krLoader->loadIcon("go-down", KIconLoader::Small)); + _createInBtn->setIcon(Icon("go-down")); _createInBtn->setCheckable(true); connect(_createInBtn, SIGNAL(toggled(bool)), this, SLOT(toggleCreateIn(bool))); layout->addWidget(_createInBtn, 2, 2); mainLayout->addLayout(layout); detailsWidget = createInWidget(); detailsWidget->setVisible(false); mainLayout->addWidget(detailsWidget); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); mainLayout->addWidget(buttonBox); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); newFolderButton = new QPushButton(i18n("New Folder")); buttonBox->addButton(newFolderButton, QDialogButtonBox::ActionRole); newFolderButton->setVisible(false);// hide it until _createIn is shown connect(newFolderButton, SIGNAL(clicked()), this, SLOT(newFolder())); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); _name->setFocus(); resize(sizeHint().width() * 2, sizeHint().height()); } void KrAddBookmarkDlg::toggleCreateIn(bool show) { - _createInBtn->setIcon(krLoader->loadIcon(show ? "go-up" : "go-down", KIconLoader::Small)); + _createInBtn->setIcon(Icon(show ? "go-up" : "go-down")); newFolderButton->setVisible(show); detailsWidget->setVisible(show); } // creates the widget that lets you decide where to put the new bookmark QWidget *KrAddBookmarkDlg::createInWidget() { _createIn = new KrTreeWidget(this); _createIn->setHeaderLabel(i18n("Folders")); _createIn->header()->hide(); _createIn->setRootIsDecorated(true); _createIn->setAlternatingRowColors(false); // disable alternate coloring QTreeWidgetItem *item = new QTreeWidgetItem(_createIn); item->setText(0, i18n("Bookmarks")); _createIn->expandItem(item); item->setSelected(true); _xr[item] = krBookMan->_root; populateCreateInWidget(krBookMan->_root, item); _createIn->setCurrentItem(item); slotSelectionChanged(); connect(_createIn, SIGNAL(itemSelectionChanged()), this, SLOT(slotSelectionChanged())); return _createIn; } void KrAddBookmarkDlg::slotSelectionChanged() { QList items = _createIn->selectedItems(); if (items.count() > 0) { _folder->setText(_xr[ items[ 0 ] ]->text()); } } void KrAddBookmarkDlg::populateCreateInWidget(KrBookmark *root, QTreeWidgetItem *parent) { QListIterator it(root->children()); while (it.hasNext()) { KrBookmark *bm = it.next(); if (bm->isFolder()) { QTreeWidgetItem *item = new QTreeWidgetItem(parent); item->setText(0, bm->text()); item->treeWidget()->expandItem(item); _xr[item] = bm; populateCreateInWidget(bm, item); } } } void KrAddBookmarkDlg::newFolder() { // get the name QString newFolder = QInputDialog::getText(this, i18n("New Folder"), i18n("Folder name:")); if (newFolder.isEmpty()) { return; } QList items = _createIn->selectedItems(); if (items.count() == 0) return; // add to the list in bookman KrBookmark *bm = new KrBookmark(newFolder); krBookMan->addBookmark(bm, _xr[ items[ 0 ]]); // fix the gui QTreeWidgetItem *item = new QTreeWidgetItem(items[ 0 ]); item->setText(0, bm->text()); _xr[item] = bm; _createIn->setCurrentItem(item); item->setSelected(true); } KrBookmark * KrAddBookmarkDlg::folder() const { QList items = _createIn->selectedItems(); if (items.count() == 0) return 0; return _xr[ items[ 0 ] ]; } diff --git a/krusader/BookMan/krbookmark.cpp b/krusader/BookMan/krbookmark.cpp index d9720a2a..a675615d 100644 --- a/krusader/BookMan/krbookmark.cpp +++ b/krusader/BookMan/krbookmark.cpp @@ -1,150 +1,150 @@ /***************************************************************************** * Copyright (C) 2002 Shie Erlich * * Copyright (C) 2002 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 "krbookmark.h" #include "../krglobal.h" +#include "../icon.h" #include "../Archive/krarchandler.h" #include "../FileSystem/krtrashhandler.h" #include "../Panel/listpanelactions.h" #include -#include #include #define BM_NAME(X) (QString("Bookmark:")+X) static const char* NAME_TRASH = I18N_NOOP("Trash bin"); static const char* NAME_VIRTUAL = I18N_NOOP("Virtual Filesystem"); static const char* NAME_LAN = I18N_NOOP("Local Network"); -KrBookmark::KrBookmark(QString name, QUrl url, KActionCollection *parent, QString icon, QString actionName) : - QAction(parent), _url(url), _icon(icon), _folder(false), _separator(false), _autoDelete(true) +KrBookmark::KrBookmark(QString name, QUrl url, KActionCollection *parent, QString iconName, QString actionName) : + QAction(parent), _url(url), _iconName(iconName), _folder(false), _separator(false), _autoDelete(true) { QString actName = actionName.isNull() ? BM_NAME(name) : BM_NAME(actionName); setText(name); parent->addAction(actName, this); connect(this, SIGNAL(triggered()), this, SLOT(activatedProxy())); // do we have an icon? - if (!icon.isEmpty()) - setIcon(QIcon::fromTheme(icon)); + if (!iconName.isEmpty()) + setIcon(Icon(iconName)); else { // what kind of a url is it? if (_url.isLocalFile()) { - setIcon(QIcon::fromTheme("folder")); + setIcon(Icon("folder")); } else { // is it an archive? if (KRarcHandler::isArchive(_url)) - setIcon(QIcon::fromTheme("application-x-tar")); - else setIcon(QIcon::fromTheme("folder-html")); + setIcon(Icon("application-x-tar")); + else setIcon(Icon("folder-html")); } } } -KrBookmark::KrBookmark(QString name, QString icon) : - QAction(QIcon::fromTheme(icon), name, 0), _icon(icon), _folder(true), _separator(false), _autoDelete(false) +KrBookmark::KrBookmark(QString name, QString iconName) : + QAction(Icon(iconName), name, 0), _iconName(iconName), _folder(true), _separator(false), _autoDelete(false) { - setIcon(QIcon::fromTheme(icon == "" ? "folder" : icon)); + setIcon(Icon(iconName == "" ? "folder" : iconName)); } KrBookmark::~KrBookmark() { if (_autoDelete) { QListIterator it(_children); while (it.hasNext()) delete it.next(); _children.clear(); } } KrBookmark * KrBookmark::getExistingBookmark(QString actionName, KActionCollection *collection) { return static_cast(collection->action(BM_NAME(actionName))); } KrBookmark * KrBookmark::trash(KActionCollection *collection) { KrBookmark *bm = getExistingBookmark(i18n(NAME_TRASH), collection); if (!bm) bm = new KrBookmark(i18n(NAME_TRASH), QUrl("trash:/"), collection); - bm->setIcon(krLoader->loadIcon(KrTrashHandler::trashIcon(), KIconLoader::Small)); + bm->setIcon(Icon(KrTrashHandler::trashIconName())); return bm; } KrBookmark * KrBookmark::virt(KActionCollection *collection) { KrBookmark *bm = getExistingBookmark(i18n(NAME_VIRTUAL), collection); if (!bm) { bm = new KrBookmark(i18n(NAME_VIRTUAL), QUrl("virt:/"), collection); - bm->setIcon(krLoader->loadIcon("document-open-remote", KIconLoader::Small)); + bm->setIcon(Icon("document-open-remote")); } return bm; } KrBookmark * KrBookmark::lan(KActionCollection *collection) { KrBookmark *bm = getExistingBookmark(i18n(NAME_LAN), collection); if (!bm) { bm = new KrBookmark(i18n(NAME_LAN), QUrl("remote:/"), collection); - bm->setIcon(krLoader->loadIcon("network-workgroup", KIconLoader::Small)); + bm->setIcon(Icon("network-workgroup")); } return bm; } QAction * KrBookmark::jumpBackAction(KActionCollection *collection, bool isSetter, ListPanelActions *sourceActions) { auto actionName = isSetter ? QString("setJumpBack") : QString("jumpBack"); auto action = collection->action(actionName); if (action) { return action; } if (!sourceActions) { return nullptr; } // copy essential part of source action auto sourceAction = isSetter ? sourceActions->actSetJumpBack : sourceActions->actJumpBack; action = new QAction(sourceAction->icon(), sourceAction->text(), sourceAction); action->setShortcut(sourceAction->shortcut()); action->setShortcutContext(Qt::WidgetShortcut); connect(action, &QAction::triggered, sourceAction, &QAction::trigger); // ensure there are no accelerator keys coming from another menu action->setText(KLocalizedString::removeAcceleratorMarker(action->text())); collection->addAction(actionName, action); return action; } KrBookmark * KrBookmark::separator() { KrBookmark *bm = new KrBookmark(""); bm->_separator = true; bm->_folder = false; return bm; } void KrBookmark::activatedProxy() { emit activated(url()); } diff --git a/krusader/BookMan/krbookmark.h b/krusader/BookMan/krbookmark.h index 65e6cf19..1f550f5d 100644 --- a/krusader/BookMan/krbookmark.h +++ b/krusader/BookMan/krbookmark.h @@ -1,88 +1,88 @@ /***************************************************************************** * Copyright (C) 2002 Shie Erlich * * Copyright (C) 2002 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/]. * *****************************************************************************/ #ifndef KRBOOKMARK_H #define KRBOOKMARK_H // QtCore #include #include // QtWidgets #include class KActionCollection; class ListPanelActions; class KrBookmark: public QAction { Q_OBJECT public: KrBookmark(QString name, QUrl url, KActionCollection *parent, QString icon = "", QString actionName = QString()); - explicit KrBookmark(QString name, QString icon = ""); // creates a folder + explicit KrBookmark(QString name, QString iconName = ""); // creates a folder ~KrBookmark(); // text() and setText() to change the name of the bookmark // icon() and setIcon() to change icons inline const QString& iconName() const { - return _icon; + return _iconName; } inline const QUrl &url() const { return _url; } inline void setURL(const QUrl &url) { _url = url; } inline bool isFolder() const { return _folder; } inline bool isSeparator() const { return _separator; } QList& children() { return _children; } static KrBookmark * getExistingBookmark(QString actionName, KActionCollection *collection); // ----- special bookmarks static KrBookmark * trash(KActionCollection *collection); static KrBookmark * virt(KActionCollection *collection); static KrBookmark * lan(KActionCollection *collection); static QAction * jumpBackAction(KActionCollection *collection, bool isSetter = false, ListPanelActions *sourceActions = 0); static KrBookmark * separator(); signals: void activated(const QUrl &url); protected slots: void activatedProxy(); private: QUrl _url; - QString _icon; + QString _iconName; bool _folder; bool _separator; bool _autoDelete; QList _children; }; #endif // KRBOOKMARK_H diff --git a/krusader/BookMan/krbookmarkbutton.cpp b/krusader/BookMan/krbookmarkbutton.cpp index 47a3ffcc..5b7041b6 100644 --- a/krusader/BookMan/krbookmarkbutton.cpp +++ b/krusader/BookMan/krbookmarkbutton.cpp @@ -1,62 +1,63 @@ /***************************************************************************** * Copyright (C) 2002 Shie Erlich * * Copyright (C) 2002 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 "krbookmarkbutton.h" #include "krbookmarkhandler.h" #include "../krglobal.h" +#include "../icon.h" // QtGui #include // QtWidgets #include #include #include -#include + KrBookmarkButton::KrBookmarkButton(QWidget *parent): QToolButton(parent) { setAutoRaise(true); - setIcon(QIcon::fromTheme("bookmarks")); + setIcon(Icon("bookmarks")); setText(i18n("BookMan II")); setToolTip(i18n("BookMan II")); setPopupMode(QToolButton::InstantPopup); setAcceptDrops(false); - acmBookmarks = new KActionMenu(QIcon::fromTheme("bookmarks"), i18n("Bookmarks"), this); + acmBookmarks = new KActionMenu(Icon("bookmarks"), i18n("Bookmarks"), this); acmBookmarks->setDelayed(false); setMenu(acmBookmarks->menu()); connect(acmBookmarks->menu(), SIGNAL(aboutToShow()), this, SLOT(populate())); connect(acmBookmarks->menu(), SIGNAL(aboutToShow()), this, SIGNAL(aboutToShow())); } void KrBookmarkButton::populate() { krBookMan->populate(static_cast(menu())); } void KrBookmarkButton::showMenu() { populate(); menu()->exec(mapToGlobal(QPoint(0, height()))); } diff --git a/krusader/BookMan/krbookmarkhandler.cpp b/krusader/BookMan/krbookmarkhandler.cpp index b3b248a7..57e759d1 100644 --- a/krusader/BookMan/krbookmarkhandler.cpp +++ b/krusader/BookMan/krbookmarkhandler.cpp @@ -1,877 +1,877 @@ /***************************************************************************** * Copyright (C) 2002 Shie Erlich * * Copyright (C) 2002 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 "krbookmarkhandler.h" #include "kraddbookmarkdlg.h" #include "../krglobal.h" +#include "../icon.h" #include "../krslots.h" #include "../kractions.h" #include "../krmainwindow.h" #include "../Dialogs/popularurls.h" #include "../FileSystem/filesystem.h" #include "../Panel/krpanel.h" #include "../Panel/listpanelactions.h" // QtCore #include #include #include #include #include #include // QtGui #include #include #include #include -#include #include #include #include #define SPECIAL_BOOKMARKS true // ------------------------ for internal use #define BOOKMARKS_FILE "krusader/krbookmarks.xml" #define CONNECT_BM(X) { disconnect(X, SIGNAL(activated(QUrl)), 0, 0); connect(X, SIGNAL(activated(QUrl)), this, SLOT(slotActivated(QUrl))); } KrBookmarkHandler::KrBookmarkHandler(KrMainWindow *mainWindow) : QObject(mainWindow->widget()), _mainWindow(mainWindow), _middleClick(false), _mainBookmarkPopup(0), _specialBookmarks(), _quickSearchAction(nullptr), _quickSearchBar(nullptr), _quickSearchMenu(nullptr) { // create our own action collection and make the shortcuts apply only to parent _privateCollection = new KActionCollection(this); _collection = _mainWindow->actions(); // create _root: father of all bookmarks. it is a dummy bookmark and never shown _root = new KrBookmark(i18n("Bookmarks")); _root->setParent(this); // load bookmarks importFromFile(); // create bookmark manager QString filename = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + BOOKMARKS_FILE; manager = KBookmarkManager::managerForFile(filename, QStringLiteral("krusader")); connect(manager, SIGNAL(changed(QString,QString)), this, SLOT(bookmarksChanged(QString,QString))); // create the quick search bar and action _quickSearchAction = new QWidgetAction(this); _quickSearchBar = new QLineEdit(); _quickSearchBar->setPlaceholderText(i18n("Type to search...")); _quickSearchAction->setDefaultWidget(_quickSearchBar); // ownership of the bar is transferred to the action _quickSearchAction->setEnabled(false); _setQuickSearchText(""); // fill a dummy menu to properly init actions (allows toolbar bookmark buttons to work properly) auto menu = new QMenu(mainWindow->widget()); populate(menu); menu->deleteLater(); } KrBookmarkHandler::~KrBookmarkHandler() { delete manager; delete _privateCollection; } void KrBookmarkHandler::bookmarkCurrent(QUrl url) { QPointer dlg = new KrAddBookmarkDlg(_mainWindow->widget(), url); if (dlg->exec() == QDialog::Accepted) { KrBookmark *bm = new KrBookmark(dlg->name(), dlg->url(), _collection); addBookmark(bm, dlg->folder()); } delete dlg; } void KrBookmarkHandler::addBookmark(KrBookmark *bm, KrBookmark *folder) { if (folder == 0) folder = _root; // add to the list (bottom) folder->children().append(bm); exportToFile(); } void KrBookmarkHandler::deleteBookmark(KrBookmark *bm) { if (bm->isFolder()) clearBookmarks(bm); // remove the child bookmarks removeReferences(_root, bm); foreach(QWidget *w, bm->associatedWidgets()) w->removeAction(bm); delete bm; exportToFile(); } void KrBookmarkHandler::removeReferences(KrBookmark *root, KrBookmark *bmToRemove) { int index = root->children().indexOf(bmToRemove); if (index >= 0) root->children().removeAt(index); QListIterator it(root->children()); while (it.hasNext()) { KrBookmark *bm = it.next(); if (bm->isFolder()) removeReferences(bm, bmToRemove); } } void KrBookmarkHandler::exportToFileBookmark(QDomDocument &doc, QDomElement &where, KrBookmark *bm) { if (bm->isSeparator()) { QDomElement bookmark = doc.createElement("separator"); where.appendChild(bookmark); } else { QDomElement bookmark = doc.createElement("bookmark"); // url bookmark.setAttribute("href", bm->url().toDisplayString()); // icon bookmark.setAttribute("icon", bm->iconName()); // title QDomElement title = doc.createElement("title"); title.appendChild(doc.createTextNode(bm->text())); bookmark.appendChild(title); where.appendChild(bookmark); } } void KrBookmarkHandler::exportToFileFolder(QDomDocument &doc, QDomElement &parent, KrBookmark *folder) { QListIterator it(folder->children()); while (it.hasNext()) { KrBookmark *bm = it.next(); if (bm->isFolder()) { QDomElement newFolder = doc.createElement("folder"); newFolder.setAttribute("icon", bm->iconName()); parent.appendChild(newFolder); QDomElement title = doc.createElement("title"); title.appendChild(doc.createTextNode(bm->text())); newFolder.appendChild(title); exportToFileFolder(doc, newFolder, bm); } else { exportToFileBookmark(doc, parent, bm); } } } // export to file using the xbel standard // // // Developer Web Site // // Title of this folder // KDE Web Site // // My own bookmarks // KOffice Web Site // // KDevelop Web Site // // // void KrBookmarkHandler::exportToFile() { QDomDocument doc("xbel"); QDomElement root = doc.createElement("xbel"); doc.appendChild(root); exportToFileFolder(doc, root, _root); if (!doc.firstChild().isProcessingInstruction()) { // adding: if not already present QDomProcessingInstruction instr = doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\" "); doc.insertBefore(instr, doc.firstChild()); } QString filename = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + BOOKMARKS_FILE; QFile file(filename); if (file.open(QIODevice::WriteOnly)) { QTextStream stream(&file); stream.setCodec("UTF-8"); stream << doc.toString(); file.close(); } else { KMessageBox::error(_mainWindow->widget(), i18n("Unable to write to %1", filename), i18n("Error")); } } bool KrBookmarkHandler::importFromFileBookmark(QDomElement &e, KrBookmark *parent, QString path, QString *errorMsg) { QString url, name, icon; // verify tag if (e.tagName() != "bookmark") { *errorMsg = i18n("%1 instead of %2", e.tagName(), QLatin1String("bookmark")); return false; } // verify href if (!e.hasAttribute("href")) { *errorMsg = i18n("missing tag %1", QLatin1String("href")); return false; } else url = e.attribute("href"); // verify title QDomElement te = e.firstChild().toElement(); if (te.tagName() != "title") { *errorMsg = i18n("missing tag %1", QLatin1String("title")); return false; } else name = te.text(); // do we have an icon? if (e.hasAttribute("icon")) { icon = e.attribute("icon"); } // ok: got name and url, let's add a bookmark KrBookmark *bm = KrBookmark::getExistingBookmark(path + name, _collection); if (!bm) { bm = new KrBookmark(name, QUrl(url), _collection, icon, path + name); parent->children().append(bm); } return true; } bool KrBookmarkHandler::importFromFileFolder(QDomNode &first, KrBookmark *parent, QString path, QString *errorMsg) { QString name; QDomNode n = first; while (!n.isNull()) { QDomElement e = n.toElement(); if (e.tagName() == "bookmark") { if (!importFromFileBookmark(e, parent, path, errorMsg)) return false; } else if (e.tagName() == "folder") { QString iconName = ""; if (e.hasAttribute("icon")) iconName = e.attribute("icon"); // the title is the first child of the folder QDomElement tmp = e.firstChild().toElement(); if (tmp.tagName() != "title") { *errorMsg = i18n("missing tag %1", QLatin1String("title")); return false; } else name = tmp.text(); KrBookmark *folder = new KrBookmark(name, iconName); parent->children().append(folder); QDomNode nextOne = tmp.nextSibling(); if (!importFromFileFolder(nextOne, folder, path + name + '/', errorMsg)) return false; } else if (e.tagName() == "separator") { parent->children().append(KrBookmark::separator()); } n = n.nextSibling(); } return true; } void KrBookmarkHandler::importFromFile() { clearBookmarks(_root); QString filename = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + BOOKMARKS_FILE; QFile file(filename); if (!file.open(QIODevice::ReadOnly)) return; // no bookmarks file QString errorMsg; QDomNode n; QDomElement e; QDomDocument doc("xbel"); if (!doc.setContent(&file, &errorMsg)) { goto BM_ERROR; } // iterate through the document: first child should be "xbel" (skip all until we find it) n = doc.firstChild(); while (!n.isNull() && n.toElement().tagName() != "xbel") n = n.nextSibling(); if (n.isNull() || n.toElement().tagName() != "xbel") { errorMsg = i18n("%1 does not seem to be a valid bookmarks file", filename); goto BM_ERROR; } else n = n.firstChild(); // skip the xbel part importFromFileFolder(n, _root, "", &errorMsg); goto BM_SUCCESS; BM_ERROR: KMessageBox::error(_mainWindow->widget(), i18n("Error reading bookmarks file: %1", errorMsg), i18n("Error")); BM_SUCCESS: file.close(); } void KrBookmarkHandler::_setQuickSearchText(const QString &text) { bool isEmptyQuickSearchBarVisible = KConfigGroup(krConfig, "Look&Feel").readEntry("Always show search bar", true); _quickSearchBar->setText(text); auto length = text.length(); bool isVisible = isEmptyQuickSearchBarVisible || length > 0; _quickSearchAction->setVisible(isVisible); _quickSearchBar->setVisible(isVisible); if (length == 0) { qDebug() << "Bookmark search: reset"; _resetActionTextAndHighlighting(); } else { qDebug() << "Bookmark search: query =" << text; } } QString KrBookmarkHandler::_quickSearchText() const { return _quickSearchBar->text(); } void KrBookmarkHandler::_highlightAction(QAction *action, bool isMatched) { auto font = action->font(); font.setBold(isMatched); action->setFont(font); } void KrBookmarkHandler::populate(QMenu *menu) { // removing action from previous menu is necessary // otherwise it won't be displayed in the currently populating menu if (_mainBookmarkPopup) { _mainBookmarkPopup->removeAction(_quickSearchAction); } _mainBookmarkPopup = menu; menu->clear(); _specialBookmarks.clear(); buildMenu(_root, menu); } void KrBookmarkHandler::buildMenu(KrBookmark *parent, QMenu *menu, int depth) { // add search bar widget to the top of the menu if (depth == 0) { menu->addAction(_quickSearchAction); } // run the loop twice, in order to put the folders on top. stupid but easy :-) // note: this code drops the separators put there by the user QListIterator it(parent->children()); while (it.hasNext()) { KrBookmark *bm = it.next(); if (!bm->isFolder()) continue; QMenu *newMenu = new QMenu(menu); - newMenu->setIcon(QIcon(krLoader->loadIcon(bm->iconName(), KIconLoader::Small))); + newMenu->setIcon(Icon(bm->iconName())); newMenu->setTitle(bm->text()); QAction *menuAction = menu->addMenu(newMenu); QVariant v; v.setValue(bm); menuAction->setData(v); buildMenu(bm, newMenu, depth + 1); } it.toFront(); while (it.hasNext()) { KrBookmark *bm = it.next(); if (bm->isFolder()) continue; if (bm->isSeparator()) { menu->addSeparator(); continue; } menu->addAction(bm); CONNECT_BM(bm); } if (depth == 0) { KConfigGroup group(krConfig, "Private"); bool hasPopularURLs = group.readEntry("BM Popular URLs", true); bool hasTrash = group.readEntry("BM Trash", true); bool hasLan = group.readEntry("BM Lan", true); bool hasVirtualFS = group.readEntry("BM Virtual FS", true); bool hasJumpback = group.readEntry("BM Jumpback", true); if (hasPopularURLs) { menu->addSeparator(); // add the popular links submenu QMenu *newMenu = new QMenu(menu); newMenu->setTitle(i18n("Popular URLs")); - newMenu->setIcon(QIcon(krLoader->loadIcon("folder-bookmark", KIconLoader::Small))); + newMenu->setIcon(Icon("folder-bookmark")); QAction *bmfAct = menu->addMenu(newMenu); _specialBookmarks.append(bmfAct); // add the top 15 urls #define MAX 15 QList list = _mainWindow->popularUrls()->getMostPopularUrls(MAX); QList::Iterator it; for (it = list.begin(); it != list.end(); ++it) { QString name; if ((*it).isLocalFile()) name = (*it).path(); else name = (*it).toDisplayString(); // note: these bookmark are put into the private collection // as to not spam the general collection KrBookmark *bm = KrBookmark::getExistingBookmark(name, _privateCollection); if (!bm) bm = new KrBookmark(name, *it, _privateCollection); newMenu->addAction(bm); CONNECT_BM(bm); } newMenu->addSeparator(); newMenu->addAction(krPopularUrls); newMenu->installEventFilter(this); } // do we need to add special bookmarks? if (SPECIAL_BOOKMARKS) { if (hasTrash || hasLan || hasVirtualFS) menu->addSeparator(); KrBookmark *bm; // note: special bookmarks are not kept inside the _bookmarks list and added ad-hoc if (hasTrash) { bm = KrBookmark::trash(_collection); menu->addAction(bm); _specialBookmarks.append(bm); CONNECT_BM(bm); } if (hasLan) { bm = KrBookmark::lan(_collection); menu->addAction(bm); _specialBookmarks.append(bm); CONNECT_BM(bm); } if (hasVirtualFS) { bm = KrBookmark::virt(_collection); menu->addAction(bm); _specialBookmarks.append(bm); CONNECT_BM(bm); } if (hasJumpback) { menu->addSeparator(); ListPanelActions *actions = _mainWindow->listPanelActions(); auto slotTriggered = [=] { if (_mainBookmarkPopup && !_mainBookmarkPopup->isHidden()) { _mainBookmarkPopup->close(); } }; auto addJumpBackAction = [=](bool isSetter) { auto action = KrBookmark::jumpBackAction(_privateCollection, isSetter, actions); if (action) { menu->addAction(action); _specialBookmarks.append(action); // disconnecting from this as a receiver is important: // we don't want to break connections established by KrBookmark::jumpBackAction disconnect(action, &QAction::triggered, this, nullptr); connect(action, &QAction::triggered, this, slotTriggered); } }; addJumpBackAction(true); addJumpBackAction(false); } } menu->addSeparator(); menu->addAction(KrActions::actAddBookmark); _specialBookmarks.append(KrActions::actAddBookmark); - QAction *bmAct = menu->addAction(krLoader->loadIcon("bookmarks", KIconLoader::Small), + QAction *bmAct = menu->addAction(Icon("bookmarks"), i18n("Manage Bookmarks"), manager, SLOT(slotEditBookmarks())); _specialBookmarks.append(bmAct); // make sure the menu is connected to us disconnect(menu, SIGNAL(triggered(QAction*)), 0, 0); } menu->installEventFilter(this); } void KrBookmarkHandler::clearBookmarks(KrBookmark *root) { QList::iterator it = root->children().begin(); while (it != root->children().end()) { KrBookmark *bm = *it; if (bm->isFolder()) clearBookmarks(bm); else { foreach(QWidget *w, bm->associatedWidgets()) w->removeAction(bm); delete bm; } it = root->children().erase(it); } } void KrBookmarkHandler::bookmarksChanged(const QString&, const QString&) { importFromFile(); } bool KrBookmarkHandler::eventFilter(QObject *obj, QEvent *ev) { auto eventType = ev->type(); QMenu *menu = dynamic_cast(obj); if (eventType == QEvent::Show && menu) { _setQuickSearchText(""); _quickSearchMenu = menu; qDebug() << "Bookmark search: menu" << menu << "is shown"; return QObject::eventFilter(obj, ev); } if (eventType == QEvent::Close && menu && _quickSearchMenu) { if (_quickSearchMenu == menu) { qDebug() << "Bookmark search: stopped on menu" << menu; _setQuickSearchText(""); _quickSearchMenu = nullptr; } else { qDebug() << "Bookmark search: active action =" << _quickSearchMenu->activeAction(); // fix automatic deactivation of current action due to spurious close event from submenu auto quickSearchMenu = _quickSearchMenu; auto activeAction = _quickSearchMenu->activeAction(); QTimer::singleShot(0, this, [=]() { qDebug() << "Bookmark search: active action =" << quickSearchMenu->activeAction(); if (!quickSearchMenu->activeAction() && activeAction) { quickSearchMenu->setActiveAction(activeAction); qDebug() << "Bookmark search: restored active action =" << quickSearchMenu->activeAction(); } }); } return QObject::eventFilter(obj, ev); } // Having it occur on keypress is consistent with other shortcuts, // such as Ctrl+W and accelerator keys if (eventType == QEvent::KeyPress && menu) { QKeyEvent *kev = static_cast(ev); QList acts = menu->actions(); bool quickSearchStarted = false; bool searchInSpecialItems = KConfigGroup(krConfig, "Look&Feel").readEntry("Search in special items", false); if (kev->key() == Qt::Key_Left && kev->modifiers() == Qt::NoModifier) { menu->close(); return true; } if ((kev->modifiers() != Qt::ShiftModifier && kev->modifiers() != Qt::NoModifier) || kev->text().isEmpty() || kev->key() == Qt::Key_Delete || kev->key() == Qt::Key_Return || kev->key() == Qt::Key_Escape) { return QObject::eventFilter(obj, ev); } // update quick search text if (kev->key() == Qt::Key_Backspace) { auto newSearchText = _quickSearchText(); newSearchText.chop(1); _setQuickSearchText(newSearchText); if (_quickSearchText().length() == 0) { return QObject::eventFilter(obj, ev); } } else { quickSearchStarted = _quickSearchText().length() == 0; _setQuickSearchText(_quickSearchText().append(kev->text())); } if (quickSearchStarted) { _quickSearchMenu = menu; qDebug() << "Bookmark search: started on menu" << menu; } // match actions QAction *matchedAction = nullptr; int nMatches = 0; const Qt::CaseSensitivity matchCase = _quickSearchText() == _quickSearchText().toLower() ? Qt::CaseInsensitive : Qt::CaseSensitive; for (auto act : acts) { if (act->isSeparator() || act->text() == "") { continue; } if (!searchInSpecialItems && _specialBookmarks.contains(act)) { continue; } if (quickSearchStarted) { // if the first key press is an accelerator key, let the accelerator handler process this event if (act->text().contains('&' + kev->text(), Qt::CaseInsensitive)) { qDebug() << "Bookmark search: hit accelerator key of" << act; _setQuickSearchText(""); return QObject::eventFilter(obj, ev); } // strip accelerator keys from actions so they don't interfere with the search key press events auto text = act->text(); _quickSearchOriginalActionTitles.insert(act, text); act->setText(KLocalizedString::removeAcceleratorMarker(text)); } // match prefix of the action text to the query if (act->text().left(_quickSearchText().length()).compare(_quickSearchText(), matchCase) == 0) { _highlightAction(act); if (!matchedAction || matchedAction->menu()) { // Can't highlight menus (see comment below), hopefully pick something we can matchedAction = act; } nMatches++; } else { _highlightAction(act, false); } } if (matchedAction) { qDebug() << "Bookmark search: primary match =" << matchedAction->text() << ", number of matches =" << nMatches; } else { qDebug() << "Bookmark search: no matches"; } // trigger the matched menu item or set an active item accordingly if (nMatches == 1) { _setQuickSearchText(""); if ((bool) matchedAction->menu()) { menu->setActiveAction(matchedAction); } else { matchedAction->activate(QAction::Trigger); } } else if (nMatches > 1) { // Because of a bug submenus cannot be highlighted // https://bugreports.qt.io/browse/QTBUG-939 if (!matchedAction->menu()) { menu->setActiveAction(matchedAction); } else { menu->setActiveAction(nullptr); } } else { menu->setActiveAction(nullptr); } return true; } if (eventType == QEvent::MouseButtonRelease) { switch (static_cast(ev)->button()) { case Qt::RightButton: _middleClick = false; if (obj->inherits("QMenu")) { QMenu *menu = static_cast(obj); QAction *act = menu->actionAt(static_cast(ev)->pos()); if (obj == _mainBookmarkPopup && _specialBookmarks.contains(act)) { rightClickOnSpecialBookmark(); return true; } KrBookmark *bm = dynamic_cast(act); if (bm != 0) { rightClicked(menu, bm); return true; } else if (act && act->data().canConvert()) { KrBookmark *bm = act->data().value(); rightClicked(menu, bm); } } break; case Qt::LeftButton: _middleClick = false; break; case Qt::MidButton: _middleClick = true; break; default: break; } } return QObject::eventFilter(obj, ev); } void KrBookmarkHandler::_resetActionTextAndHighlighting() { for (QHash::const_iterator i = _quickSearchOriginalActionTitles.begin(); i != _quickSearchOriginalActionTitles.end(); ++i) { QAction *action = i.key(); action->setText(i.value()); _highlightAction(action, false); } _quickSearchOriginalActionTitles.clear(); } #define POPULAR_URLS_ID 100100 #define TRASH_ID 100101 #define LAN_ID 100103 #define VIRTUAL_FS_ID 100102 #define JUMP_BACK_ID 100104 void KrBookmarkHandler::rightClickOnSpecialBookmark() { KConfigGroup group(krConfig, "Private"); bool hasPopularURLs = group.readEntry("BM Popular URLs", true); bool hasTrash = group.readEntry("BM Trash", true); bool hasLan = group.readEntry("BM Lan", true); bool hasVirtualFS = group.readEntry("BM Virtual FS", true); bool hasJumpback = group.readEntry("BM Jumpback", true); QMenu menu(_mainBookmarkPopup); menu.setTitle(i18n("Enable special bookmarks")); QAction *act; act = menu.addAction(i18n("Popular URLs")); act->setData(QVariant(POPULAR_URLS_ID)); act->setCheckable(true); act->setChecked(hasPopularURLs); act = menu.addAction(i18n("Trash bin")); act->setData(QVariant(TRASH_ID)); act->setCheckable(true); act->setChecked(hasTrash); act = menu.addAction(i18n("Local Network")); act->setData(QVariant(LAN_ID)); act->setCheckable(true); act->setChecked(hasLan); act = menu.addAction(i18n("Virtual Filesystem")); act->setData(QVariant(VIRTUAL_FS_ID)); act->setCheckable(true); act->setChecked(hasVirtualFS); act = menu.addAction(i18n("Jump back")); act->setData(QVariant(JUMP_BACK_ID)); act->setCheckable(true); act->setChecked(hasJumpback); connect(_mainBookmarkPopup, SIGNAL(highlighted(int)), &menu, SLOT(close())); connect(_mainBookmarkPopup, SIGNAL(activated(int)), &menu, SLOT(close())); int result = -1; QAction *res = menu.exec(QCursor::pos()); if (res && res->data().canConvert()) result = res->data().toInt(); bool doCloseMain = true; switch (result) { case POPULAR_URLS_ID: group.writeEntry("BM Popular URLs", !hasPopularURLs); break; case TRASH_ID: group.writeEntry("BM Trash", !hasTrash); break; case LAN_ID: group.writeEntry("BM Lan", !hasLan); break; case VIRTUAL_FS_ID: group.writeEntry("BM Virtual FS", !hasVirtualFS); break; case JUMP_BACK_ID: group.writeEntry("BM Jumpback", !hasJumpback); break; default: doCloseMain = false; break; } menu.close(); if (doCloseMain && _mainBookmarkPopup) _mainBookmarkPopup->close(); } #define OPEN_ID 100200 #define OPEN_NEW_TAB_ID 100201 #define DELETE_ID 100202 void KrBookmarkHandler::rightClicked(QMenu *menu, KrBookmark * bm) { QMenu popup(_mainBookmarkPopup); QAction * act; if (!bm->isFolder()) { - act = popup.addAction(krLoader->loadIcon("document-open", KIconLoader::Panel), i18n("Open")); + act = popup.addAction(Icon("document-open"), i18n("Open")); act->setData(QVariant(OPEN_ID)); - act = popup.addAction(krLoader->loadIcon("tab-new", KIconLoader::Panel), i18n("Open in a new tab")); + act = popup.addAction(Icon("tab-new"), i18n("Open in a new tab")); act->setData(QVariant(OPEN_NEW_TAB_ID)); popup.addSeparator(); } - act = popup.addAction(krLoader->loadIcon("edit-delete", KIconLoader::Panel), i18n("Delete")); + act = popup.addAction(Icon("edit-delete"), i18n("Delete")); act->setData(QVariant(DELETE_ID)); connect(menu, SIGNAL(highlighted(int)), &popup, SLOT(close())); connect(menu, SIGNAL(activated(int)), &popup, SLOT(close())); int result = -1; QAction *res = popup.exec(QCursor::pos()); if (res && res->data().canConvert ()) result = res->data().toInt(); popup.close(); if (_mainBookmarkPopup && result >= OPEN_ID && result <= DELETE_ID) { _mainBookmarkPopup->close(); } switch (result) { case OPEN_ID: SLOTS->refresh(bm->url()); break; case OPEN_NEW_TAB_ID: _mainWindow->activeManager()->newTab(bm->url()); break; case DELETE_ID: deleteBookmark(bm); break; } } // used to monitor middle clicks. if mid is found, then the // bookmark is opened in a new tab. ugly, but easier than overloading // KAction and KActionCollection. void KrBookmarkHandler::slotActivated(const QUrl &url) { if (_mainBookmarkPopup && !_mainBookmarkPopup->isHidden()) _mainBookmarkPopup->close(); if (_middleClick) _mainWindow->activeManager()->newTab(url); else SLOTS->refresh(url); } diff --git a/krusader/CMakeLists.txt b/krusader/CMakeLists.txt index 0d2f8751..0ade19c5 100644 --- a/krusader/CMakeLists.txt +++ b/krusader/CMakeLists.txt @@ -1,131 +1,132 @@ include_directories(${KF5_INCLUDES_DIRS} ${QT_INCLUDES}) configure_file(krusaderversion.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/krusaderversion.h) add_subdirectory(ActionMan) add_subdirectory(Archive) add_subdirectory(BookMan) add_subdirectory(Dialogs) add_subdirectory(DiskUsage) add_subdirectory(FileSystem) add_subdirectory(Filter) add_subdirectory(GUI) add_subdirectory(Konfigurator) add_subdirectory(KViewer) add_subdirectory(JobMan) add_subdirectory(Locate) add_subdirectory(MountMan) add_subdirectory(Panel) add_subdirectory(Search) add_subdirectory(Splitter) add_subdirectory(UserAction) if(SYNCHRONIZER_ENABLED) add_subdirectory(Synchronizer) endif(SYNCHRONIZER_ENABLED) message(STATUS "${CMAKE_CURRENT_SOURCE_DIR}: skipped subdir $(KRJSDIR)") set(krusader_SRCS krglobal.cpp + icon.cpp + filelisticon.cpp actionsbase.cpp tabactions.cpp kractions.cpp paneltabbar.cpp panelmanager.cpp krservices.cpp main.cpp krusaderview.cpp krusader.cpp krslots.cpp - kicons.cpp krdebuglogger.cpp ) file(GLOB ICONS_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/icons/*-apps-krusader_user.png") ecm_add_app_icon(krusader_SRCS ICONS ${ICONS_SRCS}) qt5_add_resources(krusader_RC_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/resources.qrc" ) add_executable(krusader ${krusader_SRCS} ${krusader_RC_SRCS}) target_link_libraries(krusader Panel PanelView BookMan Dialogs DiskUsage GUI Konfigurator KViewer MountMan FileSystem Search Splitter Locate UserAction ActionMan KViewer Filter Dialogs GUI Archive JobMan KF5::Notifications KF5::Parts KF5::WindowSystem Qt5::PrintSupport Qt5::Concurrent ) if(SYNCHRONIZER_ENABLED) target_link_libraries( krusader Synchronizer ) endif(SYNCHRONIZER_ENABLED) install(TARGETS krusader ${INSTALL_TARGETS_DEFAULT_ARGS}) install(PROGRAMS org.kde.krusader.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} ) install(FILES krusaderui.rc krusaderlisterui.rc krviewer.rc DESTINATION ${KXMLGUI_INSTALL_DIR}/krusader) install(FILES midnight_commander.color total_commander.color total_commander.keymap total_commander.keymap.info useraction_examples.xml layout.xml splash.png DESTINATION ${DATA_INSTALL_DIR}/krusader) install(FILES org.kde.krusader.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR}) ecm_install_icons(ICONS icons/16-apps-krusader_blue.png icons/16-apps-krusader_red.png icons/16-apps-krusader_root.png icons/16-apps-krusader_user.png icons/22-apps-krusader_blue.png icons/22-apps-krusader_red.png icons/22-apps-krusader_root.png icons/22-apps-krusader_shield.png icons/22-apps-krusader_user.png icons/32-apps-krusader_blue.png icons/32-apps-krusader_red.png icons/32-apps-krusader_root.png icons/32-apps-krusader_shield.png icons/32-apps-krusader_user.png icons/48-apps-krusader_blue.png icons/48-apps-krusader_red.png icons/48-apps-krusader_root.png icons/48-apps-krusader_shield.png icons/48-apps-krusader_user.png icons/64-apps-krusader_blue.png icons/64-apps-krusader_red.png icons/64-apps-krusader_root.png icons/64-apps-krusader_shield.png icons/64-apps-krusader_user.png icons/128-apps-krusader_root.png icons/128-apps-krusader_user.png DESTINATION ${ICON_INSTALL_DIR} ) diff --git a/krusader/Dialogs/checksumdlg.cpp b/krusader/Dialogs/checksumdlg.cpp index 227bdaa3..d5fb71c5 100644 --- a/krusader/Dialogs/checksumdlg.cpp +++ b/krusader/Dialogs/checksumdlg.cpp @@ -1,578 +1,576 @@ /***************************************************************************** * Copyright (C) 2005 Shie Erlich * * Copyright (C) 2007-2008 Csaba Karai * * Copyright (C) 2008 Jonas Bähr * * Copyright (C) 2005-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 "checksumdlg.h" #include "../krglobal.h" +#include "../icon.h" #include "../krservices.h" #include "../krusader.h" #include "../GUI/krlistwidget.h" #include "../GUI/krtreewidget.h" // QtCore #include #include #include #include #include #include // QtWidgets #include #include #include #include #include #include #include #include -#include #include void Checksum::startCreationWizard(const QString &path, const QStringList &files) { if (files.isEmpty()) return; QDialog *dialog = new CHECKSUM_::CreateWizard(path, files); dialog->show(); } void Checksum::startVerifyWizard(const QString &path, const QString &checksumFile) { QDialog *dialog = new CHECKSUM_::VerifyWizard(path, checksumFile); dialog->show(); } namespace CHECKSUM_ { bool stopListFiles; // async operation invoked by QtConcurrent::run in creation wizard QStringList listFiles(const QString &path, const QStringList &fileNames) { const QDir baseDir(path); QStringList allFiles; for (const QString fileName : fileNames) { if (stopListFiles) return QStringList(); QDir subDir = QDir(baseDir.filePath(fileName)); if (subDir.exists()) { subDir.setFilter(QDir::Files); QDirIterator it(subDir, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks); while (it.hasNext()) { if (stopListFiles) return QStringList(); allFiles << baseDir.relativeFilePath(it.next()); } } else { // assume this is a file allFiles << fileName; } } return allFiles; } // ------------- Checksum Process ChecksumProcess::ChecksumProcess(QObject *parent, const QString &path) : KProcess(parent), m_tmpOutFile(QDir::tempPath() + QLatin1String("/krusader_XXXXXX.stdout")), m_tmpErrFile(QDir::tempPath() + QLatin1String("/krusader_XXXXXX.stderr")) { m_tmpOutFile.open(); // necessary to create the filename m_tmpErrFile.open(); // necessary to create the filename setOutputChannelMode(KProcess::SeparateChannels); // without this the next 2 lines have no effect! setStandardOutputFile(m_tmpOutFile.fileName()); setStandardErrorFile(m_tmpErrFile.fileName()); setWorkingDirectory(path); #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) connect(this, &ChecksumProcess::errorOccurred, this, &ChecksumProcess::slotError); #endif connect(this, static_cast(&QProcess::finished), this, &ChecksumProcess::slotFinished); } ChecksumProcess::~ChecksumProcess() { disconnect(this, 0, this, 0); // QProcess emits finished() on destruction close(); } void ChecksumProcess::slotError(QProcess::ProcessError error) { if (error == QProcess::FailedToStart) { KMessageBox::error(0, i18n("Could not start %1.", program().join(" "))); } } void ChecksumProcess::slotFinished(int, QProcess::ExitStatus exitStatus) { if (exitStatus != QProcess::NormalExit) { KMessageBox::error(0, i18n("There was an error while running %1.", program().join(" "))); return; } // parse result files if (!KrServices::fileToStringList(&m_tmpOutFile, m_outputLines) || !KrServices::fileToStringList(&m_tmpErrFile, m_errorLines)) { KMessageBox::error(0, i18n("Error reading stdout or stderr")); return; } emit resultReady(); } // ------------- Generic Checksum Wizard ChecksumWizard::ChecksumWizard(const QString &path) : QWizard(krApp), m_path(path), m_process(0) { setAttribute(Qt::WA_DeleteOnClose); // init the dictionary - pity it has to be manually m_checksumTools.insert("md5", "md5sum"); m_checksumTools.insert("sha1", "sha1sum"); m_checksumTools.insert("sha256", "sha256sum"); m_checksumTools.insert("sha224", "sha224sum"); m_checksumTools.insert("sha384", "sha384sum"); m_checksumTools.insert("sha512", "sha512sum"); connect(this, &QWizard::currentIdChanged, this, &ChecksumWizard::slotCurrentIdChanged); } ChecksumWizard::~ChecksumWizard() { if (m_process) { delete m_process; } } void ChecksumWizard::slotCurrentIdChanged(int id) { if (id == m_introId) { onIntroPage(); } else if (id == m_progressId) { if (m_process) { // we are coming from the result page; delete m_process; m_process = 0; restart(); } else { button(QWizard::BackButton)->hide(); button(QWizard::NextButton)->hide(); onProgressPage(); } } else if (id == m_resultId) { onResultPage(); } } QWizardPage *ChecksumWizard::createProgressPage(const QString &title) { QWizardPage *page = new QWizardPage; page->setTitle(title); page->setPixmap(QWizard::LogoPixmap, - krLoader->loadIcon("process-working", KIconLoader::Desktop, 32)); + Icon("process-working").pixmap(32)); page->setSubTitle(i18n("Please wait...")); QVBoxLayout *mainLayout = new QVBoxLayout; page->setLayout(mainLayout); // "busy" indicator QProgressBar *bar = new QProgressBar(); bar->setRange(0,0); mainLayout->addWidget(bar); return page; } bool ChecksumWizard::checkExists(const QString type) { if (!KrServices::cmdExist(m_checksumTools[type])) { KMessageBox::error( this, i18n("Krusader cannot find a checksum tool that handles %1 on your system. " "Please check the Dependencies page in Krusader's settings.", type)); return false; } return true; } void ChecksumWizard::runProcess(const QString &type, const QStringList &args) { Q_ASSERT(m_process == 0); m_process = new ChecksumProcess(this, m_path); m_process->setProgram(KrServices::fullPathName(m_checksumTools[type]), args); // show next page (with results) (only) when process is done connect(m_process, &ChecksumProcess::resultReady, this, &QWizard::next); // run the process m_process->start(); } void ChecksumWizard::addChecksumLine(KrTreeWidget *tree, const QString &line) { QTreeWidgetItem *item = new QTreeWidgetItem(tree); const int hashLength = line.indexOf(' '); // delimiter is either " " or " *" item->setText(0, line.left(hashLength)); QString fileName = line.mid(hashLength + 2); if (fileName.endsWith('\n')) fileName.chop(1); item->setText(1, fileName); } // ------------- Create Wizard CreateWizard::CreateWizard(const QString &path, const QStringList &_files) : ChecksumWizard(path), m_fileNames(_files), m_listFilesWatcher() { m_introId = addPage(createIntroPage()); m_progressId = addPage(createProgressPage(i18n("Creating Checksums"))); m_resultId = addPage(createResultPage()); setButton(QWizard::FinishButton, QDialogButtonBox(QDialogButtonBox::Save).button(QDialogButtonBox::Save)); connect(&m_listFilesWatcher, &QFutureWatcher::resultReadyAt, this, &CreateWizard::createChecksums); } QWizardPage *CreateWizard::createIntroPage() { QWizardPage *page = new QWizardPage; page->setTitle(i18n("Create Checksums")); page->setPixmap(QWizard::LogoPixmap, - krLoader->loadIcon("document-edit-sign", KIconLoader::Desktop, 32)); + Icon("document-edit-sign").pixmap(32)); page->setSubTitle(i18n("About to calculate checksum for the following files or directories:")); QVBoxLayout *mainLayout = new QVBoxLayout; page->setLayout(mainLayout); // file list KrListWidget *listWidget = new KrListWidget; listWidget->addItems(m_fileNames); mainLayout->addWidget(listWidget); // checksum method QHBoxLayout *hLayout = new QHBoxLayout; QLabel *methodLabel = new QLabel(i18n("Select the checksum method:")); hLayout->addWidget(methodLabel); m_methodBox = new KComboBox; // -- fill the combo with available methods for (const QString type: m_checksumTools.keys()) m_methodBox->addItem(type); m_methodBox->setFocus(); hLayout->addWidget(m_methodBox); mainLayout->addLayout(hLayout); return page; } QWizardPage *CreateWizard::createResultPage() { QWizardPage *page = new QWizardPage; page->setTitle(i18n("Checksum Results")); QVBoxLayout *mainLayout = new QVBoxLayout; page->setLayout(mainLayout); m_hashesTreeWidget = new KrTreeWidget(this); m_hashesTreeWidget->setAllColumnsShowFocus(true); m_hashesTreeWidget->setHeaderLabels(QStringList() << i18n("Hash") << i18n("File")); mainLayout->addWidget(m_hashesTreeWidget); m_errorLabel = new QLabel(i18n("Errors received:")); mainLayout->addWidget(m_errorLabel); m_errorListWidget = new KrListWidget; mainLayout->addWidget(m_errorListWidget); m_onePerFileBox = new QCheckBox(i18n("Save one checksum file for each source file")); m_onePerFileBox->setChecked(false); mainLayout->addWidget(m_onePerFileBox); return page; } void CreateWizard::onIntroPage() { button(QWizard::NextButton)->show(); } void CreateWizard::onProgressPage() { // first, get all files (recurse in directories) - async stopListFiles = false; // QFuture cannot cancel QtConcurrent::run connect(this, &CreateWizard::finished, this, [=]() { stopListFiles = true; }); QFuture listFuture = QtConcurrent::run(listFiles, m_path, m_fileNames); m_listFilesWatcher.setFuture(listFuture); } void CreateWizard::createChecksums() { const QString type = m_methodBox->currentText(); if (!checkExists(type)) { button(QWizard::BackButton)->show(); return; } const QStringList &allFiles = m_listFilesWatcher.result(); if (allFiles.isEmpty()) { KMessageBox::error(this, i18n("No files found")); button(QWizard::BackButton)->show(); return; } runProcess(type, allFiles); // set suggested filename m_suggestedFilePath = QDir(m_path).filePath( (m_fileNames.count() > 1 ? "checksum." : (m_fileNames[0] + '.')) + type); } void CreateWizard::onResultPage() { // hash tools display errors into stderr, so we'll use that to determine the result of the job const QStringList outputLines = m_process->stdOutput(); const QStringList errorLines = m_process->errOutput(); bool errors = !errorLines.isEmpty(); bool successes = !outputLines.isEmpty(); QWizardPage *page = currentPage(); page->setPixmap(QWizard::LogoPixmap, - krLoader->loadIcon(errors || !successes ? "dialog-error" : "dialog-information", - KIconLoader::Desktop, 32)); + Icon(errors || !successes ? "dialog-error" : "dialog-information").pixmap(32)); page->setSubTitle(errors || !successes ? i18n("Errors were detected while creating the checksums") : i18n("Checksums were created successfully")); m_hashesTreeWidget->clear(); m_hashesTreeWidget->setVisible(successes); if (successes) { for (const QString line : outputLines) addChecksumLine(m_hashesTreeWidget, line); //m_hashesTreeWidget->sortItems(1, Qt::AscendingOrder); } m_errorLabel->setVisible(errors); m_errorListWidget->setVisible(errors); m_errorListWidget->clear(); m_errorListWidget->addItems(errorLines); m_onePerFileBox->setEnabled(outputLines.size() > 1); button(QWizard::FinishButton)->setEnabled(successes); } bool CreateWizard::savePerFile() { const QString type = m_suggestedFilePath.mid(m_suggestedFilePath.lastIndexOf('.')); krApp->startWaiting(i18n("Saving checksum files..."), 0); for (const QString line : m_process->stdOutput()) { const QString filename = line.mid(line.indexOf(' ') + 2) + type; if (!saveChecksumFile(QStringList() << line, filename)) { KMessageBox::error(this, i18n("Errors occurred while saving multiple checksums. Stopping")); krApp->stopWait(); return false; } } krApp->stopWait(); return true; } bool CreateWizard::saveChecksumFile(const QStringList &data, const QString &filename) { QString filePath = filename.isEmpty() ? m_suggestedFilePath : filename; if (filename.isEmpty() || QFile::exists(filePath)) { filePath = QFileDialog::getSaveFileName(this, QString(), filePath); if (filePath.isEmpty()) return false; // user pressed cancel } QFile file(filePath); if (file.open(QIODevice::WriteOnly)) { QTextStream stream(&file); for (const QString line : data) stream << line << "\n"; file.close(); } if (file.error() != QFile::NoError) { KMessageBox::detailedError(this, i18n("Error saving file %1", filePath), file.errorString()); return false; } return true; } void CreateWizard::accept() { const bool saved = m_onePerFileBox->isChecked() ? savePerFile() : saveChecksumFile(m_process->stdOutput()); if (saved) QWizard::accept(); } // ------------- Verify Wizard VerifyWizard::VerifyWizard(const QString &path, const QString &inputFile) : ChecksumWizard(path) { m_checksumFile = isSupported(inputFile) ? inputFile : path; m_introId = addPage(createIntroPage()); // m_checksumFile must already be set m_progressId = addPage(createProgressPage(i18n("Verifying Checksums"))); m_resultId = addPage(createResultPage()); } void VerifyWizard::slotChecksumPathChanged(const QString &path) { m_hashesTreeWidget->clear(); button(QWizard::NextButton)->setEnabled(false); if (!isSupported(path)) return; m_checksumFile = path; // parse and display checksum file content; only for the user, parsed values are not used m_hashesTreeWidget->clear(); QFile file(m_checksumFile); if (file.open(QFile::ReadOnly)) { QTextStream inStream(&file); while (!inStream.atEnd()) { addChecksumLine(m_hashesTreeWidget, file.readLine()); } } file.close(); button(QWizard::NextButton)->setEnabled(true); } QWizardPage *VerifyWizard::createIntroPage() { QWizardPage *page = new QWizardPage; page->setTitle(i18n("Verify Checksum File")); page->setPixmap(QWizard::LogoPixmap, - krLoader->loadIcon("document-edit-verify", KIconLoader::Desktop, 32)); + Icon("document-edit-verify").pixmap(32)); page->setSubTitle(i18n("About to verify the following checksum file")); QVBoxLayout *mainLayout = new QVBoxLayout; page->setLayout(mainLayout); // checksum file QHBoxLayout *hLayout = new QHBoxLayout; QLabel *checksumFileLabel = new QLabel(i18n("Checksum file:")); hLayout->addWidget(checksumFileLabel); KUrlRequester *checksumFileReq = new KUrlRequester; QString typesFilter; for (const QString ext: m_checksumTools.keys()) typesFilter += ("*." + ext + ' '); checksumFileReq->setFilter(typesFilter); checksumFileReq->setText(m_checksumFile); checksumFileReq->setFocus(); connect(checksumFileReq, &KUrlRequester::textChanged, this, &VerifyWizard::slotChecksumPathChanged); hLayout->addWidget(checksumFileReq); mainLayout->addLayout(hLayout); // content of checksum file m_hashesTreeWidget = new KrTreeWidget(page); m_hashesTreeWidget->setAllColumnsShowFocus(true); m_hashesTreeWidget->setHeaderLabels(QStringList() << i18n("Hash") << i18n("File")); mainLayout->addWidget(m_hashesTreeWidget); return page; } QWizardPage *VerifyWizard::createResultPage() { QWizardPage *page = new QWizardPage; page->setTitle(i18n("Verify Result")); QVBoxLayout *mainLayout = new QVBoxLayout; page->setLayout(mainLayout); m_outputLabel = new QLabel(i18n("Result output:")); mainLayout->addWidget(m_outputLabel); m_outputListWidget = new KrListWidget; mainLayout->addWidget(m_outputListWidget); return page; } void VerifyWizard::onIntroPage() { // cannot do this in constructor: NextButton->hide() is overridden slotChecksumPathChanged(m_checksumFile); } void VerifyWizard::onProgressPage() { // verify checksum file... const QString extension = QFileInfo(m_checksumFile).suffix(); if (!checkExists(extension)) { button(QWizard::BackButton)->show(); return; } runProcess(extension, QStringList() << "--strict" << "-c" << m_checksumFile); } void VerifyWizard::onResultPage() { // better not only trust error output const bool errors = m_process->exitCode() != 0 || !m_process->errOutput().isEmpty(); QWizardPage *page = currentPage(); page->setPixmap(QWizard::LogoPixmap, - krLoader->loadIcon(errors ? "dialog-error" : "dialog-information", - KIconLoader::Desktop, 32)); + Icon(errors ? "dialog-error" : "dialog-information").pixmap(32)); page->setSubTitle(errors ? i18n("Errors were detected while verifying the checksums") : i18n("Checksums were verified successfully")); // print everything, errors first m_outputListWidget->clear(); m_outputListWidget->addItems(m_process->errOutput() + m_process->stdOutput()); button(QWizard::FinishButton)->setEnabled(!errors); } bool VerifyWizard::isSupported(const QString &path) { const QFileInfo fileInfo(path); return fileInfo.isFile() && m_checksumTools.keys().contains(fileInfo.suffix()); } } // NAMESPACE CHECKSUM_ diff --git a/krusader/Dialogs/krspwidgets.cpp b/krusader/Dialogs/krspwidgets.cpp index 8865369b..0eed58ef 100644 --- a/krusader/Dialogs/krspwidgets.cpp +++ b/krusader/Dialogs/krspwidgets.cpp @@ -1,260 +1,259 @@ /***************************************************************************** * Copyright (C) 2000 Shie Erlich * * 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 "krspwidgets.h" #include "../krglobal.h" -#include "../kicons.h" +#include "../icon.h" #include "../Filter/filtertabs.h" #include "../GUI/krlistwidget.h" // QtCore #include // QtGui #include // QtWidgets #include #include #include #include #include #include // missing ? #include #include #include #include -#include #include ///////////////////// initiation of the static members //////////////////////// QStringList KRSpWidgets::maskList; /////////////////////////////////////////////////////////////////////////////// KRSpWidgets::KRSpWidgets() { } KRQuery KRSpWidgets::getMask(QString caption, bool nameOnly, QWidget * parent) { if (!nameOnly) { return FilterTabs::getQuery(parent); } else { QPointer p = new KRMaskChoiceSub(parent); p->setWindowTitle(caption); p->exec(); QString selection = p->selection->currentText(); delete p; if (selection.isEmpty()) { return KRQuery(); } else { return KRQuery(selection); } } } /////////////////////////// newFTP //////////////////////////////////////// QUrl KRSpWidgets::newFTP() { QPointer p = new newFTPSub(); p->exec(); QString uri = p->url->currentText(); if (uri.isEmpty()) { delete p; return QUrl(); // empty url } QString protocol = p->prefix->currentText(); protocol.truncate(protocol.length() - 3); // remove the trailing :// QString username = p->username->text().simplified(); QString password = p->password->text().simplified(); int uriStart = uri.lastIndexOf('@'); /* lets the user enter user and password in the URI field */ if (uriStart != -1) { QString uriUser = uri.left(uriStart); QString uriPsw; uri = uri.mid(uriStart + 1); int pswStart = uriUser.indexOf(':'); /* getting the password name from the URL */ if (pswStart != -1) { uriPsw = uriUser.mid(pswStart + 1); uriUser = uriUser.left(pswStart); } if (!uriUser.isEmpty()) { /* handling the ftp proxy username and password also */ username = username.isEmpty() ? uriUser : username + '@' + uriUser; } if (!uriPsw.isEmpty()) { /* handling the ftp proxy username and password also */ password = password.isEmpty() ? uriPsw : password + '@' + uriPsw; } } QString host = uri; /* separating the hostname and path from the uri */ QString path; int pathStart = uri.indexOf("/"); if (pathStart != -1) { path = host.mid(pathStart); host = host.left(pathStart); } /* setting the parameters of the URL */ QUrl url; url.setScheme(protocol); url.setHost(host); url.setPath(path); if (protocol == "ftp" || protocol == "fish" || protocol == "sftp") { url.setPort(p->port->cleanText().toInt()); } if (!username.isEmpty()) { url.setUserName(username); } if (!password.isEmpty()) { url.setPassword(password); } delete p; return url; } newFTPSub::newFTPSub() : newFTPGUI(0) { url->setFocus(); setGeometry(krMainWindow->x() + krMainWindow->width() / 2 - width() / 2, krMainWindow->y() + krMainWindow->height() / 2 - height() / 2, width(), height()); } void newFTPSub::accept() { url->addToHistory(url->currentText()); // save the history and completion list when the history combo is // destroyed KConfigGroup group(krConfig, "Private"); QStringList list = url->completionObject()->items(); group.writeEntry("newFTP Completion list", list); list = url->historyItems(); group.writeEntry("newFTP History list", list); QString protocol = prefix->currentText(); group.writeEntry("newFTP Protocol", protocol); newFTPGUI::accept(); } void newFTPSub::reject() { url->lineEdit()->setText(""); newFTPGUI::reject(); } /////////////////////////// KRMaskChoiceSub /////////////////////////////// KRMaskChoiceSub::KRMaskChoiceSub(QWidget * parent) : KRMaskChoice(parent) { - PixmapLabel1->setPixmap(krLoader->loadIcon("edit-select", KIconLoader::Desktop, 32)); + PixmapLabel1->setPixmap(Icon("edit-select").pixmap(32)); label->setText(i18n("Enter a selection:")); // the predefined selections list KConfigGroup group(krConfig, "Private"); QStringList lst = group.readEntry("Predefined Selections", QStringList()); if (lst.size() > 0) preSelections->addItems(lst); // the combo-box tweaks selection->setDuplicatesEnabled(false); selection->addItems(KRSpWidgets::maskList); selection->lineEdit()->setText("*"); selection->lineEdit()->selectAll(); selection->setFocus(); } void KRMaskChoiceSub::reject() { selection->clear(); KRMaskChoice::reject(); } void KRMaskChoiceSub::accept() { bool add = true; // make sure we don't have that already for (int i = 0; i != KRSpWidgets::maskList.count(); i++) if (KRSpWidgets::maskList[ i ].simplified() == selection->currentText().simplified()) { // break if we found one such as this add = false; break; } if (add) KRSpWidgets::maskList.insert(0, selection->currentText().toLocal8Bit()); // write down the predefined selections list QStringList list; for (int j = 0; j != preSelections->count(); j++) { QListWidgetItem *i = preSelections->item(j); list.append(i->text()); } KConfigGroup group(krConfig, "Private"); group.writeEntry("Predefined Selections", list); KRMaskChoice::accept(); } void KRMaskChoiceSub::addSelection() { QString temp = selection->currentText(); bool itemExists = false; // check if the selection already exists for (int j = 0; j != preSelections->count(); j++) { QListWidgetItem *i = preSelections->item(j); if (i->text() == temp) { itemExists = true; break; } } if (!temp.isEmpty() && !itemExists) { preSelections->addItem(selection->currentText()); preSelections->update(); } } void KRMaskChoiceSub::deleteSelection() { delete preSelections->currentItem(); preSelections->update(); } void KRMaskChoiceSub::clearSelections() { preSelections->clear(); preSelections->update(); } void KRMaskChoiceSub::acceptFromList(QListWidgetItem *i) { selection->addItem(i->text(), 0); accept(); } void KRMaskChoiceSub::currentItemChanged(QListWidgetItem *i) { if (i) selection->setEditText(i->text()); } diff --git a/krusader/Dialogs/kurllistrequester.cpp b/krusader/Dialogs/kurllistrequester.cpp index dcfa33dd..72723141 100644 --- a/krusader/Dialogs/kurllistrequester.cpp +++ b/krusader/Dialogs/kurllistrequester.cpp @@ -1,190 +1,190 @@ /***************************************************************************** * Copyright (C) 2005 Csaba Karai * * Copyright (C) 2005-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 "kurllistrequester.h" #include "../FileSystem/filesystem.h" +#include "../icon.h" // QtGui #include #include #include // QtWidgets #include #include #include #include #include -#include #include #define DELETE_ITEM_ID 100 KURLListRequester::KURLListRequester(Mode requestMode, QWidget *parent) : QWidget(parent), mode(requestMode) { // Creating the widget QGridLayout *urlListRequesterGrid = new QGridLayout(this); urlListRequesterGrid->setSpacing(0); urlListRequesterGrid->setContentsMargins(0, 0, 0, 0); urlLineEdit = new KLineEdit(this); urlListRequesterGrid->addWidget(urlLineEdit, 0, 0); urlListBox = new KrListWidget(this); urlListBox->setSelectionMode(QAbstractItemView::ExtendedSelection); urlListRequesterGrid->addWidget(urlListBox, 1, 0, 1, 3); urlAddBtn = new QToolButton(this); urlAddBtn->setText(""); - urlAddBtn->setIcon(QIcon::fromTheme("arrow-down")); + urlAddBtn->setIcon(Icon("arrow-down")); urlListRequesterGrid->addWidget(urlAddBtn, 0, 1); urlBrowseBtn = new QToolButton(this); urlBrowseBtn->setText(""); - urlBrowseBtn->setIcon(QIcon::fromTheme("folder")); + urlBrowseBtn->setIcon(Icon("folder")); urlListRequesterGrid->addWidget(urlBrowseBtn, 0, 2); // add shell completion completion.setMode(KUrlCompletion::FileCompletion); urlLineEdit->setCompletionObject(&completion); // connection table connect(urlAddBtn, SIGNAL(clicked()), this, SLOT(slotAdd())); connect(urlBrowseBtn, SIGNAL(clicked()), this, SLOT(slotBrowse())); connect(urlLineEdit, SIGNAL(returnPressed(QString)), this, SLOT(slotAdd())); connect(urlListBox, SIGNAL(itemRightClicked(QListWidgetItem*,QPoint)), this, SLOT(slotRightClicked(QListWidgetItem*,QPoint))); connect(urlLineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(changed())); } void KURLListRequester::slotAdd() { QString text = urlLineEdit->text().simplified(); if (text.length()) { QString error; emit checkValidity(text, error); if (!error.isNull()) KMessageBox::error(this, error); else { urlListBox->addItem(text); urlLineEdit->clear(); emit changed(); } } } void KURLListRequester::slotBrowse() { QUrl url; switch (mode) { case RequestFiles: url = QFileDialog::getOpenFileUrl(this); break; case RequestDirs: url = QFileDialog::getExistingDirectoryUrl(this); break; } if (!url.isEmpty()) urlLineEdit->setText(url.toDisplayString(QUrl::PreferLocalFile)); urlLineEdit->setFocus(); } void KURLListRequester::keyPressEvent(QKeyEvent *e) { if (e->key() == Qt::Key_Delete) { if (urlListBox->hasFocus()) { deleteSelectedItems(); return; } } QWidget::keyPressEvent(e); } void KURLListRequester::deleteSelectedItems() { QList delList = urlListBox->selectedItems(); for (int i = 0; i != delList.count(); i++) delete delList[ i ]; emit changed(); } void KURLListRequester::slotRightClicked(QListWidgetItem *item, const QPoint &pos) { if (item == 0) return; QMenu popupMenu(this); QAction * menuAction = popupMenu.addAction(i18n("Delete")); if (menuAction == popupMenu.exec(pos)) { if (item->isSelected()) deleteSelectedItems(); else { delete item; emit changed(); } } } QList KURLListRequester::urlList() { QList urls; QString text = urlLineEdit->text().simplified(); if (!text.isEmpty()) { QString error; emit checkValidity(text, error); if (error.isNull()) urls.append(QUrl::fromUserInput(text, QString(), QUrl::AssumeLocalFile)); } for (int i = 0; i != urlListBox->count(); i++) { QListWidgetItem *item = urlListBox->item(i); QString text = item->text().simplified(); QString error; emit checkValidity(text, error); if (error.isNull()) urls.append(QUrl::fromUserInput(text, QString(), QUrl::AssumeLocalFile)); } return urls; } void KURLListRequester::setUrlList(QList urlList) { urlLineEdit->clear(); urlListBox->clear(); QList::iterator it; for (it = urlList.begin(); it != urlList.end(); ++it) urlListBox->addItem(it->toDisplayString(QUrl::PreferLocalFile)); emit changed(); } diff --git a/krusader/Dialogs/newftpgui.cpp b/krusader/Dialogs/newftpgui.cpp index 254e1b74..4e51c4aa 100644 --- a/krusader/Dialogs/newftpgui.cpp +++ b/krusader/Dialogs/newftpgui.cpp @@ -1,205 +1,205 @@ /***************************************************************************** * Copyright (C) 2002 Shie Erlich * * Copyright (C) 2002 Rafi Yanai * * Copyright (C) 2009 Fathi Boudra * * 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 "newftpgui.h" // QtCore #include #include // QtGui #include // QtWidgets #include #include #include #include #include #include #include #include -#include #include #include "../krglobal.h" +#include "../icon.h" #define SIZE_MINIMUM QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed) const QStringList sProtocols = QStringList() << QStringLiteral("ftp") << QStringLiteral("ftps") << QStringLiteral("sftp") << QStringLiteral("fish") << QStringLiteral("nfs") << QStringLiteral("smb") << QStringLiteral("webdav") << QStringLiteral("svn") << QStringLiteral("svn+file") << QStringLiteral("svn+http") << QStringLiteral("svn+https") << QStringLiteral("svn+ssh"); /** * Constructs a newFTPGUI which is a child of 'parent', * with the name 'name' and widget flags set to 'f' */ newFTPGUI::newFTPGUI(QWidget* parent) : QDialog(parent) { setModal(true); setWindowTitle(i18n("New Network Connection")); resize(500, 240); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); QSizePolicy policy(QSizePolicy::Preferred, QSizePolicy::Preferred); policy.setHeightForWidth(sizePolicy().hasHeightForWidth()); setSizePolicy(policy); iconLabel = new QLabel(this); - iconLabel->setPixmap(krLoader->loadIcon("network-wired", KIconLoader::Desktop, 32)); + iconLabel->setPixmap(Icon("network-wired").pixmap(32)); iconLabel->setSizePolicy(SIZE_MINIMUM); aboutLabel = new QLabel(i18n("About to connect to..."), this); QFont font(aboutLabel->font()); font.setBold(true); aboutLabel->setFont(font); protocolLabel = new QLabel(i18n("Protocol:"), this); hostLabel = new QLabel(i18n("Host:"), this); portLabel = new QLabel(i18n("Port:"), this); prefix = new KComboBox(this); prefix->setObjectName(QString::fromUtf8("protocol")); prefix->setSizePolicy(SIZE_MINIMUM); url = new KHistoryComboBox(this); url->setMaxCount(50); url->setMinimumContentsLength(10); const QStringList availableProtocols = KProtocolInfo::protocols(); for (const QString protocol : sProtocols) { if (availableProtocols.contains(protocol)) prefix->addItem(protocol + QStringLiteral("://")); } // load the history and completion list after creating the history combo KConfigGroup group(krConfig, "Private"); QStringList list = group.readEntry("newFTP Completion list", QStringList()); url->completionObject()->setItems(list); list = group.readEntry("newFTP History list", QStringList()); url->setHistoryItems(list); // Select last used protocol const QString lastUsedProtocol = group.readEntry("newFTP Protocol", QString()); if(!lastUsedProtocol.isEmpty()) { prefix->setCurrentItem(lastUsedProtocol); } port = new QSpinBox(this); port->setMaximum(65535); port->setValue(21); port->setSizePolicy(SIZE_MINIMUM); usernameLabel = new QLabel(i18n("Username:"), this); username = new KLineEdit(this); passwordLabel = new QLabel(i18n("Password:"), this); password = new KLineEdit(this); password->setEchoMode(QLineEdit::Password); QHBoxLayout *horizontalLayout = new QHBoxLayout(); horizontalLayout->addWidget(iconLabel); horizontalLayout->addWidget(aboutLabel); QGridLayout *gridLayout = new QGridLayout(); gridLayout->addWidget(protocolLabel, 0, 0, 1, 1); gridLayout->addWidget(hostLabel, 0, 1, 1, 1); gridLayout->addWidget(portLabel, 0, 2, 1, 1); gridLayout->addWidget(prefix, 1, 0, 1, 1); gridLayout->addWidget(url, 1, 1, 1, 1); gridLayout->addWidget(port, 1, 2, 1, 1); gridLayout->addWidget(usernameLabel, 2, 0, 1, 1); gridLayout->addWidget(username, 3, 0, 1, 3); gridLayout->addWidget(passwordLabel, 4, 0, 1, 1); gridLayout->addWidget(password, 5, 0, 1, 3); QGridLayout *widgetLayout = new QGridLayout(); widgetLayout->addLayout(horizontalLayout, 0, 0, 1, 1); widgetLayout->addLayout(gridLayout, 1, 0, 1, 1); mainLayout->addLayout(widgetLayout); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); mainLayout->addWidget(buttonBox); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setText(i18n("&Connect")); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); connect(prefix, SIGNAL(activated(QString)), this, SLOT(slotTextChanged(QString))); connect(url, SIGNAL(activated(QString)), url, SLOT(addToHistory(QString))); if(!lastUsedProtocol.isEmpty()) { // update the port field slotTextChanged(lastUsedProtocol); } setTabOrder(url, username); setTabOrder(username, password); setTabOrder(password, prefix); } /** * Destroys the object and frees any allocated resources */ newFTPGUI::~newFTPGUI() { // no need to delete child widgets, Qt does it all for us } void newFTPGUI::slotTextChanged(const QString &string) { if (string.startsWith(QLatin1String("ftp")) || string.startsWith(QLatin1String("sftp")) || string.startsWith(QLatin1String("fish"))) { if (port->value() == 21 || port->value() == 22) { port->setValue(string.startsWith(QLatin1String("ftp")) ? 21 : 22); } port->setEnabled(true); } else { port->setEnabled(false); } } /** * Main event handler. Reimplemented to handle application font changes */ bool newFTPGUI::event(QEvent *ev) { bool ret = QDialog::event(ev); if (ev->type() == QEvent::ApplicationFontChange) { QFont font(aboutLabel->font()); font.setBold(true); aboutLabel->setFont(font); } return ret; } diff --git a/krusader/Dialogs/packguibase.cpp b/krusader/Dialogs/packguibase.cpp index 0ddb3a5b..f2049f4e 100644 --- a/krusader/Dialogs/packguibase.cpp +++ b/krusader/Dialogs/packguibase.cpp @@ -1,496 +1,496 @@ /***************************************************************************** * Copyright (C) 2000 Shie Erlich * * 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 "packguibase.h" // QtCore #include // QtGui #include #include #include #include // QtWidgets #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include "../defaults.h" #include "../krglobal.h" +#include "../icon.h" /* * Constructs a PackGUIBase which is a child of 'parent', with the * name 'name' and widget flags set to 'f' * * The dialog will by default be modeless, unless you set 'modal' to * TRUE to construct a modal dialog. */ PackGUIBase::PackGUIBase(QWidget* parent) : QDialog(parent), expanded(false) { KConfigGroup group(krConfig, "Archives"); setModal(true); resize(430, 140); setWindowTitle(i18n("Pack")); grid = new QGridLayout(this); grid->setSpacing(6); grid->setContentsMargins(11, 11, 11, 11); hbox = new QHBoxLayout; hbox->setSpacing(6); hbox->setContentsMargins(0, 0, 0, 0); TextLabel3 = new QLabel(this); TextLabel3->setText(i18n("To archive")); hbox->addWidget(TextLabel3); nameData = new QLineEdit(this); hbox->addWidget(nameData); typeData = new QComboBox(this); typeData->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed)); connect(typeData, SIGNAL(activated(QString)), this, SLOT(checkConsistency())); connect(typeData, SIGNAL(highlighted(QString)), this, SLOT(checkConsistency())); hbox->addWidget(typeData); grid->addLayout(hbox, 1, 0); hbox_2 = new QHBoxLayout; hbox_2->setSpacing(6); hbox_2->setContentsMargins(0, 0, 0, 0); TextLabel5 = new QLabel(this); TextLabel5->setText(i18n("In folder")); hbox_2->addWidget(TextLabel5); dirData = new QLineEdit(this); hbox_2->addWidget(dirData); browseButton = new QToolButton(this); - browseButton->setIcon(SmallIcon("document-open")); + browseButton->setIcon(Icon("document-open")); hbox_2->addWidget(browseButton); QSpacerItem* spacer = new QSpacerItem(48, 20, QSizePolicy::Fixed, QSizePolicy::Fixed); hbox_2->addItem(spacer); grid->addLayout(hbox_2, 2, 0); hbox_3 = new QHBoxLayout; hbox_3->setSpacing(6); hbox_3->setContentsMargins(0, 0, 0, 0); PixmapLabel1 = new QLabel(this); - PixmapLabel1->setPixmap(krLoader->loadIcon("package-x-generic", KIconLoader::Desktop, 32)); + PixmapLabel1->setPixmap(Icon("package-x-generic").pixmap(32)); PixmapLabel1->setScaledContents(true); PixmapLabel1->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); hbox_3->addWidget(PixmapLabel1); TextLabel1 = new QLabel(this); TextLabel1->setText(i18n("Pack")); hbox_3->addWidget(TextLabel1); grid->addLayout(hbox_3, 0, 0); hbox_4 = new QHBoxLayout; hbox_4->setSpacing(6); hbox_4->setContentsMargins(0, 0, 0, 0); QSpacerItem* spacer_3 = new QSpacerItem(20, 26, QSizePolicy::Fixed, QSizePolicy::Expanding); hbox_4->addItem(spacer_3); grid->addLayout(hbox_4, 3, 0); advancedWidget = new QWidget(this); hbox_5 = new QGridLayout(advancedWidget); hbox_5->setSpacing(6); hbox_5->setContentsMargins(0, 0, 0, 0); QVBoxLayout *compressLayout = new QVBoxLayout; compressLayout->setSpacing(6); compressLayout->setContentsMargins(0, 0, 0, 0); multipleVolume = new QCheckBox(i18n("Multiple volume archive"), advancedWidget); connect(multipleVolume, SIGNAL(toggled(bool)), this, SLOT(checkConsistency())); compressLayout->addWidget(multipleVolume, 0, 0); QHBoxLayout * volumeHbox = new QHBoxLayout; QSpacerItem* spacer_5 = new QSpacerItem(20, 26, QSizePolicy::Fixed, QSizePolicy::Fixed); volumeHbox->addItem(spacer_5); TextLabel7 = new QLabel(i18n("Size:"), advancedWidget); volumeHbox->addWidget(TextLabel7); volumeSpinBox = new QSpinBox(advancedWidget); volumeSpinBox->setMinimum(1); volumeSpinBox->setMaximum(9999); volumeSpinBox->setValue(1440); volumeHbox->addWidget(volumeSpinBox); volumeUnitCombo = new QComboBox(advancedWidget); volumeUnitCombo->addItem("B"); volumeUnitCombo->addItem("KB"); volumeUnitCombo->addItem("MB"); volumeUnitCombo->setCurrentIndex(1); volumeHbox->addWidget(volumeUnitCombo); compressLayout->addLayout(volumeHbox); int level = group.readEntry("Compression level", _defaultCompressionLevel); setCompressionLevel = new QCheckBox(i18n("Set compression level"), advancedWidget); if (level != _defaultCompressionLevel) setCompressionLevel->setChecked(true); connect(setCompressionLevel, SIGNAL(toggled(bool)), this, SLOT(checkConsistency())); compressLayout->addWidget(setCompressionLevel, 0, 0); QHBoxLayout * sliderHbox = new QHBoxLayout; QSpacerItem* spacer_6 = new QSpacerItem(20, 26, QSizePolicy::Fixed, QSizePolicy::Fixed); sliderHbox->addItem(spacer_6); QWidget * sliderVBoxWidget = new QWidget(advancedWidget); QVBoxLayout *sliderVBox = new QVBoxLayout(sliderVBoxWidget); compressionSlider = new QSlider(Qt::Horizontal, sliderVBoxWidget); compressionSlider->setMinimum(1); compressionSlider->setMaximum(9); compressionSlider->setPageStep(1); compressionSlider->setValue(level); compressionSlider->setTickPosition(QSlider::TicksBelow); sliderVBox->addWidget(compressionSlider); QWidget * minmaxWidget = new QWidget(sliderVBoxWidget); sliderVBox->addWidget(minmaxWidget); QHBoxLayout * minmaxHbox = new QHBoxLayout(minmaxWidget); minLabel = new QLabel(i18n("MIN"), minmaxWidget); maxLabel = new QLabel(i18n("MAX"), minmaxWidget); maxLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); minmaxHbox->addWidget(minLabel); minmaxHbox->addWidget(maxLabel); sliderHbox->addWidget(sliderVBoxWidget); compressLayout->addLayout(sliderHbox); compressLayout->addStretch(0); hbox_5->addLayout(compressLayout, 0, 0); QFrame *vline = new QFrame(advancedWidget); vline->setFrameStyle(QFrame::VLine | QFrame::Sunken); vline->setMinimumWidth(20); hbox_5->addWidget(vline, 0, 1); QGridLayout * passwordGrid = new QGridLayout; passwordGrid->setSpacing(6); passwordGrid->setContentsMargins(0, 0, 0, 0); TextLabel4 = new QLabel(advancedWidget); TextLabel4->setText(i18n("Password")); passwordGrid->addWidget(TextLabel4, 0, 0); password = new QLineEdit(advancedWidget); password->setEchoMode(QLineEdit::Password); connect(password, SIGNAL(textChanged(QString)), this, SLOT(checkConsistency())); passwordGrid->addWidget(password, 0, 1); TextLabel6 = new QLabel(advancedWidget); TextLabel6->setText(i18n("Again")); passwordGrid->addWidget(TextLabel6, 1, 0); passwordAgain = new QLineEdit(advancedWidget); passwordAgain->setEchoMode(QLineEdit::Password); connect(passwordAgain, SIGNAL(textChanged(QString)), this, SLOT(checkConsistency())); passwordGrid->addWidget(passwordAgain, 1, 1); QHBoxLayout *consistencyHbox = new QHBoxLayout; QSpacerItem* spacer_cons = new QSpacerItem(48, 20, QSizePolicy::Expanding, QSizePolicy::Fixed); consistencyHbox->addItem(spacer_cons); passwordConsistencyLabel = new QLabel(advancedWidget); consistencyHbox->addWidget(passwordConsistencyLabel); passwordGrid->addLayout(consistencyHbox, 2, 0, 1, 2); encryptHeaders = new QCheckBox(i18n("Encrypt headers"), advancedWidget); passwordGrid->addWidget(encryptHeaders, 3, 0, 1, 2); QSpacerItem* spacer_psw = new QSpacerItem(20, 20, QSizePolicy::Fixed, QSizePolicy::Expanding); passwordGrid->addItem(spacer_psw, 4, 0); hbox_5->addLayout(passwordGrid, 0, 2); hbox_7 = new QHBoxLayout; hbox_7->setSpacing(6); hbox_7->setContentsMargins(0, 0, 0, 0); TextLabel8 = new QLabel(i18n("Command line switches:"), advancedWidget); TextLabel8->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); hbox_7->addWidget(TextLabel8); commandLineSwitches = new KHistoryComboBox(advancedWidget); commandLineSwitches->setMaxCount(25); // remember 25 items commandLineSwitches->setDuplicatesEnabled(false); commandLineSwitches->setMinimumContentsLength(10); QStringList list = group.readEntry("Command Line Switches", QStringList()); commandLineSwitches->setHistoryItems(list); hbox_7->addWidget(commandLineSwitches); hbox_5->addLayout(hbox_7, 1, 0, 1, 3); advancedWidget->hide(); checkConsistency(); grid->addWidget(advancedWidget, 4, 0); hbox_6 = new QHBoxLayout; hbox_6->setSpacing(6); hbox_6->setContentsMargins(0, 0, 0, 0); advancedButton = new QPushButton(this); advancedButton->setText(i18n("&Advanced >>")); hbox_6->addWidget(advancedButton); QSpacerItem* spacer_2 = new QSpacerItem(140, 20, QSizePolicy::Expanding, QSizePolicy::Fixed); hbox_6->addItem(spacer_2); okButton = new QPushButton(this); KStandardGuiItem::assign(okButton, KStandardGuiItem::Ok); okButton->setDefault(true); hbox_6->addWidget(okButton); cancelButton = new QPushButton(this); KStandardGuiItem::assign(cancelButton, KStandardGuiItem::Cancel); hbox_6->addWidget(cancelButton); grid->addLayout(hbox_6, 6, 0); // signals and slots connections connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); connect(advancedButton, SIGNAL(clicked()), this, SLOT(expand())); connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); connect(browseButton, SIGNAL(clicked()), this, SLOT(browse())); } /* * Destroys the object and frees any allocated resources */ PackGUIBase::~PackGUIBase() { // no need to delete child widgets, Qt does it all for us } void PackGUIBase::browse() { qWarning("PackGUIBase::browse(): Not implemented yet!"); } void PackGUIBase::expand() { expanded = !expanded; advancedButton->setText(expanded ? i18n("&Advanced <<") : i18n("&Advanced >>")); if (expanded) advancedWidget->show(); else { advancedWidget->hide(); layout()->activate(); QSize minSize = minimumSize(); resize(width(), minSize.height()); } show(); } void PackGUIBase::checkConsistency() { QPalette p = QGuiApplication::palette(); QPalette pal = passwordConsistencyLabel->palette(); if (password->text().isEmpty() && passwordAgain->text().isEmpty()) { pal.setColor(passwordConsistencyLabel->foregroundRole(), p.color(QPalette::Active, QPalette::Text)); passwordConsistencyLabel->setText(i18n("No password specified")); } else if (password->text() == passwordAgain->text()) { pal.setColor(passwordConsistencyLabel->foregroundRole(), p.color(QPalette::Active, QPalette::Text)); passwordConsistencyLabel->setText(i18n("The passwords are equal")); } else { pal.setColor(passwordConsistencyLabel->foregroundRole(), Qt::red); passwordConsistencyLabel->setText(i18n("The passwords are different")); } passwordConsistencyLabel->setPalette(pal); QString packer = typeData->currentText(); bool passworded = false; if (packer == "7z" || packer == "rar" || packer == "zip" || packer == "arj") passworded = true; passwordConsistencyLabel->setEnabled(passworded); password->setEnabled(passworded); passwordAgain->setEnabled(passworded); TextLabel4->setEnabled(passworded); TextLabel6->setEnabled(passworded); encryptHeaders->setEnabled(packer == "rar"); multipleVolume->setEnabled(packer == "rar" || packer == "arj"); bool volumeEnabled = multipleVolume->isEnabled() && multipleVolume->isChecked(); volumeSpinBox->setEnabled(volumeEnabled); volumeUnitCombo->setEnabled(volumeEnabled); TextLabel7->setEnabled(volumeEnabled); /* TODO */ setCompressionLevel->setEnabled(packer == "rar" || packer == "arj" || packer == "zip" || packer == "7z"); bool sliderEnabled = setCompressionLevel->isEnabled() && setCompressionLevel->isChecked(); compressionSlider->setEnabled(sliderEnabled); minLabel->setEnabled(sliderEnabled); maxLabel->setEnabled(sliderEnabled); } bool PackGUIBase::extraProperties(QMap & inMap) { inMap.clear(); KConfigGroup group(krConfig, "Archives"); if (password->isEnabled() && passwordAgain->isEnabled()) { if (password->text() != passwordAgain->text()) { KMessageBox::error(this, i18n("Cannot pack, the passwords are different.")); return false; } if (!password->text().isEmpty()) { inMap[ "Password" ] = password->text(); if (encryptHeaders->isEnabled() && encryptHeaders->isChecked()) inMap[ "EncryptHeaders" ] = '1'; } } if (multipleVolume->isEnabled() && multipleVolume->isChecked()) { KIO::filesize_t size = volumeSpinBox->value(); switch (volumeUnitCombo->currentIndex()) { case 2: size *= 1000; #if __GNUC__ >= 7 [[gnu::fallthrough]]; #endif case 1: size *= 1000; default: break; } if (size < 10000) { KMessageBox::error(this, i18n("Invalid volume size.")); return false; } QString sbuffer; sbuffer.sprintf("%llu", size); inMap[ "VolumeSize" ] = sbuffer; } if (setCompressionLevel->isEnabled() && setCompressionLevel->isChecked()) { inMap[ "CompressionLevel" ] = QString("%1").arg(compressionSlider->value()); int level = compressionSlider->value(); group.writeEntry("Compression level", level); } QString cmdArgs = commandLineSwitches->currentText().trimmed(); if (!cmdArgs.isEmpty()) { bool firstChar = true; QChar quote = QChar::Null; for (int i = 0; i < cmdArgs.length(); i++) { QChar ch(cmdArgs[ i ]); if (ch.isSpace()) continue; if (ch == quote) { quote = QChar::Null; continue; } if (firstChar && ch != QLatin1Char('-')) { KMessageBox::error(this, i18n("Invalid command line switch.\nA switch must start with '-'.")); return false; } firstChar = false; if (quote == QLatin1Char('"')) continue; if (quote == QChar::Null && (ch == QLatin1Char('\'') || ch == QLatin1Char('"'))) quote = ch; if (ch == QLatin1Char('\\')) { if (i == cmdArgs.length() - 1) { KMessageBox::error(this, i18n("Invalid command line switch.\nBackslashes cannot be the last character.")); return false; } i++; } } if (quote != QChar::Null) { KMessageBox::error(this, i18n("Invalid command line switch.\nUnclosed quotation mark.")); return false; } commandLineSwitches->addToHistory(cmdArgs); QStringList list = commandLineSwitches->historyItems(); group.writeEntry("Command Line Switches", list); inMap[ "CommandLineSwitches" ] = cmdArgs; } return true; } diff --git a/krusader/Dialogs/popularurls.cpp b/krusader/Dialogs/popularurls.cpp index bcd40a1d..c39d8c60 100644 --- a/krusader/Dialogs/popularurls.cpp +++ b/krusader/Dialogs/popularurls.cpp @@ -1,375 +1,375 @@ /***************************************************************************** * Copyright (C) 2002 Shie Erlich * * Copyright (C) 2002 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 "popularurls.h" #include // QtCore #include // QtWidgets #include #include #include #include #include #include #include #include #include #include -#include #include #include "../krglobal.h" +#include "../icon.h" #include "../krslots.h" #include "../GUI/krtreewidget.h" #define STARTING_RANK 20 #define INCREASE 2 #define DECREASE 1 PopularUrls::PopularUrls(QObject *parent) : QObject(parent), head(0), tail(0), count(0) { dlg = new PopularUrlsDlg(); } PopularUrls::~PopularUrls() { clearList(); delete dlg; } void PopularUrls::clearList() { if (head) { UrlNodeP p = head, tmp; while (p) { tmp = p; p = p->next; delete tmp; } } ranks.clear(); head = tail = 0; } void PopularUrls::save() { KConfigGroup svr(krConfig, "Private"); // prepare the string list containing urls and int list with ranks QStringList urlList; QList rankList; UrlNodeP p = head; while (p) { urlList << p->url.toDisplayString(); rankList << p->rank; p = p->next; } svr.writeEntry("PopularUrls", urlList); svr.writeEntry("PopularUrlsRank", rankList); } void PopularUrls::load() { KConfigGroup svr(krConfig, "Private"); QStringList urlList = svr.readEntry("PopularUrls", QStringList()); QList rankList = svr.readEntry("PopularUrlsRank", QList()); if (urlList.count() != rankList.count()) { KMessageBox::error(krMainWindow, i18n("The saved 'Popular URLs' are invalid. The list will be cleared.")); return; } clearList(); count = 0; // iterate through both lists and QStringList::Iterator uit; QList::Iterator rit; for (uit = urlList.begin(), rit = rankList.begin(); uit != urlList.end() && rit != rankList.end(); ++uit, ++rit) { UrlNodeP node = new UrlNode; node->url = QUrl(*uit); node->rank = *rit; appendNode(node); ranks.insert(*uit, node); } } // returns a url list with the 'max' top popular urls QList PopularUrls::getMostPopularUrls(int max) { // get at most 'max' urls QList list; UrlNodeP p = head; int tmp = 0; if (maxUrls < max) max = maxUrls; // don't give more than maxUrls while (p && tmp < max) { list << p->url; p = p->next; ++tmp; } return list; } // adds a url to the list, or increase rank of an existing url, making // sure to bump it up the list if needed void PopularUrls::addUrl(const QUrl& url) { QUrl tmpurl = url; tmpurl.setPassword(QString()); // make sure no passwords are permanently stored if (!tmpurl.path().endsWith('/')) // make a uniform trailing slash policy tmpurl.setPath(tmpurl.path() + '/'); UrlNodeP pnode; decreaseRanks(); if (!head) { // if the list is empty ... (assumes dict to be empty as well) pnode = new UrlNode; pnode->rank = STARTING_RANK; pnode->url = tmpurl; appendNode(pnode); ranks.insert(tmpurl.url(), head); } else { if (ranks.find(tmpurl.url()) == ranks.end()) { // is the added url new? if so, append it pnode = new UrlNode; pnode->rank = STARTING_RANK; pnode->url = tmpurl; appendNode(pnode); ranks.insert(tmpurl.url(), pnode); } else { pnode = ranks[ tmpurl.url()]; pnode->rank += INCREASE; } } // do we need to change location for this one? relocateIfNeeded(pnode); // too many urls? if (count > maxUrls) removeNode(tail); //dumpList(); } // checks if 'node' needs to be bumped-up the ranking list and does it if needed void PopularUrls::relocateIfNeeded(UrlNodeP node) { if (node->prev && (node->prev->rank < node->rank)) { // iterate until we find the correct place to put it UrlNodeP tmp = node->prev->prev; while (tmp) { if (tmp->rank >= node->rank) break; // found it! else tmp = tmp->prev; } // now, if tmp isn't null, we need to move node to tmp->next // else move it to become head removeNode(node); insertNode(node, tmp); } } // iterate over the list, decreasing each url's rank // this is very naive, but a 1..30 for loop is acceptable (i hope) void PopularUrls::decreaseRanks() { if (head) { UrlNodeP p = head; while (p) { if (p->rank - DECREASE >= 0) p->rank -= DECREASE; else p->rank = 0; p = p->next; } } } // removes a node from the list, but doesn't free memory! // note: this will be buggy in case the list becomes empty (which should never happen) void PopularUrls::removeNode(UrlNodeP node) { if (node->prev) { if (tail == node) tail = node->prev; node->prev->next = node->next; } if (node->next) { if (head == node) head = node->next; node->next->prev = node->prev; } --count; } void PopularUrls::insertNode(UrlNodeP node, UrlNodeP after) { if (!after) { // make node head node->next = head; node->prev = 0; head->prev = node; head = node; } else { if (tail == after) tail = node; node->prev = after; node->next = after->next; if (node->next) { after->next->prev = node; after->next = node; } } ++count; } // appends 'node' to the end of the list, collecting garbage if needed void PopularUrls::appendNode(UrlNodeP node) { if (!tail) { // creating the first element head = tail = node; node->prev = node->next = 0; } else { node->next = 0; node->prev = tail; tail->next = node; tail = node; } ++count; } void PopularUrls::dumpList() { UrlNodeP p = head; printf("====start %d====\n", count); while (p) { printf("%d : %s\n", p->rank, p->url.url().toLatin1().data()); p = p->next; } fflush(stdout); } void PopularUrls::showDialog() { QList list = getMostPopularUrls(maxUrls); dlg->run(list); if (dlg->result() == -1) return; SLOTS->refresh(list[dlg->result()]); //printf("running %s\n", list[dlg->result()].url().toLatin1());fflush(stdout); } // ===================================== PopularUrlsDlg ====================================== PopularUrlsDlg::PopularUrlsDlg(): QDialog(krMainWindow) { setWindowTitle(i18n("Popular URLs")); setWindowModality(Qt::WindowModal); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); QGridLayout *layout = new QGridLayout; layout->setContentsMargins(0, 0, 0, 0); // listview to contain the urls urls = new KrTreeWidget(this); urls->header()->hide(); urls->setSortingEnabled(false); urls->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); // quick search search = new KTreeWidgetSearchLine(this, urls); QLabel *lbl = new QLabel(i18n("&Search:"), this); lbl->setBuddy(search); layout->addWidget(lbl, 0, 0); layout->addWidget(search, 0, 1); layout->addWidget(urls, 1, 0, 1, 2); mainLayout->addLayout(layout); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); mainLayout->addWidget(buttonBox); setTabOrder(search, urls); setTabOrder((QWidget *)urls, buttonBox->button(QDialogButtonBox::Close)); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); connect(urls, SIGNAL(activated(QModelIndex)), this, SLOT(slotItemSelected(QModelIndex))); connect(search, SIGNAL(hiddenChanged(QTreeWidgetItem*,bool)), this, SLOT(slotVisibilityChanged())); } void PopularUrlsDlg::slotItemSelected(const QModelIndex & ndx) { selection = ndx.row(); accept(); } void PopularUrlsDlg::slotVisibilityChanged() { // select the first visible item QList list = urls->selectedItems(); if (list.count() > 0 && !list[0]->isHidden()) return; urls->clearSelection(); urls->setCurrentItem(0); QTreeWidgetItemIterator it(urls); while (*it) { if (!(*it)->isHidden()) { (*it)->setSelected(true); urls->setCurrentItem(*it); break; } it++; } } PopularUrlsDlg::~PopularUrlsDlg() { delete search; delete urls; } void PopularUrlsDlg::run(QList list) { // populate the listview urls->clear(); QList::Iterator it; QTreeWidgetItem * lastItem = 0; for (it = list.begin(); it != list.end(); ++it) { QTreeWidgetItem *item = new QTreeWidgetItem(urls, lastItem); lastItem = item; item->setText(0, (*it).isLocalFile() ? (*it).path() : (*it).toDisplayString()); - item->setIcon(0, (*it).isLocalFile() ? SmallIcon("folder") : SmallIcon("folder-html")); + item->setIcon(0, (*it).isLocalFile() ? Icon("folder") : Icon("folder-html")); } setMinimumSize(urls->sizeHint().width() + 45, 400); search->clear(); search->setFocus(); selection = -1; slotVisibilityChanged(); exec(); } diff --git a/krusader/DiskUsage/diskusage.cpp b/krusader/DiskUsage/diskusage.cpp index 530c4050..fa5a3d57 100644 --- a/krusader/DiskUsage/diskusage.cpp +++ b/krusader/DiskUsage/diskusage.cpp @@ -1,1133 +1,1133 @@ /***************************************************************************** * Copyright (C) 2004 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/]. * *****************************************************************************/ #include "diskusage.h" // QtCore #include #include #include #include #include #include // QtGui #include #include #include #include #include // QtWidgets #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dufilelight.h" #include "dulines.h" #include "dulistview.h" #include "filelightParts/Config.h" #include "../FileSystem/fileitem.h" #include "../FileSystem/filesystemprovider.h" #include "../FileSystem/krpermhandler.h" #include "../Panel/krpanel.h" #include "../Panel/panelfunc.h" #include "../defaults.h" -#include "../kicons.h" #include "../krglobal.h" +#include "../filelisticon.h" // these are the values that will exist in the menu #define DELETE_ID 90 #define EXCLUDE_ID 91 #define PARENT_DIR_ID 92 #define NEW_SEARCH_ID 93 #define REFRESH_ID 94 #define STEP_INTO_ID 95 #define INCLUDE_ALL_ID 96 #define VIEW_POPUP_ID 97 #define LINES_VIEW_ID 98 #define DETAILED_VIEW_ID 99 #define FILELIGHT_VIEW_ID 100 #define NEXT_VIEW_ID 101 #define PREVIOUS_VIEW_ID 102 #define ADDITIONAL_POPUP_ID 103 #define MAX_FILENUM 100 LoaderWidget::LoaderWidget(QWidget *parent) : QScrollArea(parent), cancelled(false) { QPalette palette = viewport()->palette(); palette.setColor(viewport()->backgroundRole(), Qt::white); viewport()->setPalette(palette); widget = new QWidget(parent); QGridLayout *loaderLayout = new QGridLayout(widget); loaderLayout->setSpacing(0); loaderLayout->setContentsMargins(0, 0, 0, 0); QFrame *loaderBox = new QFrame(widget); loaderBox->setFrameShape(QFrame::Box); loaderBox->setFrameShadow(QFrame::Sunken); loaderBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); loaderBox->setFrameStyle(QFrame::Panel + QFrame::Raised); loaderBox->setLineWidth(2); QGridLayout *synchGrid = new QGridLayout(loaderBox); synchGrid->setSpacing(6); synchGrid->setContentsMargins(11, 11, 11, 11); QLabel *titleLabel = new QLabel(i18n("Loading Usage Information"), loaderBox); titleLabel->setAlignment(Qt::AlignHCenter); synchGrid->addWidget(titleLabel, 0, 0, 1, 2); QLabel *filesLabel = new QLabel(i18n("Files:"), loaderBox); filesLabel->setFrameShape(QLabel::StyledPanel); filesLabel->setFrameShadow(QLabel::Sunken); synchGrid->addWidget(filesLabel, 1, 0); QLabel *directoriesLabel = new QLabel(i18n("Directories:"), loaderBox); directoriesLabel->setFrameShape(QLabel::StyledPanel); directoriesLabel->setFrameShadow(QLabel::Sunken); synchGrid->addWidget(directoriesLabel, 2, 0); QLabel *totalSizeLabel = new QLabel(i18n("Total Size:"), loaderBox); totalSizeLabel->setFrameShape(QLabel::StyledPanel); totalSizeLabel->setFrameShadow(QLabel::Sunken); synchGrid->addWidget(totalSizeLabel, 3, 0); files = new QLabel(loaderBox); files->setFrameShape(QLabel::StyledPanel); files->setFrameShadow(QLabel::Sunken); files->setAlignment(Qt::AlignRight); synchGrid->addWidget(files, 1, 1); directories = new QLabel(loaderBox); directories->setFrameShape(QLabel::StyledPanel); directories->setFrameShadow(QLabel::Sunken); directories->setAlignment(Qt::AlignRight); synchGrid->addWidget(directories, 2, 1); totalSize = new QLabel(loaderBox); totalSize->setFrameShape(QLabel::StyledPanel); totalSize->setFrameShadow(QLabel::Sunken); totalSize->setAlignment(Qt::AlignRight); synchGrid->addWidget(totalSize, 3, 1); int width; searchedDirectory = new KSqueezedTextLabel(loaderBox); searchedDirectory->setFrameShape(QLabel::StyledPanel); searchedDirectory->setFrameShadow(QLabel::Sunken); searchedDirectory->setMinimumWidth(width = QFontMetrics(searchedDirectory->font()).width("W") * 30); searchedDirectory->setMaximumWidth(width); synchGrid->addWidget(searchedDirectory, 4, 0, 1, 2); QFrame *line = new QFrame(loaderBox); line->setFrameStyle(QFrame::HLine | QFrame::Sunken); synchGrid->addWidget(line, 5, 0, 1, 2); QWidget *hboxWidget = new QWidget(loaderBox); QHBoxLayout * hbox = new QHBoxLayout(hboxWidget); QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); hbox->addItem(spacer); QPushButton *cancelButton = new QPushButton(hboxWidget); KStandardGuiItem::assign(cancelButton, KStandardGuiItem::Cancel); hbox->addWidget(cancelButton); synchGrid->addWidget(hboxWidget, 6, 1); loaderLayout->addWidget(loaderBox, 0, 0); setWidget(widget); setAlignment(Qt::AlignCenter); connect(cancelButton, SIGNAL(clicked()), this, SLOT(slotCancelled())); } void LoaderWidget::init() { cancelled = false; } void LoaderWidget::setCurrentURL(const QUrl &url) { searchedDirectory->setText(FileSystem::ensureTrailingSlash(url).toDisplayString(QUrl::PreferLocalFile)); } void LoaderWidget::setValues(int fileNum, int dirNum, KIO::filesize_t total) { files->setText(QString("%1").arg(fileNum)); directories->setText(QString("%1").arg(dirNum)); totalSize->setText(QString("%1").arg(KRpermHandler::parseSize(total).trimmed())); } void LoaderWidget::slotCancelled() { cancelled = true; } DiskUsage::DiskUsage(QString confGroup, QWidget *parent) : QStackedWidget(parent), currentDirectory(0), root(0), configGroup(confGroup), loading(false), abortLoading(false), clearAfterAbort(false), deleting(false), searchFileSystem(0) { listView = new DUListView(this); lineView = new DULines(this); filelightView = new DUFilelight(this); loaderView = new LoaderWidget(this); addWidget(listView); addWidget(lineView); addWidget(filelightView); addWidget(loaderView); setView(VIEW_LINES); Filelight::Config::read(); connect(&loadingTimer, SIGNAL(timeout()), this, SLOT(slotLoadDirectory())); } DiskUsage::~DiskUsage() { if (listView) // don't remove these lines. The module will crash at exit if removed delete listView; if (lineView) delete lineView; if (filelightView) delete filelightView; if (root) delete root; QHashIterator< File *, Properties * > lit(propertyMap); while (lit.hasNext()) delete lit.next().value(); } void DiskUsage::load(const QUrl &baseDir) { fileNum = dirNum = 0; currentSize = 0; emit status(i18n("Loading the disk usage information...")); clear(); baseURL = baseDir.adjusted(QUrl::StripTrailingSlash); root = new Directory(baseURL.fileName(), baseDir.toDisplayString(QUrl::PreferLocalFile)); directoryStack.clear(); parentStack.clear(); directoryStack.push(""); parentStack.push(root); if (searchFileSystem) { delete searchFileSystem; searchFileSystem = 0; } searchFileSystem = FileSystemProvider::instance().getFilesystem(baseDir); if (searchFileSystem == 0) { qWarning() << "could not get filesystem for directory=" << baseDir; loading = abortLoading = clearAfterAbort = false; emit loadFinished(false); return; } currentFileItem = 0; if (!loading) { viewBeforeLoad = activeView; setView(VIEW_LOADER); } loading = true; loaderView->init(); loaderView->setCurrentURL(baseURL); loaderView->setValues(fileNum, dirNum, currentSize); loadingTimer.setSingleShot(true); loadingTimer.start(0); } void DiskUsage::slotLoadDirectory() { if ((currentFileItem == 0 && directoryStack.isEmpty()) || loaderView->wasCancelled() || abortLoading) { if (searchFileSystem) delete searchFileSystem; searchFileSystem = 0; currentFileItem = 0; setView(viewBeforeLoad); if (clearAfterAbort) clear(); else { calculateSizes(); changeDirectory(root); } emit loadFinished(!(loaderView->wasCancelled() || abortLoading)); loading = abortLoading = clearAfterAbort = false; } else if (loading) { for (int counter = 0; counter != MAX_FILENUM; counter ++) { if (currentFileItem == 0) { if (directoryStack.isEmpty()) break; dirToCheck = directoryStack.pop(); currentParent = parentStack.pop(); contentMap.insert(dirToCheck, currentParent); QUrl url = baseURL; if (!dirToCheck.isEmpty()) { url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + '/' + (dirToCheck)); } #ifdef BSD if (url.isLocalFile() && url.path().left(7) == "/procfs") break; #else if (url.isLocalFile() && url.path().left(5) == "/proc") break; #endif loaderView->setCurrentURL(url); if (!searchFileSystem->scanDir(url)) break; fileItems = searchFileSystem->fileItems(); dirNum++; currentFileItem = fileItems.isEmpty() ? 0 : fileItems.takeFirst(); } else { fileNum++; File *newItem = 0; QString mime = currentFileItem->getMime(); // fast == not using mimetype magic if (currentFileItem->isDir() && !currentFileItem->isSymLink()) { newItem = new Directory(currentParent, currentFileItem->getName(), dirToCheck, currentFileItem->getSize(), currentFileItem->getMode(), currentFileItem->getOwner(), currentFileItem->getGroup(), currentFileItem->getPerm(), currentFileItem->getTime_t(), currentFileItem->isSymLink(), mime); directoryStack.push((dirToCheck.isEmpty() ? "" : dirToCheck + '/') + currentFileItem->getName()); parentStack.push(dynamic_cast(newItem)); } else { newItem = new File(currentParent, currentFileItem->getName(), dirToCheck, currentFileItem->getSize(), currentFileItem->getMode(), currentFileItem->getOwner(), currentFileItem->getGroup(), currentFileItem->getPerm(), currentFileItem->getTime_t(), currentFileItem->isSymLink(), mime); currentSize += currentFileItem->getSize(); } currentParent->append(newItem); currentFileItem = fileItems.isEmpty() ? 0 : fileItems.takeFirst(); } } loaderView->setValues(fileNum, dirNum, currentSize); loadingTimer.setSingleShot(true); loadingTimer.start(0); } } void DiskUsage::stopLoad() { abortLoading = true; } void DiskUsage::close() { if (loading) { abortLoading = true; clearAfterAbort = true; } } void DiskUsage::dirUp() { if (currentDirectory != 0) { if (currentDirectory->parent() != 0) changeDirectory((Directory *)(currentDirectory->parent())); else { QUrl up = KIO::upUrl(baseURL); if (KMessageBox::questionYesNo(this, i18n("Stepping into the parent folder requires " "loading the content of the \"%1\" URL. Do you wish " "to continue?", up.toDisplayString(QUrl::PreferLocalFile)), i18n("Krusader::DiskUsage"), KStandardGuiItem::yes(), KStandardGuiItem::no(), "DiskUsageLoadParentDir" ) == KMessageBox::Yes) load(up); } } } Directory * DiskUsage::getDirectory(QString dir) { while (dir.endsWith('/')) dir.truncate(dir.length() - 1); if (dir.isEmpty()) return root; if (contentMap.find(dir) == contentMap.end()) return 0; return contentMap[ dir ]; } File * DiskUsage::getFile(QString path) { if (path.isEmpty()) return root; QString dir = path; int ndx = path.lastIndexOf('/'); QString file = path.mid(ndx + 1); if (ndx == -1) dir = ""; else dir.truncate(ndx); Directory *dirEntry = getDirectory(dir); if (dirEntry == 0) return 0; for (Iterator it = dirEntry->iterator(); it != dirEntry->end(); ++it) if ((*it)->name() == file) return *it; return 0; } void DiskUsage::clear() { baseURL = QUrl(); emit clearing(); QHashIterator< File *, Properties * > lit(propertyMap); while (lit.hasNext()) delete lit.next().value(); propertyMap.clear(); contentMap.clear(); if (root) delete root; root = currentDirectory = 0; } int DiskUsage::calculateSizes(Directory *dirEntry, bool emitSig, int depth) { int changeNr = 0; if (dirEntry == 0) dirEntry = root; KIO::filesize_t own = 0, total = 0; for (Iterator it = dirEntry->iterator(); it != dirEntry->end(); ++it) { File * item = *it; if (!item->isExcluded()) { if (item->isDir()) changeNr += calculateSizes(dynamic_cast(item), emitSig, depth + 1); else own += item->size(); total += item->size(); } } KIO::filesize_t oldOwn = dirEntry->ownSize(), oldTotal = dirEntry->size(); dirEntry->setSizes(total, own); if (dirEntry == currentDirectory) currentSize = total; if (emitSig && (own != oldOwn || total != oldTotal)) { emit changed(dirEntry); changeNr++; } if (depth == 0 && changeNr != 0) emit changeFinished(); return changeNr; } int DiskUsage::exclude(File *file, bool calcPercents, int depth) { int changeNr = 0; if (!file->isExcluded()) { file->exclude(true); emit changed(file); changeNr++; if (file->isDir()) { Directory *dir = dynamic_cast(file); for (Iterator it = dir->iterator(); it != dir->end(); ++it) changeNr += exclude(*it, false, depth + 1); } } if (calcPercents) { calculateSizes(root, true); calculatePercents(true); createStatus(); } if (depth == 0 && changeNr != 0) emit changeFinished(); return changeNr; } int DiskUsage::include(Directory *dir, int depth) { int changeNr = 0; if (dir == 0) return 0; for (Iterator it = dir->iterator(); it != dir->end(); ++it) { File *item = *it; if (item->isDir()) changeNr += include(dynamic_cast(item), depth + 1); if (item->isExcluded()) { item->exclude(false); emit changed(item); changeNr++; } } if (depth == 0 && changeNr != 0) emit changeFinished(); return changeNr; } void DiskUsage::includeAll() { include(root); calculateSizes(root, true); calculatePercents(true); createStatus(); } int DiskUsage::del(File *file, bool calcPercents, int depth) { int deleteNr = 0; if (file == root) return 0; KConfigGroup gg(krConfig, "General"); bool trash = gg.readEntry("Move To Trash", _MoveToTrash); QUrl url = QUrl::fromLocalFile(file->fullPath()); if (calcPercents) { // now ask the user if he want to delete: KConfigGroup ga(krConfig, "Advanced"); if (ga.readEntry("Confirm Delete", _ConfirmDelete)) { QString s; KGuiItem b; if (trash && url.isLocalFile()) { s = i18nc("singularOnly", "Do you really want to move this item to the trash?"); b = KGuiItem(i18n("&Trash")); } else { s = i18nc("singularOnly", "Do you really want to delete this item?"); b = KStandardGuiItem::del(); } QStringList name; name.append(file->fullPath()); // show message // note: i'm using continue and not yes/no because the yes/no has cancel as default button if (KMessageBox::warningContinueCancelList(krMainWindow, s, name, i18n("Warning"), b) != KMessageBox::Continue) return 0; } emit status(i18n("Deleting %1...", file->name())); } if (file == currentDirectory) dirUp(); if (file->isDir()) { Directory *dir = dynamic_cast(file); Iterator it; while ((it = dir->iterator()) != dir->end()) deleteNr += del(*it, false, depth + 1); QString path; for (const Directory *d = (Directory*)file; d != root && d && d->parent() != 0; d = d->parent()) { if (!path.isEmpty()) path = '/' + path; path = d->name() + path; } contentMap.remove(path); } emit deleted(file); deleteNr++; KIO::Job *job; if (trash) { job = KIO::trash(url); } else { job = KIO::del(QUrl::fromLocalFile(file->fullPath()), KIO::HideProgressInfo); } deleting = true; // during qApp->processEvent strange things can occur grabMouse(); // that's why we disable the mouse and keyboard events grabKeyboard(); job->exec(); delete job; releaseMouse(); releaseKeyboard(); deleting = false; ((Directory *)(file->parent()))->remove(file); delete file; if (depth == 0) createStatus(); if (calcPercents) { calculateSizes(root, true); calculatePercents(true); createStatus(); emit enteringDirectory(currentDirectory); } if (depth == 0 && deleteNr != 0) emit deleteFinished(); return deleteNr; } void * DiskUsage::getProperty(File *item, QString key) { QHash< File *, Properties *>::iterator itr = propertyMap.find(item); if (itr == propertyMap.end()) return 0; QHash::iterator it = (*itr)->find(key); if (it == (*itr)->end()) return 0; return it.value(); } void DiskUsage::addProperty(File *item, QString key, void * prop) { Properties *props; QHash< File *, Properties *>::iterator itr = propertyMap.find(item); if (itr == propertyMap.end()) { props = new Properties(); propertyMap.insert(item, props); } else props = *itr; props->insert(key, prop); } void DiskUsage::removeProperty(File *item, QString key) { QHash< File *, Properties *>::iterator itr = propertyMap.find(item); if (itr == propertyMap.end()) return; (*itr)->remove(key); if ((*itr)->count() == 0) propertyMap.remove(item); } void DiskUsage::createStatus() { Directory *dirEntry = currentDirectory; if (dirEntry == 0) return; QUrl url = baseURL; if (dirEntry != root) { url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + '/' + (dirEntry->directory())); } emit status(i18n("Current folder:%1, Total size:%2, Own size:%3", url.toDisplayString(QUrl::PreferLocalFile | QUrl::StripTrailingSlash), ' ' + KRpermHandler::parseSize(dirEntry->size()), ' ' + KRpermHandler::parseSize(dirEntry->ownSize()))); } void DiskUsage::changeDirectory(Directory *dir) { currentDirectory = dir; currentSize = dir->size(); calculatePercents(true, dir); createStatus(); emit enteringDirectory(dir); } Directory* DiskUsage::getCurrentDir() { return currentDirectory; } void DiskUsage::rightClickMenu(const QPoint & pos, File *fileItem, QMenu *addPopup, QString addPopupName) { QMenu popup(this); popup.setTitle(i18n("Disk Usage")); QHash actionHash; if (fileItem != 0) { QAction * actDelete = popup.addAction(i18n("Delete")); actionHash[ actDelete ] = DELETE_ID; actDelete->setShortcut(Qt::Key_Delete); QAction * actExclude = popup.addAction(i18n("Exclude")); actionHash[ actExclude ] = EXCLUDE_ID; actExclude->setShortcut(Qt::CTRL + Qt::Key_E); popup.addSeparator(); } QAction * myAct = popup.addAction(i18n("Up one folder")); actionHash[ myAct ] = PARENT_DIR_ID; myAct->setShortcut(Qt::SHIFT + Qt::Key_Up); myAct = popup.addAction(i18n("New search")); actionHash[ myAct ] = NEW_SEARCH_ID; myAct->setShortcut(Qt::CTRL + Qt::Key_N); myAct = popup.addAction(i18n("Refresh")); actionHash[ myAct ] = REFRESH_ID; myAct->setShortcut(Qt::CTRL + Qt::Key_R); myAct = popup.addAction(i18n("Include all")); actionHash[ myAct ] = INCLUDE_ALL_ID; myAct->setShortcut(Qt::CTRL + Qt::Key_I); myAct = popup.addAction(i18n("Step into")); actionHash[ myAct ] = STEP_INTO_ID; myAct->setShortcut(Qt::SHIFT + Qt::Key_Down); popup.addSeparator(); if (addPopup != 0) { QAction * menu = popup.addMenu(addPopup); menu->setText(addPopupName); } QMenu viewPopup; myAct = viewPopup.addAction(i18n("Lines")); actionHash[ myAct ] = LINES_VIEW_ID; myAct->setShortcut(Qt::CTRL + Qt::Key_L); myAct = viewPopup.addAction(i18n("Detailed")); actionHash[ myAct ] = DETAILED_VIEW_ID; myAct->setShortcut(Qt::CTRL + Qt::Key_D); myAct = viewPopup.addAction(i18n("Filelight")); actionHash[ myAct ] = FILELIGHT_VIEW_ID; myAct->setShortcut(Qt::CTRL + Qt::Key_F); viewPopup.addSeparator(); myAct = viewPopup.addAction(i18n("Next")); actionHash[ myAct ] = NEXT_VIEW_ID; myAct->setShortcut(Qt::SHIFT + Qt::Key_Right); myAct = viewPopup.addAction(i18n("Previous")); actionHash[ myAct ] = PREVIOUS_VIEW_ID; myAct->setShortcut(Qt::SHIFT + Qt::Key_Left); QAction * menu = popup.addMenu(&viewPopup); menu->setText(i18n("View")); QAction * res = popup.exec(pos); if (actionHash.contains(res)) executeAction(actionHash[ res ], fileItem); } void DiskUsage::executeAction(int action, File * fileItem) { // check out the user's option switch (action) { case DELETE_ID: if (fileItem) del(fileItem); break; case EXCLUDE_ID: if (fileItem) exclude(fileItem); break; case PARENT_DIR_ID: dirUp(); break; case NEW_SEARCH_ID: emit newSearch(); break; case REFRESH_ID: load(baseURL); break; case INCLUDE_ALL_ID: includeAll(); break; case STEP_INTO_ID: { QString uri; if (fileItem && fileItem->isDir()) uri = fileItem->fullPath(); else uri = currentDirectory->fullPath(); ACTIVE_FUNC->openUrl(QUrl::fromLocalFile(uri)); } break; case LINES_VIEW_ID: setView(VIEW_LINES); break; case DETAILED_VIEW_ID: setView(VIEW_DETAILED); break; case FILELIGHT_VIEW_ID: setView(VIEW_FILELIGHT); break; case NEXT_VIEW_ID: setView((activeView + 1) % 3); break; case PREVIOUS_VIEW_ID: setView((activeView + 2) % 3); break; } // currentWidget()->setFocus(); } void DiskUsage::keyPressEvent(QKeyEvent *e) { if (activeView != VIEW_LOADER) { switch (e->key()) { case Qt::Key_E: if (e->modifiers() == Qt::ControlModifier) { executeAction(EXCLUDE_ID, getCurrentFile()); return; } break; case Qt::Key_D: if (e->modifiers() == Qt::ControlModifier) { executeAction(DETAILED_VIEW_ID); return; } break; case Qt::Key_F: if (e->modifiers() == Qt::ControlModifier) { executeAction(FILELIGHT_VIEW_ID); return; } break; case Qt::Key_I: if (e->modifiers() == Qt::ControlModifier) { executeAction(INCLUDE_ALL_ID); return; } break; case Qt::Key_L: if (e->modifiers() == Qt::ControlModifier) { executeAction(LINES_VIEW_ID); return; } break; case Qt::Key_N: if (e->modifiers() == Qt::ControlModifier) { executeAction(NEW_SEARCH_ID); return; } break; case Qt::Key_R: if (e->modifiers() == Qt::ControlModifier) { executeAction(REFRESH_ID); return; } break; case Qt::Key_Up: if (e->modifiers() == Qt::ShiftModifier) { executeAction(PARENT_DIR_ID); return; } break; case Qt::Key_Down: if (e->modifiers() == Qt::ShiftModifier) { executeAction(STEP_INTO_ID); return; } break; case Qt::Key_Left: if (e->modifiers() == Qt::ShiftModifier) { executeAction(PREVIOUS_VIEW_ID); return; } break; case Qt::Key_Right: if (e->modifiers() == Qt::ShiftModifier) { executeAction(NEXT_VIEW_ID); return; } break; case Qt::Key_Delete: if (!e->modifiers()) { executeAction(DELETE_ID, getCurrentFile()); return; } break; case Qt::Key_Plus: if (activeView == VIEW_FILELIGHT) { filelightView->zoomIn(); return; } break; case Qt::Key_Minus: if (activeView == VIEW_FILELIGHT) { filelightView->zoomOut(); return; } break; } } QStackedWidget::keyPressEvent(e); } QPixmap DiskUsage::getIcon(QString mime) { QPixmap icon; if (!QPixmapCache::find(mime, icon)) { // get the icon. if (mime == "Broken Link !") // FIXME: this doesn't work anymore - the reported mimetype for a broken link is now "unknown" - icon = FL_LOADICON("file-broken"); + icon = FileListIcon("file-broken").pixmap(); else { QMimeDatabase db; QMimeType mt = db.mimeTypeForName(mime); if (mt.isValid()) - icon = FL_LOADICON(mt.iconName()); + icon = FileListIcon(mt.iconName()).pixmap(); else - icon = FL_LOADICON("file-broken"); + icon = FileListIcon("file-broken").pixmap(); } // insert it into the cache QPixmapCache::insert(mime, icon); } return icon; } int DiskUsage::calculatePercents(bool emitSig, Directory *dirEntry, int depth) { int changeNr = 0; if (dirEntry == 0) dirEntry = root; for (Iterator it = dirEntry->iterator(); it != dirEntry->end(); ++it) { File *item = *it; if (!item->isExcluded()) { int newPerc; if (dirEntry->size() == 0 && item->size() == 0) newPerc = 0; else if (dirEntry->size() == 0) newPerc = -1; else newPerc = (int)((double)item->size() / (double)currentSize * 10000. + 0.5); int oldPerc = item->intPercent(); item->setPercent(newPerc); if (emitSig && newPerc != oldPerc) { emit changed(item); changeNr++; } if (item->isDir()) changeNr += calculatePercents(emitSig, dynamic_cast(item), depth + 1); } } if (depth == 0 && changeNr != 0) emit changeFinished(); return changeNr; } QString DiskUsage::getToolTip(File *item) { QMimeDatabase db; QMimeType mt = db.mimeTypeForName(item->mime()); QString mime; if (mt.isValid()) mime = mt.comment(); time_t tma = item->time(); struct tm* t = localtime((time_t *) & tma); QDateTime tmp(QDate(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday), QTime(t->tm_hour, t->tm_min)); QString date = QLocale().toString(tmp, QLocale::ShortFormat); QString str = "
" + "" + ""; if (item->isDir()) str += ""; str += "" + "" + "" + "
" + i18n("Name:") + "" + item->name() + "
" + i18n("Type:") + "" + mime + "
" + i18n("Size:") + "" + KRpermHandler::parseSize(item->size()) + "
" + i18n("Own size:") + "" + KRpermHandler::parseSize(item->ownSize()) + "
" + i18n("Last modified:") + "" + date + "
" + i18n("Permissions:") + "" + item->perm() + "
" + i18n("Owner:") + "" + item->owner() + " - " + item->group() + "
"; str.replace(' ', " "); return str; } void DiskUsage::setView(int view) { switch (view) { case VIEW_LINES: setCurrentWidget(lineView); break; case VIEW_DETAILED: setCurrentWidget(listView); break; case VIEW_FILELIGHT: setCurrentWidget(filelightView); break; case VIEW_LOADER: setCurrentWidget(loaderView); break; } // currentWidget()->setFocus(); emit viewChanged(activeView = view); } File * DiskUsage::getCurrentFile() { File * file = 0; switch (activeView) { case VIEW_LINES: file = lineView->getCurrentFile(); break; case VIEW_DETAILED: file = listView->getCurrentFile(); break; case VIEW_FILELIGHT: file = filelightView->getCurrentFile(); break; } return file; } bool DiskUsage::event(QEvent * e) { if (deleting) { // if we are deleting, disable the mouse and switch (e->type()) { // keyboard events case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: case QEvent::MouseMove: case QEvent::KeyPress: case QEvent::KeyRelease: return true; default: break; } } if (e->type() == QEvent::ShortcutOverride) { QKeyEvent* ke = (QKeyEvent*) e; if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::KeypadModifier) { switch (ke->key()) { case Qt::Key_Delete: case Qt::Key_Plus: case Qt::Key_Minus: ke->accept(); break; } } else if (ke->modifiers() == Qt::ShiftModifier) { switch (ke->key()) { case Qt::Key_Left: case Qt::Key_Right: case Qt::Key_Up: case Qt::Key_Down: ke->accept(); break; } } else if (ke->modifiers() & Qt::ControlModifier) { switch (ke->key()) { case Qt::Key_D: case Qt::Key_E: case Qt::Key_F: case Qt::Key_I: case Qt::Key_L: case Qt::Key_N: case Qt::Key_R: ke->accept(); break; } } } return QStackedWidget::event(e); } diff --git a/krusader/DiskUsage/diskusagegui.cpp b/krusader/DiskUsage/diskusagegui.cpp index 35024713..dc7e3756 100644 --- a/krusader/DiskUsage/diskusagegui.cpp +++ b/krusader/DiskUsage/diskusagegui.cpp @@ -1,243 +1,242 @@ /***************************************************************************** * Copyright (C) 2004 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/]. * *****************************************************************************/ #include "diskusagegui.h" // QtCore #include // QtGui #include // QtWidgets #include #include #include #include #include #include -#include -#include "../kicons.h" #include "../krglobal.h" +#include "../icon.h" #include "../FileSystem/filesystem.h" #include "../Dialogs/krdialogs.h" DiskUsageGUI::DiskUsageGUI(const QUrl &openDir) : QDialog(nullptr), exitAtFailure(true) { setWindowTitle(i18n("Krusader::Disk Usage")); setAttribute(Qt::WA_DeleteOnClose); baseDirectory = openDir; QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); QGridLayout *duGrid = new QGridLayout(); duGrid->setSpacing(6); duGrid->setContentsMargins(11, 11, 11, 11); QWidget *duTools = new QWidget(this); QHBoxLayout *duHBox = new QHBoxLayout(duTools); duHBox->setContentsMargins(0, 0, 0, 0); duTools->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); btnNewSearch = new QToolButton(duTools); - btnNewSearch->setIcon(QIcon(krLoader->loadIcon("document-open", KIconLoader::Desktop))); + btnNewSearch->setIcon(Icon("document-open")); duHBox->addWidget(btnNewSearch); btnNewSearch->setToolTip(i18n("Start new disk usage search")); btnRefresh = new QToolButton(duTools); - btnRefresh->setIcon(QIcon(krLoader->loadIcon("view-refresh", KIconLoader::Desktop))); + btnRefresh->setIcon(Icon("view-refresh")); duHBox->addWidget(btnRefresh); btnRefresh->setToolTip(i18n("Refresh")); btnDirUp = new QToolButton(duTools); - btnDirUp->setIcon(QIcon(krLoader->loadIcon("go-up", KIconLoader::Desktop))); + btnDirUp->setIcon(Icon("go-up")); duHBox->addWidget(btnDirUp); btnDirUp->setToolTip(i18n("Parent folder")); QWidget *separatorWidget = new QWidget(duTools); separatorWidget->setMinimumWidth(10); duHBox->addWidget(separatorWidget); btnLines = new QToolButton(duTools); - btnLines->setIcon(QIcon(krLoader->loadIcon("view-list-details", KIconLoader::Desktop))); + btnLines->setIcon(Icon("view-list-details")); btnLines->setCheckable(true); duHBox->addWidget(btnLines); btnLines->setToolTip(i18n("Line view")); btnDetailed = new QToolButton(duTools); - btnDetailed->setIcon(QIcon(krLoader->loadIcon("view-list-tree", KIconLoader::Desktop))); + btnDetailed->setIcon(Icon("view-list-tree")); btnDetailed->setCheckable(true); duHBox->addWidget(btnDetailed); btnDetailed->setToolTip(i18n("Detailed view")); btnFilelight = new QToolButton(duTools); - btnFilelight->setIcon(QIcon(krLoader->loadIcon("kr_diskusage", KIconLoader::Desktop))); + btnFilelight->setIcon(Icon("kr_diskusage")); btnFilelight->setCheckable(true); duHBox->addWidget(btnFilelight); btnFilelight->setToolTip(i18n("Filelight view")); QWidget *spacerWidget = new QWidget(duTools); duHBox->addWidget(spacerWidget); QHBoxLayout *hboxlayout = new QHBoxLayout(spacerWidget); QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Fixed); hboxlayout->addItem(spacer); duGrid->addWidget(duTools, 0, 0); diskUsage = new DiskUsage("DiskUsage", this); duGrid->addWidget(diskUsage, 1, 0); status = new KSqueezedTextLabel(this); duGrid->addWidget(status, 2, 0); mainLayout->addLayout(duGrid); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); mainLayout->addWidget(buttonBox); connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); connect(diskUsage, SIGNAL(status(QString)), this, SLOT(slotStatus(QString))); connect(diskUsage, SIGNAL(viewChanged(int)), this, SLOT(slotViewChanged(int))); connect(diskUsage, SIGNAL(newSearch()), this, SLOT(askDir())); connect(diskUsage, SIGNAL(loadFinished(bool)), this, SLOT(slotLoadFinished(bool))); connect(btnNewSearch, SIGNAL(clicked()), this, SLOT(askDir())); connect(btnRefresh, SIGNAL(clicked()), this, SLOT(slotLoadUsageInfo())); connect(btnDirUp, SIGNAL(clicked()), diskUsage, SLOT(dirUp())); connect(btnLines, SIGNAL(clicked()), this, SLOT(slotSelectLinesView())); connect(btnDetailed, SIGNAL(clicked()), this, SLOT(slotSelectListView())); connect(btnFilelight, SIGNAL(clicked()), this, SLOT(slotSelectFilelightView())); KConfigGroup group(krConfig, "DiskUsage"); int view = group.readEntry("View", VIEW_LINES); if (view < VIEW_LINES || view > VIEW_FILELIGHT) view = VIEW_LINES; diskUsage->setView(view); sizeX = group.readEntry("Window Width", QFontMetrics(font()).width("W") * 70); sizeY = group.readEntry("Window Height", QFontMetrics(font()).height() * 25); resize(sizeX, sizeY); if (group.readEntry("Window Maximized", false)) { setWindowState(windowState() | Qt::WindowMaximized); } } void DiskUsageGUI::askDirAndShow() { if (askDir()) { show(); } } void DiskUsageGUI::slotLoadFinished(bool result) { if (exitAtFailure && !result) { close(); } else { exitAtFailure = false; } } void DiskUsageGUI::enableButtons(bool isOn) { btnNewSearch->setEnabled(isOn); btnRefresh->setEnabled(isOn); btnDirUp->setEnabled(isOn); btnLines->setEnabled(isOn); btnDetailed->setEnabled(isOn); btnFilelight->setEnabled(isOn); } void DiskUsageGUI::resizeEvent(QResizeEvent *e) { if (!isMaximized()) { sizeX = e->size().width(); sizeY = e->size().height(); } QDialog::resizeEvent(e); } void DiskUsageGUI::closeEvent(QCloseEvent *event) { KConfigGroup group(krConfig, "DiskUsage"); group.writeEntry("Window Width", sizeX); group.writeEntry("Window Height", sizeY); group.writeEntry("Window Maximized", isMaximized()); group.writeEntry("View", diskUsage->getActiveView()); event->accept(); } void DiskUsageGUI::slotLoadUsageInfo() { diskUsage->load(baseDirectory); } void DiskUsageGUI::slotStatus(QString stat) { status->setText(stat); } void DiskUsageGUI::slotViewChanged(int view) { if (view == VIEW_LOADER) { enableButtons(false); return; } enableButtons(true); btnLines->setChecked(false); btnDetailed->setChecked(false); btnFilelight->setChecked(false); switch (view) { case VIEW_LINES: btnLines->setChecked(true); break; case VIEW_DETAILED: btnDetailed->setChecked(true); break; case VIEW_FILELIGHT: btnFilelight->setChecked(true); break; case VIEW_LOADER: break; } } bool DiskUsageGUI::askDir() { // ask the user for the copy destX const QUrl newDir = KChooseDir::getDir(i18n("Viewing the usage of folder:"), baseDirectory, baseDirectory); if (newDir.isEmpty()) return false; baseDirectory = newDir; QTimer::singleShot(0, this, SLOT(slotLoadUsageInfo())); return true; } diff --git a/krusader/DiskUsage/dulines.cpp b/krusader/DiskUsage/dulines.cpp index 94ad7d4f..b51517dc 100644 --- a/krusader/DiskUsage/dulines.cpp +++ b/krusader/DiskUsage/dulines.cpp @@ -1,534 +1,535 @@ /***************************************************************************** * Copyright (C) 2004 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/]. * *****************************************************************************/ #include "dulines.h" -#include "../kicons.h" + +#include "../icon.h" #include "../krglobal.h" #include "../FileSystem/krpermhandler.h" // QtCore #include // QtGui #include #include #include #include #include #include // QtWidgets #include #include #include #include #include #include #include class DULinesItemDelegate : public QItemDelegate { public: explicit DULinesItemDelegate(QObject *parent = 0) : QItemDelegate(parent) {} virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE { QItemDelegate::paint(painter, option, index); QVariant value = index.data(Qt::UserRole); if (value.isValid()) { QString text = value.toString(); value = index.data(Qt::DisplayRole); QString display; if (value.isValid()) display = value.toString(); QSize iconSize; value = index.data(Qt::DecorationRole); if (value.isValid()) iconSize = qvariant_cast(value).actualSize(option.decorationSize); painter->save(); painter->setClipRect(option.rect); QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; if (cg == QPalette::Normal && !(option.state & QStyle::State_Active)) cg = QPalette::Inactive; if (option.state & QStyle::State_Selected) { painter->setPen(option.palette.color(cg, QPalette::HighlightedText)); } else { painter->setPen(option.palette.color(cg, QPalette::Text)); } QFont fnt = option.font; fnt.setItalic(true); painter->setFont(fnt); QFontMetrics fm(fnt); QString renderedText = text; int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin); int pos = 3 * textMargin + option.fontMetrics.width(display) + iconSize.width(); bool truncd = false; QRect rct = option.rect; if (rct.width() > pos) { rct.setX(rct.x() + pos); if (fm.width(renderedText) > rct.width()) { truncd = true; int points = fm.width("..."); while (!renderedText.isEmpty() && (fm.width(renderedText) + points > rct.width())) renderedText.truncate(renderedText.length() - 1); renderedText += "..."; } painter->drawText(rct, Qt::AlignLeft, renderedText); } else truncd = true; if (truncd) ((QAbstractItemModel *)index.model())->setData(index, QVariant(display + " " + text), Qt::ToolTipRole); else ((QAbstractItemModel *)index.model())->setData(index, QVariant(), Qt::ToolTipRole); painter->restore(); } } }; class DULinesItem : public QTreeWidgetItem { public: DULinesItem(DiskUsage *diskUsageIn, File *fileItem, QTreeWidget * parent, QString label1, QString label2, QString label3) : QTreeWidgetItem(parent), diskUsage(diskUsageIn), file(fileItem) { setText(0, label1); setText(1, label2); setText(2, label3); setTextAlignment(1, Qt::AlignRight); } DULinesItem(DiskUsage *diskUsageIn, File *fileItem, QTreeWidget * parent, QTreeWidgetItem * after, QString label1, QString label2, QString label3) : QTreeWidgetItem(parent, after), diskUsage(diskUsageIn), file(fileItem) { setText(0, label1); setText(1, label2); setText(2, label3); setTextAlignment(1, Qt::AlignRight); } virtual bool operator<(const QTreeWidgetItem &other) const Q_DECL_OVERRIDE { int column = treeWidget() ? treeWidget()->sortColumn() : 0; if (text(0) == "..") return true; const DULinesItem *compWith = dynamic_cast< const DULinesItem * >(&other); if (compWith == 0) return false; switch (column) { case 0: case 1: return file->size() > compWith->file->size(); default: return text(column) < other.text(column); } } inline File * getFile() { return file; } private: DiskUsage *diskUsage; File *file; }; DULines::DULines(DiskUsage *usage) : KrTreeWidget(usage), diskUsage(usage), refreshNeeded(false), started(false) { setItemDelegate(itemDelegate = new DULinesItemDelegate()); setAllColumnsShowFocus(true); setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); setIndentation(10); int defaultSize = QFontMetrics(font()).width("W"); QStringList labels; labels << i18n("Line View"); labels << i18n("Percent"); labels << i18n("Name"); setHeaderLabels(labels); header()->setSectionResizeMode(QHeaderView::Interactive); KConfigGroup group(krConfig, diskUsage->getConfigGroup()); showFileSize = group.readEntry("L Show File Size", true); if (group.hasKey("L State")) header()->restoreState(group.readEntry("L State", QByteArray())); else { setColumnWidth(0, defaultSize * 20); setColumnWidth(1, defaultSize * 6); setColumnWidth(2, defaultSize * 20); } setStretchingColumn(0); header()->setSortIndicatorShown(true); sortItems(1, Qt::AscendingOrder); // toolTip = new DULinesToolTip( diskUsage, viewport(), this ); connect(diskUsage, SIGNAL(enteringDirectory(Directory*)), this, SLOT(slotDirChanged(Directory*))); connect(diskUsage, SIGNAL(clearing()), this, SLOT(clear())); connect(header(), SIGNAL(sectionResized(int,int,int)), this, SLOT(sectionResized(int))); connect(this, SIGNAL(itemRightClicked(QTreeWidgetItem*,QPoint,int)), this, SLOT(slotRightClicked(QTreeWidgetItem*,QPoint))); connect(diskUsage, SIGNAL(changed(File*)), this, SLOT(slotChanged(File*))); connect(diskUsage, SIGNAL(deleted(File*)), this, SLOT(slotDeleted(File*))); started = true; } DULines::~DULines() { KConfigGroup group(krConfig, diskUsage->getConfigGroup()); group.writeEntry("L State", header()->saveState()); delete itemDelegate; } bool DULines::event(QEvent * event) { switch (event->type()) { case QEvent::ToolTip: { QHelpEvent *he = static_cast(event); if (viewport()) { QPoint pos = viewport()->mapFromGlobal(he->globalPos()); QTreeWidgetItem * item = itemAt(pos); int column = columnAt(pos.x()); if (item && column == 1) { File *fileItem = ((DULinesItem *)item)->getFile(); QToolTip::showText(he->globalPos(), diskUsage->getToolTip(fileItem), this); return true; } } } break; default: break; } return KrTreeWidget::event(event); } void DULines::slotDirChanged(Directory *dirEntry) { clear(); QTreeWidgetItem * lastItem = 0; if (!(dirEntry->parent() == 0)) { lastItem = new QTreeWidgetItem(this); lastItem->setText(0, ".."); - lastItem->setIcon(0, FL_LOADICON("go-up")); + lastItem->setIcon(0, Icon("go-up")); lastItem->setFlags(lastItem->flags() & (~Qt::ItemIsSelectable)); } int maxPercent = -1; for (Iterator it = dirEntry->iterator(); it != dirEntry->end(); ++it) { File *item = *it; if (!item->isExcluded() && item->intPercent() > maxPercent) maxPercent = item->intPercent(); } for (Iterator it = dirEntry->iterator(); it != dirEntry->end(); ++it) { File *item = *it; QString fileName = item->name(); if (lastItem == 0) lastItem = new DULinesItem(diskUsage, item, this, "", item->percent() + " ", fileName); else lastItem = new DULinesItem(diskUsage, item, this, lastItem, "", item->percent() + " ", fileName); if (item->isExcluded()) lastItem->setHidden(true); int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; lastItem->setIcon(2, diskUsage->getIcon(item->mime())); lastItem->setData(0, Qt::DecorationRole, createPixmap(item->intPercent(), maxPercent, header()->sectionSize(0) - 2 * textMargin)); if (showFileSize) lastItem->setData(2, Qt::UserRole, " [" + KIO::convertSize(item->size()) + ']'); QSize size = lastItem->sizeHint(0); size.setWidth(16); lastItem->setSizeHint(0, size); } if (topLevelItemCount() > 0) { setCurrentItem(topLevelItem(0)); } } QPixmap DULines::createPixmap(int percent, int maxPercent, int maxWidth) { if (percent < 0 || percent > maxPercent || maxWidth < 2 || maxPercent == 0) return QPixmap(); maxWidth -= 2; int actualWidth = maxWidth * percent / maxPercent; if (actualWidth == 0) return QPixmap(); QPen pen; pen.setColor(Qt::black); QPainter painter; int size = QFontMetrics(font()).height() - 2; QRect rect(0, 0, actualWidth, size); QRect frameRect(0, 0, actualWidth - 1, size - 1); QPixmap pixmap(rect.width(), rect.height()); painter.begin(&pixmap); painter.setPen(pen); for (int i = 1; i < actualWidth - 1; i++) { int color = (511 * i / (maxWidth - 1)); if (color < 256) pen.setColor(QColor(255 - color, 255, 0)); else pen.setColor(QColor(color - 256, 511 - color, 0)); painter.setPen(pen); painter.drawLine(i, 1, i, size - 1); } pen.setColor(Qt::black); painter.setPen(pen); if (actualWidth != 1) painter.drawRect(frameRect); else painter.drawLine(0, 0, 0, size); painter.end(); pixmap.detach(); return pixmap; } void DULines::resizeEvent(QResizeEvent * re) { KrTreeWidget::resizeEvent(re); if (started && (re->oldSize() != re->size())) sectionResized(0); } void DULines::sectionResized(int column) { if (topLevelItemCount() == 0 || column != 0) return; Directory * currentDir = diskUsage->getCurrentDir(); if (currentDir == 0) return; int maxPercent = -1; for (Iterator it = currentDir->iterator(); it != currentDir->end(); ++it) { File *item = *it; if (!item->isExcluded() && item->intPercent() > maxPercent) maxPercent = item->intPercent(); } QTreeWidgetItemIterator it2(this); while (*it2) { QTreeWidgetItem *lvitem = *it2; if (lvitem->text(0) != "..") { DULinesItem *duItem = dynamic_cast< DULinesItem *>(lvitem); if (duItem) { int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; duItem->setData(0, Qt::DecorationRole, createPixmap(duItem->getFile()->intPercent(), maxPercent, header()->sectionSize(0) - 2 * textMargin)); QSize size = duItem->sizeHint(0); size.setWidth(16); duItem->setSizeHint(0, size); } } it2++; } } bool DULines::doubleClicked(QTreeWidgetItem * item) { if (item) { if (item->text(0) != "..") { File *fileItem = ((DULinesItem *)item)->getFile(); if (fileItem->isDir()) diskUsage->changeDirectory(dynamic_cast(fileItem)); return true; } else { Directory *upDir = (Directory *)diskUsage->getCurrentDir()->parent(); if (upDir) diskUsage->changeDirectory(upDir); return true; } } return false; } void DULines::mouseDoubleClickEvent(QMouseEvent * e) { if (e || e->button() == Qt::LeftButton) { QPoint vp = viewport()->mapFromGlobal(e->globalPos()); QTreeWidgetItem * item = itemAt(vp); if (doubleClicked(item)) return; } KrTreeWidget::mouseDoubleClickEvent(e); } void DULines::keyPressEvent(QKeyEvent *e) { switch (e->key()) { case Qt::Key_Return : case Qt::Key_Enter : if (doubleClicked(currentItem())) return; break; case Qt::Key_Left : case Qt::Key_Right : case Qt::Key_Up : case Qt::Key_Down : if (e->modifiers() == Qt::ShiftModifier) { e->ignore(); return; } break; case Qt::Key_Delete : e->ignore(); return; } KrTreeWidget::keyPressEvent(e); } void DULines::slotRightClicked(QTreeWidgetItem *item, const QPoint &pos) { File * file = 0; if (item && item->text(0) != "..") file = ((DULinesItem *)item)->getFile(); QMenu linesPopup; QAction *act = linesPopup.addAction(i18n("Show file sizes"), this, SLOT(slotShowFileSizes())); act->setChecked(showFileSize); diskUsage->rightClickMenu(pos, file, &linesPopup, i18n("Lines")); } void DULines::slotShowFileSizes() { showFileSize = !showFileSize; slotDirChanged(diskUsage->getCurrentDir()); } File * DULines::getCurrentFile() { QTreeWidgetItem *item = currentItem(); if (item == 0 || item->text(0) == "..") return 0; return ((DULinesItem *)item)->getFile(); } void DULines::slotChanged(File * item) { QTreeWidgetItemIterator it(this); while (*it) { QTreeWidgetItem *lvitem = *it; it++; if (lvitem->text(0) != "..") { DULinesItem *duItem = (DULinesItem *)(lvitem); if (duItem->getFile() == item) { setSortingEnabled(false); duItem->setHidden(item->isExcluded()); duItem->setText(1, item->percent()); if (!refreshNeeded) { refreshNeeded = true; QTimer::singleShot(0, this, SLOT(slotRefresh())); } break; } } } } void DULines::slotDeleted(File * item) { QTreeWidgetItemIterator it(this); while (*it) { QTreeWidgetItem *lvitem = *it; it++; if (lvitem->text(0) != "..") { DULinesItem *duItem = (DULinesItem *)(lvitem); if (duItem->getFile() == item) { delete duItem; break; } } } } void DULines::slotRefresh() { if (refreshNeeded) { refreshNeeded = false; setSortingEnabled(true); sortItems(1, Qt::AscendingOrder); } } diff --git a/krusader/DiskUsage/dulistview.cpp b/krusader/DiskUsage/dulistview.cpp index 0add3bb9..716bd69d 100644 --- a/krusader/DiskUsage/dulistview.cpp +++ b/krusader/DiskUsage/dulistview.cpp @@ -1,273 +1,273 @@ /***************************************************************************** * Copyright (C) 2004 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/]. * *****************************************************************************/ #include "dulistview.h" #include "../krglobal.h" -#include "../kicons.h" +#include "../icon.h" #include "../FileSystem/krpermhandler.h" // QtCore #include #include // QtGui #include #include #include // QtWidgets #include #include #include DUListView::DUListView(DiskUsage *usage) : KrTreeWidget(usage), diskUsage(usage) { setAllColumnsShowFocus(true); setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); setRootIsDecorated(true); setIndentation(10); setItemsExpandable(true); QStringList labels; labels << i18n("Name"); labels << i18n("Percent"); labels << i18n("Total size"); labels << i18n("Own size"); labels << i18n("Type"); labels << i18n("Date"); labels << i18n("Permissions"); labels << i18n("Owner"); labels << i18n("Group"); setHeaderLabels(labels); header()->setSectionResizeMode(QHeaderView::Interactive); KConfigGroup group(krConfig, diskUsage->getConfigGroup()); if (group.hasKey("D State")) header()->restoreState(group.readEntry("D State", QByteArray())); else { int defaultSize = QFontMetrics(font()).width("W"); setColumnWidth(0, defaultSize * 20); setColumnWidth(1, defaultSize * 5); setColumnWidth(2, defaultSize * 10); setColumnWidth(3, defaultSize * 10); setColumnWidth(4, defaultSize * 10); setColumnWidth(5, defaultSize * 10); setColumnWidth(6, defaultSize * 6); setColumnWidth(7, defaultSize * 5); setColumnWidth(8, defaultSize * 5); } header()->setSortIndicatorShown(true); sortItems(2, Qt::AscendingOrder); connect(diskUsage, SIGNAL(enteringDirectory(Directory*)), this, SLOT(slotDirChanged(Directory*))); connect(diskUsage, SIGNAL(clearing()), this, SLOT(clear())); connect(diskUsage, SIGNAL(changed(File*)), this, SLOT(slotChanged(File*))); connect(diskUsage, SIGNAL(deleted(File*)), this, SLOT(slotDeleted(File*))); connect(this, SIGNAL(itemRightClicked(QTreeWidgetItem*,QPoint,int)), this, SLOT(slotRightClicked(QTreeWidgetItem*,QPoint))); connect(this, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(slotExpanded(QTreeWidgetItem*))); } DUListView::~ DUListView() { KConfigGroup group(krConfig, diskUsage->getConfigGroup()); group.writeEntry("D State", header()->saveState()); } void DUListView::addDirectory(Directory *dirEntry, QTreeWidgetItem *parent) { QTreeWidgetItem * lastItem = 0; if (parent == 0 && !(dirEntry->parent() == 0)) { lastItem = new QTreeWidgetItem(this); lastItem->setText(0, ".."); - lastItem->setIcon(0, FL_LOADICON("go-up")); + lastItem->setIcon(0, Icon("go-up")); lastItem->setFlags(Qt::ItemIsEnabled); } for (Iterator it = dirEntry->iterator(); it != dirEntry->end(); ++it) { File *item = *it; QMimeDatabase db; QMimeType mt = db.mimeTypeForName(item->mime()); QString mime; if (mt.isValid()) mime = mt.comment(); time_t tma = item->time(); struct tm* t = localtime((time_t *) & tma); QDateTime tmp(QDate(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday), QTime(t->tm_hour, t->tm_min)); QString date = QLocale().toString(tmp, QLocale::ShortFormat); QString totalSize = KRpermHandler::parseSize(item->size()) + ' '; QString ownSize = KRpermHandler::parseSize(item->ownSize()) + ' '; QString percent = item->percent(); if (lastItem == 0 && parent == 0) lastItem = new DUListViewItem(diskUsage, item, this, item->name(), percent, totalSize, ownSize, mime, date, item->perm(), item->owner(), item->group()); else if (lastItem == 0) lastItem = new DUListViewItem(diskUsage, item, parent, item->name(), percent, totalSize, ownSize, mime, date, item->perm(), item->owner(), item->group()); else if (parent == 0) lastItem = new DUListViewItem(diskUsage, item, this, lastItem, item->name(), percent, totalSize, ownSize, mime, date, item->perm(), item->owner(), item->group()); else lastItem = new DUListViewItem(diskUsage, item, parent, lastItem, item->name(), percent, totalSize, ownSize, mime, date, item->perm(), item->owner(), item->group()); if (item->isExcluded()) lastItem->setHidden(true); lastItem->setIcon(0, diskUsage->getIcon(item->mime())); if (item->isDir() && !item->isSymLink()) lastItem->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); } if (topLevelItemCount() > 0) { setCurrentItem(topLevelItem(0)); } } void DUListView::slotDirChanged(Directory *dirEntry) { clear(); addDirectory(dirEntry, 0); } File * DUListView::getCurrentFile() { QTreeWidgetItem *item = currentItem(); if (item == 0 || item->text(0) == "..") return 0; return ((DUListViewItem *)item)->getFile(); } void DUListView::slotChanged(File * item) { void * itemPtr = diskUsage->getProperty(item, "ListView-Ref"); if (itemPtr == 0) return; DUListViewItem *duItem = (DUListViewItem *)itemPtr; duItem->setHidden(item->isExcluded()); duItem->setText(1, item->percent()); duItem->setText(2, KRpermHandler::parseSize(item->size()) + ' '); duItem->setText(3, KRpermHandler::parseSize(item->ownSize()) + ' '); } void DUListView::slotDeleted(File * item) { void * itemPtr = diskUsage->getProperty(item, "ListView-Ref"); if (itemPtr == 0) return; DUListViewItem *duItem = (DUListViewItem *)itemPtr; delete duItem; } void DUListView::slotRightClicked(QTreeWidgetItem *item, const QPoint & pos) { File * file = 0; if (item && item->text(0) != "..") file = ((DUListViewItem *)item)->getFile(); diskUsage->rightClickMenu(pos, file); } bool DUListView::doubleClicked(QTreeWidgetItem * item) { if (item) { if (item->text(0) != "..") { File *fileItem = ((DUListViewItem *)item)->getFile(); if (fileItem->isDir()) diskUsage->changeDirectory(dynamic_cast(fileItem)); return true; } else { Directory *upDir = (Directory *)diskUsage->getCurrentDir()->parent(); if (upDir) diskUsage->changeDirectory(upDir); return true; } } return false; } void DUListView::mouseDoubleClickEvent(QMouseEvent * e) { if (e || e->button() == Qt::LeftButton) { QPoint vp = viewport()->mapFromGlobal(e->globalPos()); QTreeWidgetItem * item = itemAt(vp); if (doubleClicked(item)) return; } KrTreeWidget::mouseDoubleClickEvent(e); } void DUListView::keyPressEvent(QKeyEvent *e) { switch (e->key()) { case Qt::Key_Return : case Qt::Key_Enter : if (doubleClicked(currentItem())) return; break; case Qt::Key_Left : case Qt::Key_Right : case Qt::Key_Up : case Qt::Key_Down : if (e->modifiers() == Qt::ShiftModifier) { e->ignore(); return; } break; case Qt::Key_Delete : e->ignore(); return; } KrTreeWidget::keyPressEvent(e); } void DUListView::slotExpanded(QTreeWidgetItem * item) { if (item == 0 || item->text(0) == "..") return; if (item->childCount() == 0) { File *fileItem = ((DUListViewItem *)item)->getFile(); if (fileItem->isDir()) addDirectory(dynamic_cast(fileItem), item); } } diff --git a/krusader/DiskUsage/radialMap/widgetEvents.cpp b/krusader/DiskUsage/radialMap/widgetEvents.cpp index 7c5a9de8..2d4ddba7 100644 --- a/krusader/DiskUsage/radialMap/widgetEvents.cpp +++ b/krusader/DiskUsage/radialMap/widgetEvents.cpp @@ -1,252 +1,252 @@ /***************************************************************************** * Copyright (C) 2003-2004 Max Howell * * 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 "fileTree.h" #include "radialMap.h" //class Segment #include "widget.h" +#include "../../icon.h" #include // QtCore #include //::resizeEvent() // QtGui #include #include #include #include // QtWidgets #include //QApplication::setOverrideCursor() #include #include -#include #include #include #include #include #include #include void RadialMap::Widget::resizeEvent(QResizeEvent*) { if (m_map.resize(rect())) { m_timer.setSingleShot(true); m_timer.start(500); //will cause signature to rebuild for new size } //always do these as they need to be initialised on creation m_offset.rx() = (width() - m_map.width()) / 2; m_offset.ry() = (height() - m_map.height()) / 2; } void RadialMap::Widget::paintEvent(QPaintEvent*) { //bltBit for some Qt setups will bitBlt _after_ the labels are painted. Which buggers things up! //shame as bitBlt is faster, possibly Qt bug? Should report the bug? - seems to be race condition //bitBlt( this, m_offset, &m_map ); QPainter paint(this); paint.drawPixmap(m_offset, m_map); //vertical strips if (m_map.width() < width()) { paint.eraseRect(0, 0, m_offset.x(), height()); paint.eraseRect(m_map.width() + m_offset.x(), 0, m_offset.x() + 1, height()); } //horizontal strips if (m_map.height() < height()) { paint.eraseRect(0, 0, width(), m_offset.y()); paint.eraseRect(0, m_map.height() + m_offset.y(), width(), m_offset.y() + 1); } //exploded labels if (!m_map.isNull() && !m_timer.isActive()) paintExplodedLabels(paint); } const RadialMap::Segment* RadialMap::Widget::segmentAt(QPoint &e) const { //determine which segment QPoint e is above e -= m_offset; if (e.x() <= m_map.width() && e.y() <= m_map.height()) { //transform to cartesian coords e.rx() -= m_map.width() / 2; //should be an int e.ry() = m_map.height() / 2 - e.y(); double length = std::hypot(e.x(), e.y()); if (length >= m_map.m_innerRadius) { //not hovering over inner circle uint depth = ((int)length - m_map.m_innerRadius) / m_map.m_ringBreadth; if (depth <= m_map.m_visibleDepth) { //**** do earlier since you can //** check not outside of range //vector calculation, reduces to simple trigonometry //cos angle = (aibi + ajbj) / albl //ai = x, bi=1, aj=y, bj=0 //cos angle = x / (length) uint a = (uint)(acos((double)e.x() / length) * 916.736); //916.7324722 = #radians in circle * 16 //acos only understands 0-180 degrees if (e.y() < 0) a = 5760 - a; #define ring (m_map.m_signature + depth) for (ConstIterator it = ring->constIterator(); it != ring->end(); ++it) if ((*it)->intersects(a)) return *it; #undef ring } } else return m_rootSegment; //hovering over inner circle } return 0; } void RadialMap::Widget::mouseMoveEvent(QMouseEvent *e) { //set m_focus to what we hover over, update UI if it's a new segment Segment const * const oldFocus = m_focus; QPoint p = e->pos(); m_focus = segmentAt(p); //NOTE p is passed by non-const reference if (m_focus && m_focus->file() != m_tree) { if (m_focus != oldFocus) { //if not same as last time setCursor(QCursor(Qt::PointingHandCursor)); m_tip.updateTip(m_focus->file(), m_tree); emit mouseHover(m_focus->file()->fullPath()); //repaint required to update labels now before transparency is generated repaint(); } // updates tooltip pseudo-tranparent background m_tip.moveto(e->globalPos(), *this, (p.y() < 0)); } else if (oldFocus && oldFocus->file() != m_tree) { unsetCursor(); m_tip.hide(); update(); emit mouseHover(QString()); } } void RadialMap::Widget::mousePressEvent(QMouseEvent *e) { //m_tip is hidden already by event filter //m_focus is set correctly (I've been strict, I assure you it is correct!) if (m_focus && !m_focus->isFake()) { const QUrl url = Widget::url(m_focus->file()); const bool isDir = m_focus->file()->isDir(); if (e->button() == Qt::RightButton) { QMenu popup; popup.setTitle(m_focus->file()->fullPath(m_tree)); QAction * actKonq = 0, * actKonsole = 0, *actViewMag = 0, * actFileOpen = 0, * actEditDel = 0; if (isDir) { - actKonq = popup.addAction(QIcon::fromTheme("system-file-manager"), i18n("Open File Manager Here")); + actKonq = popup.addAction(Icon("system-file-manager"), i18n("Open File Manager Here")); if (url.scheme() == "file") - actKonsole = popup.addAction(QIcon::fromTheme("utilities-terminal"), i18n("Open Terminal Here")); + actKonsole = popup.addAction(Icon("utilities-terminal"), i18n("Open Terminal Here")); if (m_focus->file() != m_tree) { popup.addSeparator(); - actViewMag = popup.addAction(QIcon::fromTheme("zoom-original"), i18n("&Center Map Here")); + actViewMag = popup.addAction(Icon("zoom-original"), i18n("&Center Map Here")); } } else - actFileOpen = popup.addAction(QIcon::fromTheme("document-open"), i18n("&Open")); + actFileOpen = popup.addAction(Icon("document-open"), i18n("&Open")); popup.addSeparator(); - actEditDel = popup.addAction(QIcon::fromTheme("edit-delete"), i18n("&Delete")); + actEditDel = popup.addAction(Icon("edit-delete"), i18n("&Delete")); QAction * result = popup.exec(e->globalPos()); if (result == 0) result = (QAction *) - 1; // sanity if (result == actKonq) //KRun::runCommand will show an error message if there was trouble KRun::runCommand(QString("kfmclient openURL '%1'").arg(url.url()), this); else if (result == actKonsole) KRun::runCommand(QString("konsole --workdir '%1'").arg(url.url()), this); else if (result == actViewMag || result == actFileOpen) goto sectionTwo; else if (result == actEditDel) { const QUrl url = Widget::url(m_focus->file()); const QString message = (m_focus->file()->isDir() ? i18n("The folder at '%1' will be recursively and permanently deleted.", url.toDisplayString()) : i18n("'%1' will be permanently deleted.", url.toDisplayString())); const int userIntention = KMessageBox::warningContinueCancel(this, message, QString(), KStandardGuiItem::del()); if (userIntention == KMessageBox::Continue) { KIO::Job *job = KIO::del(url); KIO::JobUiDelegate *ui = static_cast(job->uiDelegate()); ui->setWindow(this); connect(job, SIGNAL(result(KJob*)), SLOT(deleteJobFinished(KJob*))); QApplication::setOverrideCursor(Qt::BusyCursor); } } else //ensure m_focus is set for new mouse position sendFakeMouseEvent(); } else { sectionTwo: const QRect rect(e->x() - 20, e->y() - 20, 40, 40); m_tip.hide(); //user expects this if (!isDir || e->button() == Qt::MidButton) { #if 0 // TODO: PORTME KIconEffect::visualActivate(this, rect); #endif new KRun(url, this, true); //FIXME see above } else if (m_focus->file() != m_tree) { //is left mouse button #if 0 // TODO: PORTME KIconEffect::visualActivate(this, rect); #endif emit activated(url); //activate first, this will cause UI to prepare itself if (m_focus) createFromCache((Directory *)m_focus->file()); } } } } void RadialMap::Widget::deleteJobFinished(KJob *job) { QApplication::restoreOverrideCursor(); if (!job->error()) invalidate(); else job->uiDelegate()->showErrorMessage(); } diff --git a/krusader/FileSystem/fileitem.cpp b/krusader/FileSystem/fileitem.cpp index 6f0dd3cf..71843a0c 100644 --- a/krusader/FileSystem/fileitem.cpp +++ b/krusader/FileSystem/fileitem.cpp @@ -1,230 +1,230 @@ /***************************************************************************** * 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 "fileitem.h" // QtCore #include #include #include #include #include #include "krpermhandler.h" #include "filesystemprovider.h" bool FileItem::userDefinedFolderIcons = true; // wrapper class; QCache needs objects class FileSize { public: const KIO::filesize_t m_size; FileSize(KIO::filesize_t size) : m_size(size) {} }; // cache for calculated directory sizes; static QCache s_fileSizeCache(1000); FileItem::FileItem(const QString &name, const QUrl &url, bool isDir, KIO::filesize_t size, mode_t mode, time_t mtime, time_t ctime, time_t atime, uid_t uid, gid_t gid, const QString &owner, const QString &group, bool isLink, const QString &linkDest, bool isBrokenLink, const QString &acl, const QString &defaultAcl) : m_name(name), m_url(url), m_isDir(isDir), m_size(size), m_mode(mode), m_mtime(mtime), m_ctime(ctime), m_atime(atime), m_uid(uid), m_gid(gid), m_owner(owner), m_group(group), m_isLink(isLink), m_linkDest(linkDest), m_isBrokenLink(isBrokenLink), m_acl(acl), m_defaulfAcl(defaultAcl), m_AclLoaded(false), - m_mimeType(), m_icon() + m_mimeType(), m_iconName() { m_permissions = KRpermHandler::mode2QString(mode); if (m_owner.isEmpty()) m_owner = KRpermHandler::uid2user(m_uid); if (m_group.isEmpty()) m_group = KRpermHandler::gid2group(m_gid); if (m_isDir && !m_isLink) { m_size = s_fileSizeCache.contains(m_url) ? s_fileSizeCache[m_url]->m_size : -1; } } FileItem *FileItem::createDummy() { FileItem *file = new FileItem("..", QUrl(), true, 0, 0, 0, 0, 0); - file->setIcon("go-up"); + file->setIconName("go-up"); return file; } FileItem *FileItem::createBroken(const QString &name, const QUrl &url) { FileItem *file = new FileItem(name, url, false, 0, 0, 0, 0, 0); - file->setIcon("file-broken"); + file->setIconName("file-broken"); return file; } FileItem *FileItem::createVirtualDir(const QString &name, const QUrl &url) { return new FileItem(name, url, true, 0, 0700, time(0), time(0), time(0), getuid(), getgid()); } FileItem *FileItem::createCopy(const FileItem &file, const QString &newName) { return new FileItem(newName, file.getUrl(), file.isDir(), file.getSize(), file.getMode(), file.getTime_t(), file.getChangedTime(), file.getAccessTime(), file.m_uid, file.m_gid, file.getOwner(), file.getGroup(), file.isSymLink(), file.getSymDest(), file.isBrokenLink()); } char FileItem::isReadable() const { if (m_uid != (uid_t)-1 && m_gid != (gid_t)-1) return KRpermHandler::readable(m_permissions, m_gid, m_uid); else return KRpermHandler::ftpReadable(m_owner, m_url.userName(), m_permissions); } char FileItem::isWriteable() const { if (m_uid != (uid_t)-1 && m_gid != (gid_t)-1) return KRpermHandler::writeable(m_permissions, m_gid, m_uid); else return KRpermHandler::ftpWriteable(m_owner, m_url.userName(), m_permissions); } char FileItem::isExecutable() const { if (m_uid != (uid_t)-1 && m_gid != (gid_t)-1) return KRpermHandler::executable(m_permissions, m_gid, m_uid); else return KRpermHandler::ftpExecutable(m_owner, m_url.userName(), m_permissions); } void FileItem::setSize(KIO::filesize_t size) { m_size = size; s_fileSizeCache.insert(m_url, new FileSize(size)); } const QString &FileItem::getMime() { if (m_mimeType.isEmpty()) { if (m_isDir) { m_mimeType = "inode/directory"; - m_icon = "inode-directory"; + m_iconName = "inode-directory"; } else if (isBrokenLink()) { m_mimeType = "unknown"; - m_icon = "file-broken"; + m_iconName = "file-broken"; } else { const QMimeDatabase db; const QMimeType mt = db.mimeTypeForUrl(getUrl()); m_mimeType = mt.isValid() ? mt.name() : "unknown"; - m_icon = mt.isValid() ? mt.iconName() : "file-broken"; + m_iconName = mt.isValid() ? mt.iconName() : "file-broken"; if (m_mimeType == "inode/directory") { // TODO view update needed? and does this ever happen? m_isDir = true; } } if (m_isDir && userDefinedFolderIcons) { const QUrl url = getUrl(); if (url.isLocalFile()) { const QString file = url.toLocalFile() + "/.directory"; const KDesktopFile cfg(file); - const QString icon = cfg.readIcon(); - if (!icon.isEmpty()) - m_icon = icon.startsWith(QLatin1String("./")) ? + const QString iconName = cfg.readIcon(); + if (!iconName.isEmpty()) + m_iconName = iconName.startsWith(QLatin1String("./")) ? // relative path - url.toLocalFile() + '/' + icon : - icon; + url.toLocalFile() + '/' + iconName : + iconName; } } } return m_mimeType; } const QString &FileItem::getIcon() { - if (m_icon.isEmpty()) { + if (m_iconName.isEmpty()) { getMime(); // sets the icon } - return m_icon; + return m_iconName; } const QString &FileItem::getACL() { if (!m_AclLoaded) loadACL(); return m_acl; } void FileItem::loadACL() { if (m_url.isLocalFile()) { FileSystemProvider::getACL(this, m_acl, m_defaulfAcl); } m_AclLoaded = true; } const KIO::UDSEntry FileItem::getEntry() { KIO::UDSEntry entry; entry.insert(KIO::UDSEntry::UDS_NAME, getName()); entry.insert(KIO::UDSEntry::UDS_SIZE, getSize()); entry.insert(KIO::UDSEntry::UDS_MODIFICATION_TIME, getTime_t()); entry.insert(KIO::UDSEntry::UDS_CREATION_TIME, getChangedTime()); entry.insert(KIO::UDSEntry::UDS_ACCESS_TIME, getAccessTime()); entry.insert(KIO::UDSEntry::UDS_USER, getOwner()); entry.insert(KIO::UDSEntry::UDS_GROUP, getGroup()); entry.insert(KIO::UDSEntry::UDS_MIME_TYPE, getMime()); entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, getMode() & S_IFMT); entry.insert(KIO::UDSEntry::UDS_ACCESS, getMode() & 07777); if (isSymLink()) entry.insert(KIO::UDSEntry::UDS_LINK_DEST, getSymDest()); if (!m_AclLoaded) loadACL(); if (!m_acl.isNull() || !m_defaulfAcl.isNull()) { entry.insert(KIO::UDSEntry::UDS_EXTENDED_ACL, 1); if (!m_acl.isNull()) entry.insert(KIO::UDSEntry::UDS_ACL_STRING, m_acl); if (!m_defaulfAcl.isNull()) entry.insert(KIO::UDSEntry::UDS_DEFAULT_ACL_STRING, m_defaulfAcl); } return entry; } diff --git a/krusader/FileSystem/fileitem.h b/krusader/FileSystem/fileitem.h index fb1f6b96..4eae6867 100644 --- a/krusader/FileSystem/fileitem.h +++ b/krusader/FileSystem/fileitem.h @@ -1,163 +1,163 @@ /***************************************************************************** * Copyright (C) 2000 Shie Erlich * * 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/]. * *****************************************************************************/ #ifndef FILEITEM_H #define FILEITEM_H #include // QtCore #include #include #include #include /** * A file item gives access all meta information of a (virtual, dummy or real) file or directory in * the filesystem. * * NOTE: The name of a file item is supposed to be unique within a directory. */ class FileItem { public: /** * Create a new file item. * * Don't use this constructor outside of FileSystem! If you really need to, create a new static * factory method below. * * NOTE: According to Unix standard uid and gid CAN have signed or unsigned type. We use (e.g.) * "(uid_t) -1" as a special invalid user ID for non-local files. * NOTE: ACLs are currently only used by Synchronizer. * * @param name the display name of this file. Don't have to be the real filename. * @param url (real) absolute URL of this file * @param isDir true if this file is a directory. Else false. * @param size size of file * @param mode mode of file (file type and permissions) * @param mtime file modification time * @param ctime file changed time * @param atime file access time * @param uid Unix user id of file owner. Use -1 here and provide an owner name for non-local files. * @param gid Unix group id of file group. Use -1 here and provide a group name for non-local files. * @param owner user name of file owner. Can be empty for local files * @param group group name of file group. Can be empty for local files. * @param isLink true if file is a symbolic link. Else false. * @param linkDest link destination path if file is a link. Relative or absolute. Empty by default. * @param isBrokenLink true if file is a symbolic link and destination file does not exists. Else false. * @param acl ACL string of file. Can be empty and is loaded on demand. * @param defaultAcl default ACL string of file (only for directories). Can be empty and is loaded on demand. */ FileItem(const QString &name, const QUrl &url, bool isDir, KIO::filesize_t size, mode_t mode, time_t mtime, time_t ctime, time_t atime, uid_t uid = -1, gid_t gid = -1, const QString &owner = QString(), const QString &group = QString(), bool isLink = false, const QString &linkDest = QString(), bool isBrokenLink = false, const QString &acl = QString(), const QString &defaultAcl = QString()); /** Create a new ".." dummy file item. */ static FileItem *createDummy(); /** Create a file item for a broken file which metadata could not be read. */ static FileItem *createBroken(const QString &name, const QUrl &url); /** Create a new virtual directory. */ static FileItem *createVirtualDir(const QString &name, const QUrl &url); /** Create a new file item copy with a different name. */ static FileItem *createCopy(const FileItem &file, const QString &newName); // following functions give-out file details inline const QString &getName() const { return m_name; } /** Return the file size. Returns 0 for directories with unknown size. */ inline KIO::filesize_t getSize() const { return m_size == (KIO::filesize_t)-1 ? 0 : m_size; } /** Return the file size. Returns (KIO::filesize_t)-1 for directories with unknown size. */ inline KIO::filesize_t getUISize() const { return m_size; } inline const QString &getPerm() const { return m_permissions; } inline bool isDir() const { return m_isDir; } inline bool isSymLink() const { return m_isLink; } inline bool isBrokenLink() const { return m_isBrokenLink; } inline const QString &getSymDest() const { return m_linkDest; } inline mode_t getMode() const { return m_mode; } inline time_t getTime_t() const { return m_mtime; } inline time_t getChangedTime() const { return m_ctime; } inline time_t getAccessTime() const { return m_atime; } inline const QUrl &getUrl() const { return m_url; } inline const QString &getOwner() const { return m_owner; } inline const QString &getGroup() const { return m_group; } const QString &getMime(); const QString &getIcon(); const QString &getACL(); const QString &getDefaultACL(); const KIO::UDSEntry getEntry(); //< return the UDSEntry from the file item char isReadable() const; char isWriteable() const; char isExecutable() const; /** * Set the file size. * used ONLY when calculating a directory's space, needs to change the * displayed size of the viewitem and thus the file item. For INTERNAL USE ! */ void setSize(KIO::filesize_t size); inline static void loadUserDefinedFolderIcons(bool load) { userDefinedFolderIcons = load; } private: - void setIcon(const QString &icon) { m_icon = icon; m_mimeType = "?"; } + void setIconName(const QString &icon) { m_iconName = icon; m_mimeType = "?"; } void loadACL(); QString m_name; //< file name QUrl m_url; //< file URL bool m_isDir; //< flag, true if it's a directory KIO::filesize_t m_size; //< file size mode_t m_mode; //< file mode (file type and permissions) time_t m_mtime; //< file modification time time_t m_ctime; //< file changed time time_t m_atime; //< file access time uid_t m_uid; //< file owner id gid_t m_gid; //< file group id QString m_owner; //< file owner name QString m_group; //< file group name bool m_isLink; //< true if the file is a symlink QString m_linkDest; //< if it's a sym link - its detination bool m_isBrokenLink; //< true if the link destianation does not exist QString m_permissions; //< file permissions string QString m_acl; //< ACL permission string, may lazy initialized QString m_defaulfAcl; //< ACL default string, may lazy initialized bool m_AclLoaded; //< flag, indicates that ACL permissions already loaded QString m_mimeType; //< file mimetype, lazy initialized - QString m_icon; //< the name of the icon file, lazy initialized + QString m_iconName; //< the name of the icon file, lazy initialized static bool userDefinedFolderIcons; }; #endif diff --git a/krusader/FileSystem/krtrashhandler.cpp b/krusader/FileSystem/krtrashhandler.cpp index 46e9b8b3..708a9334 100644 --- a/krusader/FileSystem/krtrashhandler.cpp +++ b/krusader/FileSystem/krtrashhandler.cpp @@ -1,116 +1,117 @@ /***************************************************************************** * Copyright (C) 2009 Csaba Karai * * Copyright (C) 2009-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 "krtrashhandler.h" // QtCore #include #include #include #include #include #include #include #include #include #include "filesystemprovider.h" #include "../kractions.h" #include "../krglobal.h" +#include "../icon.h" KrTrashWatcher * KrTrashHandler::_trashWatcher = 0; bool KrTrashHandler::isTrashEmpty() { KConfig trashConfig("trashrc"); KConfigGroup cfg(&trashConfig, "Status"); return cfg.readEntry("Empty", false); } -QString KrTrashHandler::trashIcon() +QString KrTrashHandler::trashIconName() { return isTrashEmpty() ? "user-trash" : "user-trash-full"; } void KrTrashHandler::emptyTrash() { KIO::JobUiDelegate uiDelegate; uiDelegate.setWindow(krMainWindow); if (!uiDelegate.askDeleteConfirmation(QList(), KIO::JobUiDelegate::EmptyTrash, KIO::JobUiDelegate::DefaultConfirmation)) return; KIO::Job *job = KIO::emptyTrash(); KJobWidgets::setWindow(job, krMainWindow); job->uiDelegate()->setAutoErrorHandlingEnabled(true); const QUrl url = QUrl("trash:/"); QObject::connect(job, &KIO::Job::result, [=]() { FileSystemProvider::instance().refreshFilesystems(url, false); }); } void KrTrashHandler::restoreTrashedFiles(const QList &urls) { if (urls.isEmpty()) return; KIO::RestoreJob *job = KIO::restoreFromTrash(urls); KJobWidgets::setWindow(job, krMainWindow); job->uiDelegate()->setAutoErrorHandlingEnabled(true); const QUrl url = urls.first().adjusted(QUrl::RemoveFilename); QObject::connect(job, &KIO::Job::result, [=]() { FileSystemProvider::instance().refreshFilesystems(url, false); }); } void KrTrashHandler::startWatcher() { if (!_trashWatcher) _trashWatcher = new KrTrashWatcher(); } void KrTrashHandler::stopWatcher() { delete _trashWatcher; _trashWatcher = 0; } KrTrashWatcher::KrTrashWatcher() { _watcher = new KDirWatch(); connect(_watcher, &KDirWatch::created, this, &KrTrashWatcher::slotTrashChanged); connect(_watcher, &KDirWatch::dirty, this, &KrTrashWatcher::slotTrashChanged); const QString trashrcFile = QDir(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation)).filePath("trashrc"); _watcher->addFile(trashrcFile); _watcher->startScan(true); } KrTrashWatcher::~KrTrashWatcher() { delete _watcher; _watcher = 0; } void KrTrashWatcher::slotTrashChanged() { - KrActions::actTrashBin->setIcon(QIcon::fromTheme(KrTrashHandler::trashIcon())); + KrActions::actTrashBin->setIcon(Icon(KrTrashHandler::trashIconName())); } diff --git a/krusader/FileSystem/krtrashhandler.h b/krusader/FileSystem/krtrashhandler.h index 85c26a8e..8c200ca4 100644 --- a/krusader/FileSystem/krtrashhandler.h +++ b/krusader/FileSystem/krtrashhandler.h @@ -1,63 +1,63 @@ /***************************************************************************** * Copyright (C) 2009 Csaba Karai * * Copyright (C) 2009-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 KRTRASHHANDLER_H #define KRTRASHHANDLER_H // QtCore #include #include #include class KrTrashWatcher; class KrTrashHandler { public: static bool isTrashEmpty(); - static QString trashIcon(); + static QString trashIconName(); static void emptyTrash(); static void restoreTrashedFiles(const QList &url); static void startWatcher(); static void stopWatcher(); private: static KrTrashWatcher * _trashWatcher; }; /** Watches the trashrc config file for changes and updates the trash icon. */ class KrTrashWatcher : public QObject { Q_OBJECT public: KrTrashWatcher(); virtual ~KrTrashWatcher(); public slots: void slotTrashChanged(); private: KDirWatch * _watcher; }; #endif /* __KR_TRASH_HANDLER__ */ diff --git a/krusader/Filter/advancedfilter.cpp b/krusader/Filter/advancedfilter.cpp index 1949fc91..40787741 100644 --- a/krusader/Filter/advancedfilter.cpp +++ b/krusader/Filter/advancedfilter.cpp @@ -1,612 +1,612 @@ /***************************************************************************** * Copyright (C) 2003 Shie Erlich * * Copyright (C) 2003 Rafi Yanai * * 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/]. * *****************************************************************************/ #include "advancedfilter.h" // QtCore #include #include #include // QtGui #include // QtWidgets #include #include #include #include #include #include #include #include -#include #include #include "../krglobal.h" +#include "../icon.h" #include "../Dialogs/krdialogs.h" #define USERSFILE QString("/etc/passwd") #define GROUPSFILE QString("/etc/group") AdvancedFilter::AdvancedFilter(FilterTabs *tabs, QWidget *parent) : QWidget(parent), fltTabs(tabs) { QGridLayout *filterLayout = new QGridLayout(this); filterLayout->setSpacing(6); filterLayout->setContentsMargins(11, 11, 11, 11); // Options for size QGroupBox *sizeGroup = new QGroupBox(this); QSizePolicy sizeGroupPolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); sizeGroupPolicy.setHeightForWidth(sizeGroup->sizePolicy().hasHeightForWidth()); sizeGroup->setSizePolicy(sizeGroupPolicy); sizeGroup->setTitle(i18n("Size")); QGridLayout *sizeLayout = new QGridLayout(sizeGroup); sizeLayout->setAlignment(Qt::AlignTop); sizeLayout->setSpacing(6); sizeLayout->setContentsMargins(11, 11, 11, 11); minSizeEnabled = new QCheckBox(sizeGroup); minSizeEnabled->setText(i18n("At Least")); minSizeEnabled->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); sizeLayout->addWidget(minSizeEnabled, 0, 0); minSizeAmount = new QSpinBox(sizeGroup); minSizeAmount->setRange(0, 999999999); minSizeAmount->setEnabled(false); sizeLayout->addWidget(minSizeAmount, 0, 1); minSizeType = new KComboBox(false, sizeGroup); // i18n: @item:inlistbox next to a text field containing the amount minSizeType->addItem(i18n("Byte")); // i18n: @item:inlistbox next to a text field containing the amount minSizeType->addItem(i18n("KiB")); // i18n: @item:inlistbox next to a text field containing the amount minSizeType->addItem(i18n("MiB")); // i18n: @item:inlistbox next to a text field containing the amount minSizeType->addItem(i18n("GiB")); minSizeType->setEnabled(false); sizeLayout->addWidget(minSizeType, 0, 2); maxSizeEnabled = new QCheckBox(sizeGroup); maxSizeEnabled->setText(i18n("At Most")); maxSizeEnabled->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); sizeLayout->addWidget(maxSizeEnabled, 0, 3); maxSizeAmount = new QSpinBox(sizeGroup); maxSizeAmount->setRange(0, 999999999); maxSizeAmount->setEnabled(false); sizeLayout->addWidget(maxSizeAmount, 0, 4); maxSizeType = new KComboBox(false, sizeGroup); // i18n: @item:inlistbox next to a text field containing the amount maxSizeType->addItem(i18n("Byte")); // i18n: @item:inlistbox next to a text field containing the amount maxSizeType->addItem(i18n("KiB")); // i18n: @item:inlistbox next to a text field containing the amount maxSizeType->addItem(i18n("MiB")); // i18n: @item:inlistbox next to a text field containing the amount maxSizeType->addItem(i18n("GiB")); maxSizeType->setEnabled(false); sizeLayout->addWidget(maxSizeType, 0, 5); filterLayout->addWidget(sizeGroup, 0, 0); // Options for date - QPixmap iconDate = krLoader->loadIcon("view-calendar", KIconLoader::Toolbar, 16); + Icon iconDate("view-calendar"); QGroupBox *dateGroup = new QGroupBox(this); QButtonGroup *btnGroup = new QButtonGroup(dateGroup); dateGroup->setTitle(i18n("Date")); btnGroup->setExclusive(true); QGridLayout *dateLayout = new QGridLayout(dateGroup); dateLayout->setAlignment(Qt::AlignTop); dateLayout->setSpacing(6); dateLayout->setContentsMargins(11, 11, 11, 11); anyDateEnabled = new QRadioButton(dateGroup); anyDateEnabled->setText(i18n("Any date")); btnGroup->addButton(anyDateEnabled); anyDateEnabled->setChecked(true); modifiedBetweenEnabled = new QRadioButton(dateGroup); modifiedBetweenEnabled->setText(i18n("&Modified between")); btnGroup->addButton(modifiedBetweenEnabled); modifiedBetweenData1 = new KLineEdit(dateGroup); modifiedBetweenData1->setEnabled(false); modifiedBetweenData1->setText(""); modifiedBetweenBtn1 = new QToolButton(dateGroup); modifiedBetweenBtn1->setEnabled(false); modifiedBetweenBtn1->setText(""); - modifiedBetweenBtn1->setIcon(QIcon(iconDate)); + modifiedBetweenBtn1->setIcon(iconDate); QLabel *andLabel = new QLabel(dateGroup); andLabel->setText(i18n("an&d")); modifiedBetweenData2 = new KLineEdit(dateGroup); modifiedBetweenData2->setEnabled(false); modifiedBetweenData2->setText(""); andLabel->setBuddy(modifiedBetweenData2); modifiedBetweenBtn2 = new QToolButton(dateGroup); modifiedBetweenBtn2->setEnabled(false); modifiedBetweenBtn2->setText(""); - modifiedBetweenBtn2->setIcon(QIcon(iconDate)); + modifiedBetweenBtn2->setIcon(iconDate); notModifiedAfterEnabled = new QRadioButton(dateGroup); notModifiedAfterEnabled->setText(i18n("&Not modified after")); btnGroup->addButton(notModifiedAfterEnabled); notModifiedAfterData = new KLineEdit(dateGroup); notModifiedAfterData->setEnabled(false); notModifiedAfterData->setText(""); notModifiedAfterBtn = new QToolButton(dateGroup); notModifiedAfterBtn->setEnabled(false); notModifiedAfterBtn->setText(""); - notModifiedAfterBtn->setIcon(QIcon(iconDate)); + notModifiedAfterBtn->setIcon(iconDate); modifiedInTheLastEnabled = new QRadioButton(dateGroup); modifiedInTheLastEnabled->setText(i18n("Mod&ified in the last")); btnGroup->addButton(modifiedInTheLastEnabled); modifiedInTheLastData = new QSpinBox(dateGroup); modifiedInTheLastData->setRange(0, 99999); modifiedInTheLastData->setEnabled(false); modifiedInTheLastType = new KComboBox(dateGroup); modifiedInTheLastType->addItem(i18n("days")); modifiedInTheLastType->addItem(i18n("weeks")); modifiedInTheLastType->addItem(i18n("months")); modifiedInTheLastType->addItem(i18n("years")); modifiedInTheLastType->setEnabled(false); notModifiedInTheLastData = new QSpinBox(dateGroup); notModifiedInTheLastData->setRange(0, 99999); notModifiedInTheLastData->setEnabled(false); QLabel *notModifiedInTheLastLbl = new QLabel(dateGroup); notModifiedInTheLastLbl->setText(i18n("No&t modified in the last")); notModifiedInTheLastLbl->setBuddy(notModifiedInTheLastData); notModifiedInTheLastType = new KComboBox(dateGroup); notModifiedInTheLastType->addItem(i18n("days")); notModifiedInTheLastType->addItem(i18n("weeks")); notModifiedInTheLastType->addItem(i18n("months")); notModifiedInTheLastType->addItem(i18n("years")); notModifiedInTheLastType->setEnabled(false); // Date options layout dateLayout->addWidget(anyDateEnabled, 0, 0); dateLayout->addWidget(modifiedBetweenEnabled, 1, 0); dateLayout->addWidget(modifiedBetweenData1, 1, 1); dateLayout->addWidget(modifiedBetweenBtn1, 1, 2); dateLayout->addWidget(andLabel, 1, 3); dateLayout->addWidget(modifiedBetweenData2, 1, 4); dateLayout->addWidget(modifiedBetweenBtn2, 1, 5); dateLayout->addWidget(notModifiedAfterEnabled, 2, 0); dateLayout->addWidget(notModifiedAfterData, 2, 1); dateLayout->addWidget(notModifiedAfterBtn, 2, 2); dateLayout->addWidget(modifiedInTheLastEnabled, 3, 0); QHBoxLayout *modifiedInTheLastLayout = new QHBoxLayout(); modifiedInTheLastLayout->addWidget(modifiedInTheLastData); modifiedInTheLastLayout->addWidget(modifiedInTheLastType); dateLayout->addLayout(modifiedInTheLastLayout, 3, 1); dateLayout->addWidget(notModifiedInTheLastLbl, 4, 0); modifiedInTheLastLayout = new QHBoxLayout(); modifiedInTheLastLayout->addWidget(notModifiedInTheLastData); modifiedInTheLastLayout->addWidget(notModifiedInTheLastType); dateLayout->addLayout(modifiedInTheLastLayout, 4, 1); filterLayout->addWidget(dateGroup, 1, 0); // Options for ownership QGroupBox *ownershipGroup = new QGroupBox(this); ownershipGroup->setTitle(i18n("Ownership")); QGridLayout *ownershipLayout = new QGridLayout(ownershipGroup); ownershipLayout->setAlignment(Qt::AlignTop); ownershipLayout->setSpacing(6); ownershipLayout->setContentsMargins(11, 11, 11, 11); QHBoxLayout *hboxLayout = new QHBoxLayout(); hboxLayout->setSpacing(6); hboxLayout->setContentsMargins(0, 0, 0, 0); belongsToUserEnabled = new QCheckBox(ownershipGroup); belongsToUserEnabled->setText(i18n("Belongs to &user")); hboxLayout->addWidget(belongsToUserEnabled); belongsToUserData = new KComboBox(ownershipGroup); belongsToUserData->setEnabled(false); belongsToUserData->setEditable(false); hboxLayout->addWidget(belongsToUserData); belongsToGroupEnabled = new QCheckBox(ownershipGroup); belongsToGroupEnabled->setText(i18n("Belongs to gr&oup")); hboxLayout->addWidget(belongsToGroupEnabled); belongsToGroupData = new KComboBox(ownershipGroup); belongsToGroupData->setEnabled(false); belongsToGroupData->setEditable(false); hboxLayout->addWidget(belongsToGroupData); ownershipLayout->addLayout(hboxLayout, 0, 0, 1, 4); permissionsEnabled = new QCheckBox(ownershipGroup); permissionsEnabled->setText(i18n("P&ermissions")); ownershipLayout->addWidget(permissionsEnabled, 1, 0); QGroupBox *ownerGroup = new QGroupBox(ownershipGroup); QHBoxLayout *ownerHBox = new QHBoxLayout(ownerGroup); ownerGroup->setTitle(i18n("O&wner")); ownerR = new KComboBox(ownerGroup); ownerR->addItem(i18n("?")); ownerR->addItem(i18n("r")); ownerR->addItem(i18n("-")); ownerR->setEnabled(false); ownerHBox->addWidget(ownerR); ownerW = new KComboBox(ownerGroup); ownerW->addItem(i18n("?")); ownerW->addItem(i18n("w")); ownerW->addItem(i18n("-")); ownerW->setEnabled(false); ownerHBox->addWidget(ownerW); ownerX = new KComboBox(ownerGroup); ownerX->addItem(i18n("?")); ownerX->addItem(i18n("x")); ownerX->addItem(i18n("-")); ownerX->setEnabled(false); ownerHBox->addWidget(ownerX); ownershipLayout->addWidget(ownerGroup, 1, 1); QGroupBox *groupGroup = new QGroupBox(ownershipGroup); QHBoxLayout *groupHBox = new QHBoxLayout(groupGroup); groupGroup->setTitle(i18n("Grou&p")); groupR = new KComboBox(groupGroup); groupR->addItem(i18n("?")); groupR->addItem(i18n("r")); groupR->addItem(i18n("-")); groupR->setEnabled(false); groupHBox->addWidget(groupR); groupW = new KComboBox(groupGroup); groupW->addItem(i18n("?")); groupW->addItem(i18n("w")); groupW->addItem(i18n("-")); groupW->setEnabled(false); groupHBox->addWidget(groupW); groupX = new KComboBox(groupGroup); groupX->addItem(i18n("?")); groupX->addItem(i18n("x")); groupX->addItem(i18n("-")); groupX->setEnabled(false); groupHBox->addWidget(groupX); ownershipLayout->addWidget(groupGroup, 1, 2); QGroupBox *allGroup = new QGroupBox(ownershipGroup); QHBoxLayout *allHBox = new QHBoxLayout(allGroup); allGroup->setTitle(i18n("A&ll")); allR = new KComboBox(allGroup); allR->addItem(i18n("?")); allR->addItem(i18n("r")); allR->addItem(i18n("-")); allR->setEnabled(false); allHBox->addWidget(allR); allW = new KComboBox(allGroup); allW->addItem(i18n("?")); allW->addItem(i18n("w")); allW->addItem(i18n("-")); allW->setEnabled(false); allHBox->addWidget(allW); allX = new KComboBox(allGroup); allX->addItem(i18n("?")); allX->addItem(i18n("x")); allX->addItem(i18n("-")); allX->setEnabled(false); allHBox->addWidget(allX); ownershipLayout->addWidget(allGroup, 1, 3); QLabel *infoLabel = new QLabel(ownershipGroup); QFont infoLabel_font(infoLabel->font()); infoLabel_font.setFamily("adobe-helvetica"); infoLabel_font.setItalic(true); infoLabel->setFont(infoLabel_font); infoLabel->setText(i18n("Note: a '?' is a wildcard")); ownershipLayout->addWidget(infoLabel, 2, 0, 1, 4, Qt::AlignRight); filterLayout->addWidget(ownershipGroup, 2, 0); // Connection table connect(minSizeEnabled, SIGNAL(toggled(bool)), minSizeAmount, SLOT(setEnabled(bool))); connect(minSizeEnabled, SIGNAL(toggled(bool)), minSizeType, SLOT(setEnabled(bool))); connect(maxSizeEnabled, SIGNAL(toggled(bool)), maxSizeAmount, SLOT(setEnabled(bool))); connect(maxSizeEnabled, SIGNAL(toggled(bool)), maxSizeType, SLOT(setEnabled(bool))); connect(modifiedBetweenEnabled, SIGNAL(toggled(bool)), modifiedBetweenData1, SLOT(setEnabled(bool))); connect(modifiedBetweenEnabled, SIGNAL(toggled(bool)), modifiedBetweenBtn1, SLOT(setEnabled(bool))); connect(modifiedBetweenEnabled, SIGNAL(toggled(bool)), modifiedBetweenData2, SLOT(setEnabled(bool))); connect(modifiedBetweenEnabled, SIGNAL(toggled(bool)), modifiedBetweenBtn2, SLOT(setEnabled(bool))); connect(notModifiedAfterEnabled, SIGNAL(toggled(bool)), notModifiedAfterData, SLOT(setEnabled(bool))); connect(notModifiedAfterEnabled, SIGNAL(toggled(bool)), notModifiedAfterBtn, SLOT(setEnabled(bool))); connect(modifiedInTheLastEnabled, SIGNAL(toggled(bool)), modifiedInTheLastData, SLOT(setEnabled(bool))); connect(modifiedInTheLastEnabled, SIGNAL(toggled(bool)), modifiedInTheLastType, SLOT(setEnabled(bool))); connect(modifiedInTheLastEnabled, SIGNAL(toggled(bool)), notModifiedInTheLastData, SLOT(setEnabled(bool))); connect(modifiedInTheLastEnabled, SIGNAL(toggled(bool)), notModifiedInTheLastType, SLOT(setEnabled(bool))); connect(belongsToUserEnabled, SIGNAL(toggled(bool)), belongsToUserData, SLOT(setEnabled(bool))); connect(belongsToGroupEnabled, SIGNAL(toggled(bool)), belongsToGroupData, SLOT(setEnabled(bool))); connect(permissionsEnabled, SIGNAL(toggled(bool)), ownerR, SLOT(setEnabled(bool))); connect(permissionsEnabled, SIGNAL(toggled(bool)), ownerW, SLOT(setEnabled(bool))); connect(permissionsEnabled, SIGNAL(toggled(bool)), ownerX, SLOT(setEnabled(bool))); connect(permissionsEnabled, SIGNAL(toggled(bool)), groupR, SLOT(setEnabled(bool))); connect(permissionsEnabled, SIGNAL(toggled(bool)), groupW, SLOT(setEnabled(bool))); connect(permissionsEnabled, SIGNAL(toggled(bool)), groupX, SLOT(setEnabled(bool))); connect(permissionsEnabled, SIGNAL(toggled(bool)), allR, SLOT(setEnabled(bool))); connect(permissionsEnabled, SIGNAL(toggled(bool)), allW, SLOT(setEnabled(bool))); connect(permissionsEnabled, SIGNAL(toggled(bool)), allX, SLOT(setEnabled(bool))); connect(modifiedBetweenBtn1, SIGNAL(clicked()), this, SLOT(modifiedBetweenSetDate1())); connect(modifiedBetweenBtn2, SIGNAL(clicked()), this, SLOT(modifiedBetweenSetDate2())); connect(notModifiedAfterBtn, SIGNAL(clicked()), this, SLOT(notModifiedAfterSetDate())); // fill the users and groups list fillList(belongsToUserData, USERSFILE); fillList(belongsToGroupData, GROUPSFILE); // tab order setTabOrder(minSizeEnabled, minSizeAmount); setTabOrder(minSizeAmount, maxSizeEnabled); setTabOrder(maxSizeEnabled, maxSizeAmount); setTabOrder(maxSizeAmount, modifiedBetweenEnabled); setTabOrder(modifiedBetweenEnabled, modifiedBetweenData1); setTabOrder(modifiedBetweenData1, modifiedBetweenData2); setTabOrder(modifiedBetweenData2, notModifiedAfterEnabled); setTabOrder(notModifiedAfterEnabled, notModifiedAfterData); setTabOrder(notModifiedAfterData, modifiedInTheLastEnabled); setTabOrder(modifiedInTheLastEnabled, modifiedInTheLastData); setTabOrder(modifiedInTheLastData, notModifiedInTheLastData); setTabOrder(notModifiedInTheLastData, belongsToUserEnabled); setTabOrder(belongsToUserEnabled, belongsToUserData); setTabOrder(belongsToUserData, belongsToGroupEnabled); setTabOrder(belongsToGroupEnabled, belongsToGroupData); setTabOrder(belongsToGroupData, permissionsEnabled); setTabOrder(permissionsEnabled, ownerR); setTabOrder(ownerR, ownerW); setTabOrder(ownerW, ownerX); setTabOrder(ownerX, groupR); setTabOrder(groupR, groupW); setTabOrder(groupW, groupX); setTabOrder(groupX, allR); setTabOrder(allR, allW); setTabOrder(allW, allX); setTabOrder(allX, minSizeType); setTabOrder(minSizeType, maxSizeType); setTabOrder(maxSizeType, modifiedInTheLastType); setTabOrder(modifiedInTheLastType, notModifiedInTheLastType); } void AdvancedFilter::modifiedBetweenSetDate1() { changeDate(modifiedBetweenData1); } void AdvancedFilter::modifiedBetweenSetDate2() { changeDate(modifiedBetweenData2); } void AdvancedFilter::notModifiedAfterSetDate() { changeDate(notModifiedAfterData); } void AdvancedFilter::changeDate(KLineEdit *p) { // check if the current date is valid QDate d = stringToDate(p->text()); if (!d.isValid()) d = QDate::currentDate(); KRGetDate *gd = new KRGetDate(d, this); d = gd->getDate(); // if a user pressed ESC or closed the dialog, we'll return an invalid date if (d.isValid()) p->setText(dateToString(d)); delete gd; } void AdvancedFilter::fillList(KComboBox *list, QString filename) { QFile data(filename); if (!data.open(QIODevice::ReadOnly)) { qWarning() << "Search: Unable to read " << filename << " !!!"; return; } // and read it into the temporary array QTextStream t(&data); while (!t.atEnd()) { QString s = t.readLine(); QString name = s.left(s.indexOf(':')); if (!name.startsWith('#')) list->addItem(name); } } void AdvancedFilter::invalidDateMessage(KLineEdit *p) { // FIXME p->text() is empty sometimes (to reproduce, set date to "13.09.005") KMessageBox::detailedError(this, i18n("Invalid date entered."), i18n("The date %1 is not valid according to your locale. Please re-enter a valid date (use the date button for easy access).", p->text())); p->setFocus(); } bool AdvancedFilter::getSettings(FilterSettings &s) { s.minSizeEnabled = minSizeEnabled->isChecked(); s.minSize.amount = minSizeAmount->value(); s.minSize.unit = static_cast(minSizeType->currentIndex()); s.maxSizeEnabled = maxSizeEnabled->isChecked(); s.maxSize.amount = maxSizeAmount->value(); s.maxSize.unit = static_cast(maxSizeType->currentIndex()); if (s.minSizeEnabled && s.maxSizeEnabled && (s.maxSize.size() < s.minSize.size())) { KMessageBox::detailedError(this, i18n("Specified sizes are inconsistent."), i18n("Please re-enter the values, so that the left side size " "will be smaller than (or equal to) the right side size.")); minSizeAmount->setFocus(); return false; } s.modifiedBetweenEnabled = modifiedBetweenEnabled->isChecked(); s.modifiedBetween1 = stringToDate(modifiedBetweenData1->text()); s.modifiedBetween2 = stringToDate(modifiedBetweenData2->text()); if (s.modifiedBetweenEnabled) { // check if date is valid if (!s.modifiedBetween1.isValid()) { invalidDateMessage(modifiedBetweenData1); return false; } else if (!s.modifiedBetween2.isValid()) { invalidDateMessage(modifiedBetweenData2); return false; } else if (s.modifiedBetween1 > s.modifiedBetween2) { KMessageBox::detailedError(this, i18n("Dates are inconsistent."), i18n("The date on the left is later than the date on the right. " "Please re-enter the dates, so that the left side date " "will be earlier than the right side date.")); modifiedBetweenData1->setFocus(); return false; } } s.notModifiedAfterEnabled = notModifiedAfterEnabled->isChecked(); s.notModifiedAfter = stringToDate(notModifiedAfterData->text()); if(s.notModifiedAfterEnabled && !s.notModifiedAfter.isValid()) { invalidDateMessage(notModifiedAfterData); return false; } s.modifiedInTheLastEnabled = modifiedInTheLastEnabled->isChecked(); s.modifiedInTheLast.amount = modifiedInTheLastData->value(); s.modifiedInTheLast.unit = static_cast(modifiedInTheLastType->currentIndex()); s.notModifiedInTheLast.amount = notModifiedInTheLastData->value(); s.notModifiedInTheLast.unit = static_cast(notModifiedInTheLastType->currentIndex()); if (s.modifiedInTheLastEnabled && s.modifiedInTheLast.amount && s.notModifiedInTheLast.amount) { if (s.modifiedInTheLast.days() < s.notModifiedInTheLast.days()) { KMessageBox::detailedError(this, i18n("Dates are inconsistent."), i18n("The date on top is later than the date on the bottom. " "Please re-enter the dates, so that the top date " "will be earlier than the bottom date.")); modifiedInTheLastData->setFocus(); return false; } } s.ownerEnabled = belongsToUserEnabled->isChecked(); s.owner = belongsToUserData->currentText(); s.groupEnabled = belongsToGroupEnabled->isChecked(); s.group = belongsToGroupData->currentText(); s.permissionsEnabled = permissionsEnabled->isChecked(); s.permissions = ownerR->currentText() + ownerW->currentText() + ownerX->currentText() + groupR->currentText() + groupW->currentText() + groupX->currentText() + allR->currentText() + allW->currentText() + allX->currentText(); return true; } void AdvancedFilter::applySettings(const FilterSettings &s) { minSizeEnabled->setChecked(s.minSizeEnabled); minSizeAmount->setValue(s.minSize.amount); minSizeType->setCurrentIndex(s.minSize.unit); maxSizeEnabled->setChecked(s.maxSizeEnabled); maxSizeAmount->setValue(s.maxSize.amount); maxSizeType->setCurrentIndex(s.maxSize.unit); if (s.modifiedBetweenEnabled) modifiedBetweenEnabled->setChecked(true); else if (s.notModifiedAfterEnabled) notModifiedAfterEnabled->setChecked(true); else if (s.modifiedInTheLastEnabled) modifiedInTheLastEnabled->setChecked(true); else anyDateEnabled->setChecked(true); modifiedBetweenData1->setText(dateToString(s.modifiedBetween1)); modifiedBetweenData2->setText(dateToString(s.modifiedBetween2)); notModifiedAfterData->setText(dateToString(s.notModifiedAfter)); modifiedInTheLastData->setValue(s.modifiedInTheLast.amount); modifiedInTheLastType->setCurrentIndex(s.modifiedInTheLast.unit); notModifiedInTheLastData->setValue(s.notModifiedInTheLast.amount); notModifiedInTheLastType->setCurrentIndex(s.notModifiedInTheLast.unit); belongsToUserEnabled->setChecked(s.ownerEnabled); setComboBoxValue(belongsToUserData, s.owner); belongsToGroupEnabled->setChecked(s.groupEnabled); setComboBoxValue(belongsToGroupData, s.group); permissionsEnabled->setChecked(s.permissionsEnabled); QString perm = s.permissions; if (perm.length() != 9) perm = "?????????"; setComboBoxValue(ownerR, QString(perm[0])); setComboBoxValue(ownerW, QString(perm[1])); setComboBoxValue(ownerX, QString(perm[2])); setComboBoxValue(groupR, QString(perm[3])); setComboBoxValue(groupW, QString(perm[4])); setComboBoxValue(groupX, QString(perm[5])); setComboBoxValue(allR, QString(perm[6])); setComboBoxValue(allW, QString(perm[7])); setComboBoxValue(allX, QString(perm[8])); } diff --git a/krusader/Filter/generalfilter.cpp b/krusader/Filter/generalfilter.cpp index e2eb0f6b..29378a79 100644 --- a/krusader/Filter/generalfilter.cpp +++ b/krusader/Filter/generalfilter.cpp @@ -1,636 +1,635 @@ /***************************************************************************** * Copyright (C) 2003 Shie Erlich * * Copyright (C) 2003 Rafi Yanai * * 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/]. * *****************************************************************************/ #include "generalfilter.h" #include "filtertabs.h" #include "../krglobal.h" #include "../krservices.h" #include "../FileSystem/filesystem.h" // QtWidgets #include #include #include #include #include #include #include #include #include -#include #include typedef struct { const char *description; const char *regExp; int cursorAdjustment; } term; static const term items[] = { { I18N_NOOP("Any Character"), ".", 0 }, { I18N_NOOP("Start of Line"), "^", 0 }, { I18N_NOOP("End of Line"), "$", 0 }, { I18N_NOOP("Set of Characters"), "[]", -1 }, { I18N_NOOP("Repeats, Zero or More Times"), "*", 0 }, { I18N_NOOP("Repeats, One or More Times"), "+", 0 }, { I18N_NOOP("Optional"), "?", 0 }, { I18N_NOOP("Escape"), "\\", 0 }, { I18N_NOOP("TAB"), "\\t", 0 }, { I18N_NOOP("Newline"), "\\n", 0 }, { I18N_NOOP("Carriage Return"), "\\r", 0 }, { I18N_NOOP("White Space"), "\\s", 0 }, { I18N_NOOP("Digit"), "\\d", 0 }, }; class RegExpAction : public QAction { public: RegExpAction(QObject *parent, const QString &text, const QString ®Exp, int cursor) : QAction(text, parent), mText(text), mRegExp(regExp), mCursor(cursor) { } QString text() const { return mText; } QString regExp() const { return mRegExp; } int cursor() const { return mCursor; } private: QString mText; QString mRegExp; int mCursor; }; GeneralFilter::GeneralFilter(FilterTabs *tabs, int properties, QWidget *parent, QStringList extraOptions) : QWidget(parent), profileManager(0), fltTabs(tabs) { QGridLayout *filterLayout = new QGridLayout(this); filterLayout->setSpacing(6); filterLayout->setContentsMargins(11, 11, 11, 11); this->properties = properties; // Options for name filtering QGroupBox *nameGroup = new QGroupBox(this); nameGroup->setTitle(i18n("File Name")); QGridLayout *nameGroupLayout = new QGridLayout(nameGroup); nameGroupLayout->setAlignment(Qt::AlignTop); nameGroupLayout->setSpacing(6); nameGroupLayout->setContentsMargins(11, 11, 11, 11); searchForCase = new QCheckBox(nameGroup); searchForCase->setText(i18n("&Case sensitive")); searchForCase->setChecked(false); nameGroupLayout->addWidget(searchForCase, 1, 2); QLabel *searchForLabel = new QLabel(nameGroup); searchForLabel->setText(i18n("Search &for:")); nameGroupLayout->addWidget(searchForLabel, 0, 0); searchFor = new KHistoryComboBox(false, nameGroup/*, "searchFor"*/); QSizePolicy searchForPolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); searchForPolicy.setHeightForWidth(searchFor->sizePolicy().hasHeightForWidth()); searchFor->setSizePolicy(searchForPolicy); searchFor->setEditable(true); searchFor->setDuplicatesEnabled(false); searchFor->setMaxCount(25); searchFor->setMinimumContentsLength(10); searchForLabel->setBuddy(searchFor); nameGroupLayout->addWidget(searchFor, 0, 1, 1, 2); QString s = "

" + i18n("

The filename filtering criteria is defined here.

You can make use of wildcards. Multiple patterns are separated by space (means logical OR) and patterns are excluded from the search using the pipe symbol.

If the pattern is ended with a slash (*pattern*/), that means that pattern relates to recursive search of folders.

  • pattern - means to search those files/folders that name is pattern, recursive search goes through all subfolders independently of the value of pattern
  • pattern/ - means to search all files/folders, but recursive search goes through/excludes the folders that name is pattern

It is allowed to use quotation marks for names that contain space. Filter \"Program Files\" searches out those files/folders that name is Program Files.

Examples:

  • *.o
  • *.h *.c\?\?
  • *.cpp *.h | *.moc.cpp
  • * | .svn/ .git/

Note: the search term 'text' is equivalent to '*text*'.

"); searchFor->setWhatsThis(s); searchForLabel->setWhatsThis(s); QLabel *searchType = new QLabel(nameGroup); searchType->setText(i18n("&Of type:")); nameGroupLayout->addWidget(searchType, 1, 0); ofType = new KComboBox(false, nameGroup); ofType->setObjectName("ofType"); QSizePolicy ofTypePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); ofTypePolicy.setHeightForWidth(ofType->sizePolicy().hasHeightForWidth()); ofType->setSizePolicy(ofTypePolicy); ofType->setEditable(false); searchType->setBuddy(ofType); ofType->addItem(i18n("All Files")); ofType->addItem(i18n("Archives")); ofType->addItem(i18n("Folders")); ofType->addItem(i18n("Image Files")); ofType->addItem(i18n("Text Files")); ofType->addItem(i18n("Video Files")); ofType->addItem(i18n("Audio Files")); connect(ofType, SIGNAL(currentIndexChanged(int)), this, SLOT(slotDisable())); nameGroupLayout->addWidget(ofType, 1, 1); filterLayout->addWidget(nameGroup, 0, 0); middleLayout = new QHBoxLayout(); middleLayout->setSpacing(6); middleLayout->setContentsMargins(0, 0, 0, 0); QSpacerItem* middleSpacer = new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Fixed); middleLayout->addItem(middleSpacer); if (properties & FilterTabs::HasProfileHandler) { // The profile handler QGroupBox *profileHandler = new QGroupBox(this); profileHandler->setTitle(i18n("&Profile handler")); QGridLayout *profileLayout = new QGridLayout(profileHandler); profileLayout->setAlignment(Qt::AlignTop); profileLayout->setSpacing(6); profileLayout->setContentsMargins(11, 11, 11, 11); profileListBox = new KrListWidget(profileHandler); profileLayout->addWidget(profileListBox, 0, 0, 4, 1); profileAddBtn = new QPushButton(profileHandler); KStandardGuiItem::assign(profileAddBtn, KStandardGuiItem::Add); profileLayout->addWidget(profileAddBtn, 0, 1); profileLoadBtn = new QPushButton(i18n("&Load"), profileHandler); profileLoadBtn->setEnabled(false); profileLayout->addWidget(profileLoadBtn, 1, 1); profileOverwriteBtn = new QPushButton(profileHandler); profileOverwriteBtn->setEnabled(false); KStandardGuiItem::assign(profileOverwriteBtn, KStandardGuiItem::Overwrite); profileLayout->addWidget(profileOverwriteBtn, 2, 1); profileRemoveBtn = new QPushButton(profileHandler); profileRemoveBtn->setEnabled(false); KStandardGuiItem::assign(profileRemoveBtn, KStandardGuiItem::Remove); profileLayout->addWidget(profileRemoveBtn, 3, 1); profileManager = new ProfileManager("SelectionProfile", this); profileManager->hide(); middleLayout->addWidget(profileHandler); refreshProfileListBox(); } if (properties & FilterTabs::HasSearchIn) { // Options for search in QGroupBox *searchInGroup = new QGroupBox(this); searchInGroup->setTitle(i18n("Searc&h in")); QGridLayout *searchInLayout = new QGridLayout(searchInGroup); searchInLayout->setAlignment(Qt::AlignTop); searchInLayout->setSpacing(6); searchInLayout->setContentsMargins(11, 11, 11, 11); searchIn = new KURLListRequester(KURLListRequester::RequestDirs, searchInGroup); searchInLayout->addWidget(searchIn, 0, 0); connect(searchIn, SIGNAL(changed()), this, SLOT(slotDisable())); middleLayout->addWidget(searchInGroup); } if (properties & FilterTabs::HasDontSearchIn) { // Options for don't search in QGroupBox *dontSearchInGroup = new QGroupBox(this); dontSearchInGroup->setTitle(i18n("&Do not search in")); QGridLayout *dontSearchInLayout = new QGridLayout(dontSearchInGroup); dontSearchInLayout->setAlignment(Qt::AlignTop); dontSearchInLayout->setSpacing(6); dontSearchInLayout->setContentsMargins(11, 11, 11, 11); dontSearchIn = new KURLListRequester(KURLListRequester::RequestDirs, dontSearchInGroup); dontSearchInLayout->addWidget(dontSearchIn, 0, 0, 1, 2); if (properties & FilterTabs::HasRecurseOptions) { KConfigGroup group(krConfig, "Search"); useExcludeFolderNames = new QCheckBox(this); useExcludeFolderNames->setText(i18n("Exclude Folder Names")); useExcludeFolderNames->setToolTip(i18n("Filters out specified directory names from the results.")); useExcludeFolderNames->setChecked(static_cast(group.readEntry("ExcludeFolderNamesUse", 0))); dontSearchInLayout->addWidget(useExcludeFolderNames, 1, 0, 1, 1); excludeFolderNames = new KHistoryComboBox(false, dontSearchInGroup); QSizePolicy excludeFolderNamesPolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); excludeFolderNamesPolicy.setHeightForWidth(excludeFolderNames->sizePolicy().hasHeightForWidth()); excludeFolderNames->setSizePolicy(excludeFolderNamesPolicy); excludeFolderNames->setEditable(true); excludeFolderNames->setDuplicatesEnabled(false); excludeFolderNames->setMaxCount(25); excludeFolderNames->setMinimumContentsLength(10); excludeFolderNames->lineEdit()->setPlaceholderText(i18n("Enter space-separated folder names")); excludeFolderNames->lineEdit()->setWhatsThis(i18n("You can insert names with escaped spaces or quoted.\nExample: .git \"target build\" build\\ krusader")); dontSearchInLayout->addWidget(excludeFolderNames, 1, 1, 1, 1); excludeFolderNames->setHistoryItems(group.readEntry("ExcludeFolderNamesHistory", QStringList())); excludeFolderNames->setEditText(group.readEntry("ExcludeFolderNames", "")); if (!useExcludeFolderNames->isChecked()) { excludeFolderNames->setDisabled(true); } connect(useExcludeFolderNames, &QCheckBox::toggled, excludeFolderNames, &KHistoryComboBox::setEnabled); } middleLayout->addWidget(dontSearchInGroup); } filterLayout->addLayout(middleLayout, 1, 0); // Options for containing text QGroupBox *containsGroup = new QGroupBox(this); containsGroup->setTitle(i18n("Containing text")); QGridLayout *containsLayout = new QGridLayout(containsGroup); containsLayout->setAlignment(Qt::AlignTop); containsLayout->setSpacing(6); containsLayout->setContentsMargins(11, 11, 11, 11); QHBoxLayout *containsTextLayout = new QHBoxLayout(); containsTextLayout->setSpacing(6); containsTextLayout->setContentsMargins(0, 0, 0, 0); containsLabel = new QLabel(containsGroup); QSizePolicy containsLabelPolicy(QSizePolicy::Fixed, QSizePolicy::Minimum); containsLabelPolicy.setHeightForWidth(containsLabel->sizePolicy().hasHeightForWidth()); containsLabel->setSizePolicy(containsLabelPolicy); containsLabel->setText(i18n("&Text:")); containsTextLayout->addWidget(containsLabel); containsText = new KHistoryComboBox(false, containsGroup/*, "containsText"*/); QSizePolicy containsTextPolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); containsTextPolicy.setHeightForWidth(containsText->sizePolicy().hasHeightForWidth()); containsText->setSizePolicy(containsTextPolicy); containsText->setDuplicatesEnabled(false); containsText->setMaxCount(25); containsText->setMinimumContentsLength(10); containsTextLayout->addWidget(containsText); containsLabel->setBuddy(containsText); containsRegExp = new QToolButton(containsGroup); containsRegExp->setPopupMode(QToolButton::MenuButtonPopup); containsRegExp->setCheckable(true); containsRegExp->setText(i18n("RegExp")); // Populate the popup menu. QMenu *patterns = new QMenu(containsRegExp); for (int i = 0; (unsigned)i < sizeof(items) / sizeof(items[0]); i++) { patterns->addAction(new RegExpAction(patterns, i18n(items[i].description), items[i].regExp, items[i].cursorAdjustment)); } connect(containsRegExp, SIGNAL(toggled(bool)), this, SLOT(slotDisable())); connect(containsRegExp, SIGNAL(triggered(QAction*)), this, SLOT(slotRegExpTriggered(QAction*))); containsRegExp->setMenu(patterns); patterns->setEnabled(false); containsTextLayout->addWidget(containsRegExp); containsLayout->addLayout(containsTextLayout, 0, 0); QHBoxLayout *containsCbsLayout = new QHBoxLayout(); containsCbsLayout->setSpacing(6); containsCbsLayout->setContentsMargins(0, 0, 0, 0); encLabel = new QLabel(i18n("Encoding:"), containsGroup); containsCbsLayout->addWidget(encLabel); contentEncoding = new KComboBox(containsGroup); contentEncoding->setEditable(false); contentEncoding->addItem(i18nc("Default encoding", "Default")); contentEncoding->addItems(KCharsets::charsets()->descriptiveEncodingNames()); containsCbsLayout->addWidget(contentEncoding); QSpacerItem* cbSpacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); containsCbsLayout->addItem(cbSpacer); containsWholeWord = new QCheckBox(containsGroup); QSizePolicy containsWholeWordPolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); containsWholeWordPolicy.setHeightForWidth(containsWholeWord->sizePolicy().hasHeightForWidth()); containsWholeWord->setSizePolicy(containsWholeWordPolicy); containsWholeWord->setText(i18n("&Match whole word only")); containsWholeWord->setChecked(false); containsCbsLayout->addWidget(containsWholeWord); containsTextCase = new QCheckBox(containsGroup); QSizePolicy containsTextCasePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); containsTextCasePolicy.setHeightForWidth(containsTextCase->sizePolicy().hasHeightForWidth()); containsTextCase->setSizePolicy(containsTextCasePolicy); containsTextCase->setText(i18n("Cas&e sensitive")); containsTextCase->setChecked(true); containsCbsLayout->addWidget(containsTextCase); containsLayout->addLayout(containsCbsLayout, 1, 0); filterLayout->addWidget(containsGroup, 2, 0); QHBoxLayout *recurseLayout = new QHBoxLayout(); recurseLayout->setSpacing(6); recurseLayout->setContentsMargins(0, 0, 0, 0); QSpacerItem* recurseSpacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); recurseLayout->addItem(recurseSpacer); if (properties & FilterTabs::HasRecurseOptions) { // Options for recursive searching searchInDirs = new QCheckBox(this); searchInDirs->setText(i18n("Search in s&ub folders")); searchInDirs->setChecked(true); recurseLayout->addWidget(searchInDirs); searchInArchives = new QCheckBox(this); searchInArchives->setText(i18n("Search in arch&ives")); recurseLayout->addWidget(searchInArchives); followLinks = new QCheckBox(this); followLinks->setText(i18n("Follow &links")); recurseLayout->addWidget(followLinks); } filterLayout->addLayout(recurseLayout, 3, 0); for(int i = 0; i < extraOptions.length(); i++) { QCheckBox *option = new QCheckBox(this); option->setText(extraOptions[i]); recurseLayout->addWidget(option); this->extraOptions.insert(extraOptions[i], option); } // Connection table if (properties & FilterTabs::HasProfileHandler) { connect(profileAddBtn, SIGNAL(clicked()) , this, SLOT(slotAddBtnClicked())); connect(profileLoadBtn, SIGNAL(clicked()) , this, SLOT(slotLoadBtnClicked())); connect(profileOverwriteBtn, SIGNAL(clicked()) , this, SLOT(slotOverwriteBtnClicked())); connect(profileRemoveBtn, SIGNAL(clicked()) , this, SLOT(slotRemoveBtnClicked())); connect(profileListBox, SIGNAL(itemDoubleClicked(QListWidgetItem*)) , this, SLOT(slotProfileDoubleClicked(QListWidgetItem*))); connect(profileManager, SIGNAL(loadFromProfile(QString)), fltTabs, SLOT(loadFromProfile(QString))); connect(profileManager, SIGNAL(saveToProfile(QString)), fltTabs, SLOT(saveToProfile(QString))); } connect(searchFor, SIGNAL(activated(QString)), searchFor, SLOT(addToHistory(QString))); connect(containsText, SIGNAL(activated(QString)), containsText, SLOT(addToHistory(QString))); // load the completion and history lists // ==> search for KConfigGroup group(krConfig, "Search"); QStringList list = group.readEntry("SearchFor Completion", QStringList()); searchFor->completionObject()->setItems(list); list = group.readEntry("SearchFor History", QStringList()); searchFor->setHistoryItems(list); // ==> grep list = group.readEntry("ContainsText Completion", QStringList()); containsText->completionObject()->setItems(list); list = group.readEntry("ContainsText History", QStringList()); containsText->setHistoryItems(list); setTabOrder(searchFor, containsText); // search for -> content setTabOrder(containsText, searchType); // content -> search type slotDisable(); } GeneralFilter::~GeneralFilter() { // save the history combos // ==> search for QStringList list = searchFor->completionObject()->items(); KConfigGroup group(krConfig, "Search"); group.writeEntry("SearchFor Completion", list); list = searchFor->historyItems(); group.writeEntry("SearchFor History", list); // ==> grep text list = containsText->completionObject()->items(); group.writeEntry("ContainsText Completion", list); list = containsText->historyItems(); group.writeEntry("ContainsText History", list); if ((properties & FilterTabs::HasDontSearchIn) && (properties & FilterTabs::HasRecurseOptions)) { list = excludeFolderNames->historyItems(); group.writeEntry("ExcludeFolderNamesHistory", list); group.writeEntry("ExcludeFolderNames", excludeFolderNames->currentText()); group.writeEntry("ExcludeFolderNamesUse", static_cast(useExcludeFolderNames->checkState())); } krConfig->sync(); } bool GeneralFilter::isExtraOptionChecked(QString name) { QCheckBox *option = extraOptions[name]; return option ? option->isChecked() : false; } void GeneralFilter::checkExtraOption(QString name, bool check) { QCheckBox *option = extraOptions[name]; if (option) option->setChecked(check); } void GeneralFilter::queryAccepted() { searchFor->addToHistory(searchFor->currentText()); containsText->addToHistory(containsText->currentText()); if ((properties & FilterTabs::HasDontSearchIn) && (properties & FilterTabs::HasRecurseOptions)) { excludeFolderNames->addToHistory(excludeFolderNames->currentText()); } } void GeneralFilter::refreshProfileListBox() { profileListBox->clear(); profileListBox->addItems(ProfileManager::availableProfiles("SelectionProfile")); if (profileListBox->count() != 0) { profileLoadBtn->setEnabled(true); profileOverwriteBtn->setEnabled(true); profileRemoveBtn->setEnabled(true); } else { profileLoadBtn->setEnabled(false); profileOverwriteBtn->setEnabled(false); profileRemoveBtn->setEnabled(false); } } void GeneralFilter::slotAddBtnClicked() { profileManager->newProfile(searchFor->currentText().simplified()); refreshProfileListBox(); } void GeneralFilter::slotOverwriteBtnClicked() { QListWidgetItem *item = profileListBox->currentItem(); if (item != 0) profileManager->overwriteProfile(item->text()); } void GeneralFilter::slotRemoveBtnClicked() { QListWidgetItem *item = profileListBox->currentItem(); if (item != 0) { profileManager->deleteProfile(item->text()); refreshProfileListBox(); } } void GeneralFilter::slotProfileDoubleClicked(QListWidgetItem *item) { if (item != 0) { QString profileName = item->text(); profileManager->loadProfile(profileName); fltTabs->close(true); } } void GeneralFilter::slotLoadBtnClicked() { QListWidgetItem *item = profileListBox->currentItem(); if (item != 0) profileManager->loadProfile(item->text()); } void GeneralFilter::slotDisable() { bool state = containsRegExp->isChecked(); bool global = ofType->currentText() != i18n("Folders"); bool remoteOnly = false; if (properties & FilterTabs::HasSearchIn) { QList urlList = searchIn->urlList(); remoteOnly = urlList.count() != 0; foreach(const QUrl &url, urlList) if (url.scheme() == "file") remoteOnly = false; } containsWholeWord->setEnabled(!state && global); containsRegExp->menu()->setEnabled(state && global); encLabel->setEnabled(global); contentEncoding->setEnabled(global); containsTextCase->setEnabled(global); containsRegExp->setEnabled(global); if (properties & FilterTabs::HasRecurseOptions) searchInArchives->setEnabled(global && !remoteOnly); containsLabel->setEnabled(global); containsText->setEnabled(global); } void GeneralFilter::slotRegExpTriggered(QAction * act) { if (act == 0) return; RegExpAction *regAct = dynamic_cast(act); if (regAct == 0) return; containsText->lineEdit()->insert(regAct->regExp()); containsText->lineEdit()->setCursorPosition(containsText->lineEdit()->cursorPosition() + regAct->cursor()); containsText->lineEdit()->setFocus(); } bool GeneralFilter::getSettings(FilterSettings &s) { // check that we have (at least) what to search, and where to search in if (searchFor->currentText().simplified().isEmpty()) { KMessageBox::error(this , i18n("No search criteria entered.")); searchFor->setFocus(); return false; } s.searchFor = searchFor->currentText().trimmed(); s.searchForCase = searchForCase->isChecked(); if (ofType->currentText() != i18n("All Files")) s.mimeType = ofType->currentText(); if (containsText->isEnabled()) { s.containsText = containsText->currentText(); s.containsTextCase = containsTextCase->isChecked(); s.containsWholeWord = containsWholeWord->isChecked(); s.containsRegExp = containsRegExp->isChecked(); } if (contentEncoding->currentIndex() != 0) s.contentEncoding = KCharsets::charsets()->encodingForName(contentEncoding->currentText()); if (properties & FilterTabs::HasRecurseOptions) { s.recursive = searchInDirs->isChecked(); s.searchInArchives = searchInArchives->isChecked(); s.followLinks = followLinks->isChecked(); } if (properties & FilterTabs::HasSearchIn) { s.searchIn = searchIn->urlList(); if (s.searchIn.isEmpty()) { // we need a place to search in KMessageBox::error(this , i18n("Please specify a location to search in.")); searchIn->lineEdit()->setFocus(); return false; } } if (properties & FilterTabs::HasDontSearchIn) { s.dontSearchIn = dontSearchIn->urlList(); if (properties & FilterTabs::HasRecurseOptions) { if (useExcludeFolderNames->isChecked()) { s.excludeFolderNames = KShell::splitArgs(excludeFolderNames->currentText()); } else { s.excludeFolderNames = QStringList(); } } } return true; } void GeneralFilter::applySettings(const FilterSettings &s) { searchFor->setEditText(s.searchFor); searchForCase->setChecked(s.searchForCase); setComboBoxValue(ofType, s.mimeType); containsText->setEditText(s.containsText); containsTextCase->setChecked(s.containsTextCase); containsWholeWord->setChecked(s.containsWholeWord); containsRegExp->setChecked(s.containsRegExp); setComboBoxValue(contentEncoding, KCharsets::charsets()->descriptionForEncoding(s.contentEncoding)); if (properties & FilterTabs::HasRecurseOptions) { searchInDirs->setChecked(s.recursive); searchInArchives->setChecked(s.searchInArchives); followLinks->setChecked(s.followLinks); } if (properties & FilterTabs::HasSearchIn) { searchIn->lineEdit()->clear(); searchIn->listBox()->clear(); searchIn->listBox()->addItems(KrServices::toStringList(s.searchIn)); } if (properties & FilterTabs::HasDontSearchIn) { dontSearchIn->lineEdit()->clear(); dontSearchIn->listBox()->clear(); dontSearchIn->listBox()->addItems(KrServices::toStringList(s.dontSearchIn)); } } diff --git a/krusader/GUI/dirhistorybutton.cpp b/krusader/GUI/dirhistorybutton.cpp index 1e40815a..38d0d94b 100644 --- a/krusader/GUI/dirhistorybutton.cpp +++ b/krusader/GUI/dirhistorybutton.cpp @@ -1,95 +1,96 @@ /***************************************************************************** * Copyright (C) 2004 Shie Erlich * * Copyright (C) 2004 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 "dirhistorybutton.h" +#include "../icon.h" #include "../Panel/dirhistoryqueue.h" #include "../FileSystem/filesystem.h" // QtCore #include #include // QtGui #include // QtWidgets #include #include DirHistoryButton::DirHistoryButton(DirHistoryQueue* hQ, QWidget *parent) : QToolButton(parent) { setAutoRaise(true); - setIcon(QIcon::fromTheme("chronometer")); + setIcon(Icon("chronometer")); setText(i18n("Open the folder history list")); setToolTip(i18n("Open the folder history list")); setPopupMode(QToolButton::InstantPopup); setAcceptDrops(false); popupMenu = new QMenu(this); Q_CHECK_PTR(popupMenu); setMenu(popupMenu); historyQueue = hQ; connect(popupMenu, SIGNAL(aboutToShow()), this, SLOT(slotAboutToShow())); connect(popupMenu, SIGNAL(triggered(QAction*)), this, SLOT(slotPopupActivated(QAction*))); } DirHistoryButton::~DirHistoryButton() {} void DirHistoryButton::showMenu() { QMenu * pP = menu(); if (pP) { menu() ->exec(mapToGlobal(QPoint(0, height()))); } } /** No descriptions */ void DirHistoryButton::slotPopup() { // qDebug() << "History slot"; } /** No descriptions */ void DirHistoryButton::slotAboutToShow() { emit aboutToShow(); // qDebug() << "about to show"; popupMenu->clear(); for (int i = 0; i < historyQueue->count(); i++) { QAction *act = popupMenu->addAction(historyQueue->get(i).toDisplayString()); act->setData(QVariant(i)); if(historyQueue->currentPos() == i) { act->setCheckable(true); act->setChecked(true); } } } /** No descriptions */ void DirHistoryButton::slotPopupActivated(QAction * action) { if (action && action->data().canConvert()) { int id = action->data().toInt(); emit gotoPos(id); } } diff --git a/krusader/GUI/kcmdline.cpp b/krusader/GUI/kcmdline.cpp index add559b6..09d6040c 100644 --- a/krusader/GUI/kcmdline.cpp +++ b/krusader/GUI/kcmdline.cpp @@ -1,316 +1,315 @@ /***************************************************************************** * Copyright (C) 2000 Shie Erlich * * 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 "kcmdline.h" // QtCore #include #include #include // QtGui #include #include #include #include #include // QtWidgets #include #include #include #include #include #include -#include #include "../krglobal.h" -#include "../kicons.h" +#include "../icon.h" #include "../krslots.h" #include "../defaults.h" #include "../krusaderview.h" #include "../krservices.h" #include "../ActionMan/addplaceholderpopup.h" #include "kcmdmodebutton.h" CmdLineCombo::CmdLineCombo(QWidget *parent) : KHistoryComboBox(parent), _handlingLineEditResize(false) { lineEdit()->installEventFilter(this); _pathLabel = new QLabel(this); _pathLabel->setWhatsThis(i18n("Name of folder where command will be processed.")); _pathLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); } bool CmdLineCombo::eventFilter(QObject *watched, QEvent *e) { if(watched == lineEdit() && (e->type() == QEvent::Move || e->type() == QEvent::Resize)) { if(!_handlingLineEditResize) { // avoid infinite recursion _handlingLineEditResize = true; updateLineEditGeometry(); _handlingLineEditResize = false; } } return false; } void CmdLineCombo::setPath(QString path) { _path = path; doLayout(); } void CmdLineCombo::updateLineEditGeometry() { QRect r = lineEdit()->geometry(); r.setLeft(_pathLabel->geometry().right()); lineEdit()->setGeometry(r); } void CmdLineCombo::doLayout() { QString pathNameLabel = _path; QFontMetrics fm(_pathLabel->fontMetrics()); int textWidth = fm.width(_path); int maxWidth = (width() + _pathLabel->width()) * 2 / 5; int letters = _path.length() / 2; while (letters && textWidth > maxWidth) { pathNameLabel = _path.left(letters) + "..." + _path.right(letters); letters--; textWidth = fm.width(pathNameLabel); } _pathLabel->setText(pathNameLabel + "> "); _pathLabel->adjustSize(); QStyleOptionComboBox opt; initStyleOption(&opt); QRect labelRect = style()->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxEditField, this); labelRect.adjust(2, 0, 0, 0); labelRect.setWidth(_pathLabel->width()); _pathLabel->setGeometry(labelRect); updateLineEditGeometry(); } void CmdLineCombo::resizeEvent(QResizeEvent *e) { KHistoryComboBox::resizeEvent(e); doLayout(); } void CmdLineCombo::keyPressEvent(QKeyEvent *e) { switch (e->key()) { case Qt::Key_Enter: case Qt::Key_Return: if (e->modifiers() & Qt::ControlModifier) { SLOTS->insertFileName((e->modifiers()&Qt::ShiftModifier)!=0); break; } KHistoryComboBox::keyPressEvent(e); break; case Qt::Key_Down: if (e->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { MAIN_VIEW->focusTerminalEmulator(); return; } else KHistoryComboBox::keyPressEvent(e); break; case Qt::Key_Up: if (e->modifiers() == Qt::ControlModifier || e->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { emit returnToPanel(); return; } else KHistoryComboBox::keyPressEvent(e); break; case Qt::Key_Escape: if (e->modifiers() == 0) { emit returnToPanel(); return; } else KHistoryComboBox::keyPressEvent(e); break; default: KHistoryComboBox::keyPressEvent(e); } } KCMDLine::KCMDLine(QWidget *parent) : QWidget(parent) { QGridLayout * layout = new QGridLayout(this); layout->setSpacing(0); layout->setContentsMargins(0, 0, 0, 0); int height = QFontMetrics(QFontDatabase::systemFont(QFontDatabase::GeneralFont)).height(); height = height + 5 * (height > 14) + 6; // and editable command line completion.setMode(KUrlCompletion::FileCompletion); cmdLine = new CmdLineCombo(this); cmdLine->setMaxCount(100); // remember 100 commands cmdLine->setMinimumContentsLength(10); cmdLine->setDuplicatesEnabled(false); cmdLine->setMaximumHeight(height); cmdLine->setCompletionObject(&completion); cmdLine->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed)); // load the history KConfigGroup grpSvr(krConfig, "Private"); QStringList list = grpSvr.readEntry("cmdline history", QStringList()); cmdLine->setHistoryItems(list); connect(cmdLine, SIGNAL(returnPressed(QString)), this, SLOT(slotRun())); connect(cmdLine, SIGNAL(returnPressed(QString)), cmdLine->lineEdit(), SLOT(clear())); connect(cmdLine, SIGNAL(returnToPanel()), this, SLOT(slotReturnFocus())); cmdLine->setWhatsThis(i18n("

Well, it is actually quite simple: you type your command here and Krusader obeys.

Tip: move within command line history with <Up> and <Down> arrows.

")); layout->addWidget(cmdLine, 0, 1); buttonAddPlaceholder = new QToolButton(this); buttonAddPlaceholder->setAutoRaise(true); - buttonAddPlaceholder->setIcon(SmallIcon("list-add")); + buttonAddPlaceholder->setIcon(Icon("list-add")); connect(buttonAddPlaceholder, SIGNAL(clicked()), this, SLOT(addPlaceholder())); buttonAddPlaceholder->setWhatsThis(i18n("Add Placeholders for the selected files in the panel.")); layout->addWidget(buttonAddPlaceholder, 0, 2); // a run in terminal button terminal = new KCMDModeButton(this); terminal->setAutoRaise(true); layout->addWidget(terminal, 0, 3); layout->activate(); } KCMDLine::~KCMDLine() { KConfigGroup grpSvr(krConfig, "Private"); QStringList list = cmdLine->historyItems(); //qWarning() << list[0]; grpSvr.writeEntry("cmdline history", list); krConfig->sync(); } void KCMDLine::addPlaceholder() { AddPlaceholderPopup popup(this); QString exp = popup.getPlaceholder( buttonAddPlaceholder->mapToGlobal(QPoint(0, 0)) ); this->addText(exp); } void KCMDLine::setCurrent(const QString &path) { cmdLine->setPath(path); completion.setDir(QUrl::fromLocalFile(path)); // make sure our command is executed in the right directory // This line is important for Krusader overall functions -> do not remove ! QDir::setCurrent(path); } void KCMDLine::slotRun() { const QString command1(cmdLine->currentText()); if (command1.isEmpty()) return; cmdLine->addToHistory(command1); // bugfix by aardvark: current editline is destroyed by addToHistory() in some cases cmdLine->setEditText(command1); if (command1.simplified().left(3) == "cd ") { // cd command effect the active panel QString dir = command1.right(command1.length() - command1.indexOf(" ")).trimmed(); if (dir == "~") dir = QDir::homePath(); else if (dir.left(1) != "/" && !dir.contains(":/")) dir = cmdLine->path() + (cmdLine->path() == "/" ? "" : "/") + dir; SLOTS->refresh(QUrl::fromUserInput(dir,QDir::currentPath(),QUrl::AssumeLocalFile)); } else { exec(); cmdLine->clearEditText(); } } void KCMDLine::slotReturnFocus() { MAIN_VIEW->cmdLineUnFocus(); } static const KrActionBase::ExecType execModesMenu[] = { KrActionBase::Normal, KrActionBase::CollectOutputSeparateStderr, KrActionBase::CollectOutput, KrActionBase::Terminal, KrActionBase::RunInTE, }; QString KCMDLine::command() const { return cmdLine->currentText(); } KrActionBase::ExecType KCMDLine::execType() const { KConfigGroup grp(krConfig, "Private"); int i = grp.readEntry("Command Execution Mode", (int)0); return execModesMenu[i]; } QString KCMDLine::startpath() const { return cmdLine->path(); // return path->text().left(path->text().length() - 1); } QString KCMDLine::user() const { return QString(); } QString KCMDLine::text() const { return cmdLine->currentText(); } bool KCMDLine::acceptURLs() const { return false; } bool KCMDLine::confirmExecution() const { return false; } bool KCMDLine::doSubstitution() const { return true; } void KCMDLine::setText(QString text) { cmdLine->lineEdit()->setText(text); } diff --git a/krusader/GUI/kcmdmodebutton.cpp b/krusader/GUI/kcmdmodebutton.cpp index 25a45c27..32d12b33 100644 --- a/krusader/GUI/kcmdmodebutton.cpp +++ b/krusader/GUI/kcmdmodebutton.cpp @@ -1,74 +1,74 @@ /***************************************************************************** * Copyright (C) 2006 Václav Juza * * Copyright (C) 2006-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 "kcmdmodebutton.h" #include "../kractions.h" +#include "../icon.h" // QtWidgets #include #include -#include #include /** * KCMDModeButton class, which represents a button with popup menu to switch * the mode of the krusader built-in command-line */ KCMDModeButton::KCMDModeButton(QWidget *parent) : QToolButton(parent) { /* // from the old terminal-button: setText( i18n( "If pressed, Krusader executes command line in a terminal." ) ); setToolTip( i18n( "If pressed, Krusader executes command line in a terminal." ) ); QWhatsThis::add( terminal, i18n( "The 'run in terminal' button allows Krusader " "to run console (or otherwise non-graphical) " "programs in a terminal of your choice. If it's " "pressed, terminal mode is active." ) ); */ - setIcon(SmallIcon("utilities-terminal")); + setIcon(Icon("utilities-terminal")); adjustSize(); action = new KActionMenu(i18n("Execution mode"), this); Q_CHECK_PTR(action); for (int i = 0; KrActions::execTypeArray[i] != 0; i++) { action->addAction(*KrActions::execTypeArray[i]); } QMenu *pP = action->menu(); Q_CHECK_PTR(pP); setMenu(pP); setPopupMode(QToolButton::InstantPopup); setAcceptDrops(false); } KCMDModeButton::~KCMDModeButton() { delete action; } /** called when clicked to the button */ void KCMDModeButton::showMenu() { QMenu * pP = menu(); if (pP) { menu() ->exec(mapToGlobal(QPoint(0, 0))); } } diff --git a/krusader/GUI/krremoteencodingmenu.cpp b/krusader/GUI/krremoteencodingmenu.cpp index 2eca4c76..d7910c94 100644 --- a/krusader/GUI/krremoteencodingmenu.cpp +++ b/krusader/GUI/krremoteencodingmenu.cpp @@ -1,226 +1,226 @@ /***************************************************************************** * Copyright (C) 2005 Csaba Karai * * Copyright (C) 2005-2018 Krusader Krew [https://krusader.org] * * * * Based on KRemoteEncodingPlugin from Dawit Alemayehu * * * * 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 "krremoteencodingmenu.h" // QtCore #include // QtWidgets #include #include #include #include #include #include #include #include #include "../krglobal.h" +#include "../icon.h" #include "../Panel/krpanel.h" #include "../Panel/panelfunc.h" -#include "../kicons.h" #define DATA_KEY QString::fromLatin1("Charset") -KrRemoteEncodingMenu::KrRemoteEncodingMenu(const QString &text, const QString &icon, KActionCollection *parent) : - KActionMenu(QIcon::fromTheme(icon), text, parent), settingsLoaded(false) +KrRemoteEncodingMenu::KrRemoteEncodingMenu(const QString &text, const QString &iconName, KActionCollection *parent) : + KActionMenu(Icon(iconName), text, parent), settingsLoaded(false) { connect(menu(), SIGNAL(aboutToShow()), this, SLOT(slotAboutToShow())); parent->addAction("changeremoteencoding", this); } void KrRemoteEncodingMenu::slotAboutToShow() { if (!settingsLoaded) loadSettings(); // uncheck everything QList acts = menu()->actions(); foreach(QAction *act, acts) act->setChecked(false); QString charset = currentCharacterSet(); if (!charset.isEmpty()) { int id = 1; QStringList::Iterator it; for (it = encodingNames.begin(); it != encodingNames.end(); ++it, ++id) if ((*it).indexOf(charset) != -1) break; bool found = false; foreach(QAction *act, acts) { if (act->data().canConvert ()) { int idr = act->data().toInt(); if (idr == id) { act->setChecked(found = true); break; } } } if (!found) qWarning() << Q_FUNC_INFO << "could not find entry for charset=" << charset; } else { foreach(QAction *act, acts) { if (act->data().canConvert ()) { int idr = act->data().toInt(); if (idr == -2) { act->setChecked(true); break; } } } } } QString KrRemoteEncodingMenu::currentCharacterSet() { QUrl currentURL = ACTIVE_PANEL->virtualPath(); return KProtocolManager::charsetFor(currentURL); } void KrRemoteEncodingMenu::loadSettings() { settingsLoaded = true; encodingNames = KCharsets::charsets()->descriptiveEncodingNames(); QMenu *qmenu = menu(); disconnect(qmenu, SIGNAL(triggered(QAction*)), this, SLOT(slotTriggered(QAction*))); connect(qmenu, SIGNAL(triggered(QAction*)), this, SLOT(slotTriggered(QAction*))); qmenu->clear(); QStringList::ConstIterator it; int count = 0; QAction *act; for (it = encodingNames.constBegin(); it != encodingNames.constEnd(); ++it) { act = qmenu->addAction(*it); act->setData(QVariant(++count)); act->setCheckable(true); } qmenu->addSeparator(); act = qmenu->addAction(i18n("Reload")); act->setCheckable(true); act->setData(QVariant(-1)); act = qmenu->addAction(i18nc("Default encoding", "Default")); act->setCheckable(true); act->setData(QVariant(-2)); } void KrRemoteEncodingMenu::slotTriggered(QAction * act) { if (!act || !act->data().canConvert ()) return; int id = act->data().toInt(); switch (id) { case -1: slotReload(); return; case -2: chooseDefault(); return; default: chooseEncoding(encodingNames[id - 1]); } } void KrRemoteEncodingMenu::chooseEncoding(QString encoding) { QUrl currentURL = ACTIVE_PANEL->virtualPath(); KConfig config(("kio_" + currentURL.scheme() + "rc").toLatin1()); QString host = currentURL.host(); QString charset = KCharsets::charsets()->encodingForName(encoding); KConfigGroup group(&config, host); group.writeEntry(DATA_KEY, charset); config.sync(); // Update the io-slaves... updateKIOSlaves(); } void KrRemoteEncodingMenu::slotReload() { loadSettings(); } void KrRemoteEncodingMenu::chooseDefault() { QUrl currentURL = ACTIVE_PANEL->virtualPath(); // We have no choice but delete all higher domain level // settings here since it affects what will be matched. KConfig config(("kio_" + currentURL.scheme() + "rc").toLatin1()); QStringList partList = currentURL.host().split('.', QString::SkipEmptyParts); if (!partList.isEmpty()) { partList.erase(partList.begin()); QStringList domains; // Remove the exact name match... domains << currentURL.host(); while (partList.count()) { if (partList.count() == 2) if (partList[0].length() <= 2 && partList[1].length() == 2) break; if (partList.count() == 1) break; domains << partList.join("."); partList.erase(partList.begin()); } for (QStringList::Iterator it = domains.begin(); it != domains.end(); ++it) { //qDebug() << "Domain to remove: " << *it; if (config.hasGroup(*it)) config.deleteGroup(*it); else if (config.group("").hasKey(*it)) config.group("").deleteEntry(*it); //don't know what group name is supposed to be XXX } } config.sync(); updateKIOSlaves(); } void KrRemoteEncodingMenu::updateKIOSlaves() { KIO::Scheduler::emitReparseSlaveConfiguration(); // Reload the page with the new charset QTimer::singleShot(500, ACTIVE_FUNC, SLOT(refresh())); } diff --git a/krusader/GUI/krremoteencodingmenu.h b/krusader/GUI/krremoteencodingmenu.h index 28542e4d..b6d8629b 100644 --- a/krusader/GUI/krremoteencodingmenu.h +++ b/krusader/GUI/krremoteencodingmenu.h @@ -1,63 +1,63 @@ /***************************************************************************** * Copyright (C) 2005 Csaba Karai * * Copyright (C) 2005-2018 Krusader Krew [https://krusader.org] * * * * Based on KRemoteEncodingPlugin from Dawit Alemayehu * * * * 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 KRREMOTEENCODINGMENU_H #define KRREMOTEENCODINGMENU_H // QtCore #include // QtWidgets #include # include class KActionCollection; class KrRemoteEncodingMenu: public KActionMenu { Q_OBJECT public: - KrRemoteEncodingMenu(const QString &text, const QString &icon, KActionCollection *parent = 0); + KrRemoteEncodingMenu(const QString &text, const QString &iconName, KActionCollection *parent = 0); protected slots: void slotAboutToShow(); void slotReload(); void slotTriggered(QAction *); virtual void chooseDefault(); virtual void chooseEncoding(QString encoding); protected: virtual QString currentCharacterSet(); private: void loadSettings(); void updateKIOSlaves(); QStringList encodingNames; bool settingsLoaded; }; #endif /* REMOTEENCODING_MENU_H */ diff --git a/krusader/GUI/mediabutton.cpp b/krusader/GUI/mediabutton.cpp index bbc5d1d6..516f827f 100644 --- a/krusader/GUI/mediabutton.cpp +++ b/krusader/GUI/mediabutton.cpp @@ -1,633 +1,633 @@ /***************************************************************************** * Copyright (C) 2006 Csaba Karai * * Copyright (C) 2006-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 "mediabutton.h" #include "../krglobal.h" +#include "../icon.h" #include "../MountMan/kmountman.h" // QtCore #include // QtGui #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include QString MediaButton::remotePrefix = QLatin1String("remote:"); MediaButton::MediaButton(QWidget *parent) : QToolButton(parent), popupMenu(0), rightMenu(0), openInNewTab(false) { setAutoRaise(true); - setIcon(QIcon::fromTheme("system-file-manager")); + setIcon(Icon("system-file-manager")); setText(i18n("Open the available media list")); setToolTip(i18n("Open the available media list")); setPopupMode(QToolButton::InstantPopup); setAcceptDrops(false); popupMenu = new QMenu(this); popupMenu->installEventFilter(this); Q_CHECK_PTR(popupMenu); setMenu(popupMenu); connect(popupMenu, SIGNAL(aboutToShow()), this, SLOT(slotAboutToShow())); connect(popupMenu, SIGNAL(aboutToHide()), this, SLOT(slotAboutToHide())); connect(popupMenu, SIGNAL(triggered(QAction*)), this, SLOT(slotPopupActivated(QAction*))); Solid::DeviceNotifier *notifier = Solid::DeviceNotifier::instance(); connect(notifier, SIGNAL(deviceAdded(QString)), this, SLOT(slotDeviceAdded(QString))); connect(notifier, SIGNAL(deviceRemoved(QString)), this, SLOT(slotDeviceRemoved(QString))); connect(&mountCheckerTimer, SIGNAL(timeout()), this, SLOT(slotCheckMounts())); } MediaButton::~MediaButton() { } void MediaButton::updateIcon(const QString &mountPoint) { if(!mountPoint.isEmpty() && mountPoint == currentMountPoint) return; currentMountPoint = mountPoint; - QString icon("system-file-manager"); + QString iconName("system-file-manager"); QStringList overlays; if(!mountPoint.isEmpty()) { Solid::Device device(krMtMan.findUdiForPath(mountPoint, Solid::DeviceInterface::StorageAccess));; Solid::StorageVolume *vol = device.as (); if(device.isValid()) - icon = device.icon(); + iconName = device.icon(); if (vol && vol->usage() == Solid::StorageVolume::Encrypted) overlays << "security-high"; } - setIcon(KDE::icon(icon, overlays)); + setIcon(Icon(iconName, overlays)); } void MediaButton::slotAboutToShow() { emit aboutToShow(); popupMenu->clear(); udiNameMap.clear(); createMediaList(); } void MediaButton::slotAboutToHide() { if (rightMenu) rightMenu->close(); mountCheckerTimer.stop(); } void MediaButton::createMediaList() { // devices detected by solid storageDevices = Solid::Device::listFromType(Solid::DeviceInterface::StorageAccess); for (int p = storageDevices.count() - 1 ; p >= 0; p--) { Solid::Device device = storageDevices[ p ]; QString udi = device.udi(); QString name; QIcon kdeIcon; if (!getNameAndIcon(device, name, kdeIcon)) continue; QAction * act = popupMenu->addAction(kdeIcon, name); act->setData(QVariant(udi)); udiNameMap[ udi ] = name; connect(device.as(), SIGNAL(accessibilityChanged(bool,QString)), this, SLOT(slotAccessibilityChanged(bool,QString))); } KMountPoint::List possibleMountList = KMountPoint::possibleMountPoints(); KMountPoint::List currentMountList = KMountPoint::currentMountPoints(); for (KMountPoint::List::iterator it = possibleMountList.begin(); it != possibleMountList.end(); ++it) { if (krMtMan.networkFilesystem((*it)->mountType())) { QString path = (*it)->mountPoint(); bool mounted = false; for (KMountPoint::List::iterator it2 = currentMountList.begin(); it2 != currentMountList.end(); ++it2) { if (krMtMan.networkFilesystem((*it2)->mountType()) && (*it)->mountPoint() == (*it2)->mountPoint()) { mounted = true; break; } } QString name = i18nc("%1 is the mount point of the remote share", "Remote Share [%1]", (*it)->mountPoint()); QStringList overlays; if (mounted) overlays << "emblem-mounted"; - QAction * act = popupMenu->addAction(KDE::icon("network-wired", overlays), name); + QAction * act = popupMenu->addAction(Icon("network-wired", overlays), name); QString udi = remotePrefix + (*it)->mountPoint(); act->setData(QVariant(udi)); } } mountCheckerTimer.setSingleShot(true); mountCheckerTimer.start(1000); } bool MediaButton::getNameAndIcon(Solid::Device & device, QString &name, QIcon &iconOut) { Solid::StorageAccess *access = device.as(); if (access == 0) return false; QString udi = device.udi(); QString label = i18nc("Unknown label", "Unknown"); bool mounted = access->isAccessible(); QString path = access->filePath(); QString type = i18nc("Unknown media type", "Unknown"); - QString icon = device.icon(); + QString iconName = device.icon(); QString fstype; QString size; Solid::StorageVolume * vol = device.as (); if (vol) { label = vol->label(); fstype = vol->fsType(); size = KIO::convertSize(vol->size()); } bool printSize = false; - if (icon == "media-floppy") + if (iconName == "media-floppy") type = i18n("Floppy"); - else if (icon == "drive-optical") + else if (iconName == "drive-optical") type = i18n("CD/DVD-ROM"); - else if (icon == "drive-removable-media-usb-pendrive") + else if (iconName == "drive-removable-media-usb-pendrive") type = i18n("USB pen drive"), printSize = true; - else if (icon == "drive-removable-media-usb") + else if (iconName == "drive-removable-media-usb") type = i18n("USB device"), printSize = true; - else if (icon == "drive-removable-media") + else if (iconName == "drive-removable-media") type = i18n("Removable media"), printSize = true; - else if (icon == "drive-harddisk") + else if (iconName == "drive-harddisk") type = i18n("Hard Disk"), printSize = true; - else if (icon == "camera-photo") + else if (iconName == "camera-photo") type = i18n("Camera"); - else if (icon == "media-optical-video") + else if (iconName == "media-optical-video") type = i18n("Video CD/DVD-ROM"); - else if (icon == "media-optical-audio") + else if (iconName == "media-optical-audio") type = i18n("Audio CD/DVD-ROM"); - else if (icon == "media-optical") + else if (iconName == "media-optical") type = i18n("Recordable CD/DVD-ROM"); KConfigGroup cfg(KSharedConfig::openConfig(), QStringLiteral("MediaMenu")); if (printSize) { QString showSizeSetting = cfg.readEntry("ShowSize", "Always"); if (showSizeSetting == "WhenNoLabel") printSize = label.isEmpty(); else if (showSizeSetting == "Never") printSize = false; } if (printSize && !size.isEmpty()) name += size + ' '; if (!label.isEmpty()) name += label + ' '; else name += type + ' '; if (!fstype.isEmpty() && cfg.readEntry("ShowFSType", true)) name += '(' + fstype + ") "; if (!path.isEmpty() && cfg.readEntry("ShowPath", true)) name += '[' + path + "] "; name = name.trimmed(); QStringList overlays; if (mounted) { overlays << "emblem-mounted"; } else { overlays << QString(); // We have to guarantee the placement of the next emblem } if (vol && vol->usage() == Solid::StorageVolume::Encrypted) { overlays << "security-high"; } - iconOut = KDE::icon(icon, overlays); + iconOut = Icon(iconName, overlays); return true; } void MediaButton::slotPopupActivated(QAction *action) { if (action && action->data().canConvert()) { QString udi = action->data().toString(); if (!udi.isEmpty()) { bool mounted = false; QString mountPoint; getStatus(udi, mounted, &mountPoint); if (mounted) emit openUrl(QUrl::fromLocalFile(mountPoint)); else mount(udi, true); } } } void MediaButton::showMenu() { QMenu * pP = menu(); if (pP) { menu() ->exec(mapToGlobal(QPoint(0, height()))); } } bool MediaButton::eventFilter(QObject *o, QEvent *e) { if (o == popupMenu) { if (e->type() == QEvent::ContextMenu) { QAction *act = popupMenu->activeAction(); if (act && act->data().canConvert()) { QString id = act->data().toString(); if (!id.isEmpty()) { QPoint globalPos = popupMenu->mapToGlobal(popupMenu->actionGeometry(act).topRight()); rightClickMenu(id, globalPos); return true; } } } else if (e->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast(e); if (ke->key() == Qt::Key_Return && ke->modifiers() == Qt::ControlModifier) { if (QAction *act = popupMenu->activeAction()) { QString id = act->data().toString(); if (!id.isEmpty()) { toggleMount(id); return true; } } } } else if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonRelease) { QMouseEvent *m = static_cast(e); if (m->button() == Qt::RightButton) { if (e->type() == QEvent::MouseButtonPress) { QAction * act = popupMenu->actionAt(m->pos()); if (act && act->data().canConvert()) { QString id = act->data().toString(); if (!id.isEmpty()) rightClickMenu(id, m->globalPos()); } } m->accept(); return true; } } } return false; } void MediaButton::rightClickMenu(QString udi, QPoint pos) { if (rightMenu) rightMenu->close(); bool ejectable = false; bool mounted = false; QString mountPoint; getStatus(udi, mounted, &mountPoint, &ejectable); QUrl openURL = QUrl::fromLocalFile(mountPoint); QMenu * myMenu = rightMenu = new QMenu(popupMenu); QAction * actOpen = myMenu->addAction(i18n("Open")); actOpen->setData(QVariant(1)); QAction * actOpenNewTab = myMenu->addAction(i18n("Open in a new tab")); actOpenNewTab->setData(QVariant(2)); myMenu->addSeparator(); if (!mounted) { QAction * actMount = myMenu->addAction(i18n("Mount")); actMount->setData(QVariant(3)); } else { QAction * actUnmount = myMenu->addAction(i18n("Unmount")); actUnmount->setData(QVariant(4)); } if (ejectable) { QAction * actEject = myMenu->addAction(i18n("Eject")); actEject->setData(QVariant(5)); } QAction *act = myMenu->exec(pos); int result = -1; if (act != 0 && act->data().canConvert()) result = act->data().toInt(); delete myMenu; if (rightMenu == myMenu) rightMenu = 0; else return; switch (result) { case 1: case 2: popupMenu->close(); if (mounted) { if (result == 1) emit openUrl(openURL); else emit newTab(openURL); } else { mount(udi, true, result == 2); // mount first, when mounted open the tab } break; case 3: mount(udi); break; case 4: umount(udi); break; case 5: eject(udi); break; default: break; } } void MediaButton::toggleMount(QString udi) { bool mounted = false; getStatus(udi, mounted); if (mounted) umount(udi); else mount(udi); } void MediaButton::getStatus(QString udi, bool &mounted, QString *mountPointOut, bool *ejectableOut) { mounted = false; bool network = udi.startsWith(remotePrefix); bool ejectable = false; QString mountPoint; if (network) { mountPoint = udi.mid(remotePrefix.length()); KMountPoint::List currentMountList = KMountPoint::currentMountPoints(); for (KMountPoint::List::iterator it = currentMountList.begin(); it != currentMountList.end(); ++it) { if (krMtMan.networkFilesystem((*it)->mountType()) && (*it)->mountPoint() == mountPoint) { mounted = true; break; } } } else { Solid::Device device(udi); Solid::StorageAccess *access = device.as(); Solid::OpticalDisc *optdisc = device.as(); if (access) mountPoint = access->filePath(); if (access && access->isAccessible()) mounted = true; if (optdisc) ejectable = true; } if (mountPointOut) *mountPointOut = mountPoint; if (ejectableOut) *ejectableOut = ejectable; } void MediaButton::mount(QString udi, bool open, bool newtab) { if (udi.startsWith(remotePrefix)) { QString mp = udi.mid(remotePrefix.length()); krMtMan.mount(mp, true); if (newtab) emit newTab(QUrl::fromLocalFile(mp)); else emit openUrl(QUrl::fromLocalFile(mp)); return; } Solid::Device device(udi); Solid::StorageAccess *access = device.as(); if (access && !access->isAccessible()) { if (open) udiToOpen = device.udi(), openInNewTab = newtab; connect(access, SIGNAL(setupDone(Solid::ErrorType,QVariant,QString)), this, SLOT(slotSetupDone(Solid::ErrorType,QVariant,QString))); access->setup(); } } void MediaButton::slotSetupDone(Solid::ErrorType error, QVariant errorData, const QString &udi) { if (error == Solid::NoError) { if (udi == udiToOpen) { Solid::StorageAccess *access = Solid::Device(udi).as(); if (access && access->isAccessible()) { if (openInNewTab) emit newTab(QUrl::fromLocalFile(access->filePath())); else emit openUrl(QUrl::fromLocalFile(access->filePath())); } udiToOpen = QString(), openInNewTab = false; } } else { if (udi == udiToOpen) udiToOpen = QString(), openInNewTab = false; QString name; if (udiNameMap.contains(udi)) name = udiNameMap[ udi ]; if (errorData.isValid()) { KMessageBox::sorry(this, i18n("An error occurred while accessing '%1', the system responded: %2", name, errorData.toString())); } else { KMessageBox::sorry(this, i18n("An error occurred while accessing '%1'", name)); } } } void MediaButton::umount(QString udi) { if (udi.startsWith(remotePrefix)) { krMtMan.unmount(udi.mid(remotePrefix.length()), false); return; } krMtMan.unmount(krMtMan.pathForUdi(udi), false); } void MediaButton::eject(QString udi) { krMtMan.eject(krMtMan.pathForUdi(udi)); } void MediaButton::slotAccessibilityChanged(bool /*accessible*/, const QString & udi) { QList actionList = popupMenu->actions(); foreach(QAction * act, actionList) { if (act && act->data().canConvert() && act->data().toString() == udi) { Solid::Device device(udi); QString name; QIcon kdeIcon; if (getNameAndIcon(device, name, kdeIcon)) { act->setText(name); act->setIcon(kdeIcon); } break; } } } void MediaButton::slotDeviceAdded(const QString& udi) { if (popupMenu->isHidden()) return; Solid::Device device(udi); Solid::StorageAccess *access = device.as(); if (access == 0) return; QString name; QIcon kdeIcon; if (!getNameAndIcon(device, name, kdeIcon)) return; QAction * act = popupMenu->addAction(kdeIcon, name); act->setData(QVariant(udi)); udiNameMap[ udi ] = name; connect(device.as(), SIGNAL(accessibilityChanged(bool,QString)), this, SLOT(slotAccessibilityChanged(bool,QString))); } void MediaButton::slotDeviceRemoved(const QString& udi) { if (popupMenu->isHidden()) return; QList actionList = popupMenu->actions(); foreach(QAction * act, actionList) { if (act && act->data().canConvert() && act->data().toString() == udi) { popupMenu->removeAction(act); delete act; break; } } } void MediaButton::slotCheckMounts() { if (isHidden()) return; KMountPoint::List possibleMountList = KMountPoint::possibleMountPoints(); KMountPoint::List currentMountList = KMountPoint::currentMountPoints(); QList actionList = popupMenu->actions(); foreach(QAction * act, actionList) { if (act && act->data().canConvert() && act->data().toString().startsWith(remotePrefix)) { QString mountPoint = act->data().toString().mid(remotePrefix.length()); bool available = false; for (KMountPoint::List::iterator it = possibleMountList.begin(); it != possibleMountList.end(); ++it) { if (krMtMan.networkFilesystem((*it)->mountType()) && (*it)->mountPoint() == mountPoint) { available = true; break; } } if (!available) { popupMenu->removeAction(act); delete act; } } } for (KMountPoint::List::iterator it = possibleMountList.begin(); it != possibleMountList.end(); ++it) { if (krMtMan.networkFilesystem((*it)->mountType())) { QString path = (*it)->mountPoint(); bool mounted = false; QString udi = remotePrefix + path; QAction * correspondingAct = 0; foreach(QAction * act, actionList) { if (act && act->data().canConvert() && act->data().toString() == udi) { correspondingAct = act; break; } } for (KMountPoint::List::iterator it2 = currentMountList.begin(); it2 != currentMountList.end(); ++it2) { if (krMtMan.networkFilesystem((*it2)->mountType()) && path == (*it2)->mountPoint()) { mounted = true; break; } } QString name = i18nc("%1 is the mount point of the remote share", "Remote Share [%1]", (*it)->mountPoint()); QStringList overlays; if (mounted) overlays << "emblem-mounted"; - QIcon kdeIcon = KDE::icon("network-wired", overlays); + QIcon kdeIcon = Icon("network-wired", overlays); if (!correspondingAct) { QAction * act = popupMenu->addAction(kdeIcon, name); act->setData(QVariant(udi)); } else { correspondingAct->setText(name); correspondingAct->setIcon(kdeIcon); } } } mountCheckerTimer.setSingleShot(true); mountCheckerTimer.start(1000); } diff --git a/krusader/GUI/profilemanager.cpp b/krusader/GUI/profilemanager.cpp index c0877069..db688d52 100644 --- a/krusader/GUI/profilemanager.cpp +++ b/krusader/GUI/profilemanager.cpp @@ -1,183 +1,184 @@ /***************************************************************************** * Copyright (C) 2004 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/]. * *****************************************************************************/ #include "profilemanager.h" // QtGui #include // QtWidgets #include #include #include #include #include "../krglobal.h" +#include "../icon.h" ProfileManager::ProfileManager(QString profileType, QWidget * parent) : QPushButton(parent) { setText(""); - setIcon(QIcon::fromTheme("user-identity")); + setIcon(Icon("user-identity")); setFixedWidth(16 + 15); setToolTip(i18n("Profiles")); this->profileType = profileType; connect(this, SIGNAL(clicked()), this, SLOT(profilePopup())); KConfigGroup group(krConfig, "Private"); profileList = group.readEntry(profileType, QStringList()); } void ProfileManager::profilePopup() { // profile menu identifiers #define ADD_NEW_ENTRY_ID 1000 #define LOAD_ENTRY_ID 2000 #define REMOVE_ENTRY_ID 3000 #define OVERWRITE_ENTRY_ID 4000 // create the menu QMenu popup, removePopup, overwritePopup; popup.setTitle(i18n("Profiles")); for (int i = 0; i != profileList.count() ; i++) { KConfigGroup group(krConfig, profileType + " - " + profileList[i]); QString name = group.readEntry("Name"); popup.addAction(name)->setData(QVariant((int)(LOAD_ENTRY_ID + i))); removePopup.addAction(name)->setData(QVariant((int)(REMOVE_ENTRY_ID + i))); overwritePopup.addAction(name)->setData(QVariant((int)(OVERWRITE_ENTRY_ID + i))); } popup.addSeparator(); if (profileList.count()) { popup.addMenu(&removePopup)->setText(i18n("Remove entry")); popup.addMenu(&overwritePopup)->setText(i18n("Overwrite entry")); } popup.addAction(i18n("Add new entry"))->setData(QVariant((int)(ADD_NEW_ENTRY_ID))); int result = 0; QAction * res = popup.exec(QCursor::pos()); if (res && res->data().canConvert()) result = res->data().toInt(); // check out the user's selection if (result == ADD_NEW_ENTRY_ID) newProfile(); else if (result >= LOAD_ENTRY_ID && result < LOAD_ENTRY_ID + profileList.count()) { emit loadFromProfile(profileType + " - " + profileList[ result - LOAD_ENTRY_ID ]); } else if (result >= REMOVE_ENTRY_ID && result < REMOVE_ENTRY_ID + profileList.count()) { krConfig->deleteGroup(profileType + " - " + profileList[ result - REMOVE_ENTRY_ID ]); profileList.removeAll(profileList[ result - REMOVE_ENTRY_ID ]); KConfigGroup group(krConfig, "Private"); group.writeEntry(profileType, profileList); krConfig->sync(); } else if (result >= OVERWRITE_ENTRY_ID && result < OVERWRITE_ENTRY_ID + profileList.count()) { emit saveToProfile(profileType + " - " + profileList[ result - OVERWRITE_ENTRY_ID ]); } } void ProfileManager::newProfile(QString defaultName) { QString profile = QInputDialog::getText(this, i18n("Krusader::ProfileManager"), i18n("Enter the profile name:"), QLineEdit::Normal, defaultName); if (!profile.isEmpty()) { int profileNum = 1; while (profileList.contains(QString("%1").arg(profileNum))) profileNum++; QString profileString = QString("%1").arg(profileNum); QString profileName = profileType + " - " + profileString; profileList.append(QString("%1").arg(profileString)); KConfigGroup group(krConfig, "Private"); group.writeEntry(profileType, profileList); KConfigGroup pg(krConfig, profileName); pg.writeEntry("Name", profile); emit saveToProfile(profileName); krConfig->sync(); } } void ProfileManager::deleteProfile(QString name) { for (int i = 0; i != profileList.count() ; i++) { KConfigGroup group(krConfig, profileType + " - " + profileList[ i ]); QString currentName = group.readEntry("Name"); if (name == currentName) { krConfig->deleteGroup(profileType + " - " + profileList[ i ]); profileList.removeAll(profileList[ i ]); KConfigGroup pg(krConfig, "Private"); pg.writeEntry(profileType, profileList); krConfig->sync(); return; } } } void ProfileManager::overwriteProfile(QString name) { for (int i = 0; i != profileList.count() ; i++) { KConfigGroup group(krConfig, profileType + " - " + profileList[ i ]); QString currentName = group.readEntry("Name"); if (name == currentName) { emit saveToProfile(profileType + " - " + profileList[ i ]); return; } } } bool ProfileManager::loadProfile(QString name) { for (int i = 0; i != profileList.count() ; i++) { KConfigGroup group(krConfig, profileType + " - " + profileList[i]); QString currentName = group.readEntry("Name"); if (name == currentName) { emit loadFromProfile(profileType + " - " + profileList[ i ]); return true; } } return false; } QStringList ProfileManager::availableProfiles(QString profileType) { KConfigGroup group(krConfig, "Private"); QStringList profiles = group.readEntry(profileType, QStringList()); QStringList profileNames; for (int i = 0; i != profiles.count() ; i++) { KConfigGroup pg(krConfig, profileType + " - " + profiles[ i ]); profileNames.append(pg.readEntry("Name")); } return profileNames; } diff --git a/krusader/JobMan/jobman.cpp b/krusader/JobMan/jobman.cpp index 43feef29..e041007a 100644 --- a/krusader/JobMan/jobman.cpp +++ b/krusader/JobMan/jobman.cpp @@ -1,458 +1,459 @@ /***************************************************************************** * Copyright (C) 2016-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 "jobman.h" // QtCore #include #include // QtWidgets #include #include #include #include #include #include #include #include #include #include "krjob.h" #include "../krglobal.h" +#include "../icon.h" const int MAX_OLD_MENU_ACTIONS = 10; /** The menu action entry for a job in the popup menu.*/ class JobMenuAction : public QWidgetAction { Q_OBJECT public: JobMenuAction(KrJob *krJob, QObject *parent, KJob *kJob = nullptr) : QWidgetAction(parent), m_krJob(krJob) { QWidget *container = new QWidget(); QGridLayout *layout = new QGridLayout(container); m_description = new QLabel(krJob->description()); m_progressBar = new QProgressBar(); layout->addWidget(m_description, 0, 0, 1, 3); layout->addWidget(m_progressBar, 1, 0); m_pauseResumeButton = new QPushButton(); updatePauseResumeButton(); connect(m_pauseResumeButton, &QPushButton::clicked, this, &JobMenuAction::slotPauseResumeButtonClicked); layout->addWidget(m_pauseResumeButton, 1, 1); m_cancelButton = new QPushButton(); - m_cancelButton->setIcon(QIcon::fromTheme("remove")); + m_cancelButton->setIcon(Icon("remove")); m_cancelButton->setToolTip(i18n("Cancel Job")); connect(m_cancelButton, &QPushButton::clicked, this, &JobMenuAction::slotCancelButtonClicked); layout->addWidget(m_cancelButton, 1, 2); setDefaultWidget(container); if (kJob) { slotStarted(kJob); } else { connect(krJob, &KrJob::started, this, &JobMenuAction::slotStarted); } connect(krJob, &KrJob::terminated, this, &JobMenuAction::slotTerminated); } bool isDone() { return !m_krJob; } protected slots: void slotDescription(KJob *, const QString &description, const QPair &field1, const QPair &field2) { const QPair textField = !field2.first.isEmpty() ? field2 : field1; QString text = description; if (!textField.first.isEmpty()) { text += QString(" - %1: %2").arg(textField.first, textField.second); } m_description->setText(text); if (!field2.first.isEmpty() && !field1.first.isEmpty()) { // NOTE: tooltips for QAction items in menu are not shown m_progressBar->setToolTip(QString("%1: %2").arg(field1.first, field1.second)); } } void slotPercent(KJob *, unsigned long percent) { m_progressBar->setValue(percent); } void updatePauseResumeButton() { - m_pauseResumeButton->setIcon(QIcon::fromTheme( + m_pauseResumeButton->setIcon(Icon( m_krJob->isRunning() ? "media-playback-pause" : m_krJob->isPaused() ? "media-playback-start" : "chronometer-start")); m_pauseResumeButton->setToolTip(m_krJob->isRunning() ? i18n("Pause Job") : m_krJob->isPaused() ? i18n("Resume Job") : i18n("Start Job")); } void slotResult(KJob *job) { // NOTE: m_job may already set to NULL now if(!job->error()) { // percent signal is not reliable, set manually m_progressBar->setValue(100); } } void slotTerminated() { qDebug() << "job description=" << m_krJob->description(); m_pauseResumeButton->setEnabled(false); - m_cancelButton->setIcon(QIcon::fromTheme("edit-clear")); + m_cancelButton->setIcon(Icon("edit-clear")); m_cancelButton->setToolTip(i18n("Clear")); m_krJob = nullptr; } void slotPauseResumeButtonClicked() { if (!m_krJob) return; if (m_krJob->isRunning()) m_krJob->pause(); else m_krJob->start(); } void slotCancelButtonClicked() { if (m_krJob) { m_krJob->cancel(); } else { deleteLater(); } } private slots: void slotStarted(KJob *job) { connect(job, &KJob::description, this, &JobMenuAction::slotDescription); connect(job, SIGNAL(percent(KJob *, ulong)), this, SLOT(slotPercent(KJob *, ulong))); connect(job, &KJob::suspended, this, &JobMenuAction::updatePauseResumeButton); connect(job, &KJob::resumed, this, &JobMenuAction::updatePauseResumeButton); connect(job, &KJob::result, this, &JobMenuAction::slotResult); connect(job, &KJob::warning, this, [](KJob *, const QString &plain, const QString &) { qWarning() << "unexpected job warning: " << plain; }); updatePauseResumeButton(); } private: KrJob *m_krJob; QLabel *m_description; QProgressBar *m_progressBar; QPushButton *m_pauseResumeButton; QPushButton *m_cancelButton; }; #include "jobman.moc" // required for class definitions with Q_OBJECT macro in implementation files const QString JobMan::sDefaultToolTip = i18n("No jobs"); JobMan::JobMan(QObject *parent) : QObject(parent), m_messageBox(0) { // job control action - m_controlAction = new KToolBarPopupAction(QIcon::fromTheme("media-playback-pause"), + m_controlAction = new KToolBarPopupAction(Icon("media-playback-pause"), i18n("Play/Pause &Job"), this); m_controlAction->setEnabled(false); connect(m_controlAction, &QAction::triggered, this, &JobMan::slotControlActionTriggered); QMenu *menu = new QMenu(krMainWindow); menu->setMinimumWidth(300); // make scrollable if menu is too long menu->setStyleSheet("QMenu { menu-scrollable: 1; }"); m_controlAction->setMenu(menu); // progress bar action m_progressBar = new QProgressBar(); m_progressBar->setToolTip(sDefaultToolTip); m_progressBar->setEnabled(false); // listen to clicks on progress bar m_progressBar->installEventFilter(this); QWidgetAction *progressAction = new QWidgetAction(krMainWindow); progressAction->setText(i18n("Job Progress Bar")); progressAction->setDefaultWidget(m_progressBar); m_progressAction = progressAction; // job queue mode action KConfigGroup cfg(krConfig, "JobManager"); m_queueMode = cfg.readEntry("Queue Mode", false); - m_modeAction = new QAction(QIcon::fromTheme("media-playlist-repeat"), i18n("Job Queue Mode"), + m_modeAction = new QAction(Icon("media-playlist-repeat"), i18n("Job Queue Mode"), krMainWindow); m_modeAction->setToolTip(i18n("Run only one job in parallel")); m_modeAction->setCheckable(true); m_modeAction->setChecked(m_queueMode); connect(m_modeAction, &QAction::toggled, this, [=](bool checked) mutable { m_queueMode = checked; cfg.writeEntry("Queue Mode", m_queueMode); }); // undo action KIO::FileUndoManager *undoManager = KIO::FileUndoManager::self(); undoManager->uiInterface()->setParentWidget(krMainWindow); - m_undoAction = new QAction(QIcon::fromTheme("edit-undo"), i18n("Undo Last Job"), krMainWindow); + m_undoAction = new QAction(Icon("edit-undo"), i18n("Undo Last Job"), krMainWindow); m_undoAction->setEnabled(false); connect(m_undoAction, &QAction::triggered, undoManager, &KIO::FileUndoManager::undo); connect(undoManager, static_cast(&KIO::FileUndoManager::undoAvailable), m_undoAction, &QAction::setEnabled); connect(undoManager, &KIO::FileUndoManager::undoTextChanged, this, &JobMan::slotUndoTextChange); } bool JobMan::waitForJobs(bool waitForUserInput) { if (m_jobs.isEmpty() && !waitForUserInput) return true; // attempt to get all job threads does not work //QList threads = krMainWindow->findChildren(); m_autoCloseMessageBox = !waitForUserInput; m_messageBox = new QMessageBox(krMainWindow); m_messageBox->setWindowTitle(i18n("Warning")); - m_messageBox->setIconPixmap(QIcon::fromTheme("dialog-warning") + m_messageBox->setIconPixmap(Icon("dialog-warning") .pixmap(QMessageBox::standardIcon(QMessageBox::Information).size())); m_messageBox->setText(i18n("Are you sure you want to quit?")); m_messageBox->addButton(QMessageBox::Abort); m_messageBox->addButton(QMessageBox::Cancel); m_messageBox->setDefaultButton(QMessageBox::Cancel); for (KrJob *job: m_jobs) connect(job, &KrJob::terminated, this, &JobMan::slotUpdateMessageBox); slotUpdateMessageBox(); int result = m_messageBox->exec(); // blocking m_messageBox->deleteLater(); m_messageBox = 0; // accepted -> cancel all jobs if (result == QMessageBox::Abort) { for (KrJob *job: m_jobs) { job->cancel(); } return true; } // else: return false; } void JobMan::manageJob(KrJob *job, StartMode startMode) { qDebug() << "new job, startMode=" << startMode; managePrivate(job); connect(job, &KrJob::started, this, &JobMan::slotKJobStarted); const bool enqueue = startMode == Enqueue || (startMode == Default && m_queueMode); if (startMode == Start || (startMode == Default && !m_queueMode) || (enqueue && !jobsAreRunning())) { job->start(); } updateUI(); } void JobMan::manageStartedJob(KrJob *krJob, KJob *kJob) { managePrivate(krJob, kJob); slotKJobStarted(kJob); updateUI(); } // #### protected slots void JobMan::slotKJobStarted(KJob *job) { // KJob has two percent() functions connect(job, SIGNAL(percent(KJob*,ulong)), this, SLOT(slotPercent(KJob*,ulong))); connect(job, &KJob::description, this, &JobMan::slotDescription); connect(job, &KJob::suspended, this, &JobMan::updateUI); connect(job, &KJob::resumed, this, &JobMan::updateUI); } void JobMan::slotControlActionTriggered() { if (m_jobs.isEmpty()) { m_controlAction->menu()->clear(); m_controlAction->setEnabled(false); return; } const bool anyRunning = jobsAreRunning(); if (!anyRunning && m_queueMode) { m_jobs.first()->start(); } else { for (KrJob *job : m_jobs) { if (anyRunning) job->pause(); else job->start(); } } } void JobMan::slotPercent(KJob *, unsigned long) { updateUI(); } void JobMan::slotDescription(KJob*,const QString &description, const QPair &field1, const QPair &field2) { // TODO cache all descriptions if (m_jobs.length() > 1) return; m_progressBar->setToolTip( QString("%1\n%2: %3\n%4: %5") .arg(description, field1.first, field1.second, field2.first, field2.second)); } void JobMan::slotTerminated(KrJob *krJob) { qDebug() << "terminated, job description: " << krJob->description(); m_jobs.removeAll(krJob); // NOTE: ignoring queue mode here. We assume that if queue mode is turned off, the user created // jobs which were not already started with a "queue" option and still wants queue behaviour. if (!m_jobs.isEmpty() && !jobsAreRunning()) { foreach (KrJob *job, m_jobs) { if (!job->isPaused()) { // start next job job->start(); break; } } } updateUI(); cleanupMenu(); } void JobMan::slotUpdateControlAction() { m_controlAction->setEnabled(!m_controlAction->menu()->isEmpty()); } void JobMan::slotUndoTextChange(const QString &text) { m_undoAction->setToolTip(KIO::FileUndoManager::self()->undoAvailable() ? text : i18n("Undo Last Job")); } void JobMan::slotUpdateMessageBox() { if (!m_messageBox) return; if (m_jobs.isEmpty() && m_autoCloseMessageBox) { m_messageBox->done(QMessageBox::Abort); return; } if (m_jobs.isEmpty()) { m_messageBox->setInformativeText(""); m_messageBox->setButtonText(QMessageBox::Abort, "Quit"); return; } m_messageBox->setInformativeText(i18np("There is one job operation left.", "There are %1 job operations left.", m_jobs.length())); m_messageBox->setButtonText(QMessageBox::Abort, "Abort Jobs and Quit"); } // #### private void JobMan::managePrivate(KrJob *job, KJob *kJob) { JobMenuAction *menuAction = new JobMenuAction(job, m_controlAction, kJob); connect(menuAction, &QObject::destroyed, this, &JobMan::slotUpdateControlAction); m_controlAction->menu()->addAction(menuAction); cleanupMenu(); slotUpdateControlAction(); connect(job, &KrJob::terminated, this, &JobMan::slotTerminated); m_jobs.append(job); } void JobMan::cleanupMenu() { const QList actions = m_controlAction->menu()->actions(); for (QAction *action : actions) { if (m_controlAction->menu()->actions().count() <= MAX_OLD_MENU_ACTIONS) break; JobMenuAction *jobAction = static_cast(action); if (jobAction->isDone()) { m_controlAction->menu()->removeAction(action); action->deleteLater(); } } } void JobMan::updateUI() { int totalPercent = 0; for (KrJob *job: m_jobs) { totalPercent += job->percent(); } const bool hasJobs = !m_jobs.isEmpty(); m_progressBar->setEnabled(hasJobs); if (hasJobs) { m_progressBar->setValue(totalPercent / m_jobs.length()); } else { m_progressBar->reset(); } if (!hasJobs) m_progressBar->setToolTip(i18n("No Jobs")); if (m_jobs.length() > 1) m_progressBar->setToolTip(i18np("%1 Job", "%1 Jobs", m_jobs.length())); const bool running = jobsAreRunning(); - m_controlAction->setIcon(QIcon::fromTheme( + m_controlAction->setIcon(Icon( !hasJobs ? "edit-clear" : running ? "media-playback-pause" : "media-playback-start")); m_controlAction->setToolTip(!hasJobs ? i18n("Clear Job List") : running ? i18n("Pause All Jobs") : i18n("Resume Job List")); } bool JobMan::jobsAreRunning() { for (KrJob *job: m_jobs) if (job->isRunning()) return true; return false; } diff --git a/krusader/KViewer/krviewer.cpp b/krusader/KViewer/krviewer.cpp index 507c637c..50ee9c50 100644 --- a/krusader/KViewer/krviewer.cpp +++ b/krusader/KViewer/krviewer.cpp @@ -1,715 +1,714 @@ /***************************************************************************** * Copyright (C) 2002 Shie Erlich * * Copyright (C) 2002 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 "krviewer.h" // QtCore #include #include #include #include #include // QtGui #include // QtWidgets #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include "../defaults.h" -#include "../kicons.h" +#include "../icon.h" #include "panelviewer.h" #define VIEW_ICON "document-preview" #define EDIT_ICON "document-edit" #define MODIFIED_ICON "document-save-as" #define CHECK_MODFIED_INTERVAL 500 /* NOTE: Currently the code expects PanelViewer::openUrl() to be called only once in the panel viewer's life time - otherwise unexpected things might happen. */ QList KrViewer::viewers; KrViewer::KrViewer(QWidget *parent) : KParts::MainWindow(parent, (Qt::WindowFlags)KDE_DEFAULT_WINDOWFLAGS), manager(this, this), tabBar(this), reservedKeys(), reservedKeyActions(), sizeX(-1), sizeY(-1) { //setWFlags(Qt::WType_TopLevel | WDestructiveClose); setXMLFile("krviewer.rc"); // kpart-related xml file setHelpMenuEnabled(false); connect(&manager, SIGNAL(activePartChanged(KParts::Part*)), this, SLOT(createGUI(KParts::Part*))); connect(&tabBar, &QTabWidget::currentChanged, this, &KrViewer::tabChanged); connect(&tabBar, SIGNAL(tabCloseRequested(int)), this, SLOT(tabCloseRequest(int))); tabBar.setDocumentMode(true); tabBar.setMovable(true); setCentralWidget(&tabBar); printAction = KStandardAction::print(this, SLOT(print()), 0); copyAction = KStandardAction::copy(this, SLOT(copy()), 0); viewerMenu = new QMenu(this); QAction *tempAction; KActionCollection *ac = actionCollection(); #define addCustomMenuAction(name, text, slot, shortcut)\ tempAction = ac->addAction(name, this, slot);\ tempAction->setText(text);\ ac->setDefaultShortcut(tempAction, shortcut);\ viewerMenu->addAction(tempAction); addCustomMenuAction("genericViewer", i18n("&Generic Viewer"), SLOT(viewGeneric()), Qt::CTRL + Qt::SHIFT + Qt::Key_G); addCustomMenuAction("textViewer", i18n("&Text Viewer"), SLOT(viewText()), Qt::CTRL + Qt::SHIFT + Qt::Key_T); addCustomMenuAction("hexViewer", i18n("&Hex Viewer"), SLOT(viewHex()), Qt::CTRL + Qt::SHIFT + Qt::Key_H); addCustomMenuAction("lister", i18n("&Lister"), SLOT(viewLister()), Qt::CTRL + Qt::SHIFT + Qt::Key_L); viewerMenu->addSeparator(); addCustomMenuAction("textEditor", i18n("Text &Editor"), SLOT(editText()), Qt::CTRL + Qt::SHIFT + Qt::Key_E); viewerMenu->addSeparator(); QList actList = menuBar()->actions(); bool hasPrint = false, hasCopy = false; foreach(QAction *a, actList) { if (a->shortcut().matches(printAction->shortcut()) != QKeySequence::NoMatch) hasPrint = true; if (a->shortcut().matches(copyAction->shortcut()) != QKeySequence::NoMatch) hasCopy = true; } QAction *printAct = viewerMenu->addAction(printAction->icon(), printAction->text(), this, SLOT(print())); if (hasPrint) printAct->setShortcut(printAction->shortcut()); QAction *copyAct = viewerMenu->addAction(copyAction->icon(), copyAction->text(), this, SLOT(copy())); if (hasCopy) copyAct->setShortcut(copyAction->shortcut()); viewerMenu->addSeparator(); configKeysAction = ac->addAction(KStandardAction::KeyBindings, this, SLOT(configureShortcuts())); viewerMenu->addAction(configKeysAction); viewerMenu->addSeparator(); detachAction = ac->addAction("detachTab", this, SLOT(detachTab())); detachAction->setText(i18n("&Detach Tab")); //no point in detaching only one tab.. detachAction->setEnabled(false); ac->setDefaultShortcut(detachAction, Qt::META + Qt::Key_D); viewerMenu->addAction(detachAction); quitAction = ac->addAction(KStandardAction::Quit, this, SLOT(close())); viewerMenu->addAction(quitAction); QList shortcuts; tabCloseAction = ac->addAction("closeTab", this, SLOT(tabCloseRequest())); tabCloseAction->setText(i18n("&Close Current Tab")); shortcuts = KStandardShortcut::close(); shortcuts.append(Qt::Key_Escape); ac->setDefaultShortcuts(tabCloseAction, shortcuts); tabNextAction = ac->addAction("nextTab", this, SLOT(nextTab())); tabNextAction->setText(i18n("&Next Tab")); shortcuts = KStandardShortcut::tabNext(); shortcuts.append(Qt::CTRL + Qt::Key_Tab); // reenforce QTabWidget shortcut ac->setDefaultShortcuts(tabNextAction, shortcuts); tabPrevAction = ac->addAction("prevTab", this, SLOT(prevTab())); tabPrevAction->setText(i18n("&Previous Tab")); shortcuts = KStandardShortcut::tabPrev(); shortcuts.append(Qt::CTRL + Qt::SHIFT + Qt::Key_Tab); // reenforce QTabWidget shortcut ac->setDefaultShortcuts(tabPrevAction, shortcuts); tabBar.setTabsClosable(true); checkModified(); KConfigGroup group(krConfig, "KrViewerWindow"); int sx = group.readEntry("Window Width", -1); int sy = group.readEntry("Window Height", -1); if (sx != -1 && sy != -1) resize(sx, sy); else resize(900, 700); if (group.readEntry("Window Maximized", false)) { setWindowState(windowState() | Qt::WindowMaximized); } // filtering out the key events menuBar() ->installEventFilter(this); } KrViewer::~KrViewer() { disconnect(&manager, SIGNAL(activePartChanged(KParts::Part*)), this, SLOT(createGUI(KParts::Part*))); viewers.removeAll(this); // close tabs before deleting tab bar - this avoids Qt bug 26115 // https://bugreports.qt-project.org/browse/QTBUG-26115 while(tabBar.count()) tabCloseRequest(tabBar.currentIndex(), true); delete printAction; delete copyAction; } void KrViewer::configureDeps() { PanelEditor::configureDeps(); } void KrViewer::createGUI(KParts::Part* part) { KParts::MainWindow::createGUI(part); updateActions(); toolBar() ->show(); statusBar() ->show(); // the KParts part may override the viewer shortcuts. We prevent it // by installing an event filter on the menuBar() and the part reservedKeys.clear(); reservedKeyActions.clear(); QList list = viewerMenu->actions(); // also add the actions that are not in the menu... list << tabCloseAction << tabNextAction << tabPrevAction; // getting the key sequences of the viewer menu for (int w = 0; w != list.count(); w++) { QAction *act = list[ w ]; QList sequences = act->shortcuts(); foreach(QKeySequence keySeq, sequences) { for(int i = 0; i < keySeq.count(); ++i) { reservedKeys.push_back(keySeq[i]); reservedKeyActions.push_back(act); //the same action many times in case of multiple shortcuts } } } // and "fix" the menubar QList actList = menuBar()->actions(); viewerMenu->setTitle(i18n("&KrViewer")); QAction * act = menuBar() ->addMenu(viewerMenu); act->setData(QVariant(70)); menuBar() ->show(); } void KrViewer::configureShortcuts() { KShortcutsDialog::configure(actionCollection(), KShortcutsEditor::LetterShortcutsAllowed, this); } bool KrViewer::eventFilter(QObject * /* watched */, QEvent * e) { // TODO: after porting to Qt5/KF5 we never catch *ANY* KeyPress or ShortcutOverride events here anymore. // Should look into if there is any way to fix it. Currently if a KPart has same shortcut as KrViewer then // it causes a conflict, messagebox shown to user and no action triggered. if (e->type() == QEvent::ShortcutOverride) { QKeyEvent* ke = (QKeyEvent*) e; if (reservedKeys.contains(ke->key())) { ke->accept(); QAction *act = reservedKeyActions[ reservedKeys.indexOf(ke->key())]; if (act != 0) { // don't activate the close functions immediately! // it can cause crash if (act == tabCloseAction || act == quitAction) { QTimer::singleShot(0, act, SLOT(trigger())); } else { act->activate(QAction::Trigger); } } return true; } } else if (e->type() == QEvent::KeyPress) { QKeyEvent* ke = (QKeyEvent*) e; if (reservedKeys.contains(ke->key())) { ke->accept(); return true; } } return false; } KrViewer* KrViewer::getViewer(bool new_window) { if (!new_window) { if (viewers.isEmpty()) { viewers.prepend(new KrViewer()); // add to first (active) } else { if (viewers.first()->isMinimized()) { // minimized? -> show it again viewers.first()->setWindowState((viewers.first()->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive); viewers.first()->show(); } viewers.first()->raise(); viewers.first()->activateWindow(); } return viewers.first(); } else { KrViewer *newViewer = new KrViewer(); viewers.prepend(newViewer); return newViewer; } } void KrViewer::view(QUrl url, QWidget * parent) { KConfigGroup group(krConfig, "General"); bool defaultWindow = group.readEntry("View In Separate Window", _ViewInSeparateWindow); view(url, Default, defaultWindow, parent); } void KrViewer::view(QUrl url, Mode mode, bool new_window, QWidget * parent) { KrViewer* viewer = getViewer(new_window); viewer->viewInternal(url, mode, parent); viewer->show(); } void KrViewer::edit(QUrl url, QWidget * parent) { edit(url, Text, -1, parent); } void KrViewer::edit(QUrl url, Mode mode, int new_window, QWidget * parent) { KConfigGroup group(krConfig, "General"); QString editor = group.readEntry("Editor", _Editor); if (new_window == -1) new_window = group.readEntry("View In Separate Window", _ViewInSeparateWindow); if (editor != "internal editor" && !editor.isEmpty()) { KProcess proc; QStringList cmdArgs = KShell::splitArgs(editor, KShell::TildeExpand); if (cmdArgs.isEmpty()) { KMessageBox::error(krMainWindow, i18nc("Arg is a string containing the bad quoting.", "Bad quoting in editor command:\n%1", editor)); return; } // if the file is local, pass a normal path and not a url. this solves // the problem for editors that aren't url-aware proc << cmdArgs << url.toDisplayString(QUrl::PreferLocalFile); if (!proc.startDetached()) KMessageBox::sorry(krMainWindow, i18n("Can not open \"%1\"", editor)); return; } KrViewer* viewer = getViewer(new_window); viewer->editInternal(url, mode, parent); viewer->show(); } void KrViewer::addTab(PanelViewerBase *pvb) { int tabIndex = tabBar.addTab(pvb, makeTabIcon(pvb), makeTabText(pvb)); tabBar.setCurrentIndex(tabIndex); tabBar.setTabToolTip(tabIndex, makeTabToolTip(pvb)); updateActions(); // now we can offer the option to detach tabs (we have more than one) if (tabBar.count() > 1) { detachAction->setEnabled(true); } tabBar.show(); connect(pvb, SIGNAL(openUrlFinished(PanelViewerBase*,bool)), SLOT(openUrlFinished(PanelViewerBase*,bool))); connect(pvb, SIGNAL(urlChanged(PanelViewerBase*,QUrl)), this, SLOT(tabURLChanged(PanelViewerBase*,QUrl))); } void KrViewer::tabURLChanged(PanelViewerBase *pvb, const QUrl &url) { Q_UNUSED(url) refreshTab(pvb); } void KrViewer::openUrlFinished(PanelViewerBase *pvb, bool success) { if (success) { KParts::ReadOnlyPart *part = pvb->part(); if (part) { if (!isPartAdded(part)) addPart(part); if (tabBar.currentWidget() == pvb) { manager.setActivePart(part); if (part->widget()) part->widget()->setFocus(); } } } else { tabCloseRequest(tabBar.currentIndex(), false); } } void KrViewer::tabChanged(int index) { QWidget *w = tabBar.widget(index); if(!w) return; KParts::ReadOnlyPart *part = static_cast(w)->part(); if (part && isPartAdded(part)) { manager.setActivePart(part); if (part->widget()) part->widget()->setFocus(); } else manager.setActivePart(0); // set this viewer to be the main viewer if (viewers.removeAll(this)) viewers.prepend(this); // move to first } void KrViewer::tabCloseRequest(int index, bool force) { // important to save as returnFocusTo will be cleared at removePart QWidget *returnFocusToThisWidget = returnFocusTo; PanelViewerBase *pvb = static_cast(tabBar.widget(index)); if (!pvb) return; if (!force && !pvb->queryClose()) return; if (pvb->part() && isPartAdded(pvb->part())) removePart(pvb->part()); disconnect(pvb, 0, this, 0); pvb->closeUrl(); tabBar.removeTab(index); delete pvb; pvb = 0; if (tabBar.count() <= 0) { if (returnFocusToThisWidget) { returnFocusToThisWidget->raise(); returnFocusToThisWidget->activateWindow(); } else { krMainWindow->raise(); krMainWindow->activateWindow(); } QTimer::singleShot(0, this, SLOT(close())); } else if (tabBar.count() == 1) { // no point in detaching only one tab.. detachAction->setEnabled(false); } } void KrViewer::tabCloseRequest() { tabCloseRequest(tabBar.currentIndex()); } bool KrViewer::queryClose() { KConfigGroup group(krConfig, "KrViewerWindow"); group.writeEntry("Window Width", sizeX); group.writeEntry("Window Height", sizeY); group.writeEntry("Window Maximized", isMaximized()); for (int i = 0; i != tabBar.count(); i++) { PanelViewerBase* pvb = static_cast(tabBar.widget(i)); if (!pvb) continue; tabBar.setCurrentIndex(i); if (!pvb->queryClose()) return false; } return true; } void KrViewer::viewGeneric() { PanelViewerBase* pvb = static_cast(tabBar.currentWidget()); if (pvb) viewInternal(pvb->url(), Generic); } void KrViewer::viewText() { PanelViewerBase* pvb = static_cast(tabBar.currentWidget()); if (pvb) viewInternal(pvb->url(), Text); } void KrViewer::viewLister() { PanelViewerBase* pvb = static_cast(tabBar.currentWidget()); if (pvb) viewInternal(pvb->url(), Lister); } void KrViewer::viewHex() { PanelViewerBase* pvb = static_cast(tabBar.currentWidget()); if (pvb) viewInternal(pvb->url(), Hex); } void KrViewer::editText() { PanelViewerBase* pvb = static_cast(tabBar.currentWidget()); if (pvb) editInternal(pvb->url(), Text); } void KrViewer::checkModified() { QTimer::singleShot(CHECK_MODFIED_INTERVAL, this, SLOT(checkModified())); PanelViewerBase* pvb = static_cast(tabBar.currentWidget()); if (pvb) refreshTab(pvb); } void KrViewer::refreshTab(PanelViewerBase* pvb) { int ndx = tabBar.indexOf(pvb); tabBar.setTabText(ndx, makeTabText(pvb)); tabBar.setTabIcon(ndx, makeTabIcon(pvb)); tabBar.setTabToolTip(ndx, makeTabToolTip(pvb)); } void KrViewer::nextTab() { int index = (tabBar.currentIndex() + 1) % tabBar.count(); tabBar.setCurrentIndex(index); } void KrViewer::prevTab() { int index = (tabBar.currentIndex() - 1) % tabBar.count(); while (index < 0) index += tabBar.count(); tabBar.setCurrentIndex(index); } void KrViewer::detachTab() { PanelViewerBase* pvb = static_cast(tabBar.currentWidget()); if (!pvb) return; KrViewer* viewer = getViewer(true); bool wasPartAdded = false; KParts::ReadOnlyPart *part = pvb->part(); if (part && isPartAdded(part)) { wasPartAdded = true; removePart(part); } disconnect(pvb, 0, this, 0); tabBar.removeTab(tabBar.indexOf(pvb)); if (tabBar.count() == 1) { //no point in detaching only one tab.. detachAction->setEnabled(false); } pvb->setParent(&viewer->tabBar); pvb->move(QPoint(0, 0)); viewer->addTab(pvb); if (wasPartAdded) { viewer->addPart(part); if (part->widget()) part->widget()->setFocus(); } viewer->show(); } void KrViewer::changeEvent(QEvent *e) { if (e->type() == QEvent::ActivationChange && isActiveWindow()) if (viewers.removeAll(this)) viewers.prepend(this); // move to first } void KrViewer::print() { PanelViewerBase* pvb = static_cast(tabBar.currentWidget()); if (!pvb || !pvb->part() || !isPartAdded(pvb->part())) return; KParts::BrowserExtension * ext = KParts::BrowserExtension::childObject(pvb->part()); if (ext && ext->isActionEnabled("print")) Invoker(ext, SLOT(print())).invoke(); } void KrViewer::copy() { PanelViewerBase* pvb = static_cast(tabBar.currentWidget()); if (!pvb || !pvb->part() || !isPartAdded(pvb->part())) return; KParts::BrowserExtension * ext = KParts::BrowserExtension::childObject(pvb->part()); if (ext && ext->isActionEnabled("copy")) Invoker(ext, SLOT(copy())).invoke(); } void KrViewer::updateActions() { QList actList = toolBar()->actions(); bool hasPrint = false, hasCopy = false; foreach(QAction *a, actList) { if (a->text() == printAction->text()) hasPrint = true; if (a->text() == copyAction->text()) hasCopy = true; } if (!hasPrint) toolBar()->addAction(printAction->icon(), printAction->text(), this, SLOT(print())); if (!hasCopy) toolBar()->addAction(copyAction->icon(), copyAction->text(), this, SLOT(copy())); } bool KrViewer::isPartAdded(KParts::Part* part) { return manager.parts().contains(part); } void KrViewer::resizeEvent(QResizeEvent *e) { if (!isMaximized()) { sizeX = e->size().width(); sizeY = e->size().height(); } KParts::MainWindow::resizeEvent(e); } QString KrViewer::makeTabText(PanelViewerBase *pvb) { QString fileName = pvb->url().fileName(); if (pvb->isModified()) fileName.prepend("*"); return pvb->isEditor() ? i18nc("filename (filestate)", "%1 (Editing)", fileName) : i18nc("filename (filestate)", "%1 (Viewing)", fileName); } QString KrViewer::makeTabToolTip(PanelViewerBase *pvb) { QString url = pvb->url().toDisplayString(QUrl::PreferLocalFile); return pvb->isEditor() ? i18nc("filestate: filename", "Editing: %1", url) : i18nc("filestate: filename", "Viewing: %1", url); } QIcon KrViewer::makeTabIcon(PanelViewerBase *pvb) { QString iconName; if (pvb->isModified()) iconName = MODIFIED_ICON; else if (pvb->isEditor()) iconName = EDIT_ICON; else iconName = VIEW_ICON; - return QIcon(krLoader->loadIcon(iconName, KIconLoader::Small)); + return Icon(iconName); } void KrViewer::addPart(KParts::ReadOnlyPart *part) { Q_ASSERT(part); Q_ASSERT(!isPartAdded(part)); if (isPartAdded(part)) { qDebug()<<"part already added:"<installEventFilter(this); manager.addPart(part, false); // don't automatically set active part } void KrViewer::removePart(KParts::ReadOnlyPart *part) { Q_ASSERT(part); Q_ASSERT(isPartAdded(part)); if (isPartAdded(part)) { disconnect(part, 0, this, 0); part->removeEventFilter(this); manager.removePart(part); } else qDebug()<<"part hasn't been added:"<openUrl(url); } void KrViewer::editInternal(QUrl url, Mode mode, QWidget * parent) { returnFocusTo = parent; PanelViewerBase* editWidget = new PanelEditor(&tabBar, mode); addTab(editWidget); editWidget->openUrl(url); } diff --git a/krusader/KViewer/lister.cpp b/krusader/KViewer/lister.cpp index 89b39f9b..3f7a4cd9 100644 --- a/krusader/KViewer/lister.cpp +++ b/krusader/KViewer/lister.cpp @@ -1,2276 +1,2277 @@ /***************************************************************************** * Copyright (C) 2009 Csaba Karai * * Copyright (C) 2009-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 "lister.h" // QtCore #include #include #include #include #include // QtGui #include #include #include #include #include // QtWidgets #include #include #include #include #include #include #include #include #include #include #include #include // QtPrintSupport #include #include #include #include #include #include #include #include #include #include #include #include "../krglobal.h" +#include "../icon.h" #include "../kractions.h" #include "../GUI/krremoteencodingmenu.h" #define SEARCH_CACHE_CHARS 100000 #define SEARCH_MAX_ROW_LEN 4000 #define CONTROL_CHAR 752 #define CACHE_SIZE 1048576 // cache size set to 1MiB ListerTextArea::ListerTextArea(Lister *lister, QWidget *parent) : KTextEdit(parent), _lister(lister) { connect(this, &QTextEdit::cursorPositionChanged, this, &ListerTextArea::slotCursorPositionChanged); _tabWidth = 4; setWordWrapMode(QTextOption::NoWrap); setLineWrapMode(QTextEdit::NoWrap); // zoom shortcuts connect(new QShortcut(QKeySequence("Ctrl++"), this), SIGNAL(activated()), this, SLOT(zoomIn())); connect(new QShortcut(QKeySequence("Ctrl+-"), this), SIGNAL(activated()), this, SLOT(zoomOut())); // start cursor blinking connect(&_blinkTimer, &QTimer::timeout, this, [=] { if (!_cursorBlinkMutex.tryLock()) { return; } setCursorWidth(cursorWidth() == 0 ? 2 : 0); _cursorBlinkMutex.unlock(); }); _blinkTimer.start(500); } void ListerTextArea::reset() { _screenStartPos = 0; _cursorPos = 0; _cursorAnchorPos = -1; _cursorAtFirstColumn = true; calculateText(); } void ListerTextArea::sizeChanged() { if (_cursorAnchorPos > _lister->fileSize()) _cursorAnchorPos = -1; if (_cursorPos > _lister->fileSize()) _cursorPos = _lister->fileSize(); redrawTextArea(true); } void ListerTextArea::resizeEvent(QResizeEvent * event) { KTextEdit::resizeEvent(event); redrawTextArea(); } void ListerTextArea::calculateText(const bool forcedUpdate) { const QRect contentRect = viewport()->contentsRect(); const QFontMetrics fm(font()); const int fontHeight = std::max(fm.height(), 1); // This is quite accurate (although not perfect) way of getting // a single character width along with its surrounding space. const float fontWidth = (fm.width("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW") - fm.width("W")) / 99.0; const int sizeY = contentRect.height() / fontHeight; _pageSize = sizeY; const int textViewportWidth = std::max(contentRect.width() - (int) fontWidth, 0); setTabStopWidth(fontWidth * _tabWidth); const int sizeX = textViewportWidth / fontWidth; _sizeChanged = (_sizeY != sizeY) || (_sizeX != sizeX) || forcedUpdate; _sizeY = sizeY; _sizeX = sizeX; QList rowStarts; QStringList list = readLines(_screenStartPos, _screenEndPos, _sizeY, &rowStarts); if (_sizeChanged) { _averagePageSize = _screenEndPos - _screenStartPos; setUpScrollBar(); } const QStringList listRemn = readLines(_screenEndPos, _screenEndPos, 1); list << listRemn; if (list != _rowContent) { _cursorBlinkMutex.lock(); _blinkTimer.stop(); setCursorWidth(0); setPlainText(list.join("\n")); if (_cursorAnchorPos == -1 || _cursorAnchorPos == _cursorPos) { clearSelection(); _blinkTimer.start(500); } _cursorBlinkMutex.unlock(); _rowContent = list; _rowStarts = rowStarts; if (_rowStarts.size() < _sizeY) { _rowStarts << _screenEndPos; } } } qint64 ListerTextArea::textToFilePositionOnScreen(const int x, const int y, bool &isfirst) { isfirst = (x == 0); if (y >= _rowStarts.count()) { return 0; } const qint64 rowStart = _rowStarts[ y ]; if (x == 0) { return rowStart; } if (_hexMode) { const qint64 pos = rowStart + _lister->hexPositionToIndex(_sizeX, x); if (pos > _lister->fileSize()) { return _lister->fileSize(); } return pos; } // we can't use fromUnicode because of the invalid encoded chars const int maxBytes = 2 * _sizeX * MAX_CHAR_LENGTH; QByteArray chunk = _lister->cacheChunk(rowStart, maxBytes); QTextStream stream(&chunk); stream.setCodec(_lister->codec()); stream.read(x); return rowStart + stream.pos(); } void ListerTextArea::fileToTextPositionOnScreen(const qint64 p, const bool isfirst, int &x, int &y) { // check if cursor is outside of visible area if (p < _screenStartPos || p > _screenEndPos || _rowStarts.count() < 1) { x = -1; y = (p > _screenEndPos) ? -2 : -1; return; } // find row y = 0; while (y < _rowStarts.count() && _rowStarts[ y ] <= p) { y++; } y--; if (y < 0) { x = y = -1; return; } const qint64 rowStart = _rowStarts[ y ]; if (_hexMode) { x = _lister->hexIndexToPosition(_sizeX, (int)(p - rowStart)); return; } // find column const int maxBytes = 2 * _sizeX * MAX_CHAR_LENGTH; x = 0; if (rowStart >= p) { if ((rowStart == p) && !isfirst && y > 0) { const qint64 previousRow = _rowStarts[ y - 1 ]; const QByteArray chunk = _lister->cacheChunk(previousRow, maxBytes); QByteArray cachedBuffer = chunk.left(p - previousRow); QTextStream stream(&cachedBuffer); stream.setCodec(_lister->codec()); stream.read(_rowContent[ y - 1].length()); if (previousRow + stream.pos() == p) { y--; x = _rowContent[ y ].length(); } } return; } const QByteArray chunk = _lister->cacheChunk(rowStart, maxBytes); const QByteArray cachedBuffer = chunk.left(p - rowStart); x = _lister->codec()->toUnicode(cachedBuffer).length(); } void ListerTextArea::getCursorPosition(int &x, int &y) { getScreenPosition(textCursor().position(), x, y); } void ListerTextArea::getScreenPosition(const int position, int &x, int &y) { x = position; y = 0; foreach (const QString &row, _rowContent) { const int rowLen = row.length() + 1; if (x < rowLen) { return; } x -= rowLen; y++; } } void ListerTextArea::setCursorPositionOnScreen(const int x, const int y, const int anchorX, const int anchorY) { setCursorWidth(0); int finalX = x; int finalY = y; if (finalX == -1 || finalY < 0) { if (anchorY == -1) { return; } if (finalY == -2) { finalY = _sizeY; finalX = (_rowContent.count() > _sizeY) ? _rowContent[ _sizeY ].length() : 0; } else finalX = finalY = 0; } const int realSizeY = std::min(_sizeY + 1, _rowContent.count()); const auto setUpCursor = [&] (const int cursorX, const int cursorY, const QTextCursor::MoveMode mode) -> bool { if (cursorY > realSizeY) { return false; } _skipCursorChangedListener = true; moveCursor(QTextCursor::Start, mode); for (int i = 0; i < cursorY; i++) { moveCursor(QTextCursor::Down, mode); } int finalCursorX = cursorX; if (_rowContent.count() > cursorY && finalCursorX > _rowContent[ cursorY ].length()) { finalCursorX = _rowContent[ cursorY ].length(); } for (int i = 0; i < finalCursorX; i++) { moveCursor(QTextCursor::Right, mode); } _skipCursorChangedListener = false; return true; }; QTextCursor::MoveMode mode = QTextCursor::MoveAnchor; // set cursor anchor if (anchorX != -1 && anchorY != -1) { const bool canContinue = setUpCursor(anchorX, anchorY, mode); if (!canContinue) { return; } mode = QTextCursor::KeepAnchor; } // set cursor position setUpCursor(finalX, finalY, mode); } qint64 ListerTextArea::getCursorPosition(bool &isfirst) { if (cursorWidth() == 0) { isfirst = _cursorAtFirstColumn; return _cursorPos; } int x, y; getCursorPosition(x, y); return textToFilePositionOnScreen(x, y, isfirst); } void ListerTextArea::setCursorPositionInDocument(const qint64 p, const bool isfirst) { _cursorPos = p; int x, y; fileToTextPositionOnScreen(p, isfirst, x, y); bool startBlinkTimer = _screenStartPos <= _cursorPos && _cursorPos <= _screenEndPos; int anchorX = -1, anchorY = -1; if (_cursorAnchorPos != -1 && _cursorAnchorPos != p) { int anchPos = _cursorAnchorPos; bool anchorBelow = false, anchorAbove = false; if (anchPos < _screenStartPos) { anchPos = _screenStartPos; anchorY = -2; anchorAbove = true; } if (anchPos > _screenEndPos) { anchPos = _screenEndPos; anchorY = -3; anchorBelow = true; } fileToTextPositionOnScreen(anchPos, isfirst, anchorX, anchorY); if (_hexMode) { if (anchorAbove) { anchorX = 0; } if (anchorBelow && _rowContent.count() > 0) { anchorX = _rowContent[ 0 ].length(); } } startBlinkTimer = startBlinkTimer && !anchorAbove && !anchorBelow; } if (startBlinkTimer) { _blinkTimer.start(500); } setCursorPositionOnScreen(x, y, anchorX, anchorY); _lister->slotUpdate(); } void ListerTextArea::slotCursorPositionChanged() { if (_skipCursorChangedListener) { return; } int cursorX, cursorY; getCursorPosition(cursorX, cursorY); _cursorAtFirstColumn = (cursorX == 0); _cursorPos = textToFilePositionOnScreen(cursorX, cursorY, _cursorAtFirstColumn); _lister->slotUpdate(); } QString ListerTextArea::readSection(const qint64 p1, const qint64 p2) { if (p1 == p2) return QString(); qint64 sel1 = p1; qint64 sel2 = p2; if (sel1 > sel2) { std::swap(sel1, sel2); } QString section; if (_hexMode) { while (sel1 != sel2) { const QStringList list = _lister->readHexLines(sel1, sel2, _sizeX, 1); if (list.isEmpty()) { break; } if (!section.isEmpty()) { section += QChar('\n'); } section += list.at(0); } return section; } qint64 pos = sel1; QScopedPointer decoder(_lister->codec()->makeDecoder()); do { const int maxBytes = std::min(_sizeX * _sizeY * MAX_CHAR_LENGTH, (int) (sel2 - pos)); const QByteArray chunk = _lister->cacheChunk(pos, maxBytes); if (chunk.isEmpty()) break; section += decoder->toUnicode(chunk); pos += chunk.size(); } while (pos < sel2); return section; } QStringList ListerTextArea::readLines(qint64 filePos, qint64 &endPos, const int lines, QList * locs) { QStringList list; if (_hexMode) { endPos = _lister->fileSize(); if (filePos >= endPos) { return list; } const int bytes = _lister->hexBytesPerLine(_sizeX); qint64 startPos = (filePos / bytes) * bytes; qint64 shiftPos = startPos; list = _lister->readHexLines(shiftPos, endPos, _sizeX, lines); endPos = shiftPos; if (locs) { for (int i = 0; i < list.count(); i++) { (*locs) << startPos; startPos += bytes; } } return list; } endPos = filePos; const int maxBytes = _sizeX * _sizeY * MAX_CHAR_LENGTH; const QByteArray chunk = _lister->cacheChunk(filePos, maxBytes); if (chunk.isEmpty()) return list; int byteCounter = 0; QString row = ""; int effLength = 0; if (locs) (*locs) << filePos; bool skipImmediateNewline = false; const auto performNewline = [&] (qint64 nextRowStartOffset) { list << row; effLength = 0; row = ""; if (locs) { (*locs) << (filePos + nextRowStartOffset); } }; QScopedPointer decoder(_lister->codec()->makeDecoder()); while (byteCounter < chunk.size() && list.size() < lines) { const int lastCnt = byteCounter; QString chr = decoder->toUnicode(chunk.mid(byteCounter++, 1)); if (chr.isEmpty()) { continue; } if ((chr[ 0 ] < 32) && (chr[ 0 ] != '\n') && (chr[ 0 ] != '\t')) { chr = QChar(CONTROL_CHAR); } if (chr == "\n") { if (!skipImmediateNewline) { performNewline(byteCounter); } skipImmediateNewline = false; continue; } skipImmediateNewline = false; if (chr == "\t") { effLength += _tabWidth - (effLength % _tabWidth) - 1; if (effLength > _sizeX) { performNewline(lastCnt); } } row += chr; effLength++; if (effLength >= _sizeX) { performNewline(byteCounter); skipImmediateNewline = true; } } if (list.size() < lines) list << row; endPos = filePos + byteCounter; return list; } void ListerTextArea::setUpScrollBar() { if (_averagePageSize == _lister->fileSize()) { _lister->scrollBar()->setPageStep(0); _lister->scrollBar()->setMaximum(0); _lister->scrollBar()->hide(); _lastPageStartPos = 0; } else { const int maxPage = MAX_CHAR_LENGTH * _sizeX * _sizeY; qint64 pageStartPos = _lister->fileSize() - maxPage; qint64 endPos; if (pageStartPos < 0) pageStartPos = 0; QStringList list = readLines(pageStartPos, endPos, maxPage); if (list.count() <= _sizeY) { _lastPageStartPos = 0; } else { readLines(pageStartPos, _lastPageStartPos, list.count() - _sizeY); } const int maximum = (_lastPageStartPos > SLIDER_MAX) ? SLIDER_MAX : _lastPageStartPos; int pageSize = (_lastPageStartPos > SLIDER_MAX) ? SLIDER_MAX * _averagePageSize / _lastPageStartPos : _averagePageSize; if (pageSize == 0) pageSize++; _lister->scrollBar()->setPageStep(pageSize); _lister->scrollBar()->setMaximum(maximum); _lister->scrollBar()->show(); } } void ListerTextArea::keyPressEvent(QKeyEvent * ke) { if (KrGlobal::copyShortcut == QKeySequence(ke->key() | ke->modifiers())) { copySelectedToClipboard(); ke->accept(); return; } if (ke->modifiers() == Qt::NoModifier || ke->modifiers() & Qt::ShiftModifier) { qint64 newAnchor = -1; if (ke->modifiers() & Qt::ShiftModifier) { newAnchor = _cursorAnchorPos; if (_cursorAnchorPos == -1) newAnchor = _cursorPos; } switch (ke->key()) { case Qt::Key_F3: ke->accept(); if (ke->modifiers() == Qt::ShiftModifier) _lister->searchPrev(); else _lister->searchNext(); return; case Qt::Key_Home: case Qt::Key_End: _cursorAnchorPos = newAnchor; break; case Qt::Key_Left: { _cursorAnchorPos = newAnchor; ensureVisibleCursor(); int x, y; getCursorPosition(x, y); if (y == 0 && x == 0) slotActionTriggered(QAbstractSlider::SliderSingleStepSub); } break; case Qt::Key_Right: { _cursorAnchorPos = newAnchor; ensureVisibleCursor(); if (textCursor().position() == toPlainText().length()) slotActionTriggered(QAbstractSlider::SliderSingleStepAdd); } break; case Qt::Key_Up: { _cursorAnchorPos = newAnchor; ensureVisibleCursor(); int x, y; getCursorPosition(x, y); if (y == 0) slotActionTriggered(QAbstractSlider::SliderSingleStepSub); } break; case Qt::Key_Down: { _cursorAnchorPos = newAnchor; ensureVisibleCursor(); int x, y; getCursorPosition(x, y); if (y >= _sizeY-1) slotActionTriggered(QAbstractSlider::SliderSingleStepAdd); } break; case Qt::Key_PageDown: { _cursorAnchorPos = newAnchor; ensureVisibleCursor(); ke->accept(); int x, y; getCursorPosition(x, y); slotActionTriggered(QAbstractSlider::SliderPageStepAdd); y += _sizeY - _skippedLines; if (y > _rowContent.count()) { y = _rowContent.count() - 1; if (y > 0) x = _rowContent[ y - 1 ].length(); else x = 0; } _cursorPos = textToFilePositionOnScreen(x, y, _cursorAtFirstColumn); setCursorPositionInDocument(_cursorPos, _cursorAtFirstColumn); } return; case Qt::Key_PageUp: { _cursorAnchorPos = newAnchor; ensureVisibleCursor(); ke->accept(); int x, y; getCursorPosition(x, y); slotActionTriggered(QAbstractSlider::SliderPageStepSub); y -= _sizeY - _skippedLines; if (y < 0) { y = 0; x = 0; } _cursorPos = textToFilePositionOnScreen(x, y, _cursorAtFirstColumn); setCursorPositionInDocument(_cursorPos, _cursorAtFirstColumn); } return; } } if (ke->modifiers() == Qt::ControlModifier) { switch (ke->key()) { case Qt::Key_G: ke->accept(); _lister->jumpToPosition(); return; case Qt::Key_F: ke->accept(); _lister->enableSearch(true); return; case Qt::Key_Home: _cursorAnchorPos = -1; ke->accept(); slotActionTriggered(QAbstractSlider::SliderToMinimum); setCursorPositionInDocument((qint64)0, true); return; case Qt::Key_A: case Qt::Key_End: { _cursorAnchorPos = (ke->key() == Qt::Key_A) ? 0 : -1; ke->accept(); slotActionTriggered(QAbstractSlider::SliderToMaximum); const qint64 endPos = _lister->fileSize(); setCursorPositionInDocument(endPos, false); return; } case Qt::Key_Down: ke->accept(); slotActionTriggered(QAbstractSlider::SliderSingleStepAdd); return; case Qt::Key_Up: ke->accept(); slotActionTriggered(QAbstractSlider::SliderSingleStepSub); return; case Qt::Key_PageDown: ke->accept(); slotActionTriggered(QAbstractSlider::SliderPageStepAdd); return; case Qt::Key_PageUp: ke->accept(); slotActionTriggered(QAbstractSlider::SliderPageStepSub); return; } } const int oldAnchor = textCursor().anchor(); KTextEdit::keyPressEvent(ke); handleAnchorChange(oldAnchor); } void ListerTextArea::mousePressEvent(QMouseEvent * e) { KTextEdit::mousePressEvent(e); // do change anchor only when shift is not pressed if (!(QGuiApplication::keyboardModifiers() & Qt::ShiftModifier)) { performAnchorChange(textCursor().anchor()); } } void ListerTextArea::mouseDoubleClickEvent(QMouseEvent * e) { _cursorAnchorPos = -1; const int oldAnchor = textCursor().anchor(); KTextEdit::mouseDoubleClickEvent(e); handleAnchorChange(oldAnchor); } void ListerTextArea::mouseMoveEvent(QMouseEvent * e) { if (e->pos().y() < 0) { slotActionTriggered(QAbstractSlider::SliderSingleStepSub); } else if (e->pos().y() > height()) { slotActionTriggered(QAbstractSlider::SliderSingleStepAdd); } KTextEdit::mouseMoveEvent(e); } void ListerTextArea::wheelEvent(QWheelEvent * e) { int delta = e->delta(); if (delta) { // zooming if (e->modifiers() & Qt::ControlModifier) { e->accept(); if (delta > 0) { zoomIn(); } else { zoomOut(); } return; } if (delta > 0) { e->accept(); while (delta > 0) { slotActionTriggered(QAbstractSlider::SliderSingleStepSub); slotActionTriggered(QAbstractSlider::SliderSingleStepSub); slotActionTriggered(QAbstractSlider::SliderSingleStepSub); delta -= 120; } } else { e->accept(); while (delta < 0) { slotActionTriggered(QAbstractSlider::SliderSingleStepAdd); slotActionTriggered(QAbstractSlider::SliderSingleStepAdd); slotActionTriggered(QAbstractSlider::SliderSingleStepAdd); delta += 120; } } setCursorPositionInDocument(_cursorPos, false); } } void ListerTextArea::slotActionTriggered(int action) { switch (action) { case QAbstractSlider::SliderSingleStepAdd: { qint64 endPos; readLines(_screenStartPos, endPos, 1); if (endPos <= _lastPageStartPos) { _screenStartPos = endPos; } } break; case QAbstractSlider::SliderSingleStepSub: { if (_screenStartPos == 0) { break; } if (_hexMode) { int bytesPerRow = _lister->hexBytesPerLine(_sizeX); _screenStartPos = (_screenStartPos / bytesPerRow) * bytesPerRow; _screenStartPos -= bytesPerRow; if (_screenStartPos < 0) { _screenStartPos = 0; } break; } int maxSize = _sizeX * _sizeY * MAX_CHAR_LENGTH; const QByteArray encodedEnter = _lister->codec()->fromUnicode(QString("\n")); qint64 readPos = _screenStartPos - maxSize; if (readPos < 0) { readPos = 0; } maxSize = _screenStartPos - readPos; const QByteArray chunk = _lister->cacheChunk(readPos, maxSize); int from = chunk.size(); while (from > 0) { from--; from = chunk.lastIndexOf(encodedEnter, from); if (from == -1) { from = 0; break; } const int backRef = std::max(from - 20, 0); const int size = from - backRef + encodedEnter.size(); const QString decoded = _lister->codec()->toUnicode(chunk.mid(backRef, size)); if (decoded.endsWith(QLatin1String("\n"))) { if (from < (chunk.size() - encodedEnter.size())) { from += encodedEnter.size(); break; } } } readPos += from; qint64 previousPos = readPos; while (readPos < _screenStartPos) { previousPos = readPos; readLines(readPos, readPos, 1); } _screenStartPos = previousPos; } break; case QAbstractSlider::SliderPageStepAdd: { _skippedLines = 0; qint64 endPos; for (int i = 0; i < _sizeY; i++) { readLines(_screenStartPos, endPos, 1); if (endPos <= _lastPageStartPos) { _screenStartPos = endPos; _skippedLines++; } else { break; } } } break; case QAbstractSlider::SliderPageStepSub: { _skippedLines = 0; if (_screenStartPos == 0) { break; } if (_hexMode) { const int bytesPerRow = _lister->hexBytesPerLine(_sizeX); _screenStartPos = (_screenStartPos / bytesPerRow) * bytesPerRow; _screenStartPos -= _sizeY * bytesPerRow; if (_screenStartPos < 0) { _screenStartPos = 0; } break; } // text lister mode int maxSize = 2 * _sizeX * _sizeY * MAX_CHAR_LENGTH; const QByteArray encodedEnter = _lister->codec()->fromUnicode(QString("\n")); qint64 readPos = _screenStartPos - maxSize; if (readPos < 0) readPos = 0; maxSize = _screenStartPos - readPos; const QByteArray chunk = _lister->cacheChunk(readPos, maxSize); maxSize = chunk.size(); int sizeY = _sizeY + 1; int origSizeY = sizeY; int from = maxSize; int lastEnter = maxSize; bool readNext = true; while (readNext) { readNext = false; while (from > 0) { from--; from = chunk.lastIndexOf(encodedEnter, from); if (from == -1) { from = 0; break; } const int backRef = std::max(from - 20, 0); const int size = from - backRef + encodedEnter.size(); QString decoded = _lister->codec()->toUnicode(chunk.mid(backRef, size)); if (decoded.endsWith(QLatin1String("\n"))) { if (from < (maxSize - encodedEnter.size())) { int arrayStart = from + encodedEnter.size(); decoded = _lister->codec()->toUnicode(chunk.mid(arrayStart, lastEnter - arrayStart)); sizeY -= ((decoded.length() / (_sizeX + 1)) + 1); if (sizeY < 0) { from = arrayStart; break; } } lastEnter = from; } } qint64 searchPos = readPos + from; QList locs; while (searchPos < _screenStartPos) { locs << searchPos; readLines(searchPos, searchPos, 1); } if (locs.count() >= _sizeY) { _screenStartPos = locs[ locs.count() - _sizeY ]; } else if (from != 0) { origSizeY += locs.count() + 1; sizeY = origSizeY; readNext = true; } else if (readPos == 0) { _screenStartPos = 0; } } } break; case QAbstractSlider::SliderToMinimum: _screenStartPos = 0; break; case QAbstractSlider::SliderToMaximum: _screenStartPos = _lastPageStartPos; break; case QAbstractSlider::SliderMove: { if (_inSliderOp) // self created call? return; qint64 pos = _lister->scrollBar()->sliderPosition(); if (pos == SLIDER_MAX) { _screenStartPos = _lastPageStartPos; break; } else if (pos == 0) { _screenStartPos = 0; break; } if (_lastPageStartPos > SLIDER_MAX) pos = _lastPageStartPos * pos / SLIDER_MAX; if (pos != 0) { if (_hexMode) { const int bytesPerRow = _lister->hexBytesPerLine(_sizeX); pos = (pos / bytesPerRow) * bytesPerRow; } else { const int maxSize = _sizeX * _sizeY * MAX_CHAR_LENGTH; qint64 readPos = pos - maxSize; if (readPos < 0) readPos = 0; qint64 previousPos = readPos; while (readPos <= pos) { previousPos = readPos; readLines(readPos, readPos, 1); } pos = previousPos; } } _screenStartPos = pos; } break; case QAbstractSlider::SliderNoAction: break; }; _inSliderOp = true; const int value = (_lastPageStartPos > SLIDER_MAX) ? SLIDER_MAX * _screenStartPos / _lastPageStartPos : _screenStartPos; _lister->scrollBar()->setSliderPosition(value); _inSliderOp = false; redrawTextArea(); } void ListerTextArea::redrawTextArea(bool forcedUpdate) { if (_redrawing) { return; } _redrawing = true; bool isfirst; const qint64 pos = getCursorPosition(isfirst); calculateText(forcedUpdate); setCursorPositionInDocument(pos, isfirst); _redrawing = false; } void ListerTextArea::ensureVisibleCursor() { if (_screenStartPos <= _cursorPos && _cursorPos <= _screenEndPos) { return; } int delta = _sizeY / 2; if (delta == 0) delta++; qint64 newScreenStart = _cursorPos; while (delta) { const int maxSize = _sizeX * MAX_CHAR_LENGTH; qint64 readPos = newScreenStart - maxSize; if (readPos < 0) readPos = 0; qint64 previousPos = readPos; while (readPos < newScreenStart) { previousPos = readPos; readLines(readPos, readPos, 1); if (readPos == previousPos) break; } newScreenStart = previousPos; delta--; } if (newScreenStart > _lastPageStartPos) { newScreenStart = _lastPageStartPos; } _screenStartPos = newScreenStart; slotActionTriggered(QAbstractSlider::SliderNoAction); } void ListerTextArea::setAnchorAndCursor(qint64 anchor, qint64 cursor) { _cursorPos = cursor; _cursorAnchorPos = anchor; ensureVisibleCursor(); setCursorPositionInDocument(cursor, false); } QString ListerTextArea::getSelectedText() { if (_cursorAnchorPos != -1 && _cursorAnchorPos != _cursorPos) { return readSection(_cursorAnchorPos, _cursorPos); } return QString(); } void ListerTextArea::copySelectedToClipboard() { const QString selection = getSelectedText(); if (!selection.isEmpty()) { QApplication::clipboard()->setText(selection); } } void ListerTextArea::clearSelection() { QTextCursor cursor = textCursor(); cursor.clearSelection(); setTextCursor(cursor); _cursorAnchorPos = -1; } void ListerTextArea::performAnchorChange(int anchor) { int x, y; bool isfirst; getScreenPosition(anchor, x, y); _cursorAnchorPos = textToFilePositionOnScreen(x, y, isfirst); } void ListerTextArea::handleAnchorChange(int oldAnchor) { const int anchor = textCursor().anchor(); if (oldAnchor != anchor) { performAnchorChange(anchor); } } void ListerTextArea::setHexMode(bool hexMode) { bool isfirst; const qint64 pos = getCursorPosition(isfirst); _hexMode = hexMode; _screenStartPos = 0; calculateText(true); setCursorPositionInDocument(pos, isfirst); ensureVisibleCursor(); } void ListerTextArea::zoomIn(int range) { KTextEdit::zoomIn(range); redrawTextArea(); } void ListerTextArea::zoomOut(int range) { KTextEdit::zoomOut(range); redrawTextArea(); } ListerPane::ListerPane(Lister *lister, QWidget *parent) : QWidget(parent), _lister(lister) { } bool ListerPane::event(QEvent *e) { const bool handled = ListerPane::handleCloseEvent(e); if (!handled) { return QWidget::event(e); } return true; } bool ListerPane::handleCloseEvent(QEvent *e) { if (e->type() == QEvent::ShortcutOverride) { QKeyEvent *ke = static_cast(e); if (ke->key() == Qt::Key_Escape) { if (_lister->isSearchEnabled()) { _lister->searchDelete(); _lister->enableSearch(false); ke->accept(); return true; } if (!_lister->textArea()->getSelectedText().isEmpty()) { _lister->textArea()->clearSelection(); ke->accept(); return true; } } } return false; } ListerBrowserExtension::ListerBrowserExtension(Lister * lister) : KParts::BrowserExtension(lister) { _lister = lister; emit enableAction("copy", true); emit enableAction("print", true); } void ListerBrowserExtension::copy() { _lister->textArea()->copySelectedToClipboard(); } void ListerBrowserExtension::print() { _lister->print(); } class ListerEncodingMenu : public KrRemoteEncodingMenu { public: ListerEncodingMenu(Lister *lister, const QString &text, const QString &icon, KActionCollection *parent) : KrRemoteEncodingMenu(text, icon, parent), _lister(lister) { } protected: virtual QString currentCharacterSet() { return _lister->characterSet(); } virtual void chooseDefault() { _lister->setCharacterSet(QString()); } virtual void chooseEncoding(QString encodingName) { QString charset = KCharsets::charsets()->encodingForName(encodingName); _lister->setCharacterSet(charset); } Lister * _lister; }; Lister::Lister(QWidget *parent) : KParts::ReadOnlyPart(parent) { setXMLFile("krusaderlisterui.rc"); - _actionSaveSelected = new QAction(QIcon::fromTheme("document-save"), i18n("Save selection..."), this); + _actionSaveSelected = new QAction(Icon("document-save"), i18n("Save selection..."), this); connect(_actionSaveSelected, SIGNAL(triggered(bool)), SLOT(saveSelected())); actionCollection()->addAction("save_selected", _actionSaveSelected); - _actionSaveAs = new QAction(QIcon::fromTheme("document-save-as"), i18n("Save as..."), this); + _actionSaveAs = new QAction(Icon("document-save-as"), i18n("Save as..."), this); connect(_actionSaveAs, SIGNAL(triggered(bool)), SLOT(saveAs())); actionCollection()->addAction("save_as", _actionSaveAs); - _actionPrint = new QAction(QIcon::fromTheme("document-print"), i18n("Print..."), this); + _actionPrint = new QAction(Icon("document-print"), i18n("Print..."), this); connect(_actionPrint, SIGNAL(triggered(bool)), SLOT(print())); actionCollection()->addAction("print", _actionPrint); actionCollection()->setDefaultShortcut(_actionPrint, Qt::CTRL + Qt::Key_P); - _actionSearch = new QAction(QIcon::fromTheme("system-search"), i18n("Search"), this); + _actionSearch = new QAction(Icon("system-search"), i18n("Search"), this); connect(_actionSearch, SIGNAL(triggered(bool)), SLOT(searchAction())); actionCollection()->addAction("search", _actionSearch); actionCollection()->setDefaultShortcut(_actionSearch, Qt::CTRL + Qt::Key_F); - _actionSearchNext = new QAction(QIcon::fromTheme("go-down"), i18n("Search next"), this); + _actionSearchNext = new QAction(Icon("go-down"), i18n("Search next"), this); connect(_actionSearchNext, SIGNAL(triggered(bool)), SLOT(searchNext())); actionCollection()->addAction("search_next", _actionSearchNext); actionCollection()->setDefaultShortcut(_actionSearchNext, Qt::Key_F3); - _actionSearchPrev = new QAction(QIcon::fromTheme("go-up"), i18n("Search previous"), this); + _actionSearchPrev = new QAction(Icon("go-up"), i18n("Search previous"), this); connect(_actionSearchPrev, SIGNAL(triggered(bool)), SLOT(searchPrev())); actionCollection()->addAction("search_prev", _actionSearchPrev); actionCollection()->setDefaultShortcut(_actionSearchPrev, Qt::SHIFT + Qt::Key_F3); - _actionJumpToPosition = new QAction(QIcon::fromTheme("go-jump"), i18n("Jump to position"), this); + _actionJumpToPosition = new QAction(Icon("go-jump"), i18n("Jump to position"), this); connect(_actionJumpToPosition, SIGNAL(triggered(bool)), SLOT(jumpToPosition())); actionCollection()->addAction("jump_to_position", _actionJumpToPosition); actionCollection()->setDefaultShortcut(_actionJumpToPosition, Qt::CTRL + Qt::Key_G); - _actionHexMode = new QAction(QIcon::fromTheme("document-preview"), i18n("Hex mode"), this); + _actionHexMode = new QAction(Icon("document-preview"), i18n("Hex mode"), this); connect(_actionHexMode, SIGNAL(triggered(bool)), SLOT(toggleHexMode())); actionCollection()->addAction("hex_mode", _actionHexMode); actionCollection()->setDefaultShortcut(_actionHexMode, Qt::CTRL + Qt::Key_H); new ListerEncodingMenu(this, i18n("Select charset"), "character-set", actionCollection()); QWidget * widget = new ListerPane(this, parent); widget->setFocusPolicy(Qt::StrongFocus); QGridLayout *grid = new QGridLayout(widget); _textArea = new ListerTextArea(this, widget); _textArea->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); _textArea->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard); _textArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); _textArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); widget->setFocusProxy(_textArea); grid->addWidget(_textArea, 0, 0); _scrollBar = new QScrollBar(Qt::Vertical, widget); grid->addWidget(_scrollBar, 0, 1); _scrollBar->hide(); QWidget * statusWidget = new QWidget(widget); QHBoxLayout *hbox = new QHBoxLayout(statusWidget); _listerLabel = new QLabel(i18n("Lister:"), statusWidget); hbox->addWidget(_listerLabel); _searchProgressBar = new QProgressBar(statusWidget); _searchProgressBar->setMinimum(0); _searchProgressBar->setMaximum(1000); _searchProgressBar->setValue(0); _searchProgressBar->hide(); hbox->addWidget(_searchProgressBar); _searchStopButton = new QToolButton(statusWidget); - _searchStopButton->setIcon(QIcon::fromTheme("process-stop")); + _searchStopButton->setIcon(Icon("process-stop")); _searchStopButton->setToolTip(i18n("Stop search")); _searchStopButton->hide(); connect(_searchStopButton, SIGNAL(clicked()), this, SLOT(searchDelete())); hbox->addWidget(_searchStopButton); _searchLineEdit = new KLineEdit(statusWidget); _searchLineEdit->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); _originalBackground = _searchLineEdit->palette().color(QPalette::Base); _originalForeground = _searchLineEdit->palette().color(QPalette::Text); connect(_searchLineEdit, SIGNAL(returnPressed()), this, SLOT(searchNext())); connect(_searchLineEdit, SIGNAL(textChanged(QString)), this, SLOT(searchTextChanged())); hbox->addWidget(_searchLineEdit); - _searchNextButton = new QPushButton(QIcon::fromTheme("go-down"), i18n("Next"), statusWidget); + _searchNextButton = new QPushButton(Icon("go-down"), i18n("Next"), statusWidget); _searchNextButton->setToolTip(i18n("Jump to next match")); connect(_searchNextButton, SIGNAL(clicked()), this, SLOT(searchNext())); hbox->addWidget(_searchNextButton); - _searchPrevButton = new QPushButton(QIcon::fromTheme("go-up"), i18n("Previous"), statusWidget); + _searchPrevButton = new QPushButton(Icon("go-up"), i18n("Previous"), statusWidget); _searchPrevButton->setToolTip(i18n("Jump to previous match")); connect(_searchPrevButton, SIGNAL(clicked()), this, SLOT(searchPrev())); hbox->addWidget(_searchPrevButton); _searchOptions = new QPushButton(i18n("Options"), statusWidget); _searchOptions->setToolTip(i18n("Modify search behavior")); QMenu * menu = new QMenu(); _fromCursorAction = menu->addAction(i18n("From cursor")); _fromCursorAction->setCheckable(true); _fromCursorAction->setChecked(true); _caseSensitiveAction = menu->addAction(i18n("Case sensitive")); _caseSensitiveAction->setCheckable(true); _matchWholeWordsOnlyAction = menu->addAction(i18n("Match whole words only")); _matchWholeWordsOnlyAction->setCheckable(true); _regExpAction = menu->addAction(i18n("RegExp")); _regExpAction->setCheckable(true); _hexAction = menu->addAction(i18n("Hexadecimal")); _hexAction->setCheckable(true); _searchOptions->setMenu(menu); hbox->addWidget(_searchOptions); hbox->addItem(new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum)); _statusLabel = new QLabel(statusWidget); hbox->addWidget(_statusLabel); grid->addWidget(statusWidget, 1, 0, 1, 2); setWidget(widget); connect(_scrollBar, SIGNAL(actionTriggered(int)), _textArea, SLOT(slotActionTriggered(int))); connect(&_searchUpdateTimer, &QTimer::timeout, this, &Lister::slotUpdate); new ListerBrowserExtension(this); enableSearch(false); _tempFile = new QTemporaryFile(this); _tempFile->setFileTemplate(QDir::tempPath() + QLatin1String("/krusader_lister.XXXXXX")); } bool Lister::openUrl(const QUrl &listerUrl) { _downloading = false; setUrl(listerUrl); _fileSize = 0; if (listerUrl.isLocalFile()) { _filePath = listerUrl.path(); if (!QFile::exists(_filePath)) return false; _fileSize = getFileSize(); } else { if (_tempFile->isOpen()) { _tempFile->close(); } _tempFile->open(); _filePath = _tempFile->fileName(); KIO::TransferJob *downloadJob = KIO::get(listerUrl, KIO::NoReload, KIO::HideProgressInfo); connect(downloadJob, &KIO::TransferJob::data, this, [=](KIO::Job*, QByteArray array) { if (array.size() != 0) { _tempFile->write(array); } }); connect(downloadJob, &KIO::TransferJob::result, this, [=](KJob *job) { _tempFile->flush(); if (job->error()) { /* any error occurred? */ KIO::TransferJob *kioJob = (KIO::TransferJob *)job; KMessageBox::error(_textArea, i18n("Error reading file %1.", kioJob->url().toDisplayString(QUrl::PreferLocalFile))); } _downloading = false; _downloadUpdateTimer.stop(); slotUpdate(); }); connect(&_downloadUpdateTimer, &QTimer::timeout, this, [&]() { slotUpdate(); }); _downloadUpdateTimer.start(500); _downloading = true; } // invalidate cache _cache.clear(); _textArea->reset(); emit started(0); emit setWindowCaption(listerUrl.toDisplayString()); emit completed(); return true; } QByteArray Lister::cacheChunk(const qint64 filePos, const int maxSize) { if (filePos >= _fileSize) { return QByteArray(); } int size = maxSize; if (_fileSize - filePos < size) { size = _fileSize - filePos; } if (!_cache.isEmpty() && (filePos >= _cachePos) && (filePos + size <= _cachePos + _cache.size())) { return _cache.mid(filePos - _cachePos, size); } const int negativeOffset = CACHE_SIZE * 2 / 5; qint64 cachePos = filePos - negativeOffset; if (cachePos < 0) cachePos = 0; QFile sourceFile(_filePath); if (!sourceFile.open(QIODevice::ReadOnly)) { return QByteArray(); } if (!sourceFile.seek(cachePos)) { return QByteArray(); } const QByteArray bytes = sourceFile.read(CACHE_SIZE); if (bytes.isEmpty()) { return bytes; } _cache = bytes; _cachePos = cachePos; const qint64 cacheRefIndex = filePos - _cachePos; int newSize = bytes.size() - cacheRefIndex; if (newSize < size) size = newSize; return _cache.mid(cacheRefIndex, size); } qint64 Lister::getFileSize() { return QFile(_filePath).size(); } void Lister::guiActivateEvent(KParts::GUIActivateEvent * event) { if (event->activated()) { slotUpdate(); _textArea->redrawTextArea(true); } else { enableSearch(false); } KParts::ReadOnlyPart::guiActivateEvent(event); } void Lister::slotUpdate() { const qint64 oldSize = _fileSize; _fileSize = getFileSize(); if (oldSize != _fileSize) _textArea->sizeChanged(); int cursorX = 0, cursorY = 0; _textArea->getCursorPosition(cursorX, cursorY); bool isfirst = false; const qint64 cursor = _textArea->getCursorPosition(isfirst); const int percent = (_fileSize == 0) ? 0 : (int)((201 * cursor) / _fileSize / 2); const QString status = i18n("Column: %1, Position: %2 (%3, %4%)", cursorX, cursor, _fileSize, percent); _statusLabel->setText(status); if (_searchProgressCounter) _searchProgressCounter--; } bool Lister::isSearchEnabled() { return !_searchLineEdit->isHidden() || !_searchProgressBar->isHidden(); } void Lister::enableSearch(const bool enable) { if (enable) { _listerLabel->setText(i18n("Search:")); _searchLineEdit->show(); _searchNextButton->show(); _searchPrevButton->show(); _searchOptions->show(); if (!_searchLineEdit->hasFocus()) { _searchLineEdit->setFocus(); const QString selection = _textArea->getSelectedText(); if (!selection.isEmpty()) { _searchLineEdit->setText(selection); } _searchLineEdit->selectAll(); } } else { _listerLabel->setText(i18n("Lister:")); _searchLineEdit->hide(); _searchNextButton->hide(); _searchPrevButton->hide(); _searchOptions->hide(); _textArea->setFocus(); } } void Lister::searchNext() { search(true); } void Lister::searchPrev() { search(false); } void Lister::search(const bool forward, const bool restart) { _restartFromBeginning = restart; if (_searchInProgress || _searchLineEdit->text().isEmpty()) return; if (_searchLineEdit->isHidden()) enableSearch(true); _searchPosition = forward ? 0 : _fileSize; if (_fromCursorAction->isChecked()) { bool isfirst; qint64 cursor = _textArea->getCursorPosition(isfirst); if (cursor != 0 && !forward) cursor--; if (_searchLastFailedPosition == -1 || _searchLastFailedPosition != cursor) _searchPosition = cursor; } const bool caseSensitive = _caseSensitiveAction->isChecked(); const bool matchWholeWord = _matchWholeWordsOnlyAction->isChecked(); const bool regExp = _regExpAction->isChecked(); const bool hex = _hexAction->isChecked(); if (hex) { QString hexcontent = _searchLineEdit->text(); hexcontent.remove(QLatin1String("0x")); hexcontent.remove(' '); hexcontent.remove('\t'); hexcontent.remove('\n'); hexcontent.remove('\r'); _searchHexQuery = QByteArray(); if (hexcontent.length() & 1) { setColor(false, false); return; } while (!hexcontent.isEmpty()) { const QString hexData = hexcontent.left(2); hexcontent = hexcontent.mid(2); bool ok = true; const int c = hexData.toUInt(&ok, 16); if (!ok) { setColor(false, false); return; } _searchHexQuery.push_back((char) c); } } else { _searchQuery.setContent(_searchLineEdit->text(), caseSensitive, matchWholeWord, codec()->name(), regExp); } _searchIsForward = forward; _searchHexadecimal = hex; QTimer::singleShot(0, this, SLOT(slotSearchMore())); _searchInProgress = true; _searchProgressCounter = 3; enableActions(false); } void Lister::enableActions(const bool state) { _actionSearch->setEnabled(state); _actionSearchNext->setEnabled(state); _actionSearchPrev->setEnabled(state); _actionJumpToPosition->setEnabled(state); if (state) { _searchUpdateTimer.stop(); } else { slotUpdate(); } } void Lister::slotSearchMore() { if (!_searchInProgress) return; if (!_searchUpdateTimer.isActive()) { _searchUpdateTimer.start(200); } updateProgressBar(); if (!_searchIsForward) _searchPosition--; if (_searchPosition < 0 || _searchPosition >= _fileSize) { if (_restartFromBeginning) resetSearchPosition(); else { searchFailed(); return; } } int maxCacheSize = SEARCH_CACHE_CHARS; qint64 searchPos = _searchPosition; bool setPosition = true; if (!_searchIsForward) { qint64 origSearchPos = _searchPosition; searchPos -= maxCacheSize; if (searchPos <= 0) { searchPos = 0; _searchPosition = 0; setPosition = false; } qint64 diff = origSearchPos - searchPos; if (diff < maxCacheSize) maxCacheSize = diff; } const QByteArray chunk = cacheChunk(searchPos, maxCacheSize); if (chunk.isEmpty()) { searchFailed(); return; } const int chunkSize = chunk.size(); qint64 foundAnchor = -1; qint64 foundCursor = -1; int byteCounter = 0; if (_searchHexadecimal) { const int ndx = _searchIsForward ? chunk.indexOf(_searchHexQuery) : chunk.lastIndexOf(_searchHexQuery); if (chunkSize > _searchHexQuery.length()) { if (_searchIsForward) { _searchPosition = searchPos + chunkSize; if ((_searchPosition < _fileSize) && (chunkSize > _searchHexQuery.length())) _searchPosition -= _searchHexQuery.length(); byteCounter = _searchPosition - searchPos; } else { if (_searchPosition > 0) _searchPosition += _searchHexQuery.length(); } } if (ndx != -1) { foundAnchor = searchPos + ndx; foundCursor = foundAnchor + _searchHexQuery.length(); } } else { int rowStart = 0; QString row = ""; QScopedPointer decoder(_codec->makeDecoder()); while (byteCounter < chunkSize) { const QString chr = decoder->toUnicode(chunk.mid(byteCounter++, 1)); if (chr.isEmpty() && byteCounter < chunkSize) { continue; } if (chr != "\n") row += chr; if (chr == "\n" || row.length() >= SEARCH_MAX_ROW_LEN || byteCounter >= chunkSize) { if (setPosition) { _searchPosition = searchPos + byteCounter; if (!_searchIsForward) { _searchPosition++; setPosition = false; } } if (_searchQuery.checkLine(row, !_searchIsForward)) { QByteArray cachedBuffer = chunk.mid(rowStart, chunkSize - rowStart); QTextStream stream(&cachedBuffer); stream.setCodec(_codec); stream.read(_searchQuery.matchIndex()); foundAnchor = searchPos + rowStart + stream.pos(); stream.read(_searchQuery.matchLength()); foundCursor = searchPos + rowStart + stream.pos(); if (_searchIsForward) break; } row = ""; rowStart = byteCounter; } } } if (foundAnchor != -1 && foundCursor != -1) { _textArea->setAnchorAndCursor(foundAnchor, foundCursor); searchSucceeded(); return; } if (_searchIsForward && searchPos + byteCounter >= _fileSize) { if (_restartFromBeginning) resetSearchPosition(); else { searchFailed(); return; } } else if (_searchPosition <= 0 || _searchPosition >= _fileSize) { if (_restartFromBeginning) resetSearchPosition(); else { searchFailed(); return; } } QTimer::singleShot(0, this, SLOT(slotSearchMore())); } void Lister::resetSearchPosition() { _restartFromBeginning = false; _searchPosition = _searchIsForward ? 0 : _fileSize - 1; } void Lister::searchSucceeded() { _searchInProgress = false; setColor(true, false); hideProgressBar(); _searchLastFailedPosition = -1; enableActions(true); } void Lister::searchFailed() { _searchInProgress = false; setColor(false, false); hideProgressBar(); bool isfirst; _searchLastFailedPosition = _textArea->getCursorPosition(isfirst); if (!_searchIsForward) _searchLastFailedPosition--; enableActions(true); } void Lister::searchDelete() { _searchInProgress = false; setColor(false, true); hideProgressBar(); _searchLastFailedPosition = -1; enableActions(true); } void Lister::searchTextChanged() { searchDelete(); if (_fileSize < 0x10000) { // autosearch files less than 64k if (!_searchLineEdit->text().isEmpty()) { bool isfirst; const qint64 anchor = _textArea->getCursorAnchor(); const qint64 cursor = _textArea->getCursorPosition(isfirst); if (cursor > anchor && anchor != -1) { _textArea->setCursorPositionInDocument(anchor, true); } search(true, true); } } } void Lister::setColor(const bool match, const bool restore) { QColor fore, back; if (!restore) { const KConfigGroup gc(krConfig, "Colors"); QString foreground, background; const QPalette p = QGuiApplication::palette(); if (match) { foreground = "Quicksearch Match Foreground"; background = "Quicksearch Match Background"; fore = Qt::black; back = QColor(192, 255, 192); } else { foreground = "Quicksearch Non-match Foreground"; background = "Quicksearch Non-match Background"; fore = Qt::black; back = QColor(255, 192, 192); } if (gc.readEntry(foreground, QString()) == "KDE default") fore = p.color(QPalette::Active, QPalette::Text); else if (!gc.readEntry(foreground, QString()).isEmpty()) fore = gc.readEntry(foreground, fore); if (gc.readEntry(background, QString()) == "KDE default") back = p.color(QPalette::Active, QPalette::Base); else if (!gc.readEntry(background, QString()).isEmpty()) back = gc.readEntry(background, back); } else { back = _originalBackground; fore = _originalForeground; } QPalette pal = _searchLineEdit->palette(); pal.setColor(QPalette::Base, back); pal.setColor(QPalette::Text, fore); _searchLineEdit->setPalette(pal); } void Lister::hideProgressBar() { if (!_searchProgressBar->isHidden()) { _searchProgressBar->hide(); _searchStopButton->hide(); _searchLineEdit->show(); _searchNextButton->show(); _searchPrevButton->show(); _searchOptions->show(); _listerLabel->setText(i18n("Search:")); } } void Lister::updateProgressBar() { if (_searchProgressCounter) return; if (_searchProgressBar->isHidden()) { _searchProgressBar->show(); _searchStopButton->show(); _searchOptions->hide(); _searchLineEdit->hide(); _searchNextButton->hide(); _searchPrevButton->hide(); _listerLabel->setText(i18n("Search position:")); // otherwise focus is set to document tab _textArea->setFocus(); } const qint64 pcnt = (_fileSize == 0) ? 1000 : (2001 * _searchPosition) / _fileSize / 2; const int pctInt = (int) pcnt; if (_searchProgressBar->value() != pctInt) _searchProgressBar->setValue(pctInt); } void Lister::jumpToPosition() { bool ok = true; QString res = QInputDialog::getText(_textArea, i18n("Jump to position"), i18n("Text position:"), QLineEdit::Normal, "0", &ok); if (!ok) return; res = res.trimmed(); qint64 pos = -1; if (res.startsWith(QLatin1String("0x"))) { res = res.mid(2); bool ok; const qulonglong upos = res.toULongLong(&ok, 16); if (!ok) { KMessageBox::error(_textArea, i18n("Invalid number."), i18n("Jump to position")); return; } pos = (qint64)upos; } else { bool ok; const qulonglong upos = res.toULongLong(&ok); if (!ok) { KMessageBox::error(_textArea, i18n("Invalid number."), i18n("Jump to position")); return; } pos = (qint64)upos; } if (pos < 0 || pos > _fileSize) { KMessageBox::error(_textArea, i18n("Number out of range."), i18n("Jump to position")); return; } _textArea->deleteAnchor(); _textArea->setCursorPositionInDocument(pos, true); _textArea->ensureVisibleCursor(); } void Lister::saveAs() { const QUrl url = QFileDialog::getSaveFileUrl(_textArea, i18n("Lister")); if (url.isEmpty()) return; QUrl sourceUrl; if (!_downloading) sourceUrl = QUrl::fromLocalFile(_filePath); else sourceUrl = this->url(); QList urlList; urlList << sourceUrl; KIO::Job *job = KIO::copy(urlList, url); job->setUiDelegate(new KIO::JobUiDelegate()); KIO::getJobTracker()->registerJob(job); job->uiDelegate()->setAutoErrorHandlingEnabled(true); } void Lister::saveSelected() { bool isfirst; const qint64 start = _textArea->getCursorAnchor(); const qint64 end = _textArea->getCursorPosition(isfirst); if (start == -1 || start == end) { KMessageBox::error(_textArea, i18n("Nothing is selected."), i18n("Save selection...")); return; } if (start > end) { _savePosition = end; _saveEnd = start; } else { _savePosition = start; _saveEnd = end; } const QUrl url = QFileDialog::getSaveFileUrl(_textArea, i18n("Lister")); if (url.isEmpty()) return; KIO::Job *saveJob = KIO::put(url, -1, KIO::Overwrite); connect(saveJob, SIGNAL(dataReq(KIO::Job*,QByteArray&)), this, SLOT(slotDataSend(KIO::Job*,QByteArray&))); connect(saveJob, SIGNAL(result(KJob*)), this, SLOT(slotSendFinished(KJob*))); saveJob->setUiDelegate(new KIO::JobUiDelegate()); KIO::getJobTracker()->registerJob(saveJob); saveJob->uiDelegate()->setAutoErrorHandlingEnabled(true); _actionSaveSelected->setEnabled(false); } void Lister::slotDataSend(KIO::Job *, QByteArray &array) { if (_savePosition >= _saveEnd) { array = QByteArray(); return; } qint64 max = _saveEnd - _savePosition; if (max > 1000) max = 1000; array = cacheChunk(_savePosition, (int) max); _savePosition += array.size(); } void Lister::slotSendFinished(KJob *) { _actionSaveSelected->setEnabled(true); } void Lister::setCharacterSet(const QString set) { _characterSet = set; if (_characterSet.isEmpty()) { _codec = QTextCodec::codecForLocale(); } else { _codec = KCharsets::charsets()->codecForName(_characterSet); } _textArea->redrawTextArea(true); } void Lister::print() { bool isfirst; const qint64 anchor = _textArea->getCursorAnchor(); const qint64 cursor = _textArea->getCursorPosition(isfirst); const bool hasSelection = (anchor != -1 && anchor != cursor); const QString docName = url().fileName(); QPrinter printer; printer.setDocName(docName); QScopedPointer printDialog(new QPrintDialog(&printer, _textArea)); if (hasSelection) { printDialog->addEnabledOption(QAbstractPrintDialog::PrintSelection); } if (!printDialog->exec()) { return; } if (printer.pageOrder() == QPrinter::LastPageFirst) { switch (KMessageBox::warningContinueCancel(_textArea, i18n("Reverse printing is not supported. Continue with normal printing?"))) { case KMessageBox::Continue : break; default: return; } } QPainter painter; painter.begin(&printer); const QString dateString = QDate::currentDate().toString(Qt::SystemLocaleShortDate); const QRect pageRect = printer.pageRect(); const QRect drawingRect(0, 0, pageRect.width(), pageRect.height()); const QFont normalFont = QFontDatabase::systemFont(QFontDatabase::GeneralFont); const QFont fixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); const QFontMetrics fmNormal(normalFont); const int normalFontHeight = fmNormal.height(); const QFontMetrics fmFixed(fixedFont); const int fixedFontHeight = std::max(fmFixed.height(), 1); const int fixedFontWidth = std::max(fmFixed.width("W"), 1); const int effPageSize = drawingRect.height() - normalFontHeight - 1; const int rowsPerPage = std::max(effPageSize / fixedFontHeight, 1); const int columnsPerPage = std::max(drawingRect.width() / fixedFontWidth, 1); bool firstPage = true; qint64 startPos = 0; qint64 endPos = _fileSize; if (printer.printRange() == QPrinter::Selection) { if (anchor > cursor) startPos = cursor, endPos = anchor; else startPos = anchor, endPos = cursor; } int page = 0; while (startPos < endPos) { page++; QStringList rows = readLines(startPos, endPos, columnsPerPage, rowsPerPage); // print since set-up fromPage number if (printer.fromPage() && page < printer.fromPage()) { continue; } // print until set-up toPage number if (printer.toPage() && printer.toPage() >= printer.fromPage() && page > printer.toPage()) break; if (!firstPage) { printer.newPage(); } firstPage = false; // Use the painter to draw on the page. painter.setFont(normalFont); painter.drawText(drawingRect, Qt::AlignLeft, dateString); painter.drawText(drawingRect, Qt::AlignHCenter, docName); painter.drawText(drawingRect, Qt::AlignRight, QString("%1").arg(page)); painter.drawLine(0, normalFontHeight, drawingRect.width(), normalFontHeight); painter.setFont(fixedFont); int yOffset = normalFontHeight + 1; foreach (const QString &row, rows) { painter.drawText(0, yOffset + fixedFontHeight, row); yOffset += fixedFontHeight; } } } QStringList Lister::readLines(qint64 &filePos, const qint64 endPos, const int columns, const int lines) { if (_textArea->hexMode()) { return readHexLines(filePos, endPos, columns, lines); } QStringList list; const int maxBytes = std::min(columns * lines * MAX_CHAR_LENGTH, (int) (endPos - filePos)); if (maxBytes <= 0) { return list; } const QByteArray chunk = cacheChunk(filePos, maxBytes); if (chunk.isEmpty()) { return list; } QScopedPointer decoder(_codec->makeDecoder()); int byteCounter = 0; QString row = ""; bool skipImmediateNewline = false; while (byteCounter < chunk.size() && list.size() < lines) { QString chr = decoder->toUnicode(chunk.mid(byteCounter++, 1)); if (chr.isEmpty()) { continue; } // replace unreadable characters if ((chr[ 0 ] < 32) && (chr[ 0 ] != '\n') && (chr[ 0 ] != '\t')) { chr = QChar(' '); } // handle newline if (chr == "\n") { if (!skipImmediateNewline) { list << row; row = ""; } skipImmediateNewline = false; continue; } skipImmediateNewline = false; // handle tab if (chr == "\t") { const int tabLength = _textArea->tabWidth() - (row.length() % _textArea->tabWidth()); if (row.length() + tabLength > columns) { list << row; row = ""; } row += QString(tabLength, QChar(' ')); } else { // normal printable character row += chr; } if (row.length() >= columns) { list << row; row = ""; skipImmediateNewline = true; } } if (list.size() < lines) { list << row; } filePos += byteCounter; return list; } int Lister::hexPositionDigits() { int positionDigits = 0; qint64 checker = _fileSize; while (checker) { positionDigits++; checker /= 16; } if (positionDigits < 8) { return 8; } return positionDigits; } int Lister::hexBytesPerLine(const int columns) { const int positionDigits = hexPositionDigits(); if (columns >= positionDigits + 5 + 128) { return 32; } if (columns >= positionDigits + 5 + 64) { return 16; } return 8; } QStringList Lister::readHexLines(qint64 &filePos, const qint64 endPos, const int columns, const int lines) { const int positionDigits = hexPositionDigits(); const int bytesPerRow = hexBytesPerLine(columns); QStringList list; const qint64 choppedPos = (filePos / bytesPerRow) * bytesPerRow; const int maxBytes = std::min(bytesPerRow * lines, (int) (endPos - choppedPos)); if (maxBytes <= 0) return list; const QByteArray chunk = cacheChunk(choppedPos, maxBytes); if (chunk.isEmpty()) return list; int cnt = 0; for (int l = 0; l < lines; l++) { if (filePos >= endPos) { break; } const qint64 printPos = (filePos / bytesPerRow) * bytesPerRow; QString pos; pos.setNum(printPos, 16); while (pos.length() < positionDigits) pos = QString("0") + pos; pos = QString("0x") + pos; pos += QString(": "); QString charData; for (int i = 0; i != bytesPerRow; ++i, ++cnt) { const qint64 currentPos = printPos + i; if (currentPos < filePos || currentPos >= endPos) { pos += QString(" "); charData += QString(" "); } else { char c = chunk.at(cnt); int charCode = (int)c; if (charCode < 0) charCode += 256; QString hex; hex.setNum(charCode, 16); if (hex.length() < 2) hex = QString("0") + hex; pos += hex + QString(" "); if (c < 32) c = '.'; charData += QChar(c); } } pos += QString(" ") + charData; list << pos; filePos = printPos + bytesPerRow; } if (filePos > endPos) { filePos = endPos; } return list; } int Lister::hexIndexToPosition(const int columns, const int index) { const int positionDigits = hexPositionDigits(); const int bytesPerRow = hexBytesPerLine(columns); const int finalIndex = std::min(index, bytesPerRow); return positionDigits + 4 + (3*finalIndex); } int Lister::hexPositionToIndex(const int columns, const int position) { const int positionDigits = hexPositionDigits(); const int bytesPerRow = hexBytesPerLine(columns); int finalPosition = position; finalPosition -= 4 + positionDigits; if (finalPosition <= 0) return 0; finalPosition /= 3; if (finalPosition >= bytesPerRow) return bytesPerRow; return finalPosition; } void Lister::toggleHexMode() { setHexMode(!_textArea->hexMode()); } void Lister::setHexMode(const bool mode) { if (mode) { _textArea->setHexMode(true); _actionHexMode->setText(i18n("Text mode")); } else { _textArea->setHexMode(false); _actionHexMode->setText(i18n("Hex mode")); } } diff --git a/krusader/Konfigurator/kggeneral.cpp b/krusader/Konfigurator/kggeneral.cpp index 0efb85be..ece73eab 100644 --- a/krusader/Konfigurator/kggeneral.cpp +++ b/krusader/Konfigurator/kggeneral.cpp @@ -1,331 +1,330 @@ /***************************************************************************** * Copyright (C) 2004 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/]. * *****************************************************************************/ #include "kggeneral.h" // QtCore #include // QtGui #include #include // QtWidgets #include #include #include #include #include #include -#include #include #include "krresulttabledialog.h" #include "../defaults.h" -#include "../kicons.h" +#include "../icon.h" #include "../krglobal.h" #define PAGE_GENERAL 0 #define PAGE_VIEWER 1 #define PAGE_EXTENSIONS 2 KgGeneral::KgGeneral(bool first, QWidget* parent) : KonfiguratorPage(first, parent) { if (first) slotFindTools(); tabWidget = new QTabWidget(this); setWidget(tabWidget); setWidgetResizable(true); createGeneralTab(); createViewerTab(); createExtensionsTab(); } QWidget* KgGeneral::createTab(QString name) { QScrollArea *scrollArea = new QScrollArea(tabWidget); tabWidget->addTab(scrollArea, name); scrollArea->setFrameStyle(QFrame::NoFrame); scrollArea->setWidgetResizable(true); QWidget *tab = new QWidget(scrollArea); scrollArea->setWidget(tab); return tab; } void KgGeneral::createViewerTab() { QWidget *tab = createTab(i18n("Viewer/Editor")); QGridLayout *tabLayout = new QGridLayout(tab); tabLayout->setSpacing(6); tabLayout->setContentsMargins(11, 11, 11, 11); tabLayout->addWidget(createCheckBox("General", "View In Separate Window", _ViewInSeparateWindow, i18n("Internal editor and viewer opens each file in a separate window"), tab, false, i18n("If checked, each file will open in a separate window, otherwise, the viewer will work in a single, tabbed mode"), PAGE_VIEWER)); // ------------------------- viewer ---------------------------------- QGroupBox *viewerGrp = createFrame(i18n("Viewer"), tab); tabLayout->addWidget(viewerGrp, 1, 0); QGridLayout *viewerGrid = createGridLayout(viewerGrp); QWidget * hboxWidget2 = new QWidget(viewerGrp); QHBoxLayout * hbox2 = new QHBoxLayout(hboxWidget2); QWidget * vboxWidget = new QWidget(hboxWidget2); QVBoxLayout * vbox = new QVBoxLayout(vboxWidget); vbox->addWidget(new QLabel(i18n("Default viewer mode:"), vboxWidget)); KONFIGURATOR_NAME_VALUE_TIP viewMode[] = // name value tooltip {{ i18n("Generic mode"), "generic", i18n("Use the system's default viewer") }, { i18n("Text mode"), "text", i18n("View the file in text-only mode") }, { i18n("Hex mode"), "hex", i18n("View the file in hex-mode (better for binary files)") }, { i18n("Lister mode"), "lister", i18n("View the file with lister (for huge text files)") } }; vbox->addWidget(createRadioButtonGroup("General", "Default Viewer Mode", "generic", 0, 4, viewMode, 4, vboxWidget, false, PAGE_VIEWER)); vbox->addWidget( createCheckBox("General", "UseOktetaViewer", _UseOktetaViewer, i18n("Use Okteta as Hex viewer"), vboxWidget, false, i18n("If available, use Okteta as Hex viewer instead of the internal viewer"), PAGE_VIEWER) ); QWidget * hboxWidget4 = new QWidget(vboxWidget); QHBoxLayout * hbox4 = new QHBoxLayout(hboxWidget4); QLabel *label5 = new QLabel(i18n("Use lister if the text file is bigger than:"), hboxWidget4); hbox4->addWidget(label5); KonfiguratorSpinBox *spinBox = createSpinBox("General", "Lister Limit", _ListerLimit, 0, 0x7FFFFFFF, hboxWidget4, false, PAGE_VIEWER); hbox4->addWidget(spinBox); QLabel *label6 = new QLabel(i18n("MB"), hboxWidget4); hbox4->addWidget(label6); vbox->addWidget(hboxWidget4); hbox2->addWidget(vboxWidget); viewerGrid->addWidget(hboxWidget2, 0, 0); // ------------------------- editor ---------------------------------- QGroupBox *editorGrp = createFrame(i18n("Editor"), tab); tabLayout->addWidget(editorGrp, 2, 0); QGridLayout *editorGrid = createGridLayout(editorGrp); QLabel *label1 = new QLabel(i18n("Editor:"), editorGrp); editorGrid->addWidget(label1, 0, 0); KonfiguratorURLRequester *urlReq = createURLRequester("General", "Editor", "internal editor", editorGrp, false, PAGE_VIEWER, false); editorGrid->addWidget(urlReq, 0, 1); QLabel *label2 = new QLabel(i18n("Hint: use 'internal editor' if you want to use Krusader's fast built-in editor"), editorGrp); editorGrid->addWidget(label2, 1, 0, 1, 2); } void KgGeneral::createExtensionsTab() { // ------------------------- atomic extensions ---------------------------------- QWidget *tab = createTab(i18n("Atomic extensions")); QGridLayout *tabLayout = new QGridLayout(tab); tabLayout->setSpacing(6); tabLayout->setContentsMargins(11, 11, 11, 11); QWidget * vboxWidget2 = new QWidget(tab); tabLayout->addWidget(vboxWidget2); QVBoxLayout * vbox2 = new QVBoxLayout(vboxWidget2); QWidget * hboxWidget3 = new QWidget(vboxWidget2); vbox2->addWidget(hboxWidget3); QHBoxLayout * hbox3 = new QHBoxLayout(hboxWidget3); QLabel * atomLabel = new QLabel(i18n("Atomic extensions:"), hboxWidget3); hbox3->addWidget(atomLabel); int size = QFontMetrics(atomLabel->font()).height(); QToolButton *addButton = new QToolButton(hboxWidget3); hbox3->addWidget(addButton); - QPixmap icon = krLoader->loadIcon("list-add", KIconLoader::Desktop, size); - addButton->setFixedSize(icon.width() + 4, icon.height() + 4); - addButton->setIcon(QIcon(icon)); + QPixmap iconPixmap = Icon("list-add").pixmap(size); + addButton->setFixedSize(iconPixmap.width() + 4, iconPixmap.height() + 4); + addButton->setIcon(QIcon(iconPixmap)); connect(addButton, SIGNAL(clicked()), this, SLOT(slotAddExtension())); QToolButton *removeButton = new QToolButton(hboxWidget3); hbox3->addWidget(removeButton); - icon = krLoader->loadIcon("list-remove", KIconLoader::Desktop, size); - removeButton->setFixedSize(icon.width() + 4, icon.height() + 4); - removeButton->setIcon(QIcon(icon)); + iconPixmap = Icon("list-remove").pixmap(size); + removeButton->setFixedSize(iconPixmap.width() + 4, iconPixmap.height() + 4); + removeButton->setIcon(QIcon(iconPixmap)); connect(removeButton, SIGNAL(clicked()), this, SLOT(slotRemoveExtension())); QStringList defaultAtomicExtensions; defaultAtomicExtensions += ".tar.gz"; defaultAtomicExtensions += ".tar.bz2"; defaultAtomicExtensions += ".tar.lzma"; defaultAtomicExtensions += ".tar.xz"; defaultAtomicExtensions += ".moc.cpp"; listBox = createListBox("Look&Feel", "Atomic Extensions", defaultAtomicExtensions, vboxWidget2, true, PAGE_EXTENSIONS); vbox2->addWidget(listBox); } void KgGeneral::createGeneralTab() { QWidget *tab = createTab(i18n("General")); QGridLayout *kgGeneralLayout = new QGridLayout(tab); kgGeneralLayout->setSpacing(6); kgGeneralLayout->setContentsMargins(11, 11, 11, 11); // -------------------------- GENERAL GROUPBOX ---------------------------------- QGroupBox *generalGrp = createFrame(i18n("General"), tab); QGridLayout *generalGrid = createGridLayout(generalGrp); KONFIGURATOR_CHECKBOX_PARAM settings[] = { // cfg_class cfg_name default text restart tooltip {"Look&Feel", "Warn On Exit", _WarnOnExit, i18n("Warn on exit"), false, i18n("Display a warning when trying to close the main window.") }, // KDE4: move warn on exit to the other confirmations {"Look&Feel", "Minimize To Tray", _ShowTrayIcon, i18n("Show and close to tray"), false, i18n("Show an icon in the system tray and keep running in the background when the window is closed.") }, }; KonfiguratorCheckBoxGroup *cbs = createCheckBoxGroup(2, 0, settings, 2 /*count*/, generalGrp, PAGE_GENERAL); generalGrid->addWidget(cbs, 0, 0); // temp dir QHBoxLayout *hbox = new QHBoxLayout(); hbox->addWidget(new QLabel(i18n("Temp Folder:"), generalGrp)); KonfiguratorURLRequester *urlReq3 = createURLRequester("General", "Temp Directory", _TempDirectory, generalGrp, false, PAGE_GENERAL); urlReq3->setMode(KFile::Directory); connect(urlReq3->extension(), SIGNAL(applyManually(QObject*,QString,QString)), this, SLOT(applyTempDir(QObject*,QString,QString))); hbox->addWidget(urlReq3); generalGrid->addLayout(hbox, 13, 0, 1, 1); QLabel *label4 = new QLabel(i18n("Note: you must have full permissions for the temporary folder."), generalGrp); generalGrid->addWidget(label4, 14, 0, 1, 1); kgGeneralLayout->addWidget(generalGrp, 0 , 0); // ----------------------- delete mode -------------------------------------- QGroupBox *delGrp = createFrame(i18n("Delete mode"), tab); QGridLayout *delGrid = createGridLayout(delGrp); KONFIGURATOR_NAME_VALUE_TIP deleteMode[] = // name value tooltip {{i18n("Move to trash"), "true", i18n("Files will be moved to trash when deleted.")}, {i18n("Delete files"), "false", i18n("Files will be permanently deleted.")} }; KonfiguratorRadioButtons *trashRadio = createRadioButtonGroup("General", "Move To Trash", _MoveToTrash ? "true" : "false", 2, 0, deleteMode, 2, delGrp, false, PAGE_GENERAL); delGrid->addWidget(trashRadio); kgGeneralLayout->addWidget(delGrp, 1 , 0); // ----------------------- terminal ----------------------------------------- QGroupBox *terminalGrp = createFrame(i18n("Terminal"), tab); QGridLayout *terminalGrid = createGridLayout(terminalGrp); QLabel *label3 = new QLabel(i18n("External Terminal:"), generalGrp); terminalGrid->addWidget(label3, 0, 0); KonfiguratorURLRequester *urlReq2 = createURLRequester("General", "Terminal", _Terminal, generalGrp, false, PAGE_GENERAL, false); terminalGrid->addWidget(urlReq2, 0, 1); QLabel *terminalLabel = new QLabel(i18n("%d will be replaced by the workdir."), terminalGrp); terminalGrid->addWidget(terminalLabel, 1, 1); KONFIGURATOR_CHECKBOX_PARAM terminal_settings[] = { // cfg_class cfg_name default text restart tooltip {"General", "Send CDs", _SendCDs, i18n("Embedded Terminal sends Chdir on panel change"), false, i18n("When checked, whenever the panel is changed (for example, by pressing Tab), Krusader changes the current folder in the embedded terminal.") }, }; cbs = createCheckBoxGroup(1, 0, terminal_settings, 1 /*count*/, terminalGrp, PAGE_GENERAL); terminalGrid->addWidget(cbs, 2, 0, 1, 2); kgGeneralLayout->addWidget(terminalGrp, 2 , 0); } void KgGeneral::applyTempDir(QObject *obj, QString configGroup, QString name) { KonfiguratorURLRequester *urlReq = (KonfiguratorURLRequester *)obj; QString value = urlReq->url().toDisplayString(QUrl::PreferLocalFile); KConfigGroup(krConfig, configGroup).writeEntry(name, value); } void KgGeneral::slotFindTools() { QPointer dlg = new KrResultTableDialog(this, KrResultTableDialog::Tool, i18n("Search results"), i18n("Searching for tools..."), "tools-wizard", i18n("Make sure to install new tools in your $PATH (e.g. /usr/bin)")); dlg->exec(); delete dlg; } void KgGeneral::slotAddExtension() { bool ok; QString atomExt = QInputDialog::getText(this, i18n("Add new atomic extension"), i18n("Extension:"), QLineEdit::Normal, QString(), &ok); if (ok) { if (!atomExt.startsWith('.') || atomExt.indexOf('.', 1) == -1) KMessageBox::error(krMainWindow, i18n("Atomic extensions must start with '.' and must contain at least one more '.' character."), i18n("Error")); else listBox->addItem(atomExt); } } void KgGeneral::slotRemoveExtension() { QList list = listBox->selectedItems(); for (int i = 0; i != list.count(); i++) listBox->removeItem(list[ i ]->text()); } diff --git a/krusader/Konfigurator/kgprotocols.cpp b/krusader/Konfigurator/kgprotocols.cpp index e3d42df9..51fd57b7 100644 --- a/krusader/Konfigurator/kgprotocols.cpp +++ b/krusader/Konfigurator/kgprotocols.cpp @@ -1,388 +1,389 @@ /***************************************************************************** * Copyright (C) 2004 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/]. * *****************************************************************************/ #include "kgprotocols.h" #include "../krglobal.h" +#include "../icon.h" #include "../krservices.h" // QtCore #include #include // QtWidgets #include #include #include #include #include #include -#include + KgProtocols::KgProtocols(bool first, QWidget* parent) : KonfiguratorPage(first, parent) { QGridLayout *KgProtocolsLayout = new QGridLayout(this); KgProtocolsLayout->setSpacing(6); // -------------------------- LINK VIEW ---------------------------------- QGroupBox *linkGrp = createFrame(i18n("Links"), this); QGridLayout *linkGrid = createGridLayout(linkGrp); QStringList labels; labels << i18n("Defined Links"); linkList = new KrTreeWidget(linkGrp); linkList->setHeaderLabels(labels); linkList->setRootIsDecorated(true); linkGrid->addWidget(linkList, 0, 0); KgProtocolsLayout->addWidget(linkGrp, 0, 0, 2, 1); // -------------------------- BUTTONS ---------------------------------- QWidget *vbox1Widget = new QWidget(this); QVBoxLayout *vbox1 = new QVBoxLayout(vbox1Widget); addSpacer(vbox1); btnAddProtocol = new QPushButton(vbox1Widget); - btnAddProtocol->setIcon(krLoader->loadIcon("arrow-left", KIconLoader::Small)); + btnAddProtocol->setIcon(Icon("arrow-left")); btnAddProtocol->setWhatsThis(i18n("Add protocol to the link list.")); vbox1->addWidget(btnAddProtocol); btnRemoveProtocol = new QPushButton(vbox1Widget); - btnRemoveProtocol->setIcon(krLoader->loadIcon("arrow-right", KIconLoader::Small)); + btnRemoveProtocol->setIcon(Icon("arrow-right")); btnRemoveProtocol->setWhatsThis(i18n("Remove protocol from the link list.")); vbox1->addWidget(btnRemoveProtocol); addSpacer(vbox1); KgProtocolsLayout->addWidget(vbox1Widget, 0 , 1); QWidget *vbox2Widget = new QWidget(this); QVBoxLayout *vbox2 = new QVBoxLayout(vbox2Widget); addSpacer(vbox2); btnAddMime = new QPushButton(vbox2Widget); - btnAddMime->setIcon(krLoader->loadIcon("arrow-left", KIconLoader::Small)); + btnAddMime->setIcon(Icon("arrow-left")); btnAddMime->setWhatsThis(i18n("Add MIME to the selected protocol on the link list.")); vbox2->addWidget(btnAddMime); btnRemoveMime = new QPushButton(vbox2Widget); - btnRemoveMime->setIcon(krLoader->loadIcon("arrow-right", KIconLoader::Small)); + btnRemoveMime->setIcon(Icon("arrow-right")); btnRemoveMime->setWhatsThis(i18n("Remove MIME from the link list.")); vbox2->addWidget(btnRemoveMime); addSpacer(vbox2); KgProtocolsLayout->addWidget(vbox2Widget, 1 , 1); // -------------------------- PROTOCOLS LISTBOX ---------------------------------- QGroupBox *protocolGrp = createFrame(i18n("Protocols"), this); QGridLayout *protocolGrid = createGridLayout(protocolGrp); protocolList = new KrListWidget(protocolGrp); loadProtocols(); protocolGrid->addWidget(protocolList, 0, 0); KgProtocolsLayout->addWidget(protocolGrp, 0 , 2); // -------------------------- MIMES LISTBOX ---------------------------------- QGroupBox *mimeGrp = createFrame(i18n("MIMEs"), this); QGridLayout *mimeGrid = createGridLayout(mimeGrp); mimeList = new KrListWidget(mimeGrp); loadMimes(); mimeGrid->addWidget(mimeList, 0, 0); KgProtocolsLayout->addWidget(mimeGrp, 1 , 2); // -------------------------- CONNECT TABLE ---------------------------------- connect(protocolList, SIGNAL(itemSelectionChanged()), this, SLOT(slotDisableButtons())); connect(linkList, SIGNAL(itemSelectionChanged()), this, SLOT(slotDisableButtons())); connect(mimeList, SIGNAL(itemSelectionChanged()), this, SLOT(slotDisableButtons())); connect(linkList, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(slotDisableButtons())); connect(btnAddProtocol, SIGNAL(clicked()) , this, SLOT(slotAddProtocol())); connect(btnRemoveProtocol, SIGNAL(clicked()) , this, SLOT(slotRemoveProtocol())); connect(btnAddMime, SIGNAL(clicked()) , this, SLOT(slotAddMime())); connect(btnRemoveMime, SIGNAL(clicked()) , this, SLOT(slotRemoveMime())); loadInitialValues(); slotDisableButtons(); } void KgProtocols::addSpacer(QBoxLayout *layout) { layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding)); } void KgProtocols::loadProtocols() { QStringList protocols = KProtocolInfo::protocols(); protocols.sort(); foreach(const QString &protocol, protocols) { QUrl u; u.setScheme(protocol); if(KProtocolManager::inputType(u) == KProtocolInfo::T_FILESYSTEM) { protocolList->addItem(protocol); } } } void KgProtocols::loadMimes() { QMimeDatabase db; QList mimes = db.allMimeTypes(); for (QList::const_iterator it = mimes.constBegin(); it != mimes.constEnd(); ++it) mimeList->addItem((*it).name()); mimeList->sortItems(); } void KgProtocols::slotDisableButtons() { btnAddProtocol->setEnabled(protocolList->selectedItems().count() != 0); QTreeWidgetItem *listViewItem = linkList->currentItem(); bool isProtocolSelected = (listViewItem == 0 ? false : listViewItem->parent() == 0); btnRemoveProtocol->setEnabled(isProtocolSelected); btnAddMime->setEnabled(listViewItem != 0 && mimeList->selectedItems().count() != 0); btnRemoveMime->setEnabled(listViewItem == 0 ? false : listViewItem->parent() != 0); if (linkList->currentItem() == 0 && linkList->topLevelItemCount() != 0) linkList->setCurrentItem(linkList->topLevelItem(0)); QList list = linkList->selectedItems(); if (list.count() == 0 && linkList->currentItem() != 0) linkList->currentItem()->setSelected(true); } void KgProtocols::slotAddProtocol() { QList list = protocolList->selectedItems(); if (list.count() > 0) { addProtocol(list[ 0 ]->text(), true); slotDisableButtons(); emit sigChanged(); } } void KgProtocols::addProtocol(QString name, bool changeCurrent) { QList list = protocolList->findItems(name, Qt::MatchExactly); if (list.count() > 0) { delete list[ 0 ]; QTreeWidgetItem *listViewItem = new QTreeWidgetItem(linkList); listViewItem->setText(0, name); - QString icon = KProtocolInfo::icon(name); - if (icon.isEmpty()) - icon = "go-next-view"; - listViewItem->setIcon(0, krLoader->loadIcon(icon, KIconLoader::Small)); + QString iconName = KProtocolInfo::icon(name); + if (iconName.isEmpty()) + iconName = "go-next-view"; + listViewItem->setIcon(0, Icon(iconName)); if (changeCurrent) linkList->setCurrentItem(listViewItem); } } void KgProtocols::slotRemoveProtocol() { QTreeWidgetItem *item = linkList->currentItem(); if (item) { removeProtocol(item->text(0)); slotDisableButtons(); emit sigChanged(); } } void KgProtocols::removeProtocol(QString name) { QList itemList = linkList->findItems(name, Qt::MatchExactly, 0); if (itemList.count()) { QTreeWidgetItem *item = itemList[ 0 ]; while (item->childCount() != 0) removeMime(item->child(0)->text(0)); linkList->takeTopLevelItem(linkList->indexOfTopLevelItem(item)); protocolList->addItem(name); protocolList->sortItems(); } } void KgProtocols::slotAddMime() { QList list = mimeList->selectedItems(); if (list.count() > 0 && linkList->currentItem() != 0) { QTreeWidgetItem *itemToAdd = linkList->currentItem(); if (itemToAdd->parent()) itemToAdd = itemToAdd->parent(); addMime(list[ 0 ]->text(), itemToAdd->text(0)); slotDisableButtons(); emit sigChanged(); } } void KgProtocols::addMime(QString name, QString protocol) { QList list = mimeList->findItems(name, Qt::MatchExactly); QList itemList = linkList->findItems(protocol, Qt::MatchExactly | Qt::MatchRecursive, 0); QTreeWidgetItem *currentListItem = 0; if (itemList.count() != 0) currentListItem = itemList[ 0 ]; if (list.count() > 0 && currentListItem && currentListItem->parent() == 0) { delete list[ 0 ]; QTreeWidgetItem *listViewItem = new QTreeWidgetItem(currentListItem); listViewItem->setText(0, name); - listViewItem->setIcon(0, krLoader->loadMimeTypeIcon(name, KIconLoader::Small)); + listViewItem->setIcon(0, Icon(name.replace(QLatin1Char('/'), QLatin1Char('-')), Icon("unknown"))); linkList->expandItem( currentListItem ); } } void KgProtocols::slotRemoveMime() { QTreeWidgetItem *item = linkList->currentItem(); if (item) { removeMime(item->text(0)); slotDisableButtons(); emit sigChanged(); } } void KgProtocols::removeMime(QString name) { QList itemList = linkList->findItems(name, Qt::MatchExactly | Qt::MatchRecursive, 0); QTreeWidgetItem *currentMimeItem = 0; if (itemList.count() != 0) currentMimeItem = itemList[ 0 ]; if (currentMimeItem && currentMimeItem->parent() != 0) { mimeList->addItem(currentMimeItem->text(0)); mimeList->sortItems(); currentMimeItem->parent()->removeChild(currentMimeItem); } } void KgProtocols::loadInitialValues() { if (linkList->model()->rowCount() > 0) while (linkList->topLevelItemCount() != 0) removeProtocol(linkList->topLevelItem(0)->text(0)); KConfigGroup group(krConfig, "Protocols"); QStringList protList = group.readEntry("Handled Protocols", QStringList()); for (QStringList::Iterator it = protList.begin(); it != protList.end(); ++it) { addProtocol(*it); QStringList mimes = group.readEntry(QString("Mimes For %1").arg(*it), QStringList()); for (QStringList::Iterator it2 = mimes.begin(); it2 != mimes.end(); ++it2) addMime(*it2, *it); } if (linkList->topLevelItemCount() != 0) linkList->setCurrentItem(linkList->topLevelItem(0)); slotDisableButtons(); linkList->expandAll(); emit sigChanged(); } void KgProtocols::setDefaults() { while (linkList->topLevelItemCount() != 0) removeProtocol(linkList->topLevelItem(0)->text(0)); slotDisableButtons(); if (isChanged()) emit sigChanged(); } bool KgProtocols::isChanged() { KConfigGroup group(krConfig, "Protocols"); QStringList protList = group.readEntry("Handled Protocols", QStringList()); if ((int)protList.count() != linkList->topLevelItemCount()) return true; for (int i = 0; i != linkList->topLevelItemCount(); i++) { QTreeWidgetItem *item = linkList->topLevelItem(i); if (!protList.contains(item->text(0))) return true; QStringList mimes = group.readEntry(QString("Mimes For %1").arg(item->text(0)), QStringList()); if ((int)mimes.count() != item->childCount()) return true; for (int j = 0; j != item->childCount(); j++) { QTreeWidgetItem *children = item->child(j); if (!mimes.contains(children->text(0))) return true; } } return false; } bool KgProtocols::apply() { KConfigGroup group(krConfig, "Protocols"); QStringList protocolList; for (int i = 0; i != linkList->topLevelItemCount(); i++) { QTreeWidgetItem *item = linkList->topLevelItem(i); protocolList.append(item->text(0)); QStringList mimes; for (int j = 0; j != item->childCount(); j++) { QTreeWidgetItem *children = item->child(j); mimes.append(children->text(0)); } group.writeEntry(QString("Mimes For %1").arg(item->text(0)), mimes); } group.writeEntry("Handled Protocols", protocolList); krConfig->sync(); KrServices::clearProtocolCache(); emit sigChanged(); return false; } void KgProtocols::init() { } diff --git a/krusader/Konfigurator/kgstartup.cpp b/krusader/Konfigurator/kgstartup.cpp index 4cf73641..320c20e5 100644 --- a/krusader/Konfigurator/kgstartup.cpp +++ b/krusader/Konfigurator/kgstartup.cpp @@ -1,127 +1,140 @@ /***************************************************************************** * Copyright (C) 2004 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/]. * *****************************************************************************/ #include "kgstartup.h" #include "../defaults.h" #include "../GUI/profilemanager.h" // QtWidgets #include #include #include #include KgStartup::KgStartup(bool first, QWidget* parent) : KonfiguratorPage(first, parent), profileCombo(0) { QWidget *innerWidget = new QFrame(this); setWidget(innerWidget); setWidgetResizable(true); QGridLayout *kgStartupLayout = new QGridLayout(innerWidget); kgStartupLayout->setSpacing(6); // --------------------------- PANELS GROUPBOX ---------------------------------- QGroupBox *panelsGrp = createFrame(i18n("General"), innerWidget); QGridLayout *panelsGrid = createGridLayout(panelsGrp); QString s = "

" + i18n("Defines the panel profile used at startup. A panel profile contains:
  • all the tabs paths
  • the current tab
  • the active panel
<Last session> is a special panel profile which is saved automatically when Krusader is closed."); QLabel *label = addLabel(panelsGrid, 0, 0, i18n("Startup profile:"), panelsGrp); label->setWhatsThis(s); panelsGrp->setWhatsThis(s); QStringList profileList = ProfileManager::availableProfiles("Panel"); profileList.push_front(i18n("")); const int profileListSize = profileList.size(); KONFIGURATOR_NAME_VALUE_PAIR *comboItems = new KONFIGURATOR_NAME_VALUE_PAIR[ profileListSize ]; for (int i = 0; i != profileListSize; i++) comboItems[ i ].text = comboItems[ i ].value = profileList [ i ]; comboItems[ 0 ].value = ""; profileCombo = createComboBox("Startup", "Starter Profile Name", comboItems[ 0 ].value, comboItems, profileListSize, panelsGrp, false, false); profileCombo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); panelsGrid->addWidget(profileCombo, 0, 1); delete [] comboItems; //------------------------------------------------ panelsGrid->addWidget(createLine(panelsGrp), 1, 0, 1, 2); KONFIGURATOR_CHECKBOX_PARAM settings[] = { // cfg_class cfg_name default text restart tooltip {"Look&Feel", "Show splashscreen", _ShowSplashScreen, i18n("Show splashscreen"), false, i18n("Display a splashscreen when starting Krusader.") }, {"Look&Feel", "Single Instance Mode", _SingleInstanceMode, i18n("Single instance mode"), false, i18n("Only one Krusader instance is allowed to run.") } }; KonfiguratorCheckBoxGroup* cbs = createCheckBoxGroup(2, 0, settings, 2 /* settings count */, panelsGrp); panelsGrid->addWidget(cbs, 2, 0, 1, 2); + QHBoxLayout *iconThemeLayout = new QHBoxLayout(); + QLabel *iconThemeLabel = new QLabel(i18n("Fallback Icon Theme:")); + iconThemeLabel->setWhatsThis(i18n("Whenever icon is not found in system icon theme, " + "this theme will be used as a fallback. " + "If fallback theme doesn't contain the icon, " + "Breeze or Oxygen will be used if any of these are present.")); + iconThemeLayout->addWidget(iconThemeLabel); + KonfiguratorEditBox *iconThemeEditBox = createEditBox("Startup", "Fallback Icon Theme", "", + panelsGrp, true); + iconThemeLayout->addWidget(iconThemeEditBox); + iconThemeLayout->addStretch(1); + panelsGrid->addLayout(iconThemeLayout, 3, 0, 1, 2); + kgStartupLayout->addWidget(panelsGrp, 0, 0); // ------------------------ USERINTERFACE GROUPBOX ------------------------------ QGroupBox *uiGrp = createFrame(i18n("User Interface"), innerWidget); QGridLayout *uiGrid = createGridLayout(uiGrp); KONFIGURATOR_CHECKBOX_PARAM uiSettings[] = { // cfg_class cfg_name default text restart tooltip {"Startup", "Remember Position", _RememberPos,i18n("Save last position, size and panel settings"), false, i18n("

At startup, the main window will resize itself to the size it was when last shutdown. " "It will also appear in the same location of the screen, having panels sorted and aligned as they were before.

" "

If this option is disabled, you can use the menu Window -> Save Position option " "to manually set the main window's size and position at startup.

") }, {"Startup", "Update Default Panel Settings", _RememberPos, i18n("Update default panel settings"), true, i18n("When settings of a panel are changed, save them as the default for new panels of the same type.") }, {"Startup", "Start To Tray", _StartToTray, i18n("Start to tray"), false, i18n("Krusader starts to tray, without showing the main window") }, }; KonfiguratorCheckBoxGroup *uiSettingsGroup = createCheckBoxGroup(1, 0, uiSettings, 3, uiGrp); uiGrid->addWidget(uiSettingsGroup, 1, 0); KONFIGURATOR_CHECKBOX_PARAM uiCheckBoxes[] = { // cfg_class, cfg_name, default, text, restart, ToolTip {"Startup", "UI Save Settings", _UiSave, i18n("Save component settings on exit"), false, i18n("Check the state of the user interface components and restore them to their condition when last shutdown.") }, {"Startup", "Show FN Keys", _ShowFNkeys, i18n("Show function keys"), false, i18n("Function keys will be visible after startup.") }, {"Startup", "Show Cmd Line", _ShowCmdline, i18n("Show command line"), false, i18n("Command line will be visible after startup.") }, {"Startup", "Show Terminal Emulator", _ShowTerminalEmulator, i18n("Show embedded terminal"), false, i18n("Embedded terminal will be visible after startup.") }, }; uiCbGroup = createCheckBoxGroup(1, 0, uiCheckBoxes, 4, uiGrp); connect(uiCbGroup->find("UI Save Settings"), SIGNAL(stateChanged(int)), this, SLOT(slotDisable())); uiGrid->addWidget(uiCbGroup, 2, 0); slotDisable(); kgStartupLayout->addWidget(uiGrp, 1, 0); } void KgStartup::slotDisable() { bool isUiSave = !uiCbGroup->find("UI Save Settings")->isChecked(); int i = 1; while (uiCbGroup->find(i)) uiCbGroup->find(i++)->setEnabled(isUiSave); } diff --git a/krusader/Konfigurator/konfigurator.cpp b/krusader/Konfigurator/konfigurator.cpp index d39aded4..a2b7cb30 100644 --- a/krusader/Konfigurator/konfigurator.cpp +++ b/krusader/Konfigurator/konfigurator.cpp @@ -1,241 +1,241 @@ /***************************************************************************** * Copyright (C) 2000 Shie Erlich * * 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 "konfigurator.h" #include "../krglobal.h" +#include "../icon.h" #include "../Dialogs/krdialogs.h" -#include "../kicons.h" // QtGui #include #include #include #include #include #include #include "../defaults.h" #include "../krusaderview.h" #include "../GUI/kfnkeys.h" // the frames #include "kgstartup.h" #include "kgpanel.h" #include "kggeneral.h" #include "kgadvanced.h" #include "kgarchives.h" #include "kgdependencies.h" #include "kgcolors.h" #include "kguseractions.h" #include "kgprotocols.h" Konfigurator::Konfigurator(bool f, int startPage) : KPageDialog((QWidget *)0), firstTime(f), internalCall(false), sizeX(-1), sizeY(-1) { setWindowTitle(i18n("Konfigurator - Creating Your Own Krusader")); setWindowModality(Qt::ApplicationModal); setFaceType(KPageDialog::List); setStandardButtons(QDialogButtonBox::Help|QDialogButtonBox::RestoreDefaults|QDialogButtonBox::Close| QDialogButtonBox::Apply|QDialogButtonBox::Reset); button(QDialogButtonBox::Apply)->setDefault(true); connect(button(QDialogButtonBox::Close), SIGNAL(clicked()), SLOT(slotClose())); connect(button(QDialogButtonBox::Help), SIGNAL(clicked()), SLOT(slotShowHelp())); connect(button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked()), SLOT(slotRestoreDefaults())); connect(button(QDialogButtonBox::Reset), SIGNAL(clicked()), SLOT(slotReset())); connect(button(QDialogButtonBox::Apply), SIGNAL(clicked()), SLOT(slotApply())); connect(this, SIGNAL(currentPageChanged(KPageWidgetItem*,KPageWidgetItem*)), this, SLOT(slotPageSwitch(KPageWidgetItem*,KPageWidgetItem*))); connect(&restoreTimer, SIGNAL(timeout()), this, SLOT(slotRestorePage())); createLayout(startPage); KConfigGroup group(krConfig, "Konfigurator"); int sx = group.readEntry("Window Width", -1); int sy = group.readEntry("Window Height", -1); if (sx != -1 && sy != -1) resize(sx, sy); else resize(900, 680); if (group.readEntry("Window Maximized", false)) showMaximized(); else show(); } void Konfigurator::resizeEvent(QResizeEvent *e) { if (!isMaximized()) { sizeX = e->size().width(); sizeY = e->size().height(); } QDialog::resizeEvent(e); } void Konfigurator::closeDialog() { KConfigGroup group(krConfig, "Konfigurator"); group.writeEntry("Window Width", sizeX); group.writeEntry("Window Height", sizeY); group.writeEntry("Window Maximized", isMaximized()); } void Konfigurator::reject() { closeDialog(); QDialog::reject(); } void Konfigurator::newPage(KonfiguratorPage *page, const QString &name, const QString &desc, const QIcon &icon) { KPageWidgetItem *item = new KPageWidgetItem(page, name); item->setIcon(icon); item->setHeader(desc); addPage(item); kgPages.append(item); connect(page, SIGNAL(sigChanged()), this, SLOT(slotApplyEnable())); } void Konfigurator::createLayout(int startPage) { // startup - newPage(new KgStartup(firstTime, this), i18n("Startup"), i18n("Krusader's settings upon startup"), QIcon::fromTheme("go-home")); + newPage(new KgStartup(firstTime, this), i18n("Startup"), i18n("Krusader's settings upon startup"), Icon("go-home")); // panel - newPage(new KgPanel(firstTime, this), i18n("Panel"), i18n("Panel"), QIcon::fromTheme("view-choose")); + newPage(new KgPanel(firstTime, this), i18n("Panel"), i18n("Panel"), Icon("view-choose")); // colors - newPage(new KgColors(firstTime, this), i18n("Colors"), i18n("Colors"), QIcon::fromTheme("color-picker")); + newPage(new KgColors(firstTime, this), i18n("Colors"), i18n("Colors"), Icon("color-picker")); // general - newPage(new KgGeneral(firstTime, this), i18n("General"), i18n("Basic Operations"), QIcon::fromTheme("system-run")); + newPage(new KgGeneral(firstTime, this), i18n("General"), i18n("Basic Operations"), Icon("system-run")); // advanced - newPage(new KgAdvanced(firstTime, this), i18n("Advanced"), i18n("Be sure you know what you are doing."), QIcon::fromTheme("dialog-messages")); + newPage(new KgAdvanced(firstTime, this), i18n("Advanced"), i18n("Be sure you know what you are doing."), Icon("dialog-messages")); // archives newPage(new KgArchives(firstTime, this), i18n("Archives"), i18n("Customize the way Krusader deals with archives"), - QIcon::fromTheme("archive-extract")); + Icon("archive-extract")); // dependencies newPage(new KgDependencies(firstTime, this), i18n("Dependencies"), i18n("Set the full path of the external applications"), - QIcon::fromTheme("debug-run")); + Icon("debug-run")); // useractions newPage(new KgUserActions(firstTime, this), i18n("User Actions"), i18n("Configure your personal actions"), - QIcon::fromTheme("user-properties")); + Icon("user-properties")); // protocols newPage(new KgProtocols(firstTime, this), i18n("Protocols"), i18n("Link MIMEs to protocols"), - QIcon::fromTheme("document-preview")); + Icon("document-preview")); setCurrentPage(kgPages.at(startPage)); slotApplyEnable(); } void Konfigurator::closeEvent(QCloseEvent *event) { lastPage = currentPage(); if(slotPageSwitch(lastPage, lastPage)) { hide(); KPageDialog::closeEvent(event); } else event->ignore(); } void Konfigurator::slotApplyEnable() { lastPage = currentPage(); bool isChanged = ((KonfiguratorPage *)(lastPage->widget()))->isChanged(); button(QDialogButtonBox::Apply)->setEnabled(isChanged); button(QDialogButtonBox::Reset)->setEnabled(isChanged); } bool Konfigurator::slotPageSwitch(KPageWidgetItem *current, KPageWidgetItem *before) { if (before == 0) return true; KonfiguratorPage *currentPg = (KonfiguratorPage *)(before->widget()); if (internalCall) { internalCall = false; return true; } if (currentPg->isChanged()) { int result = KMessageBox::questionYesNoCancel(0, i18n("The current page has been changed. Do you want to apply changes?")); switch (result) { case KMessageBox::No: currentPg->loadInitialValues(); currentPg->apply(); break; case KMessageBox::Yes: emit configChanged(currentPg->apply()); break; default: restoreTimer.setSingleShot(true); restoreTimer.start(0); return false; } } button(QDialogButtonBox::Apply)->setEnabled(currentPg->isChanged()); lastPage = current; return true; } void Konfigurator::slotRestorePage() { if (lastPage != currentPage()) { internalCall = true; setCurrentPage(lastPage); } } void Konfigurator::slotClose() { lastPage = currentPage(); if (slotPageSwitch(lastPage, lastPage)) { reject(); } } void Konfigurator::slotApply() { emit configChanged(((KonfiguratorPage*)(currentPage()->widget()))->apply()); } void Konfigurator::slotReset() { ((KonfiguratorPage *)(currentPage()->widget()))->loadInitialValues(); } void Konfigurator::slotRestoreDefaults() { ((KonfiguratorPage *)(currentPage()->widget()))->setDefaults(); } void Konfigurator::slotShowHelp() { KHelpClient::invokeHelp(QStringLiteral("konfigurator")); } diff --git a/krusader/Konfigurator/konfiguratoritems.cpp b/krusader/Konfigurator/konfiguratoritems.cpp index a14917e7..37e86b6d 100644 --- a/krusader/Konfigurator/konfiguratoritems.cpp +++ b/krusader/Konfigurator/konfiguratoritems.cpp @@ -1,836 +1,838 @@ /***************************************************************************** * 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/]. * *****************************************************************************/ #include "konfiguratoritems.h" + #include "../krglobal.h" +#include "../icon.h" // QtCore #include // QtGui #include #include #include // QtWidgets #include #include #include #include #include #include -#include + KonfiguratorExtension::KonfiguratorExtension(QObject *obj, QString cfgGroup, QString cfgName, bool restartNeeded, int page) : QObject(), objectPtr(obj), applyConnected(false), setDefaultsConnected(false), changed(false), restartNeeded(restartNeeded), subpage(page), configGroup(cfgGroup), configName(cfgName) { } void KonfiguratorExtension::connectNotify(const QMetaMethod &signal) { if (signal == QMetaMethod::fromSignal(&KonfiguratorExtension::applyManually)) applyConnected = true; else if (signal == QMetaMethod::fromSignal(&KonfiguratorExtension::setDefaultsManually)) setDefaultsConnected = true; QObject::connectNotify(signal); } bool KonfiguratorExtension::apply() { if (!changed) return false; if (applyConnected) emit applyManually(objectPtr, configGroup, configName); else emit applyAuto(objectPtr, configGroup, configName); setChanged(false); return restartNeeded; } void KonfiguratorExtension::setDefaults() { if (setDefaultsConnected) emit setDefaultsManually(objectPtr); else emit setDefaultsAuto(objectPtr); } void KonfiguratorExtension::loadInitialValue() { emit setInitialValue(objectPtr); } bool KonfiguratorExtension::isChanged() { return changed; } // KonfiguratorCheckBox class /////////////////////////////// KonfiguratorCheckBox::KonfiguratorCheckBox(QString configGroup, QString name, bool defaultValue, QString text, QWidget *parent, bool restart, int page) : QCheckBox(text, parent), defaultValue(defaultValue) { ext = new KonfiguratorExtension(this, configGroup, name, restart, page); connect(ext, SIGNAL(applyAuto(QObject*,QString,QString)), this, SLOT(slotApply(QObject*,QString,QString))); connect(ext, SIGNAL(setDefaultsAuto(QObject*)), this, SLOT(slotSetDefaults(QObject*))); connect(ext, SIGNAL(setInitialValue(QObject*)), this, SLOT(loadInitialValue())); connect(this, SIGNAL(stateChanged(int)), ext, SLOT(setChanged())); loadInitialValue(); } KonfiguratorCheckBox::~KonfiguratorCheckBox() { delete ext; } void KonfiguratorCheckBox::loadInitialValue() { KConfigGroup group(krConfig, ext->getConfigGroup()); setChecked(group.readEntry(ext->getConfigName(), defaultValue)); ext->setChanged(false); } void KonfiguratorCheckBox::checkStateSet() { QCheckBox::checkStateSet(); updateDeps(); } void KonfiguratorCheckBox::nextCheckState() { QCheckBox::nextCheckState(); updateDeps(); } void KonfiguratorCheckBox::addDep(KonfiguratorCheckBox *dep) { deps << dep; dep->setEnabled(isChecked()); } void KonfiguratorCheckBox::updateDeps() { foreach(KonfiguratorCheckBox *dep, deps) dep->setEnabled(isChecked()); } void KonfiguratorCheckBox::slotApply(QObject *, QString configGroup, QString name) { KConfigGroup(krConfig, configGroup).writeEntry(name, isChecked()); } void KonfiguratorCheckBox::slotSetDefaults(QObject *) { if (isChecked() != defaultValue) setChecked(defaultValue); } // KonfiguratorSpinBox class /////////////////////////////// KonfiguratorSpinBox::KonfiguratorSpinBox(QString configGroup, QString configName, int defaultValue, int min, int max, QWidget *parent, bool restartNeeded, int page) : QSpinBox(parent), defaultValue(defaultValue) { ext = new KonfiguratorExtension(this, configGroup, configName, restartNeeded, page); connect(ext, SIGNAL(applyAuto(QObject*,QString,QString)), this, SLOT(slotApply(QObject*,QString,QString))); connect(ext, SIGNAL(setDefaultsAuto(QObject*)), this, SLOT(slotSetDefaults(QObject*))); connect(ext, SIGNAL(setInitialValue(QObject*)), this, SLOT(loadInitialValue())); connect(this, SIGNAL(valueChanged(int)), ext, SLOT(setChanged())); setMinimum(min); setMaximum(max); loadInitialValue(); } KonfiguratorSpinBox::~KonfiguratorSpinBox() { delete ext; } void KonfiguratorSpinBox::loadInitialValue() { KConfigGroup group(krConfig, ext->getConfigGroup()); setValue(group.readEntry(ext->getConfigName(), defaultValue)); ext->setChanged(false); } void KonfiguratorSpinBox::slotApply(QObject *, QString configGroup, QString name) { KConfigGroup(krConfig, configGroup).writeEntry(name, value()); } void KonfiguratorSpinBox::slotSetDefaults(QObject *) { if (value() != defaultValue) setValue(defaultValue); } // KonfiguratorCheckBoxGroup class /////////////////////////////// void KonfiguratorCheckBoxGroup::add(KonfiguratorCheckBox *checkBox) { checkBoxList.append(checkBox); } KonfiguratorCheckBox * KonfiguratorCheckBoxGroup::find(int index) { if (index < 0 || index >= checkBoxList.count()) return 0; return checkBoxList.at(index); } KonfiguratorCheckBox * KonfiguratorCheckBoxGroup::find(QString name) { QListIterator it(checkBoxList); while (it.hasNext()) { KonfiguratorCheckBox * checkBox = it.next(); if (checkBox->extension()->getConfigName() == name) return checkBox; } return 0; } // KonfiguratorRadioButtons class /////////////////////////////// KonfiguratorRadioButtons::KonfiguratorRadioButtons(QString configGroup, QString name, QString defaultValue, QWidget *parent, bool restart, int page) : QWidget(parent), defaultValue(defaultValue) { ext = new KonfiguratorExtension(this, configGroup, name, restart, page); connect(ext, SIGNAL(applyAuto(QObject*,QString,QString)), this, SLOT(slotApply(QObject*,QString,QString))); connect(ext, SIGNAL(setDefaultsAuto(QObject*)), this, SLOT(slotSetDefaults(QObject*))); connect(ext, SIGNAL(setInitialValue(QObject*)), this, SLOT(loadInitialValue())); } KonfiguratorRadioButtons::~KonfiguratorRadioButtons() { delete ext; } void KonfiguratorRadioButtons::addRadioButton(QRadioButton *radioWidget, QString name, QString value) { radioButtons.append(radioWidget); radioNames.push_back(name); radioValues.push_back(value); connect(radioWidget, SIGNAL(toggled(bool)), ext, SLOT(setChanged())); } QRadioButton * KonfiguratorRadioButtons::find(int index) { if (index < 0 || index >= radioButtons.count()) return 0; return radioButtons.at(index); } QRadioButton * KonfiguratorRadioButtons::find(QString name) { int index = radioNames.indexOf(name); if (index == -1) return 0; return radioButtons.at(index); } void KonfiguratorRadioButtons::selectButton(QString value) { int cnt = 0; QListIterator it(radioButtons); while (it.hasNext()) { QRadioButton * btn = it.next(); if (value == radioValues[ cnt ]) { btn->setChecked(true); return; } cnt++; } if (!radioButtons.isEmpty()) radioButtons.first()->setChecked(true); } void KonfiguratorRadioButtons::loadInitialValue() { KConfigGroup group(krConfig, ext->getConfigGroup()); QString initValue = group.readEntry(ext->getConfigName(), defaultValue); selectButton(initValue); ext->setChanged(false); } QString KonfiguratorRadioButtons::selectedValue() { int cnt = 0; QListIterator it(radioButtons); while (it.hasNext()) { QRadioButton * btn = it.next(); if (btn->isChecked()) { return radioValues[ cnt ]; } cnt++; } return QString(); } void KonfiguratorRadioButtons::slotApply(QObject *, QString configGroup, QString name) { QString value = selectedValue(); if (!value.isEmpty()) KConfigGroup(krConfig, configGroup).writeEntry(name, value); } void KonfiguratorRadioButtons::slotSetDefaults(QObject *) { selectButton(defaultValue); } // KonfiguratorEditBox class /////////////////////////////// KonfiguratorEditBox::KonfiguratorEditBox(QString configGroup, QString name, QString defaultValue, QWidget *parent, bool restart, int page) : QLineEdit(parent), defaultValue(defaultValue) { ext = new KonfiguratorExtension(this, configGroup, name, restart, page); connect(ext, SIGNAL(applyAuto(QObject *, QString, QString)), this, SLOT(slotApply(QObject *, QString, QString))); connect(ext, SIGNAL(setDefaultsAuto(QObject*)), this, SLOT(slotSetDefaults(QObject*))); connect(ext, SIGNAL(setInitialValue(QObject*)), this, SLOT(loadInitialValue())); connect(this, SIGNAL(textChanged(QString)), ext, SLOT(setChanged())); loadInitialValue(); } KonfiguratorEditBox::~KonfiguratorEditBox() { delete ext; } void KonfiguratorEditBox::loadInitialValue() { KConfigGroup group(krConfig, ext->getConfigGroup()); setText(group.readEntry(ext->getConfigName(), defaultValue)); ext->setChanged(false); } void KonfiguratorEditBox::slotApply(QObject *, QString configGroup, QString name) { KConfigGroup(krConfig, configGroup).writeEntry(name, text()); } void KonfiguratorEditBox::slotSetDefaults(QObject *) { if (text() != defaultValue) setText(defaultValue); } // KonfiguratorURLRequester class /////////////////////////////// KonfiguratorURLRequester::KonfiguratorURLRequester(QString configGroup, QString name, QString defaultValue, QWidget *parent, bool restart, int page, bool expansion) : KUrlRequester(parent), defaultValue(defaultValue), expansion(expansion) { ext = new KonfiguratorExtension(this, configGroup, name, restart, page); connect(ext, SIGNAL(applyAuto(QObject *, QString, QString)), this, SLOT(slotApply(QObject *, QString, QString))); connect(ext, SIGNAL(setDefaultsAuto(QObject*)), this, SLOT(slotSetDefaults(QObject*))); connect(ext, SIGNAL(setInitialValue(QObject*)), this, SLOT(loadInitialValue())); connect(this, SIGNAL(textChanged(QString)), ext, SLOT(setChanged())); loadInitialValue(); } KonfiguratorURLRequester::~KonfiguratorURLRequester() { delete ext; } void KonfiguratorURLRequester::loadInitialValue() { KConfigGroup group(krConfig, ext->getConfigGroup()); lineEdit()->setText(group.readEntry(ext->getConfigName(), defaultValue)); ext->setChanged(false); } void KonfiguratorURLRequester::slotApply(QObject *, QString configGroup, QString name) { KConfigGroup(krConfig, configGroup) .writeEntry(name, expansion ? url().toDisplayString(QUrl::PreferLocalFile) : text()); } void KonfiguratorURLRequester::slotSetDefaults(QObject *) { if (url().toDisplayString(QUrl::PreferLocalFile) != defaultValue) lineEdit()->setText(defaultValue); } // KonfiguratorFontChooser class /////////////////////////////// KonfiguratorFontChooser::KonfiguratorFontChooser(QString configGroup, QString name, QFont defaultValue, QWidget *parent, bool restart, int page) : QWidget(parent), defaultValue(defaultValue) { QHBoxLayout *layout = new QHBoxLayout(this); ext = new KonfiguratorExtension(this, configGroup, name, restart, page); connect(ext, SIGNAL(applyAuto(QObject*,QString,QString)), this, SLOT(slotApply(QObject*,QString,QString))); connect(ext, SIGNAL(setDefaultsAuto(QObject*)), this, SLOT(slotSetDefaults(QObject*))); connect(ext, SIGNAL(setInitialValue(QObject*)), this, SLOT(loadInitialValue())); pLabel = new QLabel(this); pLabel->setMinimumWidth(150); layout->addWidget(pLabel); pToolButton = new QToolButton(this); connect(pToolButton, SIGNAL(clicked()), this, SLOT(slotBrowseFont())); - pToolButton->setIcon(SmallIcon("document-open")); + pToolButton->setIcon(Icon("document-open")); layout->addWidget(pToolButton); loadInitialValue(); } KonfiguratorFontChooser::~KonfiguratorFontChooser() { delete ext; } void KonfiguratorFontChooser::loadInitialValue() { KConfigGroup group(krConfig, ext->getConfigGroup()); font = group.readEntry(ext->getConfigName(), defaultValue); ext->setChanged(false); setFont(); } void KonfiguratorFontChooser::setFont() { pLabel->setFont(font); pLabel->setText(font.family() + QString(", %1").arg(font.pointSize())); } void KonfiguratorFontChooser::slotApply(QObject *, QString configGroup, QString name) { KConfigGroup(krConfig, configGroup).writeEntry(name, font); } void KonfiguratorFontChooser::slotSetDefaults(QObject *) { font = defaultValue; ext->setChanged(); setFont(); } void KonfiguratorFontChooser::slotBrowseFont() { bool ok; font = QFontDialog::getFont(&ok, font, this); if (!ok) return; // cancelled by the user, and font is actually not changed (getFont returns the font we gave it) ext->setChanged(); setFont(); } // KonfiguratorComboBox class /////////////////////////////// KonfiguratorComboBox::KonfiguratorComboBox(QString configGroup, QString name, QString defaultValue, KONFIGURATOR_NAME_VALUE_PAIR *listIn, int listInLen, QWidget *parent, bool restart, bool editable, int page) : QComboBox(parent), defaultValue(defaultValue), listLen(listInLen) { list = new KONFIGURATOR_NAME_VALUE_PAIR[ listInLen ]; for (int i = 0; i != listLen; i++) { list[i] = listIn[i]; addItem(list[i].text); } ext = new KonfiguratorExtension(this, configGroup, name, restart, page); connect(ext, SIGNAL(applyAuto(QObject*,QString,QString)), this, SLOT(slotApply(QObject*,QString,QString))); connect(ext, SIGNAL(setDefaultsAuto(QObject*)), this, SLOT(slotSetDefaults(QObject*))); connect(ext, SIGNAL(setInitialValue(QObject*)), this, SLOT(loadInitialValue())); // connect( this, SIGNAL(highlighted(int)), ext, SLOT(setChanged()) ); /* Removed because of startup combo failure */ connect(this, SIGNAL(activated(int)), ext, SLOT(setChanged())); connect(this, SIGNAL(currentTextChanged(QString)), ext, SLOT(setChanged())); setEditable(editable); loadInitialValue(); } KonfiguratorComboBox::~KonfiguratorComboBox() { delete []list; delete ext; } void KonfiguratorComboBox::loadInitialValue() { KConfigGroup group(krConfig, ext->getConfigGroup()); QString select = group.readEntry(ext->getConfigName(), defaultValue); selectEntry(select); ext->setChanged(false); } void KonfiguratorComboBox::slotApply(QObject *, QString configGroup, QString name) { QString text = isEditable() ? lineEdit()->text() : currentText(); QString value = text; for (int i = 0; i != listLen; i++) if (list[i].text == text) { value = list[i].value; break; } KConfigGroup(krConfig, configGroup).writeEntry(name, value); } void KonfiguratorComboBox::selectEntry(QString entry) { for (int i = 0; i != listLen; i++) if (list[i].value == entry) { setCurrentIndex(i); return; } if (isEditable()) lineEdit()->setText(entry); else setCurrentIndex(0); } void KonfiguratorComboBox::slotSetDefaults(QObject *) { selectEntry(defaultValue); } // KonfiguratorColorChooser class /////////////////////////////// KonfiguratorColorChooser::KonfiguratorColorChooser(QString configGroup, QString name, QColor defaultValue, QWidget *parent, bool restart, ADDITIONAL_COLOR *addColPtr, int addColNum, int page) : QComboBox(parent), defaultValue(defaultValue), disableColorChooser(true) { ext = new KonfiguratorExtension(this, configGroup, name, restart, page); connect(ext, SIGNAL(applyAuto(QObject*,QString,QString)), this, SLOT(slotApply(QObject*,QString,QString))); connect(ext, SIGNAL(setDefaultsAuto(QObject*)), this, SLOT(slotSetDefaults(QObject*))); connect(ext, SIGNAL(setInitialValue(QObject*)), this, SLOT(loadInitialValue())); addColor(i18n("Custom color"), QColor(255, 255, 255)); addColor(i18nc("Default color", "Default"), defaultValue); for (int i = 0; i != addColNum; i++) { additionalColors.push_back(addColPtr[i]); addColor(addColPtr[i].name, addColPtr[i].color); } addColor(i18n("Red"), Qt::red); addColor(i18n("Green"), Qt::green); addColor(i18n("Blue"), Qt::blue); addColor(i18n("Cyan"), Qt::cyan); addColor(i18n("Magenta"), Qt::magenta); addColor(i18n("Yellow"), Qt::yellow); addColor(i18n("Dark Red"), Qt::darkRed); addColor(i18n("Dark Green"), Qt::darkGreen); addColor(i18n("Dark Blue"), Qt::darkBlue); addColor(i18n("Dark Cyan"), Qt::darkCyan); addColor(i18n("Dark Magenta"), Qt::darkMagenta); addColor(i18n("Dark Yellow"), Qt::darkYellow); addColor(i18n("White"), Qt::white); addColor(i18n("Light Gray"), Qt::lightGray); addColor(i18n("Gray"), Qt::gray); addColor(i18n("Dark Gray"), Qt::darkGray); addColor(i18n("Black"), Qt::black); connect(this, SIGNAL(activated(int)), this, SLOT(slotCurrentChanged(int))); loadInitialValue(); } KonfiguratorColorChooser::~KonfiguratorColorChooser() { delete ext; } QPixmap KonfiguratorColorChooser::createPixmap(QColor color) { QPainter painter; QPen pen; int size = QFontMetrics(font()).height() * 3 / 4; QRect rect(0, 0, size, size); QPixmap pixmap(rect.width(), rect.height()); pen.setColor(Qt::black); painter.begin(&pixmap); QBrush brush(color); painter.fillRect(rect, brush); painter.setPen(pen); painter.drawRect(rect); painter.end(); pixmap.detach(); return pixmap; } void KonfiguratorColorChooser::addColor(QString text, QColor color) { addItem(createPixmap(color), text); palette.push_back(color); } void KonfiguratorColorChooser::loadInitialValue() { KConfigGroup group(krConfig, ext->getConfigGroup()); QString selected = group.readEntry(ext->getConfigName(), QString("")); setValue(selected); ext->setChanged(false); } void KonfiguratorColorChooser::setDefaultColor(QColor dflt) { defaultValue = dflt; palette[1] = defaultValue; setItemIcon(1, createPixmap(defaultValue)); if (currentIndex() == 1) emit colorChanged(); } void KonfiguratorColorChooser::changeAdditionalColor(int num, QColor color) { if (num < additionalColors.size()) { palette[2+num] = color; additionalColors[num].color = color; setItemIcon(2 + num, createPixmap(color)); if (currentIndex() == 2 + num) emit colorChanged(); } } void KonfiguratorColorChooser::setDefaultText(QString text) { setItemIcon(1, createPixmap(defaultValue)); setItemText(1, text); } void KonfiguratorColorChooser::slotApply(QObject *, QString configGroup, QString name) { KConfigGroup(krConfig, configGroup).writeEntry(name, getValue()); } void KonfiguratorColorChooser::setValue(QString value) { disableColorChooser = true; if (value.isEmpty()) { setCurrentIndex(1); customValue = defaultValue; } else { bool found = false; for (int j = 0; j != additionalColors.size(); j++) if (additionalColors[j].value == value) { setCurrentIndex(2 + j); found = true; break; } if (! found) { KConfigGroup colGroup(krConfig, ext->getConfigGroup()); colGroup.writeEntry("TmpColor", value); QColor color = colGroup.readEntry("TmpColor", defaultValue); customValue = color; colGroup.deleteEntry("TmpColor"); setCurrentIndex(0); for (int i = 2 + additionalColors.size(); i != palette.size(); i++) if (palette[i] == color) { setCurrentIndex(i); break; } } } palette[0] = customValue; setItemIcon(0, createPixmap(customValue)); ext->setChanged(); emit colorChanged(); disableColorChooser = false; } QString KonfiguratorColorChooser::getValue() { QColor color = palette[ currentIndex()]; if (currentIndex() == 1) /* it's the default value? */ return ""; else if (currentIndex() >= 2 && currentIndex() < 2 + additionalColors.size()) return additionalColors[ currentIndex() - 2 ].value; else return QString("%1,%2,%3").arg(color.red()).arg(color.green()).arg(color.blue()); } bool KonfiguratorColorChooser::isValueRGB() { return !(currentIndex() >= 1 && currentIndex() < 2 + additionalColors.size()); } void KonfiguratorColorChooser::slotSetDefaults(QObject *) { ext->setChanged(); setCurrentIndex(1); emit colorChanged(); } void KonfiguratorColorChooser::slotCurrentChanged(int number) { ext->setChanged(); if (number == 0 && !disableColorChooser) { QColor color = QColorDialog::getColor(customValue, this); if (color.isValid()) { disableColorChooser = true; customValue = color; palette[0] = customValue; setItemIcon(0, createPixmap(customValue)); disableColorChooser = false; } } emit colorChanged(); } QColor KonfiguratorColorChooser::getColor() { return palette[ currentIndex()]; } // KonfiguratorListBox class /////////////////////////////// KonfiguratorListBox::KonfiguratorListBox(QString configGroup, QString name, QStringList defaultValue, QWidget *parent, bool restart, int page) : KrListWidget(parent), defaultValue(defaultValue) { ext = new KonfiguratorExtension(this, configGroup, name, restart, page); connect(ext, SIGNAL(applyAuto(QObject*,QString,QString)), this, SLOT(slotApply(QObject*,QString,QString))); connect(ext, SIGNAL(setDefaultsAuto(QObject*)), this, SLOT(slotSetDefaults(QObject*))); connect(ext, SIGNAL(setInitialValue(QObject*)), this, SLOT(loadInitialValue())); loadInitialValue(); } KonfiguratorListBox::~KonfiguratorListBox() { delete ext; } void KonfiguratorListBox::loadInitialValue() { KConfigGroup group(krConfig, ext->getConfigGroup()); setList(group.readEntry(ext->getConfigName(), defaultValue)); ext->setChanged(false); } void KonfiguratorListBox::slotApply(QObject *, QString configGroup, QString name) { KConfigGroup(krConfig, configGroup).writeEntry(name, list()); } void KonfiguratorListBox::slotSetDefaults(QObject *) { if (list() != defaultValue) { ext->setChanged(); setList(defaultValue); } } void KonfiguratorListBox::setList(QStringList list) { clear(); addItems(list); } QStringList KonfiguratorListBox::list() { QStringList lst; for (int i = 0; i != count(); i++) lst += item(i)->text(); return lst; } void KonfiguratorListBox::addItem(const QString & item) { if (!list().contains(item)) { KrListWidget::addItem(item); ext->setChanged(); } } void KonfiguratorListBox::removeItem(const QString & item) { QList list = findItems(item, Qt::MatchExactly); for (int i = 0; i != list.count(); i++) delete list[ i ]; if (list.count()) ext->setChanged(); } diff --git a/krusader/Konfigurator/krresulttabledialog.cpp b/krusader/Konfigurator/krresulttabledialog.cpp index 61196bea..65f85312 100644 --- a/krusader/Konfigurator/krresulttabledialog.cpp +++ b/krusader/Konfigurator/krresulttabledialog.cpp @@ -1,124 +1,124 @@ /***************************************************************************** * Copyright (C) 2005 Dirk Eschler * * Copyright (C) 2005-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 "krresulttabledialog.h" // QtGui #include // QtWidgets #include #include #include #include #include #include -#include #include "../krglobal.h" +#include "../icon.h" KrResultTableDialog::KrResultTableDialog(QWidget *parent, DialogType type, const QString& caption, const QString& heading, const QString& headerIcon, const QString& hint) : QDialog(parent, 0) { setWindowTitle(caption); setWindowModality(Qt::WindowModal); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); QVBoxLayout *_topLayout = new QVBoxLayout(); _topLayout->setAlignment(Qt::AlignTop); // +++ Heading +++ // prepare the icon QWidget *_iconWidget = new QWidget(this); QHBoxLayout * _iconBox = new QHBoxLayout(_iconWidget); QLabel *_iconLabel = new QLabel(_iconWidget); - _iconLabel->setPixmap(krLoader->loadIcon(headerIcon, KIconLoader::Desktop, 32)); + _iconLabel->setPixmap(Icon(headerIcon).pixmap(32)); _iconLabel->setMinimumWidth(fontMetrics().maxWidth()*20); _iconLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); _iconLabel->setFixedSize(_iconLabel->sizeHint()); _iconBox->addWidget(_iconLabel); QLabel *_headingLabel = new QLabel(heading, _iconWidget); QFont defFont = QFontDatabase::systemFont(QFontDatabase::GeneralFont); defFont.setBold(true); _headingLabel->setFont(defFont); _headingLabel->setIndent(10); _iconBox->addWidget(_headingLabel); _topLayout->addWidget(_iconWidget); // +++ Add some space between heading and table +++ QSpacerItem* hSpacer1 = new QSpacerItem(0, 5); _topLayout->addItem(hSpacer1); // +++ Table +++ switch (type) { case Archiver: _resultTable = new KrArchiverResultTable(this); helpAnchor = QStringLiteral("konfig-archives"); // launch handbook at sect1-id via help button break; case Tool: _resultTable = new KrToolResultTable(this); helpAnchor = QStringLiteral("konfig-dependencies"); // TODO find a good anchor break; default: break; } _topLayout->addWidget(_resultTable); // +++ Separator +++ KSeparator* hSep = new KSeparator(Qt::Horizontal, this); hSep->setContentsMargins(5, 5, 5, 5); _topLayout->addWidget(hSep); // +++ Hint +++ if (!hint.isEmpty()) { QLabel *_hintLabel = new QLabel(hint, this); _hintLabel->setIndent(5); _hintLabel->setAlignment(Qt::AlignRight); _topLayout->addWidget(_hintLabel); } mainLayout->addLayout(_topLayout); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Help); mainLayout->addWidget(buttonBox); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, &QDialogButtonBox::accepted, this, &KrResultTableDialog::accept); connect(buttonBox, &QDialogButtonBox::helpRequested, this, &KrResultTableDialog::showHelp); buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); this->setFixedSize(this->sizeHint()); // make non-resizeable } KrResultTableDialog::~KrResultTableDialog() { } void KrResultTableDialog::showHelp() { if(!helpAnchor.isEmpty()) { KHelpClient::invokeHelp(helpAnchor); } } diff --git a/krusader/Locate/locate.cpp b/krusader/Locate/locate.cpp index 1c009c9b..825a7c42 100644 --- a/krusader/Locate/locate.cpp +++ b/krusader/Locate/locate.cpp @@ -1,692 +1,692 @@ /***************************************************************************** * Copyright (C) 2004 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/]. * *****************************************************************************/ #include "locate.h" #include "../kractions.h" #include "../krglobal.h" +#include "../filelisticon.h" #include "../krslots.h" #include "../krusaderview.h" #include "../Panel/krpanel.h" #include "../Panel/panelfunc.h" #include "../GUI/krtreewidget.h" #include "../defaults.h" #include "../krservices.h" #include "../FileSystem/filesystem.h" #include "../FileSystem/virtualfilesystem.h" #include "../KViewer/krviewer.h" #include "../panelmanager.h" -#include "../kicons.h" // QtCore #include #include #include #include // QtGui #include #include #include #include #include #include // QtWidgets #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // these are the values that will exist in the menu #define VIEW_ID 90 #define EDIT_ID 91 #define FIND_ID 92 #define FIND_NEXT_ID 93 #define FIND_PREV_ID 94 #define COPY_SELECTED_TO_CLIPBOARD 95 #define COMPARE_ID 96 ////////////////////////////////////////////////////////// class LocateListView : public KrTreeWidget { public: explicit LocateListView(QWidget * parent) : KrTreeWidget(parent) { setAlternatingRowColors(true); } void startDrag(Qt::DropActions supportedActs) { Q_UNUSED(supportedActs); QList urls; QList list = selectedItems(); QListIterator it(list); while (it.hasNext()) { QTreeWidgetItem * item = it.next(); urls.push_back(QUrl::fromLocalFile(item->text(0))); } if (urls.count() == 0) return; QDrag *drag = new QDrag(this); QMimeData *mimeData = new QMimeData; - mimeData->setImageData(FL_LOADICON("file")); + mimeData->setImageData(FileListIcon("file").pixmap()); mimeData->setUrls(urls); drag->setMimeData(mimeData); drag->start(); } }; KProcess * LocateDlg::updateProcess = 0; LocateDlg * LocateDlg::LocateDialog = 0; LocateDlg::LocateDlg() : QDialog(0), isFeedToListBox(false) { setWindowTitle(i18n("Krusader::Locate")); setWindowModality(Qt::NonModal); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); QGridLayout *grid = new QGridLayout(); grid->setSpacing(6); grid->setContentsMargins(11, 11, 11, 11); QWidget *hboxWidget = new QWidget(this); QHBoxLayout *hbox = new QHBoxLayout(hboxWidget); hbox->setContentsMargins(0, 0, 0, 0); QLabel *label = new QLabel(i18n("Search for:"), hboxWidget); hbox->addWidget(label); locateSearchFor = new KHistoryComboBox(false, hboxWidget); locateSearchFor->setMinimumContentsLength(10); hbox->addWidget(locateSearchFor); label->setBuddy(locateSearchFor); KConfigGroup group(krConfig, "Locate"); QStringList list = group.readEntry("Search For", QStringList()); locateSearchFor->setMaxCount(25); // remember 25 items locateSearchFor->setHistoryItems(list); locateSearchFor->setEditable(true); locateSearchFor->setDuplicatesEnabled(false); locateSearchFor->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); locateSearchFor->lineEdit()->setFocus(); grid->addWidget(hboxWidget, 0, 0); QWidget *hboxWidget2 = new QWidget(this); QHBoxLayout * hbox2 = new QHBoxLayout(hboxWidget2); hbox2->setContentsMargins(0, 0, 0, 0); QSpacerItem* spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); hbox2->addItem(spacer); dontSearchInPath = new QCheckBox(i18n("Do not search in path"), hboxWidget2); hbox2->addWidget(dontSearchInPath); dontSearchInPath->setChecked(group.readEntry("Don't Search In Path", false)); existingFiles = new QCheckBox(i18n("Show only the existing files"), hboxWidget2); existingFiles->setChecked(group.readEntry("Existing Files", false)); hbox2->addWidget(existingFiles); caseSensitive = new QCheckBox(i18n("Case Sensitive"), hboxWidget2); caseSensitive->setChecked(group.readEntry("Case Sensitive", false)); hbox2->addWidget(caseSensitive); grid->addWidget(hboxWidget2, 1, 0); QFrame *line1 = new QFrame(this); line1->setFrameStyle(QFrame::HLine | QFrame::Sunken); grid->addWidget(line1, 2, 0); resultList = new LocateListView(this); // create the main container resultList->setColumnCount(1); resultList->setHeaderLabel(i18n("Results")); resultList->setColumnWidth(0, QFontMetrics(resultList->font()).width("W") * 60); KConfigGroup gl(krConfig, "Look&Feel"); resultList->setFont(gl.readEntry("Filelist Font", _FilelistFont)); resultList->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); resultList->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); resultList->header()->setSortIndicatorShown(false); resultList->setSortingEnabled(false); resultList->setSelectionMode(QAbstractItemView::ExtendedSelection); resultList->setDragEnabled(true); connect(resultList, SIGNAL(itemRightClicked(QTreeWidgetItem*,QPoint,int)), this, SLOT(slotRightClick(QTreeWidgetItem*,QPoint))); connect(resultList, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(slotDoubleClick(QTreeWidgetItem*))); connect(resultList, SIGNAL(itemActivated(QTreeWidgetItem*,int)), this, SLOT(slotDoubleClick(QTreeWidgetItem*))); grid->addWidget(resultList, 3, 0); QFrame *line2 = new QFrame(this); line2->setFrameStyle(QFrame::HLine | QFrame::Sunken); grid->addWidget(line2, 4, 0); mainLayout->addLayout(grid); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); mainLayout->addWidget(buttonBox); locateButton = new QPushButton(i18n("Locate")); - locateButton->setIcon(QIcon::fromTheme(QStringLiteral("system-search"))); + locateButton->setIcon(Icon(QStringLiteral("system-search"))); locateButton->setDefault(true); buttonBox->addButton(locateButton, QDialogButtonBox::ActionRole); updateDbButton = new QPushButton(i18n("Update DB")); - updateDbButton->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); + updateDbButton->setIcon(Icon(QStringLiteral("view-refresh"))); buttonBox->addButton(updateDbButton, QDialogButtonBox::ActionRole); feedStopButton = new QPushButton; buttonBox->addButton(feedStopButton, QDialogButtonBox::ActionRole); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); connect(locateButton, SIGNAL(clicked()), this, SLOT(slotLocate())); connect(updateDbButton, SIGNAL(clicked()), this, SLOT(slotUpdateDb())); connect(feedStopButton, SIGNAL(clicked()), this, SLOT(slotFeedStop())); updateButtons(false); if (updateProcess) { if (updateProcess->state() == QProcess::Running) { connect(updateProcess, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(updateFinished())); updateDbButton->setEnabled(false); } else updateFinished(); } show(); LocateDialog = this; } void LocateDlg::slotFeedStop() /* The stop / feed to listbox button */ { if (isFeedToListBox) feedToListBox(); else locateProc->kill(); } void LocateDlg::slotUpdateDb() /* The Update DB button */ { if (!updateProcess) { KConfigGroup group(krConfig, "Locate"); updateProcess = new KProcess(); // don't set the parent to 'this'! That would cause this process to be deleted once the dialog is closed *updateProcess << KrServices::fullPathName("updatedb"); *updateProcess << KShell::splitArgs(group.readEntry("UpdateDB Arguments")); connect(updateProcess, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(updateFinished())); updateProcess->start(); updateDbButton->setEnabled(false); } } void LocateDlg::updateFinished() { delete updateProcess; updateProcess = 0; updateDbButton->setEnabled(true); } void LocateDlg::slotLocate() /* The locate button */ { locateSearchFor->addToHistory(locateSearchFor->currentText()); QStringList list = locateSearchFor->historyItems(); KConfigGroup group(krConfig, "Locate"); group.writeEntry("Search For", list); group.writeEntry("Don't Search In Path", dontSearchPath = dontSearchInPath->isChecked()); group.writeEntry("Existing Files", onlyExist = existingFiles->isChecked()); group.writeEntry("Case Sensitive", isCs = caseSensitive->isChecked()); if (!KrServices::cmdExist("locate")) { KMessageBox::error(0, i18n("Cannot start 'locate'. Check the 'Dependencies' page in konfigurator.")); return; } resultList->clear(); lastItem = 0; remaining = ""; updateButtons(true); isFeedToListBox = false; resultList->setFocus(); qApp->processEvents(); //FIXME - whats's this for ? locateProc = new KProcess(this); locateProc->setOutputChannelMode(KProcess::SeparateChannels); // default is forwarding to the parent channels connect(locateProc, SIGNAL(readyReadStandardOutput()), SLOT(processStdout())); connect(locateProc, SIGNAL(readyReadStandardError()), SLOT(processStderr())); connect(locateProc, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(locateFinished())); connect(locateProc, SIGNAL(error(QProcess::ProcessError)), SLOT(locateError())); *locateProc << KrServices::fullPathName("locate"); if (!isCs) *locateProc << "-i"; *locateProc << (pattern = locateSearchFor->currentText()); if (!pattern.startsWith('*')) pattern = '*' + pattern; if (!pattern.endsWith('*')) pattern = pattern + '*'; collectedErr = ""; locateProc->start(); } void LocateDlg::locateError() { if (locateProc->error() == QProcess::FailedToStart) KMessageBox::error(krMainWindow, i18n("Error during the start of 'locate' process.")); } void LocateDlg::locateFinished() { if (locateProc->exitStatus() != QProcess::NormalExit || locateProc->exitStatus()) { if (!collectedErr.isEmpty()) KMessageBox::error(krMainWindow, i18n("Locate produced the following error message:\n\n%1", collectedErr)); } if (resultList->topLevelItemCount() == 0) { locateSearchFor->setFocus(); isFeedToListBox = false; } else { isFeedToListBox = true; } updateButtons(false); } void LocateDlg::processStdout() { remaining += QString::fromLocal8Bit(locateProc->readAllStandardOutput()); QStringList list = remaining.split('\n'); int items = list.size(); for (QStringList::Iterator it = list.begin(); it != list.end(); ++it) { if (--items == 0 && !remaining.endsWith('\n')) remaining = *it; else { if (dontSearchPath) { QRegExp regExp(pattern, isCs ? Qt::CaseSensitive : Qt::CaseInsensitive, QRegExp::Wildcard); QString fileName = (*it).trimmed(); if (fileName.endsWith(QLatin1String("/")) && fileName != "/") { fileName.truncate(fileName.length() - 1); } fileName = fileName.mid(fileName.lastIndexOf('/') + 1); if (!regExp.exactMatch(fileName)) continue; } if (onlyExist) { KFileItem file(QUrl::fromLocalFile((*it).trimmed())); if (!file.isReadable()) continue; } if (lastItem) lastItem = new QTreeWidgetItem(resultList, lastItem); else lastItem = new QTreeWidgetItem(resultList); lastItem->setText(0, *it); } } } void LocateDlg::processStderr() { collectedErr += QString::fromLocal8Bit(locateProc->readAllStandardError()); } void LocateDlg::slotRightClick(QTreeWidgetItem *item, const QPoint &pos) { if (!item) return; // create the menu QMenu popup; popup.setTitle(i18nc("@title:menu", "Locate")); QAction * actView = popup.addAction(i18n("View (F3)")); QAction * actEdit = popup.addAction(i18n("Edit (F4)")); QAction * actComp = popup.addAction(i18n("Compare by content (F10)")); if (resultList->selectedItems().count() != 2) actComp->setEnabled(false); popup.addSeparator(); QAction * actFind = popup.addAction(i18n("Find (Ctrl+F)")); QAction * actNext = popup.addAction(i18n("Find next (Ctrl+N)")); QAction * actPrev = popup.addAction(i18n("Find previous (Ctrl+P)")); popup.addSeparator(); QAction * actClip = popup.addAction(i18n("Copy selected to clipboard")); QAction * result = popup.exec(pos); int ret = -1; if (result == actView) ret = VIEW_ID; else if (result == actEdit) ret = EDIT_ID; else if (result == actFind) ret = FIND_ID; else if (result == actNext) ret = FIND_NEXT_ID; else if (result == actPrev) ret = FIND_PREV_ID; else if (result == actClip) ret = COPY_SELECTED_TO_CLIPBOARD; else if (result == actComp) ret = COMPARE_ID; if (ret != - 1) operate(item, ret); } void LocateDlg::slotDoubleClick(QTreeWidgetItem *item) { if (!item) return; QString dirName = item->text(0); QString fileName; if (!QDir(dirName).exists()) { fileName = dirName.mid(dirName.lastIndexOf('/') + 1); dirName.truncate(dirName.lastIndexOf('/')); } ACTIVE_FUNC->openUrl(QUrl::fromLocalFile(dirName), fileName); QDialog::accept(); } void LocateDlg::keyPressEvent(QKeyEvent *e) { if (KrGlobal::copyShortcut == QKeySequence(e->key() | e->modifiers())) { operate(0, COPY_SELECTED_TO_CLIPBOARD); e->accept(); return; } switch (e->key()) { case Qt::Key_M : if (e->modifiers() == Qt::ControlModifier) { resultList->setFocus(); e->accept(); } break; case Qt::Key_F3 : if (resultList->currentItem()) operate(resultList->currentItem(), VIEW_ID); break; case Qt::Key_F4 : if (resultList->currentItem()) operate(resultList->currentItem(), EDIT_ID); break; case Qt::Key_F10 : operate(0, COMPARE_ID); break; case Qt::Key_N : if (e->modifiers() == Qt::ControlModifier) operate(resultList->currentItem(), FIND_NEXT_ID); break; case Qt::Key_P : if (e->modifiers() == Qt::ControlModifier) operate(resultList->currentItem(), FIND_PREV_ID); break; case Qt::Key_F : if (e->modifiers() == Qt::ControlModifier) operate(resultList->currentItem(), FIND_ID); break; } QDialog::keyPressEvent(e); } void LocateDlg::operate(QTreeWidgetItem *item, int task) { QUrl name; if (item != 0) name = QUrl::fromLocalFile(item->text(0)); switch (task) { case VIEW_ID: KrViewer::view(name, this); // view the file break; case EDIT_ID: KrViewer::edit(name, this); // view the file break; case COMPARE_ID: { QList list = resultList->selectedItems(); if (list.count() != 2) break; QUrl url1 = QUrl::fromLocalFile(list[ 0 ]->text(0)); QUrl url2 = QUrl::fromLocalFile(list[ 1 ]->text(0)); SLOTS->compareContent(url1,url2); } break; case FIND_ID: { KConfigGroup group(krConfig, "Locate"); long options = group.readEntry("Find Options", (long long)0); QStringList list = group.readEntry("Find Patterns", QStringList()); QPointer dlg = new KFindDialog(this, options, list); if (dlg->exec() != QDialog::Accepted) { delete dlg; return; } QString first; if (list.count() != 0) { first = list.first(); } if (first != (findPattern = dlg->pattern())) { list.push_front(dlg->pattern()); } group.writeEntry("Find Options", (long long)(findOptions = dlg->options())); group.writeEntry("Find Patterns", list); if (!(findOptions & KFind::FromCursor) && resultList->topLevelItemCount()) resultList->setCurrentItem((findOptions & KFind::FindBackwards) ? resultList->topLevelItem(resultList->topLevelItemCount() - 1) : resultList->topLevelItem(0)); findCurrentItem = resultList->currentItem(); if (find() && findCurrentItem) { resultList->selectionModel()->clearSelection(); // HACK: QT 4 is not able to paint the focus frame because of a bug resultList->setCurrentItem(findCurrentItem); } else { KMessageBox::information(this, i18n("Search string not found.")); } resultList->scrollTo(resultList->currentIndex()); delete dlg; } break; case FIND_NEXT_ID: case FIND_PREV_ID: { if (task == FIND_PREV_ID) findOptions ^= KFind::FindBackwards; findCurrentItem = resultList->currentItem(); nextLine(); if (find() && findCurrentItem) { resultList->selectionModel()->clearSelection(); // HACK: QT 4 is not able to paint the focus frame because of a bug resultList->setCurrentItem(findCurrentItem); } else KMessageBox::information(this, i18n("Search string not found.")); resultList->scrollTo(resultList->currentIndex()); if (task == FIND_PREV_ID) findOptions ^= KFind::FindBackwards; } break; case COPY_SELECTED_TO_CLIPBOARD: { QList urls; QTreeWidgetItemIterator it(resultList); while (*it) { if ((*it)->isSelected()) urls.push_back(QUrl::fromLocalFile((*it)->text(0))); it++; } if (urls.count() == 0) return; QMimeData *mimeData = new QMimeData; - mimeData->setImageData(FL_LOADICON("file")); + mimeData->setImageData(FileListIcon("file").pixmap()); mimeData->setUrls(urls); QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard); } break; } } void LocateDlg::nextLine() { if (findOptions & KFind::FindBackwards) findCurrentItem = resultList->itemAbove(findCurrentItem); else findCurrentItem = resultList->itemBelow(findCurrentItem); } bool LocateDlg::find() { while (findCurrentItem) { QString item = findCurrentItem->text(0); if (findOptions & KFind::RegularExpression) { if (item.contains(QRegExp(findPattern, ((findOptions & KFind::CaseSensitive) != 0) ? Qt::CaseSensitive : Qt::CaseInsensitive))) return true; } else { if (item.contains(findPattern, ((findOptions & KFind::CaseSensitive) != 0) ? Qt::CaseSensitive : Qt::CaseInsensitive)) return true; } nextLine(); } return false; } void LocateDlg::feedToListBox() { VirtualFileSystem virtFilesystem; virtFilesystem.scanDir(QUrl::fromLocalFile(QStringLiteral("/"))); KConfigGroup group(krConfig, "Locate"); int listBoxNum = group.readEntry("Feed To Listbox Counter", 1); QString queryName; do { queryName = i18n("Locate results") + QString(" %1").arg(listBoxNum++); } while (virtFilesystem.getFileItem(queryName) != 0); group.writeEntry("Feed To Listbox Counter", listBoxNum); KConfigGroup ga(krConfig, "Advanced"); if (ga.readEntry("Confirm Feed to Listbox", _ConfirmFeedToListbox)) { bool ok; queryName = QInputDialog::getText(this, i18n("Query Name"), i18n("Here you can name the file collection:"), QLineEdit::Normal, queryName, &ok); if (! ok) return; } QList urlList; QTreeWidgetItemIterator it(resultList); while (*it) { QTreeWidgetItem * item = *it; urlList.push_back(QUrl::fromLocalFile(item->text(0))); it++; } QUrl url = QUrl(QStringLiteral("virt:/") + queryName); virtFilesystem.refresh(url); // create directory if it does not exist virtFilesystem.addFiles(urlList); //ACTIVE_FUNC->openUrl(url); ACTIVE_MNG->slotNewTab(url); accept(); } void LocateDlg::reset() { locateSearchFor->lineEdit()->setFocus(); locateSearchFor->lineEdit()->selectAll(); } void LocateDlg::updateButtons(bool locateIsRunning) { locateButton->setEnabled(!locateIsRunning); if (locateIsRunning) { feedStopButton->setEnabled(true); feedStopButton->setText(i18n("Stop")); - feedStopButton->setIcon(QIcon::fromTheme(QStringLiteral("process-stop"))); + feedStopButton->setIcon(Icon(QStringLiteral("process-stop"))); } else { if (resultList->topLevelItemCount() == 0) { feedStopButton->setEnabled(false); feedStopButton->setText(i18n("Stop")); - feedStopButton->setIcon(QIcon::fromTheme(QStringLiteral("process-stop"))); + feedStopButton->setIcon(Icon(QStringLiteral("process-stop"))); } else { feedStopButton->setEnabled(true); feedStopButton->setText(i18n("Feed to listbox")); - feedStopButton->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); + feedStopButton->setIcon(Icon(QStringLiteral("list-add"))); } } } diff --git a/krusader/MountMan/kmountman.cpp b/krusader/MountMan/kmountman.cpp index 56aae039..c227ccdf 100644 --- a/krusader/MountMan/kmountman.cpp +++ b/krusader/MountMan/kmountman.cpp @@ -1,499 +1,500 @@ /***************************************************************************** * Copyright (C) 2000 Shie Erlich * * 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 "kmountman.h" // QtCore #include // QtWidgets #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../krglobal.h" +#include "../icon.h" #include "../kractions.h" #include "../defaults.h" #include "../Dialogs/krdialogs.h" #include "../krservices.h" #include "kmountmangui.h" #include "../FileSystem/krpermhandler.h" #ifdef _OS_SOLARIS_ #define FSTAB "/etc/filesystemtab" #else #define FSTAB "/etc/fstab" #endif KMountMan::KMountMan(QWidget *parent) : QObject(), _operational(false), waiting(false), mountManGui(0), parentWindow(parent) { - _action = new KToolBarPopupAction(QIcon::fromTheme("kr_mountman"), i18n("&MountMan..."), this); + _action = new KToolBarPopupAction(Icon("kr_mountman"), i18n("&MountMan..."), this); connect(_action, &QAction::triggered, this, &KMountMan::mainWindow); connect(_action->menu(), &QMenu::aboutToShow, this, &KMountMan::quickList); _manageAction = _action->menu()->addAction(i18n("Open &MountMan")); connect(_manageAction, &QAction::triggered, this, &KMountMan::mainWindow); _action->menu()->addSeparator(); // added as a precaution, although we use kde services now _operational = KrServices::cmdExist("mount"); network_fs << "nfs" << "smbfs" << "fuse.fusesmb" << "fuse.sshfs"; //TODO: is this list complete ? // list of FS that we don't manage at all invalid_fs << "swap" << "/dev/pts" << "tmpfs" << "devpts" << "sysfs" << "rpc_pipefs" << "usbfs" << "binfmt_misc"; #ifdef BSD invalid_fs << "procfs"; #else invalid_fs << "proc"; #endif // list of FS that we don't allow to mount/unmount nonmount_fs << "supermount"; { KConfigGroup group(krConfig, "Advanced"); QStringList nonmount = group.readEntry("Nonmount Points", _NonMountPoints).split(','); nonmount_fs_mntpoint += nonmount; // simplify the white space for (QStringList::Iterator it = nonmount_fs_mntpoint.begin(); it != nonmount_fs_mntpoint.end(); ++it) { *it = (*it).simplified(); } } } KMountMan::~KMountMan() {} bool KMountMan::invalidFilesystem(QString type) { return (invalid_fs.contains(type) > 0); } // this is an ugly hack, but type can actually be a mountpoint. oh well... bool KMountMan::nonmountFilesystem(QString type, QString mntPoint) { return((nonmount_fs.contains(type) > 0) || (nonmount_fs_mntpoint.contains(mntPoint) > 0)); } bool KMountMan::networkFilesystem(QString type) { return (network_fs.contains(type) > 0); } void KMountMan::mainWindow() { // left as a precaution, although we use kde's services now if (!KrServices::cmdExist("mount")) { KMessageBox::error(0, i18n("Cannot start 'mount'. Check the 'Dependencies' page in konfigurator.")); return; } mountManGui = new KMountManGUI(this); delete mountManGui; /* as KMountManGUI is modal, we can now delete it */ mountManGui = nullptr; /* for sanity */ } QExplicitlySharedDataPointer KMountMan::findInListByMntPoint(KMountPoint::List &lst, QString value) { if (value.length() > 1 && value.endsWith('/')) value = value.left(value.length() - 1); QExplicitlySharedDataPointer m; for (KMountPoint::List::iterator it = lst.begin(); it != lst.end(); ++it) { m = it->data(); QString mntPnt = m->mountPoint(); if (mntPnt.length() > 1 && mntPnt.endsWith('/')) mntPnt = mntPnt.left(mntPnt.length() - 1); if (mntPnt == value) return m; } return QExplicitlySharedDataPointer(); } void KMountMan::jobResult(KJob *job) { waiting = false; if (job->error()) job->uiDelegate()->showErrorMessage(); } void KMountMan::mount(QString mntPoint, bool blocking) { QString udi = findUdiForPath(mntPoint, Solid::DeviceInterface::StorageAccess); if (!udi.isNull()) { Solid::Device device(udi); Solid::StorageAccess *access = device.as(); if (access && !access->isAccessible()) { connect(access, &Solid::StorageAccess::setupDone, this, &KMountMan::slotSetupDone, Qt::UniqueConnection); if (blocking) waiting = true; // prepare to block access->setup(); } } else { KMountPoint::List possible = KMountPoint::possibleMountPoints(KMountPoint::NeedMountOptions); QExplicitlySharedDataPointer m = findInListByMntPoint(possible, mntPoint); if (!((bool)m)) return; if (blocking) waiting = true; // prepare to block // KDE4 doesn't allow mounting devices as user, because they think it's the right behaviour. // I add this patch, as I don't think so. if (geteuid()) { // tries to mount as an user? KProcess proc; proc << KrServices::fullPathName("mount") << mntPoint; proc.start(); if (!blocking) return; proc.waitForFinished(-1); // -1 msec blocks without timeout if (proc.exitStatus() == QProcess::NormalExit && proc.exitCode() == 0) return; } KIO::SimpleJob *job = KIO::mount(false, m->mountType().toLocal8Bit(), m->mountedFrom(), m->mountPoint(), KIO::DefaultFlags); job->setUiDelegate(new KIO::JobUiDelegate()); KIO::getJobTracker()->registerJob(job); connect(job, SIGNAL(result(KJob*)), this, SLOT(jobResult(KJob*))); } while (blocking && waiting) { qApp->processEvents(); usleep(1000); } } void KMountMan::unmount(QString mntPoint, bool blocking) { //if working dir is below mountpoint cd to ~ first if(QUrl::fromLocalFile(QDir(mntPoint).canonicalPath()).isParentOf(QUrl::fromLocalFile(QDir::current().canonicalPath()))) QDir::setCurrent(QDir::homePath()); QString udi = findUdiForPath(mntPoint, Solid::DeviceInterface::StorageAccess); if (!udi.isNull()) { Solid::Device device(udi); Solid::StorageAccess *access = device.as(); if (access && access->isAccessible()) { connect(access, &Solid::StorageAccess::teardownDone, this, &KMountMan::slotTeardownDone, Qt::UniqueConnection); access->teardown(); } } else { if (blocking) waiting = true; // prepare to block // KDE4 doesn't allow unmounting devices as user, because they think it's the right behaviour. // I add this patch, as I don't think so. if (geteuid()) { // tries to mount as an user? KProcess proc; proc << KrServices::fullPathName("umount") << mntPoint; proc.start(); if (!blocking) return; proc.waitForFinished(-1); // -1 msec blocks without timeout if (proc.exitStatus() == QProcess::NormalExit && proc.exitCode() == 0) return; } KIO::SimpleJob *job = KIO::unmount(mntPoint, KIO::DefaultFlags); job->setUiDelegate(new KIO::JobUiDelegate()); KIO::getJobTracker()->registerJob(job); connect(job, SIGNAL(result(KJob*)), this, SLOT(jobResult(KJob*))); } while (blocking && waiting) { qApp->processEvents(); usleep(1000); } } KMountMan::mntStatus KMountMan::getStatus(QString mntPoint) { QExplicitlySharedDataPointer mountPoint; // 1: is it already mounted KMountPoint::List current = KMountPoint::currentMountPoints(); mountPoint = findInListByMntPoint(current, mntPoint); if ((bool) mountPoint) return MOUNTED; // 2: is it a mount point but not mounted? KMountPoint::List possible = KMountPoint::possibleMountPoints(); mountPoint = findInListByMntPoint(possible, mntPoint); if ((bool) mountPoint) return NOT_MOUNTED; // 3: unknown return DOESNT_EXIST; } void KMountMan::toggleMount(QString mntPoint) { mntStatus status = getStatus(mntPoint); switch (status) { case MOUNTED: unmount(mntPoint); break; case NOT_MOUNTED: mount(mntPoint); break; case DOESNT_EXIST: // do nothing: no-op to make the compiler quiet ;-) break; } } void KMountMan::autoMount(QString path) { KConfigGroup group(krConfig, "Advanced"); if (!group.readEntry("AutoMount", _AutoMount)) return; // auto mount disabled if (getStatus(path) == NOT_MOUNTED) mount(path); } void KMountMan::eject(QString mntPoint) { QString udi = findUdiForPath(mntPoint, Solid::DeviceInterface::OpticalDrive); if (udi.isNull()) return; Solid::Device dev(udi); Solid::OpticalDrive *drive = dev.as(); if (drive == 0) return; //if working dir is below mountpoint cd to ~ first if(QUrl::fromLocalFile(QDir(mntPoint).canonicalPath()).isParentOf(QUrl::fromLocalFile(QDir::current().canonicalPath()))) QDir::setCurrent(QDir::homePath()); connect(drive, SIGNAL(ejectDone(Solid::ErrorType,QVariant,QString)), this, SLOT(slotTeardownDone(Solid::ErrorType,QVariant,QString))); drive->eject(); } // returns true if the path is an ejectable mount point (at the moment CDROM and DVD) bool KMountMan::ejectable(QString path) { QString udi = findUdiForPath(path, Solid::DeviceInterface::OpticalDisc); if (udi.isNull()) return false; Solid::Device dev(udi); return dev.as() != 0; } bool KMountMan::removable(QString path) { QString udi = findUdiForPath(path, Solid::DeviceInterface::StorageAccess); if (udi.isNull()) return false; return removable(Solid::Device(udi)); } bool KMountMan::removable(Solid::Device d) { if(!d.isValid()) return false; Solid::StorageDrive *drive = d.as(); if(drive) return drive->isRemovable(); else return(removable(d.parent())); } // a mountMan special version of KIO::convertSize, which deals // with large filesystems ==> > 4GB, it actually receives size in // a minimum block of 1024 ==> data is KB not bytes QString KMountMan::convertSize(KIO::filesize_t size) { float fsize; QString s; QLocale loc; // Tera-byte if (size >= 1073741824) { fsize = (float) size / (float) 1073741824; if (fsize > 1024) // no name for something bigger than tera byte // let's call it Zega-Byte, who'll ever find out? :-) s = i18n("%1 ZB", loc.toString(fsize / (float) 1024, 'f', 1)); else s = i18n("%1 TB", loc.toString(fsize, 'f', 1)); } // Giga-byte else if (size >= 1048576) { fsize = (float) size / (float) 1048576; s = i18n("%1 GB", loc.toString(fsize, 'f', 1)); } // Mega-byte else if (size > 1024) { fsize = (float) size / (float) 1024; s = i18n("%1 MB", loc.toString(fsize, 'f', 1)); } // Kilo-byte else { fsize = (float) size; s = i18n("%1 KB", loc.toString(fsize, 'f', 0)); } return s; } // populate the pop-up menu of the mountman tool-button with actions void KMountMan::quickList() { if (!_operational) { KMessageBox::error(0, i18n("MountMan is not operational. Sorry")); return; } // clear mount / unmount actions for (QAction *action : _action->menu()->actions()) { if (action == _manageAction || action->isSeparator()) { continue; } _action->menu()->removeAction(action); } // create lists of current and possible mount points const KMountPoint::List currentMountPoints = KMountPoint::currentMountPoints(); // create a menu, displaying mountpoints with possible actions for (QExplicitlySharedDataPointer possibleMountPoint : KMountPoint::possibleMountPoints()) { // skip nonmountable file systems if (nonmountFilesystem(possibleMountPoint->mountType(), possibleMountPoint->mountPoint()) || invalidFilesystem(possibleMountPoint->mountType())) { continue; } // does the mountpoint exist in current list? // if so, it can only be umounted, otherwise, it can be mounted bool needUmount = false; for (QExplicitlySharedDataPointer currentMountPoint : currentMountPoints) { if (currentMountPoint->mountPoint() == possibleMountPoint->mountPoint()) { // found -> needs umount needUmount = true; break; } } // add the item to the menu const QString text = QString("%1 %2 (%3)").arg(needUmount ? i18n("Unmount") : i18n("Mount"), possibleMountPoint->mountPoint(), possibleMountPoint->mountedFrom()); QAction *act = _action->menu()->addAction(text); act->setData(QList({ QVariant(needUmount ? KMountMan::ActionType::Unmount : KMountMan::ActionType::Mount), QVariant(possibleMountPoint->mountPoint()) })); } connect(_action->menu(), &QMenu::triggered, this, &KMountMan::delayedPerformAction); } void KMountMan::delayedPerformAction(const QAction *action) { if (!action || !action->data().canConvert>()) { return; } disconnect(_action->menu(), &QMenu::triggered, 0, 0); const QList actData = action->data().toList(); const int actionType = actData[0].toInt(); const QString mountPoint = actData[1].toString(); QTimer::singleShot(0, this, [=] { if (actionType == KMountMan::ActionType::Mount) { mount(mountPoint); } else { unmount(mountPoint); } }); } QString KMountMan::findUdiForPath(QString path, const Solid::DeviceInterface::Type &expType) { KMountPoint::List current = KMountPoint::currentMountPoints(); KMountPoint::List possible = KMountPoint::possibleMountPoints(); QExplicitlySharedDataPointer mp = findInListByMntPoint(current, path); if (!(bool)mp) { mp = findInListByMntPoint(possible, path); if (!(bool)mp) return QString(); } QString dev = QDir(mp->mountedFrom()).canonicalPath(); QList storageDevices = Solid::Device::listFromType(Solid::DeviceInterface::Block); for (int p = storageDevices.count() - 1 ; p >= 0; p--) { Solid::Device device = storageDevices[ p ]; QString udi = device.udi(); Solid::Block * sb = device.as(); if (sb) { QString devb = QDir(sb->device()).canonicalPath(); if (expType != Solid::DeviceInterface::Unknown && !device.isDeviceInterface(expType)) continue; if (devb == dev) return udi; } } return QString(); } QString KMountMan::pathForUdi(QString udi) { Solid::Device device(udi); Solid::StorageAccess *access = device.as(); if(access) return access->filePath(); else return QString(); } void KMountMan::slotTeardownDone(Solid::ErrorType error, QVariant errorData, const QString& /*udi*/) { waiting = false; if (error != Solid::NoError && errorData.isValid()) { KMessageBox::sorry(parentWindow, errorData.toString()); } } void KMountMan::slotSetupDone(Solid::ErrorType error, QVariant errorData, const QString& /*udi*/) { waiting = false; if (error != Solid::NoError && errorData.isValid()) { KMessageBox::sorry(parentWindow, errorData.toString()); } } diff --git a/krusader/MountMan/kmountmangui.cpp b/krusader/MountMan/kmountmangui.cpp index d55d5e08..dc49ad92 100644 --- a/krusader/MountMan/kmountmangui.cpp +++ b/krusader/MountMan/kmountmangui.cpp @@ -1,531 +1,530 @@ /***************************************************************************** * Copyright (C) 2000 Shie Erlich * * 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 "kmountmangui.h" #include "../krglobal.h" +#include "../icon.h" #include "../Dialogs/krspecialwidgets.h" -#include "../kicons.h" #include "../defaults.h" #include "../FileSystem/filesystem.h" // QtCore #include #include #include // QtGui #include #include #include // QtWidgets #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #ifndef BSD #define MTAB "/etc/mtab" #endif KMountManGUI::KMountManGUI(KMountMan *mntMan) : QDialog(mntMan->parentWindow), mountMan(mntMan), info(0), mountList(0), cbShowOnlyRemovable(0), watcher(0), sizeX(-1), sizeY(-1) { setWindowTitle(i18n("MountMan - Your Mount-Manager")); setWindowModality(Qt::WindowModal); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); watcher = new QTimer(this); connect(watcher, SIGNAL(timeout()), this, SLOT(checkMountChange())); mainLayout->addLayout(createMainPage()); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); mainLayout->addWidget(buttonBox); ejectButton = new QPushButton(i18n("&Eject")); - ejectButton->setIcon(QIcon::fromTheme(QStringLiteral("media-eject"))); + ejectButton->setIcon(Icon(QStringLiteral("media-eject"))); ejectButton->setEnabled(false); buttonBox->addButton(ejectButton, QDialogButtonBox::ActionRole); mountButton = new QPushButton(i18n("&Unmount")); mountButton->setEnabled(false); buttonBox->addButton(mountButton, QDialogButtonBox::ActionRole); // connections connect(buttonBox, SIGNAL(rejected()), SLOT(reject())); connect(ejectButton, SIGNAL(clicked()), SLOT(slotEject())); connect(mountButton, SIGNAL(clicked()), SLOT(slotToggleMount())); connect(mountList, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(doubleClicked(QTreeWidgetItem*))); connect(mountList, SIGNAL(itemRightClicked(QTreeWidgetItem*,QPoint,int)), this, SLOT(clicked(QTreeWidgetItem*,QPoint))); connect(mountList, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(changeActive(QTreeWidgetItem*))); connect(mountList, SIGNAL(itemSelectionChanged()), this, SLOT(changeActive())); KConfigGroup group(krConfig, "MountMan"); int sx = group.readEntry("Window Width", -1); int sy = group.readEntry("Window Height", -1); if (sx != -1 && sy != -1) resize(sx, sy); else resize(600, 300); if (group.readEntry("Window Maximized", false)) showMaximized(); else show(); getSpaceData(); exec(); } KMountManGUI::~KMountManGUI() { watcher->stop(); delete watcher; KConfigGroup group(krConfig, "MountMan"); group.writeEntry("Window Width", sizeX); group.writeEntry("Window Height", sizeY); group.writeEntry("Window Maximized", isMaximized()); group.writeEntry("Last State", mountList->header()->saveState()); group.writeEntry("ShowOnlyRemovable", cbShowOnlyRemovable->isChecked()); } void KMountManGUI::resizeEvent(QResizeEvent *e) { if (!isMaximized()) { sizeX = e->size().width(); sizeY = e->size().height(); } QDialog::resizeEvent(e); } QLayout *KMountManGUI::createMainPage() { QGridLayout *layout = new QGridLayout(); layout->setSpacing(10); mountList = new KrTreeWidget(this); // create the main container KConfigGroup grp(krConfig, "Look&Feel"); mountList->setFont(grp.readEntry("Filelist Font", _FilelistFont)); mountList->setSelectionMode(QAbstractItemView::SingleSelection); mountList->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); mountList->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); QStringList labels; labels << i18n("Name"); labels << i18n("Type"); labels << i18n("Mnt.Point"); labels << i18n("Total Size"); labels << i18n("Free Size"); labels << i18n("Free %"); mountList->setHeaderLabels(labels); mountList->header()->setSectionResizeMode(QHeaderView::Interactive); grp = KConfigGroup(krConfig, "MountMan"); if (grp.hasKey("Last State")) mountList->header()->restoreState(grp.readEntry("Last State", QByteArray())); else { int i = QFontMetrics(mountList->font()).width("W"); int j = QFontMetrics(mountList->font()).width("0"); j = (i > j ? i : j); mountList->setColumnWidth(0, j*8); mountList->setColumnWidth(1, j*4); mountList->setColumnWidth(2, j*8); mountList->setColumnWidth(3, j*6); mountList->setColumnWidth(4, j*6); mountList->setColumnWidth(5, j*5); } mountList->setAllColumnsShowFocus(true); mountList->header()->setSortIndicatorShown(true); mountList->sortItems(0, Qt::AscendingOrder); // now the list is created, time to fill it with data. //=>mountMan->forceUpdate(); QGroupBox *box = new QGroupBox(i18n("MountMan.Info"), this); box->setAlignment(Qt::AlignHCenter); QVBoxLayout *vboxl = new QVBoxLayout(box); info = new KRFSDisplay(box); vboxl->addWidget(info); info->resize(info->width(), height()); cbShowOnlyRemovable = new QCheckBox(i18n("Show only removable devices"), this); cbShowOnlyRemovable->setChecked(grp.readEntry("ShowOnlyRemovable", false)); connect(cbShowOnlyRemovable , SIGNAL(stateChanged(int)), SLOT(updateList())); layout->addWidget(box, 0, 0); layout->addWidget(cbShowOnlyRemovable, 1, 0); layout->addWidget(mountList, 0, 1, 2, 1); return layout; } void KMountManGUI::getSpaceData() { fileSystems.clear(); KrMountDetector::getInstance()->hasMountsChanged(); mounted = KMountPoint::currentMountPoints(); possible = KMountPoint::possibleMountPoints(); if (mounted.size() == 0) { // nothing is mounted addNonMounted(); updateList(); // let's continue return; } for (KMountPoint::List::iterator it = mounted.begin(); it != mounted.end(); ++it) { // don't bother with invalid file systems if (mountMan->invalidFilesystem((*it)->mountType())) { continue; } KDiskFreeSpaceInfo info = KDiskFreeSpaceInfo::freeSpaceInfo((*it) ->mountPoint()); if(!info.isValid()) { continue; } fsData data; data.setMntPoint((*it) ->mountPoint()); data.setMounted(true); data.setTotalBlks(info.size() / 1024); data.setFreeBlks(info.available() / 1024); data.setName((*it)->mountedFrom()); data.setType((*it)->mountType()); fileSystems.append(data); } addNonMounted(); updateList(); } void KMountManGUI::addNonMounted() { // handle the non-mounted ones for (KMountPoint::List::iterator it = possible.begin(); it != possible.end(); ++it) { // make sure we don't add things we've already added if (KMountMan::findInListByMntPoint(mounted, (*it)->mountPoint())) { continue; } else { fsData data; data.setMntPoint((*it)->mountPoint()); data.setMounted(false); data.setType((*it)->mountType()); data.setName((*it)->mountedFrom()); if (mountMan->invalidFilesystem(data.type())) continue; fileSystems.append(data); } } } void KMountManGUI::addItemToMountList(KrTreeWidget *lst, fsData &fs) { Solid::Device device(mountMan->findUdiForPath(fs.mntPoint(), Solid::DeviceInterface::StorageAccess)); if (cbShowOnlyRemovable->isChecked() && !mountMan->removable(device)) return; bool mtd = fs.mounted(); QString tSize = QString("%1").arg(KIO::convertSizeFromKiB(fs.totalBlks())); QString fSize = QString("%1").arg(KIO::convertSizeFromKiB(fs.freeBlks())); QString sPrct = QString("%1%").arg(100 - (fs.usedPerct())); QTreeWidgetItem *item = new QTreeWidgetItem(lst); item->setText(0, fs.name()); item->setText(1, fs.type()); item->setText(2, fs.mntPoint()); item->setText(3, (mtd ? tSize : QString("N/A"))); item->setText(4, (mtd ? fSize : QString("N/A"))); item->setText(5, (mtd ? sPrct : QString("N/A"))); Solid::StorageVolume *vol = device.as (); - QString icon; + QString iconName; if(device.isValid()) - icon = device.icon(); + iconName = device.icon(); else if(mountMan->networkFilesystem(fs.type())) - icon = "folder-remote"; + iconName = "folder-remote"; QStringList overlays; if (mtd) { overlays << "emblem-mounted"; } else { overlays << QString(); // We have to guarantee the placement of the next emblem } if (vol && vol->usage() == Solid::StorageVolume::Encrypted) { overlays << "security-high"; } - item->setIcon(0, KDE::icon(icon, overlays)); + item->setIcon(0, Icon(iconName, overlays)); } void KMountManGUI::updateList() { QString currentMP; int currentIdx = 0; QTreeWidgetItem *currentItem = mountList->currentItem(); if(currentItem) { currentMP = getMntPoint(currentItem); currentIdx = mountList->indexOfTopLevelItem(currentItem); } mountList->clearSelection(); mountList->clear(); for (QList::iterator it = fileSystems.begin(); it != fileSystems.end() ; ++it) addItemToMountList(mountList, *it); currentItem = mountList->topLevelItem(currentIdx); for(int i = 0; i < mountList->topLevelItemCount(); i++) { QTreeWidgetItem *item = mountList->topLevelItem(i); if(getMntPoint(item) == currentMP) currentItem = item; } if(!currentItem) currentItem = mountList->topLevelItem(0); mountList->setCurrentItem(currentItem); changeActive(currentItem); mountList->setFocus(); watcher->setSingleShot(true); watcher->start(WATCHER_DELAY); // starting the watch timer ( single shot ) } void KMountManGUI::checkMountChange() { if (KrMountDetector::getInstance()->hasMountsChanged()) getSpaceData(); watcher->setSingleShot(true); watcher->start(WATCHER_DELAY); // starting the watch timer ( single shot ) } void KMountManGUI::doubleClicked(QTreeWidgetItem *i) { if (!i) return; // we don't want to refresh to swap, do we ? // change the active panel to this mountpoint mountMan->emitRefreshPanel(QUrl::fromLocalFile(getMntPoint(i))); close(); } void KMountManGUI::changeActive() { QList seld = mountList->selectedItems(); if (seld.count() > 0) changeActive(seld[ 0 ]); } // when user clicks on a filesystem, change information void KMountManGUI::changeActive(QTreeWidgetItem *i) { if (!i) { if (info) { info->setEmpty(true); info->update(); } mountButton->setEnabled(false); ejectButton->setEnabled(false); return; } fsData *system = getFsData(i); info->setAlias(system->mntPoint()); info->setRealName(system->name()); info->setMounted(system->mounted()); info->setEmpty(false); info->setTotalSpace(system->totalBlks()); info->setFreeSpace(system->freeBlks()); info->repaint(); if(system->mounted()) mountButton->setText(i18n("&Unmount")); else mountButton->setText(i18n("&Mount")); ejectButton->setEnabled(mountMan->ejectable(system->mntPoint())); mountButton->setEnabled(true); } // called when right-clicked on a filesystem void KMountManGUI::clicked(QTreeWidgetItem *item, const QPoint & pos) { // these are the values that will exist in the menu #define MOUNT_ID 90 #define UNMOUNT_ID 91 #define FORMAT_ID 93 #define EJECT_ID 94 ////////////////////////////////////////////////////////// if (!item) return; fsData *system = getFsData(item); // create the menu QMenu popup; popup.setTitle(i18n("MountMan")); if (!system->mounted()) { QAction *mountAct = popup.addAction(i18n("Mount")); mountAct->setData(QVariant(MOUNT_ID)); bool enable = !(mountMan->nonmountFilesystem(system->type(), system->mntPoint())); mountAct->setEnabled(enable); } else { QAction * umountAct = popup.addAction(i18n("Unmount")); umountAct->setData(QVariant(UNMOUNT_ID)); bool enable = !(mountMan->nonmountFilesystem(system->type(), system->mntPoint())); umountAct->setEnabled(enable); } if (mountMan->ejectable(system->mntPoint())) // if (system->type()=="iso9660" || mountMan->followLink(system->name()).left(2)=="cd") popup.addAction(i18n("Eject"))->setData(QVariant(EJECT_ID)); else { QAction *formatAct = popup.addAction(i18n("Format")); formatAct->setData(QVariant(FORMAT_ID)); formatAct->setEnabled(false); } QString mountPoint = system->mntPoint(); QAction * res = popup.exec(pos); int result = -1; if (res && res->data().canConvert()) result = res->data().toInt(); // check out the user's option switch (result) { case - 1 : return ; // the user clicked outside of the menu case MOUNT_ID : case UNMOUNT_ID : mountMan->toggleMount(mountPoint); break; case FORMAT_ID : break; case EJECT_ID : mountMan->eject(mountPoint); break; } } void KMountManGUI::slotToggleMount() { QTreeWidgetItem *item = mountList->currentItem(); if(item) { mountMan->toggleMount(getFsData(item)->mntPoint()); } } void KMountManGUI::slotEject() { QTreeWidgetItem *item = mountList->currentItem(); if(item) { mountMan->eject(getFsData(item)->mntPoint()); } } fsData* KMountManGUI::getFsData(QTreeWidgetItem *item) { for (QList::Iterator it = fileSystems.begin(); it != fileSystems.end(); ++it) { // the only thing which is unique is the mount point if ((*it).mntPoint() == getMntPoint(item)) { return & (*it); } } //this point shouldn't be reached abort(); return 0; } QString KMountManGUI::getMntPoint(QTreeWidgetItem *item) { return item->text(2); // text(2) ? ugly ugly ugly } KrMountDetector::KrMountDetector() { hasMountsChanged(); } bool KrMountDetector::hasMountsChanged() { bool result = false; #ifndef BSD QFileInfo mtabInfo(MTAB); if (!mtabInfo.exists() || mtabInfo.isSymLink()) { // if mtab is a symlimk to /proc/mounts the mtime is unusable #endif KMountPoint::List mountPoints = KMountPoint::currentMountPoints(KMountPoint::NeedRealDeviceName); QCryptographicHash md5(QCryptographicHash::Md5); for (KMountPoint::List::iterator i = mountPoints.begin(); i != mountPoints.end(); ++i) { md5.addData((*i)->mountedFrom().toUtf8()); md5.addData((*i)->realDeviceName().toUtf8()); md5.addData((*i)->mountPoint().toUtf8()); md5.addData((*i)->mountType().toUtf8()); } QString s = md5.result(); result = s != checksum; checksum = s; #ifndef BSD } else { result = mtabInfo.lastModified() != lastMtab; lastMtab = mtabInfo.lastModified(); } #endif return result; } KrMountDetector krMountDetector; KrMountDetector * KrMountDetector::getInstance() { return & krMountDetector; } diff --git a/krusader/Panel/PanelView/krview.cpp b/krusader/Panel/PanelView/krview.cpp index b92c9f4e..a7f04374 100644 --- a/krusader/Panel/PanelView/krview.cpp +++ b/krusader/Panel/PanelView/krview.cpp @@ -1,1223 +1,1223 @@ /***************************************************************************** * Copyright (C) 2000-2002 Shie Erlich * * Copyright (C) 2000-2002 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 "krview.h" #include "krselectionmode.h" #include "krviewfactory.h" #include "krviewitem.h" #include "../FileSystem/dirlisterinterface.h" #include "../FileSystem/fileitem.h" #include "../FileSystem/krpermhandler.h" #include "../Filter/filterdialog.h" #include "../defaults.h" -#include "../kicons.h" +#include "../filelisticon.h" #include "../krcolorcache.h" #include "../krglobal.h" #include "../krpreviews.h" #include "../viewactions.h" // QtCore #include #include // QtGui #include #include #include #include // QtWidgets #include #include #include #include #include #include #include -#include + #define FILEITEM getFileItem() KrView *KrViewOperator::_changedView = 0; KrViewProperties::PropertyType KrViewOperator::_changedProperties = KrViewProperties::NoProperty; // ----------------------------- operator KrViewOperator::KrViewOperator(KrView *view, QWidget *widget) : _view(view), _widget(widget), _massSelectionUpdate(false) { _saveDefaultSettingsTimer.setSingleShot(true); connect(&_saveDefaultSettingsTimer, SIGNAL(timeout()), SLOT(saveDefaultSettings())); } KrViewOperator::~KrViewOperator() { if(_changedView == _view) saveDefaultSettings(); } void KrViewOperator::startUpdate() { _view->refresh(); } void KrViewOperator::cleared() { _view->clear(); } void KrViewOperator::fileAdded(FileItem *fileitem) { _view->addItem(fileitem); } void KrViewOperator::fileUpdated(FileItem *newFileitem) { _view->updateItem(newFileitem); } void KrViewOperator::startDrag() { QStringList items; _view->getSelectedItems(&items); if (items.empty()) return ; // don't drag an empty thing QPixmap px; if (items.count() > 1 || _view->getCurrentKrViewItem() == 0) - px = FL_LOADICON("queue"); // how much are we dragging + px = FileListIcon("document-multiple").pixmap(); // we are dragging multiple items else - px = _view->getCurrentKrViewItem() ->icon(); + px = _view->getCurrentKrViewItem()->icon(); emit letsDrag(items, px); } bool KrViewOperator::searchItem(const QString &text, bool caseSensitive, int direction) { KrViewItem * item = _view->getCurrentKrViewItem(); if (!item) { return false; } const QRegExp regeEx(text, caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive, QRegExp::Wildcard); if (!direction) { if (regeEx.indexIn(item->name()) == 0) { return true; } direction = 1; } KrViewItem * startItem = item; while (true) { item = (direction > 0) ? _view->getNext(item) : _view->getPrev(item); if (!item) item = (direction > 0) ? _view->getFirst() : _view->getLast(); if (regeEx.indexIn(item->name()) == 0) { _view->setCurrentKrViewItem(item); _view->makeItemVisible(item); return true; } if (item == startItem) { return false; } } } bool KrViewOperator::filterSearch(const QString &text, bool caseSensitive) { _view->_quickFilterMask = QRegExp(text, caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive, QRegExp::Wildcard); _view->refresh(); return _view->_count || !_view->_files->numFileItems(); } void KrViewOperator::setMassSelectionUpdate(bool upd) { _massSelectionUpdate = upd; if (!upd) { emit selectionChanged(); _view->redraw(); } } void KrViewOperator::settingsChanged(KrViewProperties::PropertyType properties) { if(!_view->_updateDefaultSettings || _view->_ignoreSettingsChange) return; if(_changedView != _view) saveDefaultSettings(); _changedView = _view; _changedProperties = static_cast(_changedProperties | properties); _saveDefaultSettingsTimer.start(100); } void KrViewOperator::saveDefaultSettings() { _saveDefaultSettingsTimer.stop(); if(_changedView) _changedView->saveDefaultSettings(_changedProperties); _changedProperties = KrViewProperties::NoProperty; _changedView = 0; } // ----------------------------- krview const KrView::IconSizes KrView::iconSizes; KrView::KrView(KrViewInstance &instance, KConfig *cfg) : _config(cfg), _properties(0), _focused(false), _fileIconSize(0), _instance(instance), _files(0), _mainWindow(0), _widget(0), _nameToMakeCurrent(QString()), _previews(0), _updateDefaultSettings(false), _ignoreSettingsChange(false), _count(0), _numDirs(0), _dummyFileItem(0) { } KrView::~KrView() { _instance.m_objects.removeOne(this); delete _previews; _previews = 0; delete _dummyFileItem; _dummyFileItem = 0; if (_properties) qFatal("A class inheriting KrView didn't delete _properties!"); if (_operator) qFatal("A class inheriting KrView didn't delete _operator!"); } void KrView::init(bool enableUpdateDefaultSettings) { // sanity checks: if (!_widget) qFatal("_widget must be set during construction of KrView inheritors"); // ok, continue initProperties(); _operator = createOperator(); setup(); restoreDefaultSettings(); _updateDefaultSettings = enableUpdateDefaultSettings && KConfigGroup(_config, "Startup").readEntry("Update Default Panel Settings", _RememberPos); _instance.m_objects.append(this); } void KrView::initProperties() { const KConfigGroup grpInstance(_config, _instance.name()); const bool displayIcons = grpInstance.readEntry("With Icons", _WithIcons); const KConfigGroup grpSvr(_config, "Look&Feel"); const bool numericPermissions = grpSvr.readEntry("Numeric permissions", _NumericPermissions); int sortOps = 0; if (grpSvr.readEntry("Show Directories First", true)) sortOps |= KrViewProperties::DirsFirst; if(grpSvr.readEntry("Always sort dirs by name", false)) sortOps |= KrViewProperties::AlwaysSortDirsByName; if (!grpSvr.readEntry("Case Sensative Sort", _CaseSensativeSort)) sortOps |= KrViewProperties::IgnoreCase; if (grpSvr.readEntry("Locale Aware Sort", true)) sortOps |= KrViewProperties::LocaleAwareSort; KrViewProperties::SortOptions sortOptions = static_cast(sortOps); KrViewProperties::SortMethod sortMethod = static_cast( grpSvr.readEntry("Sort method", (int)_DefaultSortMethod)); const bool humanReadableSize = grpSvr.readEntry("Human Readable Size", _HumanReadableSize); // see KDE bug #40131 const bool localeAwareCompareIsCaseSensitive = QString("a").localeAwareCompare("B") > 0; QStringList defaultAtomicExtensions; defaultAtomicExtensions += ".tar.gz"; defaultAtomicExtensions += ".tar.bz2"; defaultAtomicExtensions += ".tar.lzma"; defaultAtomicExtensions += ".tar.xz"; defaultAtomicExtensions += ".moc.cpp"; QStringList atomicExtensions = grpSvr.readEntry("Atomic Extensions", defaultAtomicExtensions); for (QStringList::iterator i = atomicExtensions.begin(); i != atomicExtensions.end();) { QString & ext = *i; ext = ext.trimmed(); if (!ext.length()) { i = atomicExtensions.erase(i); continue; } if (!ext.startsWith('.')) ext.insert(0, '.'); ++i; } _properties = new KrViewProperties(displayIcons, numericPermissions, sortOptions, sortMethod, humanReadableSize, localeAwareCompareIsCaseSensitive, atomicExtensions); } void KrView::showPreviews(bool show) { if(show) { if(!_previews) { _previews = new KrPreviews(this); _previews->update(); } } else { delete _previews; _previews = 0; } redraw(); // op()->settingsChanged(KrViewProperties::PropShowPreviews); op()->emitRefreshActions(); } void KrView::updatePreviews() { if(_previews) _previews->update(); } QPixmap KrView::processIcon(const QPixmap &icon, bool dim, const QColor & dimColor, int dimFactor, bool symlink) { QPixmap pixmap = icon; if (symlink) { const QStringList overlays = QStringList() << QString() << "emblem-symbolic-link"; - KIconLoader::global()->drawOverlays(overlays, pixmap, KIconLoader::Desktop); + Icon::applyOverlays(&pixmap, overlays); } if(!dim) return pixmap; QImage dimmed = pixmap.toImage(); QPainter p(&dimmed); p.setCompositionMode(QPainter::CompositionMode_SourceIn); p.fillRect(0, 0, icon.width(), icon.height(), dimColor); p.setCompositionMode(QPainter::CompositionMode_SourceOver); p.setOpacity((qreal)dimFactor / (qreal)100); p.drawPixmap(0, 0, icon.width(), icon.height(), pixmap); return QPixmap::fromImage(dimmed, Qt::ColorOnly | Qt::ThresholdDither | Qt::ThresholdAlphaDither | Qt::NoOpaqueDetection ); } QPixmap KrView::getIcon(FileItem *fileitem, bool active, int size/*, KRListItem::cmpColor color*/) { // KConfigGroup ag( krConfig, "Advanced"); ////////////////////////////// QPixmap icon; - QString icon_name = fileitem->getIcon(); + QString iconName = fileitem->getIcon(); QString cacheName; if(!size) size = _FilelistIconSize.toInt(); QColor dimColor; int dimFactor; bool dim = !active && KrColorCache::getColorCache().getDimSettings(dimColor, dimFactor); - if (icon_name.isNull()) - icon_name = ""; + if (iconName.isNull()) + iconName = ""; cacheName.append(QString::number(size)); if(fileitem->isSymLink()) cacheName.append("LINK_"); if(dim) cacheName.append("DIM_"); - cacheName.append(icon_name); + cacheName.append(iconName); //QPixmapCache::setCacheLimit( ag.readEntry("Icon Cache Size",_IconCacheSize) ); // first try the cache if (!QPixmapCache::find(cacheName, icon)) { - icon = processIcon(krLoader->loadIcon(icon_name, KIconLoader::Desktop, size), + icon = processIcon(Icon(iconName, Icon("unknown")).pixmap(size), dim, dimColor, dimFactor, fileitem->isSymLink()); // insert it into the cache QPixmapCache::insert(cacheName, icon); } return icon; } QPixmap KrView::getIcon(FileItem *fileitem) { if(_previews) { QPixmap icon; if(_previews->getPreview(fileitem, icon, _focused)) return icon; } return getIcon(fileitem, _focused, _fileIconSize); } /** * this function ADDs a list of selected item names into 'names'. * it assumes the list is ready and doesn't initialize it, or clears it */ void KrView::getItemsByMask(QString mask, QStringList* names, bool dirs, bool files) { for (KrViewItem * it = getFirst(); it != 0; it = getNext(it)) { if ((it->name() == "..") || !QDir::match(mask, it->name())) continue; // if we got here, than the item fits the mask if (it->getFileItem()->isDir() && !dirs) continue; // do we need to skip folders? if (!it->getFileItem()->isDir() && !files) continue; // do we need to skip files names->append(it->name()); } } /** * this function ADDs a list of selected item names into 'names'. * it assumes the list is ready and doesn't initialize it, or clears it */ void KrView::getSelectedItems(QStringList *names, bool fallbackToFocused) { for (KrViewItem *it = getFirst(); it != 0; it = getNext(it)) if (it->isSelected() && (it->name() != "..")) names->append(it->name()); if (fallbackToFocused) { // if all else fails, take the current item const QString item = getCurrentItem(); if (names->empty() && !item.isEmpty() && item != "..") { names->append(item); } } } void KrView::getSelectedKrViewItems(KrViewItemList *items) { for (KrViewItem * it = getFirst(); it != 0; it = getNext(it)) if (it->isSelected() && (it->name() != "..")) items->append(it); // if all else fails, take the current item QString item = getCurrentItem(); if (items->empty() && !item.isEmpty() && item != ".." && getCurrentKrViewItem() != 0) { items->append(getCurrentKrViewItem()); } } QString KrView::statistics() { KIO::filesize_t size = calcSize(); KIO::filesize_t selectedSize = calcSelectedSize(); QString tmp; KConfigGroup grp(_config, "Look&Feel"); if(grp.readEntry("Show Size In Bytes", false)) { tmp = i18nc("%1=number of selected items,%2=total number of items, \ %3=filesize of selected items,%4=filesize in Bytes, \ %5=filesize of all items in folder,%6=filesize in Bytes", "%1 out of %2, %3 (%4) out of %5 (%6)", numSelected(), _count, KIO::convertSize(selectedSize), KRpermHandler::parseSize(selectedSize), KIO::convertSize(size), KRpermHandler::parseSize(size)); } else { tmp = i18nc("%1=number of selected items,%2=total number of items, \ %3=filesize of selected items,%4=filesize of all items in folder", "%1 out of %2, %3 out of %4", numSelected(), _count, KIO::convertSize(selectedSize), KIO::convertSize(size)); } // notify if we're running a filtered view if (filter() != KrViewProperties::All) tmp = ">> [ " + filterMask().nameFilter() + " ] " + tmp; return tmp; } bool KrView::changeSelection(const KRQuery& filter, bool select) { KConfigGroup grpSvr(_config, "Look&Feel"); return changeSelection(filter, select, grpSvr.readEntry("Mark Dirs", _MarkDirs), true); } bool KrView::changeSelection(const KRQuery& filter, bool select, bool includeDirs, bool makeVisible) { if (op()) op()->setMassSelectionUpdate(true); KrViewItem *temp = getCurrentKrViewItem(); KrViewItem *firstMatch = 0; for (KrViewItem * it = getFirst(); it != 0; it = getNext(it)) { if (it->name() == "..") continue; if (it->getFileItem()->isDir() && !includeDirs) continue; FileItem * file = it->getMutableFileItem(); // filter::match calls getMimetype which isn't const if (file == 0) continue; if (filter.match(file)) { it->setSelected(select); if (!firstMatch) firstMatch = it; } } if (op()) op()->setMassSelectionUpdate(false); updateView(); if (ensureVisibilityAfterSelect() && temp != 0) { makeItemVisible(temp); } else if (makeVisible && firstMatch != 0) { // if no selected item is visible... KrViewItemList selectedItems; getSelectedKrViewItems(&selectedItems); bool anyVisible = false; for (KrViewItem *item : selectedItems) { if (isItemVisible(item)) { anyVisible = true; break; } } if (!anyVisible) { // ...scroll to fist selected item makeItemVisible(firstMatch); } } redraw(); return firstMatch != 0; // return if any file was selected } void KrView::invertSelection() { if (op()) op()->setMassSelectionUpdate(true); KConfigGroup grpSvr(_config, "Look&Feel"); bool markDirs = grpSvr.readEntry("Mark Dirs", _MarkDirs); KrViewItem *temp = getCurrentKrViewItem(); for (KrViewItem * it = getFirst(); it != 0; it = getNext(it)) { if (it->name() == "..") continue; if (it->getFileItem()->isDir() && !markDirs && !it->isSelected()) continue; it->setSelected(!it->isSelected()); } if (op()) op()->setMassSelectionUpdate(false); updateView(); if (ensureVisibilityAfterSelect() && temp != 0) makeItemVisible(temp); } QString KrView::firstUnmarkedBelowCurrent(const bool skipCurrent) { if (getCurrentKrViewItem() == 0) return QString(); KrViewItem *iterator = getCurrentKrViewItem(); if (skipCurrent) iterator = getNext(iterator); while (iterator && iterator->isSelected()) iterator = getNext(iterator); if (!iterator) { iterator = getPrev(getCurrentKrViewItem()); while (iterator && iterator->isSelected()) iterator = getPrev(iterator); } if (!iterator) return QString(); return iterator->name(); } void KrView::deleteItem(const QString &name, bool onUpdate) { KrViewItem *viewItem = findItemByName(name); if (!viewItem) return; if (_previews && !onUpdate) _previews->deletePreview(viewItem); preDeleteItem(viewItem); if (viewItem->FILEITEM->isDir()) { --_numDirs; } --_count; delete viewItem; if (!onUpdate) op()->emitSelectionChanged(); } void KrView::addItem(FileItem *fileItem, bool onUpdate) { if (isFiltered(fileItem)) return; KrViewItem *viewItem = preAddItem(fileItem); if (!viewItem) return; // not added if (_previews) _previews->updatePreview(viewItem); if (fileItem->isDir()) ++_numDirs; ++_count; if (!onUpdate) { op()->emitSelectionChanged(); } } void KrView::updateItem(FileItem *newFileItem) { // file name did not change const QString name = newFileItem->getName(); // preserve 'current' and 'selection' const bool isCurrent = getCurrentItem() == name; QStringList selectedNames; getSelectedItems(&selectedNames, false); const bool isSelected = selectedNames.contains(name); // delete old file item deleteItem(name, true); if (!isFiltered(newFileItem)) { addItem(newFileItem, true); } if (isCurrent) setCurrentItem(name, false); if (isSelected) setSelected(newFileItem, true); op()->emitSelectionChanged(); } void KrView::clear() { if(_previews) _previews->clear(); _count = _numDirs = 0; delete _dummyFileItem; _dummyFileItem = 0; redraw(); } bool KrView::handleKeyEvent(QKeyEvent *e) { qDebug() << "key event=" << e; switch (e->key()) { case Qt::Key_Enter : case Qt::Key_Return : { if (e->modifiers() & Qt::ControlModifier) // let the panel handle it e->ignore(); else { KrViewItem * i = getCurrentKrViewItem(); if (i == 0) return true; QString tmp = i->name(); op()->emitExecuted(tmp); } return true; } case Qt::Key_QuoteLeft : // Terminal Emulator bugfix if (e->modifiers() == Qt::ControlModifier) { // let the panel handle it e->ignore(); } else { // a normal click - do a lynx-like moving thing // ask krusader to move to the home directory op()->emitGoHome(); } return true; case Qt::Key_Delete : // delete/trash the file (delete with alternative mode is a panel action) // allow only no modifier or KeypadModifier (i.e. Del on a Numeric Keypad) if ((e->modifiers() & ~Qt::KeypadModifier) == Qt::NoModifier) { op()->emitDefaultDeleteFiles(); } return true; case Qt::Key_Insert: { KrViewItem * i = getCurrentKrViewItem(); if (!i) return true; i->setSelected(!i->isSelected()); if (KrSelectionMode::getSelectionHandler()->insertMovesDown()) { KrViewItem * next = getNext(i); if (next) { setCurrentKrViewItem(next); makeItemVisible(next); } } op()->emitSelectionChanged(); return true; } case Qt::Key_Space: { KrViewItem * viewItem = getCurrentKrViewItem(); if (viewItem != 0) { viewItem->setSelected(!viewItem->isSelected()); if (viewItem->getFileItem()->isDir() && KrSelectionMode::getSelectionHandler()->spaceCalculatesDiskSpace()) { op()->emitQuickCalcSpace(viewItem); } if (KrSelectionMode::getSelectionHandler()->spaceMovesDown()) { KrViewItem * next = getNext(viewItem); if (next) { setCurrentKrViewItem(next); makeItemVisible(next); } } op()->emitSelectionChanged(); } return true; } case Qt::Key_Backspace : // Terminal Emulator bugfix case Qt::Key_Left : if (e->modifiers() == Qt::ControlModifier || e->modifiers() == Qt::ShiftModifier || e->modifiers() == Qt::AltModifier) { // let the panel handle it e->ignore(); } else { // a normal click - do a lynx-like moving thing // ask krusader to move up a directory op()->emitDirUp(); } return true; // safety case Qt::Key_Right : if (e->modifiers() == Qt::ControlModifier || e->modifiers() == Qt::ShiftModifier || e->modifiers() == Qt::AltModifier) { // let the panel handle it e->ignore(); } else { // just a normal click - do a lynx-like moving thing KrViewItem *i = getCurrentKrViewItem(); if (i) op()->emitGoInside(i->name()); } return true; case Qt::Key_Up : if (e->modifiers() == Qt::ControlModifier) { // let the panel handle it - jump to the Location Bar e->ignore(); } else { KrViewItem *item = getCurrentKrViewItem(); if (item) { if (e->modifiers() == Qt::ShiftModifier) { item->setSelected(!item->isSelected()); op()->emitSelectionChanged(); } item = getPrev(item); if (item) { setCurrentKrViewItem(item); makeItemVisible(item); } } } return true; case Qt::Key_Down : if (e->modifiers() == Qt::ControlModifier || e->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { // let the panel handle it - jump to command line e->ignore(); } else { KrViewItem *item = getCurrentKrViewItem(); if (item) { if (e->modifiers() == Qt::ShiftModifier) { item->setSelected(!item->isSelected()); op()->emitSelectionChanged(); } item = getNext(item); if (item) { setCurrentKrViewItem(item); makeItemVisible(item); } } } return true; case Qt::Key_Home: { if (e->modifiers() & Qt::ShiftModifier) { bool select = true; KrViewItem *pos = getCurrentKrViewItem(); if (pos == 0) pos = getLast(); KrViewItem *item = getFirst(); op()->setMassSelectionUpdate(true); while (item) { item->setSelected(select); if (item == pos) select = false; item = getNext(item); } op()->setMassSelectionUpdate(false); } KrViewItem * first = getFirst(); if (first) { setCurrentKrViewItem(first); makeItemVisible(first); } } return true; case Qt::Key_End: if (e->modifiers() & Qt::ShiftModifier) { bool select = false; KrViewItem *pos = getCurrentKrViewItem(); if (pos == 0) pos = getFirst(); op()->setMassSelectionUpdate(true); KrViewItem *item = getFirst(); while (item) { if (item == pos) select = true; item->setSelected(select); item = getNext(item); } op()->setMassSelectionUpdate(false); } else { KrViewItem *last = getLast(); if (last) { setCurrentKrViewItem(last); makeItemVisible(last); } } return true; case Qt::Key_PageDown: { KrViewItem * current = getCurrentKrViewItem(); int downStep = itemsPerPage(); while (downStep != 0 && current) { KrViewItem * newCurrent = getNext(current); if (newCurrent == 0) break; current = newCurrent; downStep--; } if (current) { setCurrentKrViewItem(current); makeItemVisible(current); } return true; } case Qt::Key_PageUp: { KrViewItem * current = getCurrentKrViewItem(); int upStep = itemsPerPage(); while (upStep != 0 && current) { KrViewItem * newCurrent = getPrev(current); if (newCurrent == 0) break; current = newCurrent; upStep--; } if (current) { setCurrentKrViewItem(current); makeItemVisible(current); } return true; } case Qt::Key_Escape: e->ignore(); return true; // otherwise the selection gets lost??!?? // also it is needed by the panel case Qt::Key_A : // mark all if (e->modifiers() == Qt::ControlModifier) { //FIXME: shouldn't there also be a shortcut for unselecting everything ? selectAllIncludingDirs(); return true; } #if __GNUC__ >= 7 [[gnu::fallthrough]]; #endif default: return false; } return false; } void KrView::zoomIn() { int idx = iconSizes.indexOf(_fileIconSize); if(idx >= 0 && (idx+1) < iconSizes.count()) setFileIconSize(iconSizes[idx+1]); } void KrView::zoomOut() { int idx = iconSizes.indexOf(_fileIconSize); if(idx > 0) setFileIconSize(iconSizes[idx-1]); } void KrView::setFileIconSize(int size) { if(iconSizes.indexOf(size) < 0) return; _fileIconSize = size; if(_previews) { _previews->clear(); _previews->update(); } redraw(); op()->emitRefreshActions(); } int KrView::defaultFileIconSize() { KConfigGroup grpSvr(_config, _instance.name()); return grpSvr.readEntry("IconSize", _FilelistIconSize).toInt(); } void KrView::saveDefaultSettings(KrViewProperties::PropertyType properties) { saveSettings(KConfigGroup(_config, _instance.name()), properties); op()->emitRefreshActions(); } void KrView::restoreDefaultSettings() { restoreSettings(KConfigGroup(_config, _instance.name())); } void KrView::saveSettings(KConfigGroup group, KrViewProperties::PropertyType properties) { if(properties & KrViewProperties::PropIconSize) group.writeEntry("IconSize", fileIconSize()); if(properties & KrViewProperties::PropShowPreviews) group.writeEntry("ShowPreviews", previewsShown()); if(properties & KrViewProperties::PropSortMode) saveSortMode(group); if(properties & KrViewProperties::PropFilter) { group.writeEntry("Filter", static_cast(_properties->filter)); group.writeEntry("FilterApplysToDirs", _properties->filterApplysToDirs); if(_properties->filterSettings.isValid()) _properties->filterSettings.save(KConfigGroup(&group, "FilterSettings")); } } void KrView::restoreSettings(KConfigGroup group) { _ignoreSettingsChange = true; doRestoreSettings(group); _ignoreSettingsChange = false; refresh(); } void KrView::doRestoreSettings(KConfigGroup group) { restoreSortMode(group); setFileIconSize(group.readEntry("IconSize", defaultFileIconSize())); showPreviews(group.readEntry("ShowPreviews", false)); _properties->filter = static_cast(group.readEntry("Filter", static_cast(KrViewProperties::All))); _properties->filterApplysToDirs = group.readEntry("FilterApplysToDirs", false); _properties->filterSettings.load(KConfigGroup(&group, "FilterSettings")); _properties->filterMask = _properties->filterSettings.toQuery(); } void KrView::applySettingsToOthers() { for(int i = 0; i < _instance.m_objects.length(); i++) { KrView *view = _instance.m_objects[i]; if(this != view) { view->_ignoreSettingsChange = true; view->copySettingsFrom(this); view->_ignoreSettingsChange = false; } } } void KrView::sortModeUpdated(KrViewProperties::ColumnType sortColumn, bool descending) { if(sortColumn == _properties->sortColumn && descending == (bool) (_properties->sortOptions & KrViewProperties::Descending)) return; int options = _properties->sortOptions; if(descending) options |= KrViewProperties::Descending; else options &= ~KrViewProperties::Descending; _properties->sortColumn = sortColumn; _properties->sortOptions = static_cast(options); // op()->settingsChanged(KrViewProperties::PropSortMode); } bool KrView::drawCurrent() const { return isFocused() || KConfigGroup(_config, "Look&Feel") .readEntry("Always Show Current Item", _AlwaysShowCurrentItem); } void KrView::saveSortMode(KConfigGroup &group) { group.writeEntry("Sort Column", static_cast(_properties->sortColumn)); group.writeEntry("Descending Sort Order", _properties->sortOptions & KrViewProperties::Descending); } void KrView::restoreSortMode(KConfigGroup &group) { int column = group.readEntry("Sort Column", static_cast(KrViewProperties::Name)); bool isDescending = group.readEntry("Descending Sort Order", false); setSortMode(static_cast(column), isDescending); } QString KrView::krPermissionText(const FileItem * fileitem) { QString tmp; switch (fileitem->isReadable()) { case ALLOWED_PERM: tmp+='r'; break; case UNKNOWN_PERM: tmp+='?'; break; case NO_PERM: tmp+='-'; break; } switch (fileitem->isWriteable()) { case ALLOWED_PERM: tmp+='w'; break; case UNKNOWN_PERM: tmp+='?'; break; case NO_PERM: tmp+='-'; break; } switch (fileitem->isExecutable()) { case ALLOWED_PERM: tmp+='x'; break; case UNKNOWN_PERM: tmp+='?'; break; case NO_PERM: tmp+='-'; break; } return tmp; } QString KrView::permissionsText(const KrViewProperties *properties, const FileItem *fileItem) { return properties->numericPermissions ? QString().asprintf("%.4o", fileItem->getMode() & (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)) : fileItem->getPerm(); } QString KrView::sizeText(const KrViewProperties *properties, KIO::filesize_t size) { return properties->humanReadableSize ? KIO::convertSize(size) : KRpermHandler::parseSize(size); } QString KrView::mimeTypeText(FileItem *fileItem) { QMimeType mt = QMimeDatabase().mimeTypeForName(fileItem->getMime()); return mt.isValid() ? mt.comment() : QString(); } bool KrView::isFiltered(FileItem *fileitem) { if (_quickFilterMask.isValid() && _quickFilterMask.indexIn(fileitem->getName()) == -1) return true; bool filteredOut = false; bool isDir = fileitem->isDir(); if (!isDir || (isDir && properties()->filterApplysToDirs)) { switch (properties()->filter) { case KrViewProperties::All : break; case KrViewProperties::Custom : if (!properties()->filterMask.match(fileitem)) filteredOut = true; break; case KrViewProperties::Dirs: if (!isDir) filteredOut = true; break; case KrViewProperties::Files: if (isDir) filteredOut = true; break; default: break; } } return filteredOut; } void KrView::setFiles(DirListerInterface *files) { if(files != _files) { clear(); if(_files) QObject::disconnect(_files, 0, op(), 0); _files = files; } if(!_files) return; QObject::disconnect(_files, 0, op(), 0); QObject::connect(_files, &DirListerInterface::scanDone, op(), &KrViewOperator::startUpdate); QObject::connect(_files, &DirListerInterface::cleared, op(), &KrViewOperator::cleared); QObject::connect(_files, &DirListerInterface::addedFileItem, op(), &KrViewOperator::fileAdded); QObject::connect(_files, &DirListerInterface::updatedFileItem, op(), &KrViewOperator::fileUpdated); } void KrView::setFilter(KrViewProperties::FilterSpec filter, FilterSettings customFilter, bool applyToDirs) { _properties->filter = filter; _properties->filterSettings = customFilter; _properties->filterMask = customFilter.toQuery(); _properties->filterApplysToDirs = applyToDirs; refresh(); } void KrView::setFilter(KrViewProperties::FilterSpec filter) { KConfigGroup cfg(_config, "Look&Feel"); bool rememberSettings = cfg.readEntry("FilterDialogRemembersSettings", _FilterDialogRemembersSettings); bool applyToDirs = rememberSettings ? _properties->filterApplysToDirs : false; switch (filter) { case KrViewProperties::All : break; case KrViewProperties::Custom : { FilterDialog dialog(_widget, i18n("Filter Files"), QStringList(i18n("Apply filter to folders")), false); dialog.checkExtraOption(i18n("Apply filter to folders"), applyToDirs); if(rememberSettings) dialog.applySettings(_properties->filterSettings); dialog.exec(); FilterSettings s(dialog.getSettings()); if(!s.isValid()) // if the user canceled - quit return; _properties->filterSettings = s; _properties->filterMask = s.toQuery(); applyToDirs = dialog.isExtraOptionChecked(i18n("Apply filter to folders")); } break; default: return; } _properties->filterApplysToDirs = applyToDirs; _properties->filter = filter; refresh(); } void KrView::customSelection(bool select) { KConfigGroup grpSvr(_config, "Look&Feel"); bool includeDirs = grpSvr.readEntry("Mark Dirs", _MarkDirs); FilterDialog dialog(0, i18n("Select Files"), QStringList(i18n("Apply selection to folders")), false); dialog.checkExtraOption(i18n("Apply selection to folders"), includeDirs); dialog.exec(); KRQuery query = dialog.getQuery(); // if the user canceled - quit if (query.isNull()) return; includeDirs = dialog.isExtraOptionChecked(i18n("Apply selection to folders")); changeSelection(query, select, includeDirs); } void KrView::refresh() { const QString currentItem = !nameToMakeCurrent().isEmpty() ? // nameToMakeCurrent() : getCurrentItem(); bool scrollToCurrent = !nameToMakeCurrent().isEmpty() || isItemVisible(getCurrentKrViewItem()); setNameToMakeCurrent(QString()); const QModelIndex currentIndex = getCurrentIndex(); const QList selection = selectedUrls(); clear(); if(!_files) return; QList fileItems; // if we are not at the root add the ".." entry if(!_files->isRoot()) { _dummyFileItem = FileItem::createDummy(); fileItems << _dummyFileItem; } foreach(FileItem *fileitem, _files->fileItems()) { if(!fileitem || isFiltered(fileitem)) continue; if(fileitem->isDir()) _numDirs++; _count++; fileItems << fileitem; } populate(fileItems, _dummyFileItem); if(!selection.isEmpty()) setSelectionUrls(selection); if (!currentItem.isEmpty()) { if (currentItem == ".." && _count > 0 && // !_quickFilterMask.isEmpty() && _quickFilterMask.isValid()) { // In a filtered view we should never select the dummy entry if // there are real matches. setCurrentKrViewItem(getNext(getFirst())); } else { setCurrentItem(currentItem, scrollToCurrent, currentIndex); } } else { setCurrentKrViewItem(getFirst()); } updatePreviews(); redraw(); op()->emitSelectionChanged(); } void KrView::setSelected(const FileItem* fileitem, bool select) { if (fileitem == _dummyFileItem) return; if (select) clearSavedSelection(); intSetSelected(fileitem, select); } void KrView::saveSelection() { _savedSelection = selectedUrls(); op()->emitRefreshActions(); } void KrView::restoreSelection() { if(canRestoreSelection()) setSelectionUrls(_savedSelection); } void KrView::clearSavedSelection() { _savedSelection.clear(); op()->emitRefreshActions(); } void KrView::markSameBaseName() { KrViewItem* item = getCurrentKrViewItem(); if (!item) return; KRQuery query(QString("%1.*").arg(item->name(false))); changeSelection(query, true, false); } void KrView::markSameExtension() { KrViewItem* item = getCurrentKrViewItem(); if (!item) return; KRQuery query(QString("*.%1").arg(item->extension())); changeSelection(query, true, false); } diff --git a/krusader/Panel/PanelView/krviewfactory.cpp b/krusader/Panel/PanelView/krviewfactory.cpp index 1756e8c2..037f9280 100644 --- a/krusader/Panel/PanelView/krviewfactory.cpp +++ b/krusader/Panel/PanelView/krviewfactory.cpp @@ -1,107 +1,107 @@ /***************************************************************************** * Copyright (C) 2000-2007 Shie Erlich * * Copyright (C) 2000-2007 Rafi Yanai * * Copyright (C) 2000-2007 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/]. * *****************************************************************************/ #include "krviewfactory.h" #include "krinterdetailedview.h" #include "krinterbriefview.h" #include #include KrViewInstance::KrViewInstance(int id, const QString &name, const QString &desc, - const QString &icon, const QKeySequence &shortcut) - : m_id(id), m_name(name), m_description(desc), m_icon(icon), m_shortcut(shortcut) + const QString &iconName, const QKeySequence &shortcut) + : m_id(id), m_name(name), m_description(desc), m_iconName(iconName), m_shortcut(shortcut) { } template class KrViewInstanceImpl : public KrViewInstance { public: KrViewInstanceImpl(int id, const QString &name, const QString &desc, const QString &icon, const QKeySequence &shortcut) : KrViewInstance(id, name, desc, icon, shortcut) {} virtual KrView *create(QWidget *w, KConfig *cfg) Q_DECL_OVERRIDE { return new T(w, *this, cfg); } }; KrViewFactory::KrViewFactory() : m_defaultViewId(-1) {} // static initialization, on first use idiom KrViewFactory &KrViewFactory::self() { static KrViewFactory *factory = 0; if (!factory) { factory = new KrViewFactory(); factory->init(); } return *factory; } void KrViewFactory::init() { registerView(new KrViewInstanceImpl (0, "KrInterDetailedView", i18n("&Detailed View"), "view-list-details", Qt::ALT + Qt::SHIFT + Qt::Key_D)); registerView(new KrViewInstanceImpl (1, "KrInterBriefView", i18n("&Brief View"), "view-list-icons", Qt::ALT + Qt::SHIFT + Qt::Key_B)); } KrView *KrViewFactory::createView(int id, QWidget *widget, KConfig *cfg) { return self().viewInstance(id)->create(widget, cfg); } void KrViewFactory::registerView(KrViewInstance *inst) { int position = 0; while (position < m_registeredViews.count()) { if (m_registeredViews[position]->id() > inst->id()) break; position++; } m_registeredViews.insert(m_registeredViews.begin() + position, inst); if (m_defaultViewId == -1 || inst->id() < m_defaultViewId) m_defaultViewId = inst->id(); } KrViewInstance *KrViewFactory::viewInstance(int id) { foreach (KrViewInstance *inst, m_registeredViews) { if (inst->id() == id) return inst; } foreach (KrViewInstance *inst_dflt, m_registeredViews) { if (inst_dflt->id() == m_defaultViewId) return inst_dflt; } fprintf(stderr, "Internal Error: no views registered!\n"); exit(-1); } diff --git a/krusader/Panel/PanelView/krviewfactory.h b/krusader/Panel/PanelView/krviewfactory.h index 2b2b745e..ec00a58a 100644 --- a/krusader/Panel/PanelView/krviewfactory.h +++ b/krusader/Panel/PanelView/krviewfactory.h @@ -1,86 +1,86 @@ /***************************************************************************** * Copyright (C) 2000-2008 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 KRVIEWFACTORY_H #define KRVIEWFACTORY_H // QtCore #include #include // QtGui #include // QtWidgets #include class KrView; class KConfig; /** Abstract container for KrView implementation classes. Created internally by KrViewFactory. */ class KrViewInstance { friend class KrView; public: inline int id() const { return m_id; } inline QString name() const { return m_name; } inline QString description() const { return m_description; } - inline QString icon() const { return m_icon; } + inline QString iconName() const { return m_iconName; } inline QKeySequence shortcut() const { return m_shortcut; } virtual KrView *create(QWidget *w, KConfig *cfg) = 0; protected: - KrViewInstance(int id, const QString &name, const QString &desc, const QString &icon, + KrViewInstance(int id, const QString &name, const QString &desc, const QString &iconName, const QKeySequence &shortcut); virtual ~KrViewInstance() {} private: const int m_id; const QString m_name; const QString m_description; - const QString m_icon; + const QString m_iconName; const QKeySequence m_shortcut; QList m_objects; // direct access in KrView }; /** Factory for KrView implementations. This is a hidden singleton. */ class KrViewFactory { friend class KrViewInstance; public: static KrView *createView(int id, QWidget *widget, KConfig *cfg); static const QList ®isteredViews() { return self().m_registeredViews; } static int defaultViewId() { return self().m_defaultViewId; } private: KrViewFactory(); void init(); void registerView(KrViewInstance *); KrViewInstance *viewInstance(int id); static KrViewFactory &self(); QList m_registeredViews; int m_defaultViewId; }; #endif /* __KRVIEWFACTORY_H__ */ diff --git a/krusader/Panel/krfiletreeview.cpp b/krusader/Panel/krfiletreeview.cpp index e6c173b4..1c14abed 100644 --- a/krusader/Panel/krfiletreeview.cpp +++ b/krusader/Panel/krfiletreeview.cpp @@ -1,400 +1,401 @@ /***************************************************************************** * Copyright (C) 2010 Jan Lepper * * Copyright (C) 2010-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 "krfiletreeview.h" #include "panelfunc.h" #include "../defaults.h" #include "../krglobal.h" +#include "../icon.h" #include "../FileSystem/filesystemprovider.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class KrDirModel : public KDirModel { public: KrDirModel(QWidget *parent, KrFileTreeView *ftv) : KDirModel(parent), fileTreeView(ftv) {} protected: virtual Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE { Qt::ItemFlags itflags = KDirModel::flags(index); if (index.column() != KDirModel::Name) itflags &= ~Qt::ItemIsDropEnabled; return itflags; } private: KrFileTreeView *fileTreeView; }; class TreeStyle : public QProxyStyle { public: explicit TreeStyle(QStyle *style) : QProxyStyle(style) {} int styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const Q_DECL_OVERRIDE { if (hint == QStyle::SH_ItemView_ActivateItemOnSingleClick) { return true; } return QProxyStyle::styleHint(hint, option, widget, returnData); } }; KrFileTreeView::KrFileTreeView(QWidget *parent) : QTreeView(parent), mCurrentUrl(), mCurrentTreeBase(), mStartTreeFromCurrent(false), mStartTreeFromPlace(true) { mSourceModel = new KrDirModel(this, this); mSourceModel->dirLister()->setDirOnlyMode(true); mProxyModel = new KDirSortFilterProxyModel(this); mProxyModel->setSourceModel(mSourceModel); setModel(mProxyModel); mFilePlacesModel = new KFilePlacesModel(this); setItemDelegate(new KFileItemDelegate(this)); setUniformRowHeights(true); // drag&drop setAcceptDrops(true); setDragEnabled(true); setDropIndicatorShown(true); mSourceModel->setDropsAllowed(KDirModel::DropOnDirectory); setStyle(new TreeStyle(style())); connect(this, &KrFileTreeView::activated, this, &KrFileTreeView::slotActivated); connect(mSourceModel, &KDirModel::expand, this, &KrFileTreeView::slotExpanded); QFontMetrics fontMetrics(viewport()->font()); header()->resizeSection(KDirModel::Name, fontMetrics.width("WWWWWWWWWWWWWWW")); header()->setContextMenuPolicy(Qt::CustomContextMenu); connect(header(), &QHeaderView::customContextMenuRequested, this, &KrFileTreeView::showHeaderContextMenu); setBriefMode(true); setContextMenuPolicy(Qt::CustomContextMenu); connect(this, &KrFileTreeView::customContextMenuRequested, this, &KrFileTreeView::slotCustomContextMenuRequested); setTree(mStartTreeFromCurrent, mStartTreeFromPlace); } void KrFileTreeView::setCurrentUrl(const QUrl &url) { mCurrentUrl = url; if (mStartTreeFromCurrent) { setTreeRoot(url); } else { if (mStartTreeFromPlace) { const QModelIndex index = mFilePlacesModel->closestItem(url); // magic here const QUrl rootBase = index.isValid() ? mFilePlacesModel->url(index) : QUrl::fromLocalFile(QDir::root().path()); setTreeRoot(rootBase); } if (isVisible(url)) { // avoid unwanted scrolling by KDirModel::expandToUrl() setCurrentIndex(mProxyModel->mapFromSource(mSourceModel->indexForUrl(url))); } else { mSourceModel->expandToUrl(url); } } } QUrl KrFileTreeView::urlForProxyIndex(const QModelIndex &index) const { const KFileItem item = mSourceModel->itemForIndex(mProxyModel->mapToSource(index)); return !item.isNull() ? item.url() : QUrl(); } void KrFileTreeView::slotActivated(const QModelIndex &index) { const QUrl url = urlForProxyIndex(index); if (url.isValid()) { emit urlActivated(url); } } void KrFileTreeView::dropEvent(QDropEvent *event) { QUrl destination = urlForProxyIndex(indexAt(event->pos())); if (destination.isEmpty()) { return; } FileSystemProvider::instance().startDropFiles(event, destination); } void KrFileTreeView::slotExpanded(const QModelIndex &baseIndex) { const QModelIndex index = mProxyModel->mapFromSource(baseIndex); expand(index); // expand view now after model was expanded selectionModel()->clearSelection(); selectionModel()->setCurrentIndex(index, QItemSelectionModel::SelectCurrent); scrollTo(index); } void KrFileTreeView::showHeaderContextMenu() { QMenu popup(this); popup.setToolTipsVisible(true); QAction *detailAction = popup.addAction(i18n("Show Details")); detailAction->setCheckable(true); detailAction->setChecked(!briefMode()); detailAction->setToolTip(i18n("Show columns with details")); QAction *showHiddenAction = popup.addAction(i18n("Show Hidden Folders")); showHiddenAction->setCheckable(true); showHiddenAction->setChecked(mSourceModel->dirLister()->showingDotFiles()); showHiddenAction->setToolTip(i18n("Show folders starting with a dot")); popup.addSeparator(); QActionGroup *rootActionGroup = new QActionGroup(this); QAction *startFromRootAction = popup.addAction(i18n("Start From Root")); startFromRootAction->setCheckable(true); startFromRootAction->setChecked(!mStartTreeFromCurrent && !mStartTreeFromPlace); startFromRootAction->setToolTip(i18n("Set root of the tree to root of filesystem")); startFromRootAction->setActionGroup(rootActionGroup); QAction *startFromCurrentAction = popup.addAction(i18n("Start From Current")); startFromCurrentAction->setCheckable(true); startFromCurrentAction->setChecked(mStartTreeFromCurrent); startFromCurrentAction->setToolTip(i18n("Set root of the tree to the current folder")); startFromCurrentAction->setActionGroup(rootActionGroup); QAction *startFromPlaceAction = popup.addAction(i18n("Start From Place")); startFromPlaceAction->setCheckable(true); startFromPlaceAction->setChecked(mStartTreeFromPlace); startFromPlaceAction->setToolTip( i18n("Set root of the tree to closest folder listed in 'Places'")); startFromPlaceAction->setActionGroup(rootActionGroup); QAction *triggeredAction = popup.exec(QCursor::pos()); if (triggeredAction == detailAction) { setBriefMode(!detailAction->isChecked()); } else if (triggeredAction == showHiddenAction) { KDirLister *dirLister = mSourceModel->dirLister(); dirLister->setShowingDotFiles(showHiddenAction->isChecked()); dirLister->emitChanges(); } else if (triggeredAction && triggeredAction->actionGroup() == rootActionGroup) { setTree(startFromCurrentAction->isChecked(), startFromPlaceAction->isChecked()); } } void KrFileTreeView::slotCustomContextMenuRequested(const QPoint &point) { const QModelIndex index = indexAt(point); if (!index.isValid()) return; const KFileItem fileItem = mSourceModel->itemForIndex(mProxyModel->mapToSource(index)); const KFileItemListProperties capabilities(KFileItemList() << fileItem); QMenu* popup = new QMenu(this); // TODO nice to have: "open with" // cut/copy/paste - QAction* cutAction = new QAction(QIcon::fromTheme(QStringLiteral("edit-cut")), i18nc("@action:inmenu", "Cut"), this); + QAction* cutAction = new QAction(Icon(QStringLiteral("edit-cut")), i18nc("@action:inmenu", "Cut"), this); cutAction->setEnabled(capabilities.supportsMoving()); connect(cutAction, &QAction::triggered, this, [=]() { copyToClipBoard(fileItem, true); }); popup->addAction(cutAction); - QAction* copyAction = new QAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18nc("@action:inmenu", "Copy"), this); + QAction* copyAction = new QAction(Icon(QStringLiteral("edit-copy")), i18nc("@action:inmenu", "Copy"), this); connect(copyAction, &QAction::triggered, this, [=]() { copyToClipBoard(fileItem, false); }); popup->addAction(copyAction); const QMimeData *mimeData = QApplication::clipboard()->mimeData(); bool canPaste; const QString text = KIO::pasteActionText(mimeData, &canPaste, fileItem); - QAction* pasteAction = new QAction(QIcon::fromTheme(QStringLiteral("edit-paste")), text, this); + QAction* pasteAction = new QAction(Icon(QStringLiteral("edit-paste")), text, this); connect(pasteAction, &QAction::triggered, this, [=]() { KIO::PasteJob *job = KIO::paste(QApplication::clipboard()->mimeData(), fileItem.url()); KJobWidgets::setWindow(job, this); }); pasteAction->setEnabled(canPaste); popup->addAction(pasteAction); popup->addSeparator(); // TODO nice to have: rename // trash if (KConfigGroup(krConfig, "General").readEntry("Move To Trash", _MoveToTrash)) { - QAction* moveToTrashAction = new QAction(QIcon::fromTheme(QStringLiteral("user-trash")), + QAction* moveToTrashAction = new QAction(Icon(QStringLiteral("user-trash")), i18nc("@action:inmenu", "Move to Trash"), this); const bool enableMoveToTrash = capabilities.isLocal() && capabilities.supportsMoving(); moveToTrashAction->setEnabled(enableMoveToTrash); connect(moveToTrashAction, &QAction::triggered, this, [=]() { deleteFile(fileItem, true); }); popup->addAction(moveToTrashAction); } // delete - QAction *deleteAction = new QAction(QIcon::fromTheme(QStringLiteral("edit-delete")), + QAction *deleteAction = new QAction(Icon(QStringLiteral("edit-delete")), i18nc("@action:inmenu", "Delete"), this); deleteAction->setEnabled(capabilities.supportsDeleting()); connect(deleteAction, &QAction::triggered, this, [=]() { deleteFile(fileItem, false); }); popup->addAction(deleteAction); popup->addSeparator(); // properties if (!fileItem.isNull()) { QAction* propertiesAction = new QAction(i18nc("@action:inmenu", "Properties"), this); - propertiesAction->setIcon(QIcon::fromTheme(QStringLiteral("document-properties"))); + propertiesAction->setIcon(Icon(QStringLiteral("document-properties"))); connect(propertiesAction, &QAction::triggered, this, [=]() { KPropertiesDialog* dialog = new KPropertiesDialog(fileItem.url(), this); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->show(); }); popup->addAction(propertiesAction); } QPointer popupPtr = popup; popup->exec(QCursor::pos()); if (popupPtr.data()) { popupPtr.data()->deleteLater(); } } void KrFileTreeView::copyToClipBoard(const KFileItem &fileItem, bool cut) const { QMimeData* mimeData = new QMimeData(); QList kdeUrls; kdeUrls.append(fileItem.url()); QList mostLocalUrls; bool dummy; mostLocalUrls.append(fileItem.mostLocalUrl(dummy)); KIO::setClipboardDataCut(mimeData, cut); KUrlMimeData::setUrls(kdeUrls, mostLocalUrls, mimeData); QApplication::clipboard()->setMimeData(mimeData); } void KrFileTreeView::deleteFile(const KFileItem &fileItem, bool moveToTrash) const { const QList confirmedFiles = ListPanelFunc::confirmDeletion(QList() << fileItem.url(), moveToTrash, false, true); if (confirmedFiles.isEmpty()) return; FileSystemProvider::instance().startDeleteFiles(confirmedFiles, moveToTrash); } bool KrFileTreeView::briefMode() const { return isColumnHidden(mProxyModel->columnCount() - 1); // find out by last column } void KrFileTreeView::setBriefMode(bool brief) { for (int i=1; i < mProxyModel->columnCount(); i++) { // show only first column setColumnHidden(i, brief); } } void KrFileTreeView::setTree(bool startFromCurrent, bool startFromPlace) { mStartTreeFromCurrent = startFromCurrent; mStartTreeFromPlace = startFromPlace; if (!mStartTreeFromCurrent && !mStartTreeFromPlace) { setTreeRoot(QUrl::fromLocalFile(QDir::root().path())); } setCurrentUrl(mCurrentUrl); // refresh } void KrFileTreeView::setTreeRoot(const QUrl &rootBase) { if (rootBase == mCurrentTreeBase) // avoid collapsing the subdirs in tree return; mCurrentTreeBase = rootBase; mSourceModel->dirLister()->openUrl(mCurrentTreeBase); } void KrFileTreeView::saveSettings(KConfigGroup cfg) const { KConfigGroup group = KConfigGroup(&cfg, "TreeView"); group.writeEntry("BriefMode", briefMode()); group.writeEntry("ShowHiddenFolders", mSourceModel->dirLister()->showingDotFiles()); group.writeEntry("StartFromCurrent", mStartTreeFromCurrent); group.writeEntry("StartFromPlace", mStartTreeFromPlace); } void KrFileTreeView::restoreSettings(const KConfigGroup &cfg) { const KConfigGroup group = KConfigGroup(&cfg, "TreeView"); setBriefMode(group.readEntry("BriefMode", true)); mSourceModel->dirLister()->setShowingDotFiles(group.readEntry("ShowHiddenFolders", false)); setTree(group.readEntry("StartFromCurrent", false), group.readEntry("StartFromPlace", false)); } bool KrFileTreeView::isVisible(const QUrl &url) { QModelIndex index = indexAt(rect().topLeft()); while (index.isValid()) { if (url == urlForProxyIndex(index)) { return true; } index = indexBelow(index); } return false; } diff --git a/krusader/Panel/krsearchbar.cpp b/krusader/Panel/krsearchbar.cpp index b59d2536..ce48f923 100644 --- a/krusader/Panel/krsearchbar.cpp +++ b/krusader/Panel/krsearchbar.cpp @@ -1,430 +1,430 @@ /***************************************************************************** * Copyright (C) 2010 Jan Lepper * * Copyright (C) 2010-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 "krsearchbar.h" #include "PanelView/krview.h" #include "PanelView/krviewitem.h" #include "../FileSystem/dirlisterinterface.h" #include "../defaults.h" #include "../krglobal.h" +#include "../icon.h" #include #include #include #include #include #include #include #include -#include #include KrSearchBar::KrSearchBar(KrView *view, QWidget *parent) : QWidget(parent), _view(0), _rightArrowEntersDirFlag(true) { // close button QToolButton *closeButton = new QToolButton(this); closeButton->setAutoRaise(true); - closeButton->setIcon(QIcon::fromTheme(QStringLiteral("dialog-close"))); + closeButton->setIcon(Icon(QStringLiteral("dialog-close"))); closeButton->setToolTip(i18n("Close the search bar")); connect(closeButton, SIGNAL(clicked()), SLOT(hideBar())); // combo box for changing search mode _modeBox = new QComboBox(this); _modeBox->addItems(QStringList() << i18n("Search") << i18n("Select") << i18n("Filter")); int defaultIndex = KConfigGroup (krConfig, "Look&Feel") .readEntry("Default Search Mode", QString::number(KrSearchBar::MODE_SEARCH)).toInt(); _modeBox->setCurrentIndex(defaultIndex); _modeBox->setToolTip(i18n("Change the search mode")); connect(_modeBox, SIGNAL(currentIndexChanged(int)), SLOT(onModeChange())); _currentMode = static_cast(_modeBox->currentIndex()); // combo box for entering search string _textBox = new KComboBox(this); _textBox->setEditable(true); _modeBox->setToolTip(i18n("Enter or select search string")); QStringList savedSearches = KConfigGroup(krConfig, "Private") .readEntry("Predefined Selections", QStringList()); if (savedSearches.count() > 0) _textBox->addItems(savedSearches); _textBox->setCurrentText(""); _textBox->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred)); connect(_textBox, SIGNAL(currentTextChanged(QString)), SLOT(onSearchChange())); QToolButton *saveSearchBtn = new QToolButton(this); - saveSearchBtn->setIcon(krLoader->loadIcon("document-save", KIconLoader::Toolbar, 16)); + saveSearchBtn->setIcon(Icon("document-save")); saveSearchBtn->setFixedSize(20, 20); saveSearchBtn->setToolTip(i18n("Save the current search string")); connect(saveSearchBtn, SIGNAL(clicked()), this, SLOT(saveSearchString())); _openSelectDialogBtn = new QToolButton(this); - _openSelectDialogBtn->setIcon(krLoader->loadIcon("configure", KIconLoader::Toolbar, 16)); + _openSelectDialogBtn->setIcon(Icon("configure")); _openSelectDialogBtn->setFixedSize(20, 20); _openSelectDialogBtn->setToolTip(i18n("Open selection dialog")); QHBoxLayout *layout = new QHBoxLayout(this); layout->setMargin(0); layout->addWidget(closeButton); layout->addWidget(_modeBox); layout->addWidget(_textBox); layout->addWidget(saveSearchBtn); layout->addWidget(_openSelectDialogBtn); _textBox->installEventFilter(this); setView(view); } void KrSearchBar::setView(KrView *view) { if (_view) { _view->widget()->removeEventFilter(this); disconnect(_openSelectDialogBtn, 0, 0, 0); } _view = view; connect(_openSelectDialogBtn, &QToolButton::clicked, [this](){ _view->customSelection(true); }); _view->widget()->installEventFilter(this); } // #### public slots void KrSearchBar::showBar(SearchMode mode) { if (mode != MODE_LAST) { _modeBox->setCurrentIndex(mode); } show(); _textBox->setFocus(); _rightArrowEntersDirFlag = true; } void KrSearchBar::hideBar() { resetSearch(); if (_textBox->hasFocus()) _view->widget()->setFocus(); hide(); } void KrSearchBar::resetSearch() { _textBox->clearEditText(); indicateMatch(true); } // #### protected slots void KrSearchBar::onModeChange() { if (_currentMode == MODE_FILTER) { _view->op()->filterSearch(QString(), true); // reset filter } _currentMode = static_cast(_modeBox->currentIndex()); onSearchChange(); } void KrSearchBar::onSearchChange() { const QString text = _textBox->currentText(); switch(_currentMode) { case MODE_SEARCH: { const bool anyMatch = _view->op()->searchItem(text, caseSensitive()); indicateMatch(anyMatch); break; } case MODE_SELECT: { _view->unselectAll(); if (!text.isEmpty()) { const bool anyMatch = _view->changeSelection(KRQuery(text, caseSensitive()), true); indicateMatch(anyMatch); } break; } case MODE_FILTER: { const bool anyMatch =_view->op()->filterSearch(text, caseSensitive()); indicateMatch(anyMatch); break; } default: qWarning() << "unexpected search mode: " << _currentMode; } _textBox->setFocus(); } void KrSearchBar::saveSearchString() { KConfigGroup group(krConfig, "Private"); QStringList lst = group.readEntry("Predefined Selections", QStringList()); QString searchString = _textBox->currentText(); if (lst.indexOf(searchString) != -1) { // already saved return; } lst.append(searchString); group.writeEntry("Predefined Selections", lst); _textBox->addItem(searchString); QToolTip::showText(QCursor::pos(), i18n("Saved search text to history")); } // #### protected void KrSearchBar::keyPressEvent(QKeyEvent *event) { const bool handled = handleKeyPressEvent(static_cast(event)); if (handled) { return; } QWidget::keyPressEvent(event); } bool KrSearchBar::eventFilter(QObject *watched, QEvent *event) { if (event->type() != QEvent::ShortcutOverride && watched == _view->widget()) { QKeyEvent *ke = static_cast(event); // overwrite "escape" shortcut if bar is shown if ((ke->key() == Qt::Key_Escape) && (ke->modifiers() == Qt::NoModifier) && !isHidden()) { ke->accept(); handleKeyPressEvent(ke); return true; } } if (event->type() != QEvent::KeyPress) { return false; } qDebug() << "key press event=" << event; QKeyEvent *ke = static_cast(event); if (watched == _view->widget()) { KConfigGroup grpSv(krConfig, "Look&Feel"); const bool autoShow = grpSv.readEntry("New Style Quicksearch", _NewStyleQuicksearch); if (isHidden() && !autoShow) { return false; } if (!isHidden()) { // view widget has focus but search bar is open and may wants to steal key events const bool handled = handleKeyPressEvent(ke); if (handled) { return true; } } if (isHidden() || // view can handle its own event if user does not want to remove text or... !((ke->key() == Qt::Key_Backspace && !_textBox->currentText().isEmpty()) || // ...insert space in search bar (even if not focused) (ke->key() == Qt::Key_Space && _currentMode == KrSearchBar::MODE_SEARCH))) { const bool handled = _view->handleKeyEvent(ke); if (handled) { return true; } } if (ke->text().isEmpty() || (ke->modifiers() != Qt::NoModifier && ke->modifiers() != Qt::ShiftModifier && ke->modifiers() != Qt::KeypadModifier)) { return false; } // start searching if bar is hidden? if (isHidden()) { if (autoShow) { showBar(); } else { return false; } } // bar is visible and gets the key input _textBox->setFocus(); if (ke->key() == Qt::Key_Backspace) { _textBox->lineEdit()->backspace(); } else { _textBox->setEditText(_textBox->currentText().append(ke->text())); } return true; } else if (watched == _textBox) { const bool handled = handleKeyPressEvent(ke); if (handled) { _view->widget()->setFocus(); return true; } // allow the view to handle (most) key events from the text box if (ke->modifiers() == Qt::NoModifier && ke->key() != Qt::Key_Space && ke->key() != Qt::Key_Backspace && ke->key() != Qt::Key_Left && ke->key() != Qt::Key_Right) { const bool handled = _view->handleKeyEvent(ke); if (handled) { _view->widget()->setFocus(); return true; } } } return false; } // #### private bool KrSearchBar::handleKeyPressEvent(QKeyEvent *ke) { if (ke->modifiers() != Qt::NoModifier) { return false; } switch (ke->key()) { case Qt::Key_Escape: { hideBar(); return true; } case Qt::Key_Up: return handleUpDownKeyPress(true); case Qt::Key_Down: return handleUpDownKeyPress(false); case Qt::Key_Left: case Qt::Key_Right: return handleLeftRightKeyPress(ke); case Qt::Key_Insert: { // select current item and jump to next search result KrViewItem * item = _view->getCurrentKrViewItem(); if (item) { item->setSelected(!item->isSelected()); _view->op()->searchItem(_textBox->currentText(), caseSensitive(), 1); } return true; } case Qt::Key_Home: { // jump to first search result KrViewItem * item = _view->getLast(); if (item) { _view->setCurrentKrViewItem(_view->getLast()); _view->op()->searchItem(_textBox->currentText(), caseSensitive(), 1); } return true; } case Qt::Key_End: { // jump to last search result KrViewItem * item = _view->getFirst(); if (item) { _view->setCurrentKrViewItem(_view->getFirst()); _view->op()->searchItem(_textBox->currentText(), caseSensitive(), -1); } return true; } } return false; } bool KrSearchBar::handleUpDownKeyPress(bool up) { if (_currentMode != MODE_SEARCH) { return false; } const bool updownCancel = KConfigGroup(krConfig, "Look&Feel") .readEntry("Up/Down Cancels Quicksearch", false); if (updownCancel) { hideBar(); return false; } const bool anyMatch = _view->op()->searchItem(_textBox->currentText(), caseSensitive(), up ? -1 : 1); indicateMatch(anyMatch); return true; } bool KrSearchBar::handleLeftRightKeyPress(QKeyEvent *ke) { const bool useQuickDirectoryNavigation = KConfigGroup(krConfig, "Look&Feel") .readEntry("Navigation with Right Arrow Quicksearch", true); if (!useQuickDirectoryNavigation) return false; const bool isRight = ke->key() == Qt::Key_Right; if (isRight && _rightArrowEntersDirFlag) { // in case the Right Arrow has been pressed when cursor is in the end of the line if (_textBox->cursorPosition() == _textBox->currentText().length()) // we let the view enter the directory if it's selected return _view->handleKeyEvent(ke); } else { _rightArrowEntersDirFlag = false; } return false; } void KrSearchBar::indicateMatch(bool anyMatch) { KConfigGroup gc(krConfig, "Colors"); QPalette p = QGuiApplication::palette(); QString foreground, background; if (anyMatch) { foreground = "Quicksearch Match Foreground"; background = "Quicksearch Match Background"; } else { foreground = "Quicksearch Non-match Foreground"; background = "Quicksearch Non-match Background"; } QColor fore = Qt::black; QString foreSetting = gc.readEntry(foreground, QString()); if (foreSetting == "KDE default") { fore = p.color(QPalette::Active, QPalette::Text); } else if (!foreSetting.isEmpty()) { fore = gc.readEntry(foreground, fore); } QColor back = anyMatch ? QColor(192, 255, 192) : QColor(255, 192, 192); QString backSetting = gc.readEntry(background, QString()); if (backSetting == "KDE default") { back = p.color(QPalette::Active, QPalette::Base); } else if (!backSetting.isEmpty()) { back = gc.readEntry(background, back); } QPalette pal = palette(); pal.setColor(QPalette::Base, back); pal.setColor(QPalette::Text, fore); _textBox->lineEdit()->setPalette(pal); } bool KrSearchBar::caseSensitive() { KConfigGroup grpSvr(krConfig, "Look&Feel"); return grpSvr.readEntry("Case Sensitive Quicksearch", _CaseSensitiveQuicksearch); } diff --git a/krusader/Panel/listpanel.cpp b/krusader/Panel/listpanel.cpp index 4b2fefda..e0c146ab 100644 --- a/krusader/Panel/listpanel.cpp +++ b/krusader/Panel/listpanel.cpp @@ -1,1379 +1,1378 @@ /***************************************************************************** * Copyright (C) 2000 Shie Erlich * * 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 "listpanel.h" // QtCore #include #include #include #include #include #include #include // QtGui #include #include #include #include #include #include #include #include // QtWidgets #include #include #include #include #include #include #include -#include #include #include #include #include #include #include "dirhistoryqueue.h" #include "krcolorcache.h" #include "krerrordisplay.h" #include "krlayoutfactory.h" #include "krpreviewpopup.h" #include "krsearchbar.h" #include "listpanelactions.h" #include "panelcontextmenu.h" #include "panelfunc.h" #include "sidebar.h" #include "viewactions.h" #include "PanelView/krview.h" #include "PanelView/krviewfactory.h" #include "PanelView/krviewitem.h" #include "../defaults.h" -#include "../kicons.h" +#include "../icon.h" #include "../krservices.h" #include "../krslots.h" #include "../krusader.h" #include "../krusaderview.h" #include "../Archive/krarchandler.h" #include "../BookMan/krbookmarkbutton.h" #include "../FileSystem/fileitem.h" #include "../FileSystem/filesystem.h" #include "../FileSystem/krpermhandler.h" #include "../FileSystem/sizecalculator.h" #include "../Dialogs/krdialogs.h" #include "../Dialogs/krspwidgets.h" #include "../Dialogs/krsqueezedtextlabel.h" #include "../Dialogs/percentalsplitter.h" #include "../Dialogs/popularurls.h" #include "../GUI/dirhistorybutton.h" #include "../GUI/kcmdline.h" #include "../GUI/mediabutton.h" #include "../MountMan/kmountman.h" #include "../UserAction/useractionpopupmenu.h" class ActionButton : public QToolButton { public: ActionButton(QWidget *parent, ListPanel *panel, QAction *action, QString text = QString()) : QToolButton(parent), panel(panel), action(action) { setText(text); setAutoRaise(true); if(KConfigGroup(krConfig, "ListPanelButtons").readEntry("Icons", false) || text.isEmpty()) setIcon(action->icon()); setToolTip(action->toolTip()); } protected: virtual void mousePressEvent(QMouseEvent *) Q_DECL_OVERRIDE { panel->slotFocusOnMe(); action->trigger(); } ListPanel *panel; QAction *action; }; ///////////////////////////////////////////////////// // The list panel constructor // ///////////////////////////////////////////////////// ListPanel::ListPanel(QWidget *parent, AbstractPanelManager *manager, KConfigGroup cfg) : QWidget(parent), KrPanel(manager, this, new ListPanelFunc(this)), panelType(-1), colorMask(255), compareMode(false), previewJob(0), inlineRefreshJob(0), searchBar(0), cdRootButton(0), cdUpButton(0), sidebarButton(0), sidebar(0), fileSystemError(0), _navigatorUrl(), _tabState(TabState::DEFAULT) { if(cfg.isValid()) panelType = cfg.readEntry("Type", -1); if (panelType == -1) panelType = defaultPanelType(); _actions = krApp->listPanelActions(); setAcceptDrops(true); QHash widgets; #define ADD_WIDGET(widget) widgets.insert(#widget, widget); // media button mediaButton = new MediaButton(this); connect(mediaButton, SIGNAL(aboutToShow()), this, SLOT(slotFocusOnMe())); connect(mediaButton, SIGNAL(openUrl(QUrl)), func, SLOT(openUrl(QUrl))); connect(mediaButton, SIGNAL(newTab(QUrl)), SLOT(newTab(QUrl))); ADD_WIDGET(mediaButton); // status bar status = new KrSqueezedTextLabel(this); KConfigGroup group(krConfig, "Look&Feel"); status->setFont(group.readEntry("Filelist Font", _FilelistFont)); status->setAutoFillBackground(false); status->setText(""); // needed for initialization code! status->setWhatsThis(i18n("The statusbar displays information about the filesystem " "which holds your current folder: total size, free space, " "type of filesystem, etc.")); ADD_WIDGET(status); // back button backButton = new ActionButton(this, this, _actions->actHistoryBackward); ADD_WIDGET(backButton); // forward button forwardButton = new ActionButton(this, this, _actions->actHistoryForward); ADD_WIDGET(forwardButton); // ... create the history button historyButton = new DirHistoryButton(func->history, this); connect(historyButton, SIGNAL(aboutToShow()), this, SLOT(slotFocusOnMe())); connect(historyButton, SIGNAL(gotoPos(int)), func, SLOT(historyGotoPos(int))); ADD_WIDGET(historyButton); // bookmarks button bookmarksButton = new KrBookmarkButton(this); connect(bookmarksButton, SIGNAL(aboutToShow()), this, SLOT(slotFocusOnMe())); connect(bookmarksButton, SIGNAL(openUrl(QUrl)), func, SLOT(openUrl(QUrl))); bookmarksButton->setWhatsThis(i18n("Open menu with bookmarks. You can also add " "current location to the list, edit bookmarks " "or add subfolder to the list.")); ADD_WIDGET(bookmarksButton); // url input field urlNavigator = new KUrlNavigator(new KFilePlacesModel(this), QUrl(), this); urlNavigator->setWhatsThis(i18n("Name of folder where you are. You can also " "enter name of desired location to move there. " "Use of Net protocols like ftp or fish is possible.")); // handle certain key events here in event filter urlNavigator->editor()->installEventFilter(this); urlNavigator->setUrlEditable(isNavigatorEditModeSet()); urlNavigator->setShowFullPath(group.readEntry("Navigator Full Path", false)); connect(urlNavigator, SIGNAL(returnPressed()), this, SLOT(slotFocusOnMe())); connect(urlNavigator, &KUrlNavigator::urlChanged, this, &ListPanel::slotNavigatorUrlChanged); connect(urlNavigator->editor()->lineEdit(), &QLineEdit::editingFinished, this, &ListPanel::resetNavigatorMode); connect(urlNavigator, SIGNAL(tabRequested(QUrl)), this, SLOT(newTab(QUrl))); connect(urlNavigator, SIGNAL(urlsDropped(QUrl,QDropEvent*)), this, SLOT(handleDrop(QUrl,QDropEvent*))); ADD_WIDGET(urlNavigator); // toolbar QWidget * toolbar = new QWidget(this); QHBoxLayout * toolbarLayout = new QHBoxLayout(toolbar); toolbarLayout->setContentsMargins(0, 0, 0, 0); toolbarLayout->setSpacing(0); ADD_WIDGET(toolbar); fileSystemError = new KrErrorDisplay(this); fileSystemError->setWordWrap(true); fileSystemError->hide(); ADD_WIDGET(fileSystemError); // client area clientArea = new QWidget(this); QVBoxLayout *clientLayout = new QVBoxLayout(clientArea); clientLayout->setSpacing(0); clientLayout->setContentsMargins(0, 0, 0, 0); ADD_WIDGET(clientArea); // totals label totals = new KrSqueezedTextLabel(this); totals->setFont(group.readEntry("Filelist Font", _FilelistFont)); totals->setAutoFillBackground(false); totals->setWhatsThis(i18n("The totals bar shows how many files exist, " "how many selected and the bytes math")); ADD_WIDGET(totals); // free space label freeSpace = new KrSqueezedTextLabel(this); freeSpace->setFont(group.readEntry("Filelist Font", _FilelistFont)); freeSpace->setAutoFillBackground(false); freeSpace->setText(""); freeSpace->setAlignment(Qt::AlignRight | Qt::AlignVCenter); ADD_WIDGET(freeSpace); // progress indicator and cancel button for the quick calc size quickSizeCalcProgress = new QProgressBar(this); quickSizeCalcProgress->hide(); ADD_WIDGET(quickSizeCalcProgress); cancelQuickSizeCalcButton = new QToolButton(this); cancelQuickSizeCalcButton->hide(); - cancelQuickSizeCalcButton->setIcon(krLoader->loadIcon("dialog-cancel", KIconLoader::Toolbar, 16)); + cancelQuickSizeCalcButton->setIcon(Icon("dialog-cancel")); cancelQuickSizeCalcButton->setToolTip(i18n("Cancel directory space calculation")); ADD_WIDGET(cancelQuickSizeCalcButton); // progress indicator for the preview job previewProgress = new QProgressBar(this); previewProgress->hide(); ADD_WIDGET(previewProgress); // a cancel button for the filesystem refresh and preview job cancelProgressButton = new QToolButton(this); cancelProgressButton->hide(); - cancelProgressButton->setIcon(krLoader->loadIcon("dialog-cancel", KIconLoader::Toolbar, 16)); + cancelProgressButton->setIcon(Icon("dialog-cancel")); connect(cancelProgressButton, SIGNAL(clicked()), this, SLOT(cancelProgress())); ADD_WIDGET(cancelProgressButton); // button for changing the panel sidebar position in the panel sidebarPositionButton = new QToolButton(this); sidebarPositionButton->hide(); sidebarPositionButton->setAutoRaise(true); - sidebarPositionButton->setIcon(krLoader->loadIcon("exchange-positions", KIconLoader::Toolbar, 16)); + sidebarPositionButton->setIcon(Icon("exchange-positions")); sidebarPositionButton->setToolTip(i18n("Move Sidebar clockwise")); connect(sidebarPositionButton, &QToolButton::clicked, [this]() { // moving position clockwise setSidebarPosition((sidebarPosition() + 1) % 4); }); ADD_WIDGET(sidebarPositionButton); // a quick button to open the sidebar sidebarButton = new QToolButton(this); sidebarButton->setAutoRaise(true); - sidebarButton->setIcon(krLoader->loadIcon("arrow-up", KIconLoader::Toolbar, 16)); + sidebarButton->setIcon(Icon("arrow-up")); connect(sidebarButton, &QToolButton::clicked, this, &ListPanel::toggleSidebar); sidebarButton->setToolTip(i18n("Open the Sidebar")); ADD_WIDGET(sidebarButton); #undef ADD_WIDGET // toolbar buttons cdOtherButton = new ActionButton(toolbar, this, _actions->actCdToOther, "="); toolbarLayout->addWidget(cdOtherButton); cdUpButton = new ActionButton(toolbar, this, _actions->actDirUp, ".."); toolbarLayout->addWidget(cdUpButton); cdHomeButton = new ActionButton(toolbar, this, _actions->actHome, "~"); toolbarLayout->addWidget(cdHomeButton); cdRootButton = new ActionButton(toolbar, this, _actions->actRoot, "/"); toolbarLayout->addWidget(cdRootButton); // create the button for sync-browsing syncBrowseButton = new QToolButton(toolbar); - syncBrowseButton->setIcon(QIcon::fromTheme("kr_syncbrowse_off")); + syncBrowseButton->setIcon(Icon("kr_syncbrowse_off")); syncBrowseButton->setCheckable(true); const QString syncBrowseText = i18n("This button toggles the sync-browse mode.\n" "When active, each folder change is performed in the\n" "active and inactive panel - if possible."); syncBrowseButton->setText(syncBrowseText); syncBrowseButton->setToolTip(syncBrowseText); connect(syncBrowseButton, &QToolButton::toggled, [=](bool checked) { syncBrowseButton->setIcon( - QIcon::fromTheme(checked ? "kr_syncbrowse_on" : "kr_syncbrowse_off")); + Icon(checked ? "kr_syncbrowse_on" : "kr_syncbrowse_off")); }); syncBrowseButton->setAutoRaise(true); toolbarLayout->addWidget(syncBrowseButton); setButtons(); // create a splitter to hold the view and the sidebar sidebarSplitter = new PercentalSplitter(clientArea); sidebarSplitter->setChildrenCollapsible(true); sidebarSplitter->setOrientation(Qt::Horizontal); // expand vertical if splitter orientation is horizontal QSizePolicy sizePolicy = sidebarSplitter->sizePolicy(); sizePolicy.setVerticalPolicy(QSizePolicy::Expanding); sidebarSplitter->setSizePolicy(sizePolicy); clientLayout->addWidget(sidebarSplitter); // view createView(); // search (in folder) bar searchBar = new KrSearchBar(view, clientArea); searchBar->hide(); bool top = group.readEntry("Quicksearch Position", "bottom") == "top"; clientLayout->insertWidget(top ? 0 : -1, searchBar); // create the layout KrLayoutFactory fact(this, widgets); QLayout *layout = fact.createLayout(); if(!layout) { // fallback: create a layout by ourself QVBoxLayout *v = new QVBoxLayout; v->setContentsMargins(0, 0, 0, 0); v->setSpacing(0); QHBoxLayout *h = new QHBoxLayout; h->setContentsMargins(0, 0, 0, 0); h->setSpacing(0); h->addWidget(urlNavigator); h->addWidget(toolbar); h->addStretch(); v->addLayout(h); h = new QHBoxLayout; h->setContentsMargins(0, 0, 0, 0); h->setSpacing(0); h->addWidget(mediaButton); h->addWidget(status); h->addWidget(backButton); h->addWidget(forwardButton); h->addWidget(historyButton); h->addWidget(bookmarksButton); v->addLayout(h); v->addWidget(fileSystemError); v->addWidget(clientArea); h = new QHBoxLayout; h->setContentsMargins(0, 0, 0, 0); h->setSpacing(0); h->addWidget(totals); h->addWidget(freeSpace); h->addWidget(quickSizeCalcProgress); h->addWidget(cancelQuickSizeCalcButton); h->addWidget(previewProgress); h->addWidget(cancelProgressButton); h->addWidget(sidebarButton); v->addLayout(h); layout = v; } setLayout(layout); connect(&KrColorCache::getColorCache(), SIGNAL(colorsRefreshed()), this, SLOT(refreshColors())); connect(krApp, SIGNAL(shutdown()), SLOT(cancelProgress())); } ListPanel::~ListPanel() { cancelProgress(); delete view; view = 0; delete func; delete status; delete bookmarksButton; delete totals; delete urlNavigator; delete cdRootButton; delete cdHomeButton; delete cdUpButton; delete cdOtherButton; delete syncBrowseButton; // delete layout; } void ListPanel::reparent(QWidget *parent, AbstractPanelManager *manager) { setParent(parent); _manager = manager; } int ListPanel::defaultPanelType() { KConfigGroup group(krConfig, "Look&Feel"); return group.readEntry("Default Panel Type", KrViewFactory::defaultViewId()); } bool ListPanel::isNavigatorEditModeSet() { KConfigGroup group(krConfig, "Look&Feel"); return group.readEntry("Navigator Edit Mode", false); } void ListPanel::createView() { view = KrViewFactory::createView(panelType, sidebarSplitter, krConfig); view->init(); view->setMainWindow(krApp); // KrViewFactory may create a different view type than requested panelType = view->instance()->id(); if(this == ACTIVE_PANEL) view->prepareForActive(); else view->prepareForPassive(); view->refreshColors(); sidebarSplitter->insertWidget(sidebarPosition() < 2 ? 1 : 0, view->widget()); view->widget()->installEventFilter(this); connect(view->op(), &KrViewOperator::quickCalcSpace, func, &ListPanelFunc::quickCalcSpace); connect(view->op(), SIGNAL(goHome()), func, SLOT(home())); connect(view->op(), SIGNAL(dirUp()), func, SLOT(dirUp())); connect(view->op(), &KrViewOperator::defaultDeleteFiles, func, &ListPanelFunc::defaultDeleteFiles); connect(view->op(), SIGNAL(middleButtonClicked(KrViewItem*)), SLOT(newTab(KrViewItem*))); connect(view->op(), SIGNAL(currentChanged(KrViewItem*)), SLOT(slotCurrentChanged(KrViewItem*))); connect(view->op(), SIGNAL(renameItem(QString,QString)), func, SLOT(rename(QString,QString))); connect(view->op(), SIGNAL(executed(QString)), func, SLOT(execute(QString))); connect(view->op(), SIGNAL(goInside(QString)), func, SLOT(goInside(QString))); connect(view->op(), SIGNAL(needFocus()), this, SLOT(slotFocusOnMe())); connect(view->op(), SIGNAL(selectionChanged()), this, SLOT(slotUpdateTotals())); connect(view->op(), SIGNAL(itemDescription(QString)), krApp, SLOT(statusBarUpdate(QString))); connect(view->op(), SIGNAL(contextMenu(QPoint)), this, SLOT(popRightClickMenu(QPoint))); connect(view->op(), SIGNAL(emptyContextMenu(QPoint)), this, SLOT(popEmptyRightClickMenu(QPoint))); connect(view->op(), SIGNAL(letsDrag(QStringList,QPixmap)), this, SLOT(startDragging(QStringList,QPixmap))); connect(view->op(), &KrViewOperator::gotDrop, this, [this](QDropEvent *event) {handleDrop(event, true); }); connect(view->op(), SIGNAL(previewJobStarted(KJob*)), this, SLOT(slotPreviewJobStarted(KJob*))); connect(view->op(), SIGNAL(refreshActions()), krApp->viewActions(), SLOT(refreshActions())); connect(view->op(), SIGNAL(currentChanged(KrViewItem*)), func->history, SLOT(saveCurrentItem())); connect(view->op(), &KrViewOperator::goBack, func, &ListPanelFunc::historyBackward); connect(view->op(), &KrViewOperator::goForward, func, &ListPanelFunc::historyForward); view->setFiles(func->files()); func->refreshActions(); } void ListPanel::changeType(int type) { if (panelType != type) { QString current = view->getCurrentItem(); QList selection = view->selectedUrls(); bool filterApplysToDirs = view->properties()->filterApplysToDirs; KrViewProperties::FilterSpec filter = view->filter(); FilterSettings filterSettings = view->properties()->filterSettings; panelType = type; KrView *oldView = view; createView(); searchBar->setView(view); delete oldView; view->setFilter(filter, filterSettings, filterApplysToDirs); view->setSelectionUrls(selection); view->setCurrentItem(current); view->makeItemVisible(view->getCurrentKrViewItem()); } } int ListPanel::getProperties() { int props = 0; if (syncBrowseButton->isChecked()) { props |= PROP_SYNC_BUTTON_ON; } if (isLocked()) { props |= PROP_LOCKED; } else if (isPinned()) { props |= PROP_PINNED; } return props; } void ListPanel::setProperties(int prop) { syncBrowseButton->setChecked(prop & PROP_SYNC_BUTTON_ON); if (prop & PROP_LOCKED) { _tabState = TabState::LOCKED; } else if (prop & PROP_PINNED) { _tabState = TabState::PINNED; } else { _tabState = TabState::DEFAULT; } } bool ListPanel::eventFilter(QObject * watched, QEvent * e) { if(view && watched == view->widget()) { if(e->type() == QEvent::FocusIn && this != ACTIVE_PANEL && !isHidden()) slotFocusOnMe(); else if(e->type() == QEvent::ShortcutOverride) { QKeyEvent *ke = static_cast(e); if(ke->key() == Qt::Key_Escape && ke->modifiers() == Qt::NoModifier) { // if the cancel refresh action has no shortcut assigned, // we need this event ourselves to cancel refresh if(_actions->actCancelRefresh->shortcut().isEmpty()) { e->accept(); return true; } } } } // handle URL navigator key events else if(watched == urlNavigator->editor()) { // override default shortcut for panel focus if(e->type() == QEvent::ShortcutOverride) { QKeyEvent *ke = static_cast(e); if ((ke->key() == Qt::Key_Escape) && (ke->modifiers() == Qt::NoModifier)) { e->accept(); // we will get the key press event now return true; } } else if(e->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast(e); if ((ke->key() == Qt::Key_Down) && (ke->modifiers() == Qt::ControlModifier)) { slotFocusOnMe(); return true; } else if ((ke->key() == Qt::Key_Escape) && (ke->modifiers() == Qt::NoModifier)) { // reset navigator urlNavigator->editor()->setUrl(urlNavigator->locationUrl()); slotFocusOnMe(); return true; } } } return false; } void ListPanel::toggleSidebar() { if(!sidebar) { sidebar = new Sidebar(sidebarSplitter); // fix vertical grow of splitter (and entire window) if its content // demands more space QSizePolicy sizePolicy = sidebar->sizePolicy(); sizePolicy.setVerticalPolicy(QSizePolicy::Ignored); sidebar->setSizePolicy(sizePolicy); connect(this, &ListPanel::pathChanged, sidebar, &Sidebar::onPanelPathChange); connect(sidebar, &Sidebar::urlActivated, SLOTS, &KRslots::refresh); sidebarSplitter->insertWidget(0, sidebar); } if (sidebar->isHidden()) { if (sidebarSplitterSizes.count() > 0) { sidebarSplitter->setSizes(sidebarSplitterSizes); } else { // on the first time, resize to 50% QList lst; lst << height() / 2 << height() / 2; sidebarSplitter->setSizes(lst); } sidebar->show(); - sidebarButton->setIcon(krLoader->loadIcon("arrow-down", KIconLoader::Toolbar, 16)); + sidebarButton->setIcon(Icon("arrow-down")); sidebarButton->setToolTip(i18n("Close the Sidebar")); sidebarPositionButton->show(); } else { sidebarSplitterSizes.clear(); sidebarSplitterSizes = sidebarSplitter->sizes(); sidebar->hide(); - sidebarButton->setIcon(krLoader->loadIcon("arrow-up", KIconLoader::Toolbar, 16)); + sidebarButton->setIcon(Icon("arrow-up")); sidebarButton->setToolTip(i18n("Open the Sidebar")); sidebarPositionButton->hide(); QList lst; lst << height() << 0; sidebarSplitter->setSizes(lst); if (ACTIVE_PANEL) ACTIVE_PANEL->gui->slotFocusOnMe(); } } QString ListPanel::lastLocalPath() const { return _lastLocalPath; } void ListPanel::setButtons() { KConfigGroup group(krConfig, "Look&Feel"); mediaButton->setVisible(group.readEntry("Media Button Visible", true)); backButton->setVisible(group.readEntry("Back Button Visible", false)); forwardButton->setVisible(group.readEntry("Forward Button Visible", false)); historyButton->setVisible(group.readEntry("History Button Visible", true)); bookmarksButton->setVisible(group.readEntry("Bookmarks Button Visible", true)); if (group.readEntry("Panel Toolbar visible", _PanelToolBar)) { cdRootButton->setVisible(group.readEntry("Root Button Visible", _cdRoot)); cdHomeButton->setVisible(group.readEntry("Home Button Visible", _cdHome)); cdUpButton->setVisible(group.readEntry("Up Button Visible", _cdUp)); cdOtherButton->setVisible(group.readEntry("Equal Button Visible", _cdOther)); syncBrowseButton->setVisible(group.readEntry("SyncBrowse Button Visible", _syncBrowseButton)); } else { cdRootButton->hide(); cdHomeButton->hide(); cdUpButton->hide(); cdOtherButton->hide(); syncBrowseButton->hide(); } } void ListPanel::slotUpdateTotals() { totals->setText(view->statistics()); } void ListPanel::compareDirs(bool otherPanelToo) { // Performs a check in order to avoid that the next code is executed twice if (otherPanelToo == true) { // If both panels are showing the same directory if (_manager->currentPanel()->virtualPath() == otherPanel()->virtualPath()) { if (KMessageBox::warningContinueCancel(this, i18n("Warning: The left and the right side are showing the same folder.")) != KMessageBox::Continue) { return; } } } KConfigGroup pg(krConfig, "Private"); int compareMode = pg.readEntry("Compare Mode", 0); KConfigGroup group(krConfig, "Look&Feel"); bool selectDirs = group.readEntry("Mark Dirs", false); KrViewItem *item, *otherItem; for (item = view->getFirst(); item != 0; item = view->getNext(item)) { if (item->name() == "..") continue; for (otherItem = otherPanel()->view->getFirst(); otherItem != 0 && otherItem->name() != item->name(); otherItem = otherPanel()->view->getNext(otherItem)); bool isSingle = (otherItem == 0), isDifferent = false, isNewer = false; if (func->getFileItem(item)->isDir() && !selectDirs) { item->setSelected(false); continue; } if (otherItem) { if (!func->getFileItem(item)->isDir()) isDifferent = otherPanel()->func->getFileItem(otherItem)->getSize() != func->getFileItem(item)->getSize(); isNewer = func->getFileItem(item)->getTime_t() > otherPanel()->func->getFileItem(otherItem)->getTime_t(); } switch (compareMode) { case 0: item->setSelected(isNewer || isSingle); break; case 1: item->setSelected(isNewer); break; case 2: item->setSelected(isSingle); break; case 3: item->setSelected(isDifferent || isSingle); break; case 4: item->setSelected(isDifferent); break; } } view->updateView(); if (otherPanelToo) otherPanel()->gui->compareDirs(false); } void ListPanel::refreshColors() { view->refreshColors(); emit refreshColors(this == ACTIVE_PANEL); } void ListPanel::slotFocusOnMe(bool focus) { if (focus && _manager->currentPanel() != this) { // ignore focus request if this panel is not shown return; } krApp->setUpdatesEnabled(false); if(focus) { emit activate(); _actions->activePanelChanged(); func->refreshActions(); slotCurrentChanged(view->getCurrentKrViewItem()); view->prepareForActive(); otherPanel()->gui->slotFocusOnMe(false); } else { // in case a new url was entered but not refreshed to, // reset url navigator to the current url setNavigatorUrl(virtualPath()); view->prepareForPassive(); } urlNavigator->setActive(focus); refreshColors(); krApp->setUpdatesEnabled(true); } // this is used to start the panel ////////////////////////////////////////////////////////////////// void ListPanel::start(const QUrl &url) { QUrl startUrl(url); if (!startUrl.isValid()) startUrl = QUrl::fromLocalFile(ROOT_DIR); _lastLocalPath = startUrl.isLocalFile() ? startUrl.path() : ROOT_DIR; func->openUrl(startUrl); setJumpBack(startUrl); } void ListPanel::slotStartUpdate(bool directoryChange) { if (inlineRefreshJob) inlineRefreshListResult(0); setCursor(Qt::BusyCursor); const QUrl currentUrl = virtualPath(); if (directoryChange) { if (this == ACTIVE_PANEL) { slotFocusOnMe(); } if (currentUrl.isLocalFile()) _lastLocalPath = currentUrl.path(); setNavigatorUrl(currentUrl); emit pathChanged(currentUrl); krApp->popularUrls()->addUrl(currentUrl); searchBar->hideBar(); } if (compareMode) otherPanel()->view->refresh(); // return cursor to normal arrow setCursor(Qt::ArrowCursor); slotUpdateTotals(); } void ListPanel::updateFilesystemStats(const QString &metaInfo, const QString &fsType, KIO::filesize_t total, KIO::filesize_t free) { QString statusText, mountPoint, freeSpaceText; if (!metaInfo.isEmpty()) { statusText = metaInfo; mountPoint = freeSpaceText = ""; } else { const int perc = total == 0 ? 0 : (int)(((float)free / (float)total) * 100.0); mountPoint = func->files()->mountPoint(); statusText = i18nc("%1=free space,%2=total space,%3=percentage of usage, " "%4=mountpoint,%5=filesystem type", "%1 free out of %2 (%3%) on %4 [(%5)]", KIO::convertSize(free), KIO::convertSize(total), perc, mountPoint, fsType); freeSpaceText = " " + i18n("%1 free", KIO::convertSize(free)); } status->setText(statusText); freeSpace->setText(freeSpaceText); mediaButton->updateIcon(mountPoint); } void ListPanel::handleDrop(QDropEvent *event, bool onView) { // check what was dropped const QList urls = KUrlMimeData::urlsFromMimeData(event->mimeData()); if (urls.isEmpty()) { event->ignore(); // not for us to handle! return; } // find dropping destination QString destinationDir = ""; const bool dragFromThisPanel = event->source() == this; const KrViewItem *item = onView ? view->getKrViewItemAt(event->pos()) : 0; if (item) { const FileItem *file = item->getFileItem(); if (file && !file->isDir() && dragFromThisPanel) { event->ignore(); // dragging on files in same panel, ignore return; } else if (!file || file->isDir()) { // item is ".." dummy or a directory destinationDir = item->name(); } } else if (dragFromThisPanel) { event->ignore(); // dragged from this panel onto an empty spot in this panel, ignore return; } QUrl destination = QUrl(virtualPath()); destination.setPath(destination.path() + '/' + destinationDir); func->files()->dropFiles(destination, event); if(KConfigGroup(krConfig, "Look&Feel").readEntry("UnselectBeforeOperation", _UnselectBeforeOperation)) { KrPanel *p = dragFromThisPanel ? this : otherPanel(); p->view->saveSelection(); p->view->unselectAll(); } } void ListPanel::handleDrop(const QUrl &destination, QDropEvent *event) { func->files()->dropFiles(destination, event); } void ListPanel::startDragging(QStringList names, QPixmap px) { if (names.isEmpty()) { // avoid dragging empty urls return; } QList urls = func->files()->getUrls(names); QDrag *drag = new QDrag(this); QMimeData *mimeData = new QMimeData; drag->setPixmap(px); mimeData->setUrls(urls); drag->setMimeData(mimeData); drag->start(Qt::MoveAction | Qt::CopyAction | Qt::LinkAction); } // pops a right-click menu for items void ListPanel::popRightClickMenu(const QPoint &loc) { // run it, on the mouse location int j = QFontMetrics(font()).height() * 2; PanelContextMenu::run(QPoint(loc.x() + 5, loc.y() + j), this); } void ListPanel::popEmptyRightClickMenu(const QPoint &loc) { PanelContextMenu::run(loc, this); } QString ListPanel::getCurrentName() { QString name = view->getCurrentItem(); if (name != "..") return name; else return QString(); } QStringList ListPanel::getSelectedNames() { QStringList fileNames; view->getSelectedItems(&fileNames); return fileNames; } void ListPanel::prepareToDelete() { const bool skipCurrent = (view->numSelected() == 0); view->setNameToMakeCurrent(view->firstUnmarkedBelowCurrent(skipCurrent)); } void ListPanel::keyPressEvent(QKeyEvent *e) { switch (e->key()) { case Qt::Key_Enter : case Qt::Key_Return : if (e->modifiers() & Qt::ControlModifier) { if (e->modifiers() & Qt::AltModifier) { FileItem *fileitem = func->files()->getFileItem(view->getCurrentKrViewItem()->name()); if (fileitem && fileitem->isDir()) newTab(fileitem->getUrl(), true); } else { SLOTS->insertFileName((e->modifiers() & Qt::ShiftModifier) != 0); } } else { e->ignore(); } break; case Qt::Key_Right : case Qt::Key_Left : if (e->modifiers() == Qt::ControlModifier) { // user pressed CTRL+Right/Left - refresh other panel to the selected path if it's a // directory otherwise as this one if ((isLeft() && e->key() == Qt::Key_Right) || (!isLeft() && e->key() == Qt::Key_Left)) { QUrl newPath; KrViewItem *it = view->getCurrentKrViewItem(); if (it->name() == "..") { newPath = KIO::upUrl(virtualPath()); } else { FileItem *v = func->getFileItem(it); // If it's a directory different from ".." if (v && v->isDir() && v->getName() != "..") { newPath = v->getUrl(); } else { // If it's a supported compressed file if (v && KRarcHandler::arcSupported(v->getMime())) { newPath = func->browsableArchivePath(v->getUrl().fileName()); } else { newPath = virtualPath(); } } } otherPanel()->func->openUrl(newPath); } else { func->openUrl(otherPanel()->virtualPath()); } return; } else e->ignore(); break; case Qt::Key_Down : if (e->modifiers() == Qt::ControlModifier) { // give the keyboard focus to the command line if (MAIN_VIEW->cmdLine()->isVisible()) MAIN_VIEW->cmdLineFocus(); else MAIN_VIEW->focusTerminalEmulator(); return; } else if (e->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { // give the keyboard focus to TE MAIN_VIEW->focusTerminalEmulator(); } else e->ignore(); break; case Qt::Key_Up : if (e->modifiers() == Qt::ControlModifier) { // give the keyboard focus to the url navigator editLocation(); return; } else e->ignore(); break; case Qt::Key_Escape: cancelProgress(); break; default: // if we got this, it means that the view is not doing // the quick search thing, so send the characters to the commandline, if normal key if (e->modifiers() == Qt::NoModifier) MAIN_VIEW->cmdLine()->addText(e->text()); //e->ignore(); } } void ListPanel::showEvent(QShowEvent *e) { panelVisible(); QWidget::showEvent(e); } void ListPanel::hideEvent(QHideEvent *e) { panelHidden(); QWidget::hideEvent(e); } void ListPanel::panelVisible() { func->setPaused(false); } void ListPanel::panelHidden() { func->setPaused(true); } void ListPanel::slotPreviewJobStarted(KJob *job) { previewJob = job; connect(job, SIGNAL(percent(KJob*,ulong)), SLOT(slotPreviewJobPercent(KJob*,ulong))); connect(job, &KJob::result, this, &ListPanel::slotPreviewJobResult); cancelProgressButton->setMaximumHeight(sidebarButton->height()); cancelProgressButton->show(); previewProgress->setValue(0); previewProgress->setFormat(i18n("loading previews: %p%")); previewProgress->setMaximumHeight(cancelProgressButton->height()); previewProgress->show(); } void ListPanel::slotPreviewJobPercent(KJob* /*job*/, unsigned long percent) { previewProgress->setValue(percent); } void ListPanel::slotPreviewJobResult(KJob* /*job*/) { previewJob = 0; previewProgress->hide(); if(!inlineRefreshJob) cancelProgressButton->hide(); } void ListPanel::slotRefreshJobStarted(KIO::Job* job) { // disable the parts of the panel we don't want touched status->setEnabled(false); urlNavigator->setEnabled(false); cdRootButton->setEnabled(false); cdHomeButton->setEnabled(false); cdUpButton->setEnabled(false); cdOtherButton->setEnabled(false); sidebarButton->setEnabled(false); if(sidebar) sidebar->setEnabled(false); bookmarksButton->setEnabled(false); historyButton->setEnabled(false); syncBrowseButton->setEnabled(false); // connect to the job interface to provide in-panel refresh notification connect(job, SIGNAL(infoMessage(KJob*,QString)), SLOT(inlineRefreshInfoMessage(KJob*,QString))); connect(job, SIGNAL(percent(KJob*,ulong)), SLOT(inlineRefreshPercent(KJob*,ulong))); connect(job, SIGNAL(result(KJob*)), this, SLOT(inlineRefreshListResult(KJob*))); inlineRefreshJob = job; totals->setText(i18n(">> Reading...")); cancelProgressButton->show(); } void ListPanel::cancelProgress() { if (inlineRefreshJob) { disconnect(inlineRefreshJob, 0, this, 0); inlineRefreshJob->kill(KJob::EmitResult); inlineRefreshListResult(0); } if(previewJob) { disconnect(previewJob, 0, this, 0); previewJob->kill(KJob::EmitResult); slotPreviewJobResult(0); } } void ListPanel::setNavigatorUrl(const QUrl &url) { _navigatorUrl = url; urlNavigator->setLocationUrl(url); } void ListPanel::inlineRefreshPercent(KJob*, unsigned long perc) { QString msg = i18n(">> Reading: %1 % complete...", perc); totals->setText(msg); } void ListPanel::inlineRefreshInfoMessage(KJob*, const QString &msg) { totals->setText(i18n(">> Reading: %1", msg)); } void ListPanel::inlineRefreshListResult(KJob*) { if(inlineRefreshJob) disconnect(inlineRefreshJob, 0, this, 0); inlineRefreshJob = 0; // reenable everything status->setEnabled(true); urlNavigator->setEnabled(true); cdRootButton->setEnabled(true); cdHomeButton->setEnabled(true); cdUpButton->setEnabled(true); cdOtherButton->setEnabled(true); sidebarButton->setEnabled(true); if(sidebar) sidebar->setEnabled(true); bookmarksButton->setEnabled(true); historyButton->setEnabled(true); syncBrowseButton->setEnabled(true); if(!previewJob) cancelProgressButton->hide(); } void ListPanel::jumpBack() { func->openUrl(_jumpBackURL); } void ListPanel::setJumpBack(QUrl url) { _jumpBackURL = url; } void ListPanel::slotFilesystemError(QString msg) { refreshColors(); fileSystemError->setText(i18n("Error: %1", msg)); fileSystemError->show(); } void ListPanel::showButtonMenu(QToolButton *b) { if(this != ACTIVE_PANEL) slotFocusOnMe(); if(b->isHidden()) b->menu()->exec(mapToGlobal(clientArea->pos())); else b->click(); } void ListPanel::openBookmarks() { showButtonMenu(bookmarksButton); } void ListPanel::openHistory() { showButtonMenu(historyButton); } void ListPanel::openMedia() { showButtonMenu(mediaButton); } void ListPanel::rightclickMenu() { if (view->getCurrentKrViewItem()) popRightClickMenu(mapToGlobal(view->getCurrentKrViewItem()->itemRect().topLeft())); } void ListPanel::toggleSyncBrowse() { syncBrowseButton->toggle(); } void ListPanel::editLocation() { urlNavigator->setUrlEditable(true); urlNavigator->setFocus(); urlNavigator->editor()->lineEdit()->selectAll(); } void ListPanel::showSearchBar() { searchBar->showBar(); } void ListPanel::showSearchFilter() { searchBar->showBar(KrSearchBar::MODE_FILTER); } void ListPanel::saveSettings(KConfigGroup cfg, bool saveHistory) { QUrl url = virtualPath(); url.setPassword(QString()); // make sure no password is saved cfg.writeEntry("Url", url.toString()); cfg.writeEntry("Type", getType()); cfg.writeEntry("Properties", getProperties()); cfg.writeEntry("PinnedUrl", pinnedUrl().toString()); if(saveHistory) func->history->save(KConfigGroup(&cfg, "History")); view->saveSettings(KConfigGroup(&cfg, "View")); // splitter/sidebar state if (sidebar && !sidebar->isHidden()) { sidebar->saveSettings(KConfigGroup(&cfg, "PanelPopup")); cfg.writeEntry("PopupPosition", sidebarPosition()); cfg.writeEntry("SplitterSizes", sidebarSplitter->saveState()); cfg.writeEntry("PopupPage", sidebar->currentPage()); } else { cfg.deleteEntry("PopupPosition"); cfg.deleteEntry("SplitterSizes"); cfg.deleteEntry("PopupPage"); } } void ListPanel::restoreSettings(KConfigGroup cfg) { changeType(cfg.readEntry("Type", defaultPanelType())); view->restoreSettings(KConfigGroup(&cfg, "View")); // "locked" property must be set after URL path is restored! // This panel can be reused when loading a profile, // so we reset its properties before calling openUrl(). setProperties(0); _lastLocalPath = ROOT_DIR; if(func->history->restore(KConfigGroup(&cfg, "History"))) { func->refresh(); } else { QUrl url(cfg.readEntry("Url", "invalid")); if (!url.isValid()) url = QUrl::fromLocalFile(ROOT_DIR); func->openUrl(url); } setJumpBack(func->history->currentUrl()); setProperties(cfg.readEntry("Properties", 0)); if (isPinned()) { QUrl pinnedUrl(cfg.readEntry("PinnedUrl", "invalid")); if (!pinnedUrl.isValid()) { pinnedUrl = func->history->currentUrl(); } func->openUrl(pinnedUrl); setPinnedUrl(pinnedUrl); } if (cfg.hasKey("PopupPosition")) { // sidebar was visible, restore toggleSidebar(); // create and show sidebar->restoreSettings(KConfigGroup(&cfg, "PanelPopup")); setSidebarPosition(cfg.readEntry("PopupPosition", 42 /* dummy */)); sidebarSplitter->restoreState(cfg.readEntry("SplitterSizes", QByteArray())); sidebar->setCurrentPage(cfg.readEntry("PopupPage", 0)); } } void ListPanel::slotCurrentChanged(KrViewItem *item) { // update status bar if (item) krApp->statusBarUpdate(item->description()); // update sidebar; which panel to display on? Sidebar *p; if (sidebar && !sidebar->isHidden()) { p = sidebar; } else if(otherPanel()->gui->sidebar && !otherPanel()->gui->sidebar->isHidden()) { p = otherPanel()->gui->sidebar; } else { return; } p->update(item ? func->files()->getFileItem(item->name()) : nullptr); } void ListPanel::otherPanelChanged() { func->syncURL = QUrl(); } void ListPanel::getFocusCandidates(QVector &widgets) { if(urlNavigator->editor()->isVisible()) widgets << urlNavigator->editor(); if(view->widget()->isVisible()) widgets << view->widget(); if(sidebar && sidebar->isVisible()) widgets << sidebar; } void ListPanel::updateButtons() { backButton->setEnabled(func->history->canGoBack()); forwardButton->setEnabled(func->history->canGoForward()); historyButton->setEnabled(func->history->count() > 1); cdRootButton->setEnabled(!virtualPath().matches(QUrl::fromLocalFile(ROOT_DIR), QUrl::StripTrailingSlash)); cdUpButton->setEnabled(!func->files()->isRoot()); cdHomeButton->setEnabled(!func->atHome()); } void ListPanel::newTab(KrViewItem *it) { if (!it) return; else if (it->name() == "..") { newTab(KIO::upUrl(virtualPath()), true); } else if (func->getFileItem(it)->isDir()) { QUrl url = virtualPath(); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + '/' + (it->name())); newTab(url, true); } } void ListPanel::newTab(const QUrl &url, bool nextToThis) { _manager->newTab(url, nextToThis ? this : 0); } void ListPanel::slotNavigatorUrlChanged(const QUrl &url) { if (url == _navigatorUrl) return; // this is the URL we just set ourself if (!isNavigatorEditModeSet()) { urlNavigator->setUrlEditable(false); } func->openUrl(KrServices::escapeFileUrl(url), QString(), true); } void ListPanel::resetNavigatorMode() { if (isNavigatorEditModeSet()) return; // set to "navigate" mode if url wasn't changed if (urlNavigator->uncommittedUrl().matches(virtualPath(), QUrl::StripTrailingSlash)) { // NOTE: this also sets focus to the navigator urlNavigator->setUrlEditable(false); slotFocusOnMe(); } } int ListPanel::sidebarPosition() const { int pos = sidebarSplitter->orientation() == Qt::Vertical ? 1 : 0; return pos + (qobject_cast(sidebarSplitter->widget(0)) == NULL ? 2 : 0); } void ListPanel::setSidebarPosition(int pos) { sidebarSplitter->setOrientation(pos % 2 == 0 ? Qt::Horizontal : Qt::Vertical); if ((pos < 2) != (qobject_cast(sidebarSplitter->widget(0)) != NULL)) { sidebarSplitter->insertWidget(0, sidebarSplitter->widget(1)); // swapping widgets in splitter } } void ListPanel::connectQuickSizeCalculator(SizeCalculator *sizeCalculator) { connect(sizeCalculator, &SizeCalculator::started, this, [=]() { quickSizeCalcProgress->reset(); quickSizeCalcProgress->show(); cancelQuickSizeCalcButton->show(); }); connect(cancelQuickSizeCalcButton, &QToolButton::clicked, sizeCalculator, &SizeCalculator::cancel); connect(sizeCalculator, &SizeCalculator::progressChanged, quickSizeCalcProgress, &QProgressBar::setValue); connect(sizeCalculator, &SizeCalculator::finished, this, [=]() { cancelQuickSizeCalcButton->hide(); quickSizeCalcProgress->hide(); }); } diff --git a/krusader/Panel/listpanelactions.cpp b/krusader/Panel/listpanelactions.cpp index 005db4bb..5b2426e9 100644 --- a/krusader/Panel/listpanelactions.cpp +++ b/krusader/Panel/listpanelactions.cpp @@ -1,215 +1,216 @@ /***************************************************************************** * Copyright (C) 2010 Jan Lepper * * Copyright (C) 2010-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 "listpanelactions.h" #include "listpanel.h" #include "panelfunc.h" #include "PanelView/krviewfactory.h" #include "../krmainwindow.h" #include "../Dialogs/krdialogs.h" #include "../KViewer/krviewer.h" +#include "../icon.h" // QtCore #include // QtWidgets #include #include #include ListPanelActions::ListPanelActions(QObject *parent, KrMainWindow *mainWindow) : ActionsBase(parent, mainWindow) { // set view type QSignalMapper *mapper = new QSignalMapper(this); connect(mapper, SIGNAL(mapped(int)), SLOT(setView(int))); QActionGroup *group = new QActionGroup(this); group->setExclusive(true); QList views = KrViewFactory::registeredViews(); for(int i = 0; i < views.count(); i++) { KrViewInstance *inst = views[i]; - QAction *action = new QAction(QIcon::fromTheme(inst->icon()), inst->description(), group); + QAction *action = new QAction(Icon(inst->iconName()), inst->description(), group); action->setCheckable(true); connect(action, SIGNAL(triggered()), mapper, SLOT(map())); mapper->setMapping(action, inst->id()); _mainWindow->actions()->addAction("view" + QString::number(i), action); _mainWindow->actions()->setDefaultShortcut(action, inst->shortcut()); setViewActions.insert(inst->id(), action); } // standard actions actHistoryBackward = stdAction(KStandardAction::Back, _func, SLOT(historyBackward())); actHistoryForward = stdAction(KStandardAction::Forward, _func, SLOT(historyForward())); //FIXME: second shortcut for up: see actDirUp // KStandardAction::up( this, SLOT(dirUp()), actionCollection )->setShortcut(Qt::Key_Backspace); /* Shortcut disabled because of the Terminal Emulator bug. */ actDirUp = stdAction(KStandardAction::Up, _func, SLOT(dirUp())); actHome = stdAction(KStandardAction::Home, _func, SLOT(home())); actCut = stdAction(KStandardAction::Cut, _func, SLOT(cut())); actCut->setText(i18n("Cut to Clipboard")); // removing alternative shift+del shortcut, it is used for the alternative delete files action QList cutShortcuts = actCut->shortcuts(); cutShortcuts.removeAll(QKeySequence(Qt::SHIFT | Qt::Key_Delete)); _mainWindow->actions()->setDefaultShortcuts(actCut, cutShortcuts); actCopy = stdAction(KStandardAction::Copy, _func, SLOT(copyToClipboard())); actCopy->setText(i18n("Copy to Clipboard")); actPaste = stdAction(KStandardAction::Paste, _func, SLOT(pasteFromClipboard())); actPaste->setText(i18n("Paste from Clipboard")); // Fn keys actRenameF2 = action(i18n("Rename"), "edit-rename", Qt::Key_F2, _func, SLOT(rename()) , "F2_Rename"); actViewFileF3 = action(i18n("View File"), 0, Qt::Key_F3, _func, SLOT(view()), "F3_View"); actEditFileF4 = action(i18n("Edit File"), 0, Qt::Key_F4, _func, SLOT(edit()) , "F4_Edit"); actCopyF5 = action(i18n("Copy to other panel"), 0, Qt::Key_F5, _func, SLOT(copyFiles()) , "F5_Copy"); actMoveF6 = action(i18n("Move to other panel"), 0, Qt::Key_F6, _func, SLOT(moveFiles()) , "F6_Move"); actCopyDelayedF5 = action(i18n("Copy delayed..."), 0, Qt::SHIFT + Qt::Key_F5, _func, SLOT(copyFilesDelayed()) , "F5_Copy_Queue"); actMoveDelayedShiftF6 = action(i18n("Move delayed..."), 0, Qt::SHIFT + Qt::Key_F6, _func, SLOT(moveFilesDelayed()) , "F6_Move_Queue"); actNewFolderF7 = action(i18n("New Folder..."), "folder-new", Qt::Key_F7, _func, SLOT(mkdir()) , "F7_Mkdir"); actDeleteF8 = action(i18n("Delete"), "edit-delete", Qt::Key_F8, _func, SLOT(defaultDeleteFiles()) , "F8_Delete"); actTerminalF9 = action(i18n("Start Terminal Here"), "utilities-terminal", Qt::Key_F9, _func, SLOT(terminal()) , "F9_Terminal"); action(i18n("&New Text File..."), "document-new", Qt::SHIFT + Qt::Key_F4, _func, SLOT(editNew()), "edit_new_file"); action(i18n("F3 View Dialog"), 0, Qt::SHIFT + Qt::Key_F3, _func, SLOT(viewDlg()), "F3_ViewDlg"); // file operations action(i18n("Right-click Menu"), 0, Qt::Key_Menu, _gui, SLOT(rightclickMenu()), "rightclick menu"); actProperties = action(i18n("&Properties..."), "document-properties", Qt::ALT + Qt::Key_Return, _func, SLOT(properties()), "properties"); actCompDirs = action(i18n("&Compare Folders"), "kr_comparedirs", Qt::ALT + Qt::SHIFT + Qt::Key_C, _gui, SLOT(compareDirs()), "compare dirs"); actCalculate = action(i18n("Calculate &Occupied Space"), "accessories-calculator", 0, _func, SLOT(calcSpace()), "calculate"); actPack = action(i18n("Pac&k..."), "archive-insert", Qt::ALT + Qt::SHIFT + Qt::Key_P, _func, SLOT(pack()), "pack"); actUnpack = action(i18n("&Unpack..."), "archive-extract", Qt::ALT + Qt::SHIFT + Qt::Key_U, _func, SLOT(unpack()), "unpack"); actCreateChecksum = action(i18n("Create Checksum..."), "document-edit-sign", 0, _func, SLOT(createChecksum()), "create checksum"); actMatchChecksum = action(i18n("Verify Checksum..."), "document-edit-decrypt-verify", 0, _func, SLOT(matchChecksum()), "match checksum"); action(i18n("New Symlink..."), 0, Qt::CTRL + Qt::ALT + Qt::Key_S, _func, SLOT(krlink()), "new symlink"); actTest = action(i18n("T&est Archive"), "archive-extract", Qt::ALT + Qt::SHIFT + Qt::Key_E, _func, SLOT(testArchive()), "test archives"); action(i18n("Alternative Delete"), "edit-delete", Qt::Key_Delete + Qt::CTRL, _func, SLOT(alternativeDeleteFiles()), "alternative delete"); // navigation actRoot = action(i18n("Root"), "folder-red", Qt::CTRL + Qt::Key_Backspace, _func, SLOT(root()), "root"); actCdToOther = action(i18n("Go to Other Panel's Folder"), 0, Qt::CTRL + Qt::Key_Equal, _func, SLOT(cdToOtherPanel()), "cd to other panel"); action(i18n("&Reload"), "view-refresh", Qt::CTRL + Qt::Key_R, _func, SLOT(refresh()), "std_redisplay"); actCancelRefresh = action(i18n("Cancel Refresh of View"), "dialog-cancel", 0, _gui, SLOT(cancelProgress()), "cancel refresh"); actFTPNewConnect = action(i18n("New Net &Connection..."), "network-connect", Qt::CTRL + Qt::Key_N, _func, SLOT(newFTPconnection()), "ftp new connection"); actFTPDisconnect = action(i18n("Disconnect &from Net"), "network-disconnect", Qt::SHIFT + Qt::CTRL + Qt::Key_D, _func, SLOT(FTPDisconnect()), "ftp disconnect"); action(i18n("Sync Panels"), 0, Qt::ALT + Qt::SHIFT + Qt::Key_O, _func, SLOT(syncOtherPanel()), "sync panels"); actJumpBack = action(i18n("Jump Back"), "go-jump", Qt::CTRL + Qt::Key_J, _gui, SLOT(jumpBack()), "jump_back"); actSetJumpBack = action(i18n("Set Jump Back Point"), "go-jump-definition", Qt::CTRL + Qt::SHIFT + Qt::Key_J, _gui, SLOT(setJumpBack()), "set_jump_back"); actSyncBrowse = action(i18n("S&ynchron Folder Changes"), "kr_syncbrowse_off", Qt::ALT + Qt::SHIFT + Qt::Key_Y, _gui, SLOT(toggleSyncBrowse()), "sync browse"); actLocationBar = action(i18n("Go to Location Bar"), 0, Qt::CTRL + Qt::Key_L, _gui, SLOT(editLocation()), "location_bar"); actSearchBar = action(i18n("Find in folder..."), 0, Qt::CTRL + Qt::Key_F, _gui, SLOT(showSearchBar()), "search bar"); action(i18n("Open search filter"), 0, Qt::CTRL + Qt::Key_I, _gui, SLOT(showSearchFilter()), "search bar filter"); toggleAction(i18n("Toggle Sidebar"), 0, Qt::ALT + Qt::Key_Down, _gui, SLOT(toggleSidebar()), "toggle sidebar"); action(i18n("Bookmarks"), 0, Qt::CTRL + Qt::Key_D, _gui, SLOT(openBookmarks()), "bookmarks"); action(i18n("Left Bookmarks"), 0, 0, this, SLOT(openLeftBookmarks()), "left bookmarks"); action(i18n("Right Bookmarks"), 0, 0, this, SLOT(openRightBookmarks()), "right bookmarks"); action(i18n("History"), 0, Qt::CTRL + Qt::Key_H, _gui, SLOT(openHistory()), "history"); action(i18n("Left History"), 0, Qt::ALT + Qt::CTRL + Qt::Key_Left, this, SLOT(openLeftHistory()), "left history"); action(i18n("Right History"), 0, Qt::ALT + Qt::CTRL + Qt::Key_Right, this, SLOT(openRightHistory()), "right history"); action(i18n("Media"), 0, Qt::CTRL + Qt::Key_M, _gui, SLOT(openMedia()), "media"); action(i18n("Left Media"), 0, Qt::CTRL + Qt::SHIFT + Qt::Key_Left, this, SLOT(openLeftMedia()), "left media"); action(i18n("Right Media"), 0, Qt::CTRL + Qt::SHIFT + Qt::Key_Right, this, SLOT(openRightMedia()), "right media"); // and at last we can set the tool-tips actRoot->setToolTip(i18n("ROOT (/)")); actRenameF2->setToolTip(i18n("Rename file, folder, etc.")); actViewFileF3->setToolTip(i18n("Open file in viewer.")); actEditFileF4->setToolTip(i18n("

Edit file.

" "

The editor can be defined in Konfigurator, " "default is internal editor.

")); actCopyF5->setToolTip(i18n("Copy file from one panel to the other.")); actMoveF6->setToolTip(i18n("Move file from one panel to the other.")); actNewFolderF7->setToolTip(i18n("Create folder in current panel.")); actDeleteF8->setToolTip(i18n("Delete file, folder, etc.")); actTerminalF9->setToolTip(i18n("

Open terminal in current folder.

" "

The terminal can be defined in Konfigurator, " "default is konsole.

")); } void ListPanelActions::activePanelChanged() { _gui.reconnect(activePanel()->gui); _func.reconnect(activePanel()->func); } void ListPanelActions::guiUpdated() { QList actions; foreach(QAction *action, setViewActions.values()) actions << action; static_cast(_mainWindow)->plugActionList("view_actionlist", actions); } inline KrPanel *ListPanelActions::activePanel() { return static_cast(_mainWindow)->activePanel(); } inline KrPanel *ListPanelActions::leftPanel() { return static_cast(_mainWindow)->leftPanel(); } inline KrPanel *ListPanelActions::rightPanel() { return static_cast(_mainWindow)->rightPanel(); } // set view type void ListPanelActions::setView(int id) { activePanel()->gui->changeType(id); } // navigation void ListPanelActions::openLeftBookmarks() { leftPanel()->gui->openBookmarks(); } void ListPanelActions::openRightBookmarks() { rightPanel()->gui->openBookmarks(); } void ListPanelActions::openLeftHistory() { leftPanel()->gui->openHistory(); } void ListPanelActions::openRightHistory() { rightPanel()->gui->openHistory(); } void ListPanelActions::openLeftMedia() { leftPanel()->gui->openMedia(); } void ListPanelActions::openRightMedia() { rightPanel()->gui->openMedia(); } diff --git a/krusader/Panel/panelcontextmenu.cpp b/krusader/Panel/panelcontextmenu.cpp index 94f394f8..ad8fdbb9 100644 --- a/krusader/Panel/panelcontextmenu.cpp +++ b/krusader/Panel/panelcontextmenu.cpp @@ -1,433 +1,433 @@ /***************************************************************************** * Copyright (C) 2003 Shie Erlich * * Copyright (C) 2003 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 "panelcontextmenu.h" // QtGui #include #include #include #include -#include #include #include #include #include #include #include #include #include "krpreviewpopup.h" #include "listpanel.h" #include "listpanelactions.h" #include "panelfunc.h" #include "PanelView/krview.h" #include "PanelView/krviewitem.h" #include "../defaults.h" +#include "../icon.h" #include "../krservices.h" #include "../krslots.h" #include "../krusader.h" #include "../krusaderview.h" #include "../panelmanager.h" #include "../Archive/krarchandler.h" #include "../FileSystem/fileitem.h" #include "../FileSystem/filesystem.h" #include "../FileSystem/krtrashhandler.h" #include "../MountMan/kmountman.h" #include "../UserAction/useractionpopupmenu.h" void PanelContextMenu::run(const QPoint &pos, KrPanel *panel) { PanelContextMenu menu(panel); QAction * res = menu.exec(pos); int result = -1; if (res && res->data().canConvert()) result = res->data().toInt(); menu.performAction(result); } /** * Copied from dolphin/src/dolphincontextmenu.cpp and modified to add only compress and extract submenus. */ void PanelContextMenu::addCompressAndExtractPluginActions() { KFileItemListProperties props(_items); QVector jsonPlugins = KPluginLoader::findPlugins("kf5/kfileitemaction", [=](const KPluginMetaData& metaData) { return metaData.pluginId() == "compressfileitemaction" || metaData.pluginId() == "extractfileitemaction"; }); foreach (const KPluginMetaData &jsonMetadata, jsonPlugins) { KAbstractFileItemActionPlugin* abstractPlugin = KPluginLoader(jsonMetadata.fileName()) .factory()->create(); if (abstractPlugin) { abstractPlugin->setParent(this); addActions(abstractPlugin->actions(props, this)); } } } PanelContextMenu::PanelContextMenu(KrPanel *krPanel, QWidget *parent) : QMenu(parent), panel(krPanel) { // selected file names const QStringList fileNames = panel->gui->getSelectedNames(); // file items QList files; for (const QString fileName : fileNames) { files.append(panel->func->files()->getFileItem(fileName)); } // KFileItems for (FileItem *file : files) { _items.append(KFileItem(file->getUrl(), file->getMime(), file->getMode())); } if (files.empty()) { addCreateNewMenu(); addSeparator(); addEmptyMenuEntries(); return; } const bool multipleSelections = files.size() > 1; QSet protocols; for (FileItem *file : files) { protocols.insert(file->getUrl().scheme()); } const bool inTrash = protocols.contains("trash"); const bool trashOnly = inTrash && protocols.count() == 1; FileItem *file = files.first(); // ------------ the OPEN/BROWSE option - open preferred service QAction * openAct = addAction(i18n("Open/Run")); openAct->setData(QVariant(OPEN_ID)); if (!multipleSelections) { // meaningful only if one file is selected KrViewItemList viewItems; panel->view->getSelectedKrViewItems(&viewItems); openAct->setIcon(viewItems.first()->icon()); openAct->setText(file->isExecutable() && !file->isDir() ? i18n("Run") : i18n("Open")); // open in a new tab (if folder) if (file->isDir()) { QAction * openTab = addAction(i18n("Open in New Tab")); openTab->setData(QVariant(OPEN_TAB_ID)); - openTab->setIcon(krLoader->loadIcon("tab-new", KIconLoader::Panel)); + openTab->setIcon(Icon("tab-new")); openTab->setText(i18n("Open in New Tab")); } // if the file can be browsed as archive... if (!panel->func->browsableArchivePath(file->getName()).isEmpty() // ...but user disabled archive browsing... && (!KConfigGroup(krConfig, "Archives") .readEntry("ArchivesAsDirectories", _ArchivesAsDirectories) // ...or the file is not a standard archive (e.g. odt, docx, etc.)... || !KRarcHandler::arcSupported(file->getMime()))) { // ...it will not be browsed as a directory by default, but add an option for it QAction *browseAct = addAction(i18n("Browse")); browseAct->setData(QVariant(BROWSE_ID)); - browseAct->setIcon(krLoader->loadIcon("", KIconLoader::Panel)); + browseAct->setIcon(Icon()); browseAct->setText(i18n("Browse Archive")); } addSeparator(); } // ------------- Preview - local filesystem only ? if (panel->func->files()->isLocal()) { // create the preview popup KrPreviewPopup preview; preview.setUrls(panel->func->files()->getUrls(fileNames)); QAction *previewAction = addMenu(&preview); previewAction->setData(QVariant(PREVIEW_ID)); previewAction->setText(i18n("Preview")); - previewAction->setIcon(krLoader->loadIcon("document-print-preview", KIconLoader::Small)); + previewAction->setIcon(Icon("document-print-preview")); } // -------------- Open with: try to find-out which apps can open the file QSet uniqueMimeTypes; for (FileItem *file : files) uniqueMimeTypes.insert(file->getMime()); const QStringList mimeTypes = uniqueMimeTypes.toList(); offers = mimeTypes.count() == 1 ? KMimeTypeTrader::self()->query(mimeTypes.first()) : KFileItemActions::associatedApplications(mimeTypes, QString()); if (!offers.isEmpty()) { QMenu *openWithMenu = new QMenu(this); for (int i = 0; i < offers.count(); ++i) { QExplicitlySharedDataPointer service = offers[i]; if (service->isValid() && service->isApplication()) { - openWithMenu->addAction(krLoader->loadIcon(service->icon(), KIconLoader::Small), + openWithMenu->addAction(Icon(service->icon()), service->name())->setData(QVariant(SERVICE_LIST_ID + i)); } } openWithMenu->addSeparator(); if (!multipleSelections && file->isDir()) - openWithMenu->addAction(krLoader->loadIcon("utilities-terminal", KIconLoader::Small), + openWithMenu->addAction(Icon("utilities-terminal"), i18n("Terminal"))->setData(QVariant(OPEN_TERM_ID)); openWithMenu->addAction(i18n("Other..."))->setData(QVariant(CHOOSE_ID)); QAction *openWithAction = addMenu(openWithMenu); openWithAction->setText(i18n("Open With")); - openWithAction->setIcon(krLoader->loadIcon("document-open", KIconLoader::Small)); + openWithAction->setIcon(Icon("document-open")); addSeparator(); } // --------------- user actions QAction *userAction = new UserActionPopupMenu(file->getUrl(), this); userAction->setText(i18n("User Actions")); addAction(userAction); // --------------- compress/extract actions // workaround for Bug 372999: application freezes very long time if many files are selected if (_items.length() < 1000) // add compress and extract plugins (if available) addCompressAndExtractPluginActions(); // --------------- KDE file item actions // NOTE: design and usability problem here. Services disabled in kservicemenurc settings won't // be added to the menu. But Krusader does not provide a way do change these settings (only // Dolphin does). KFileItemActions *fileItemActions = new KFileItemActions(this); fileItemActions->setItemListProperties(KFileItemListProperties(_items)); fileItemActions->setParentWidget(MAIN_VIEW); fileItemActions->addServiceActionsTo(this); addSeparator(); // ------------- 'create new' submenu addCreateNewMenu(); addSeparator(); // ---------- COPY addAction(panel->gui->actions()->actCopyF5); // ------- MOVE addAction(panel->gui->actions()->actMoveF6); // ------- RENAME - only one file if (!multipleSelections && !inTrash) { addAction(panel->gui->actions()->actRenameF2); } // -------- MOVE TO TRASH if (KConfigGroup(krConfig, "General").readEntry("Move To Trash", _MoveToTrash) && panel->func->files()->canMoveToTrash(fileNames)) { - addAction(krLoader->loadIcon("user-trash", KIconLoader::Small), + addAction(Icon("user-trash"), i18n("Move to Trash"))->setData(QVariant(TRASH_ID)); } // -------- DELETE - addAction(krLoader->loadIcon("edit-delete", KIconLoader::Small), + addAction(Icon("edit-delete"), i18n("Delete"))->setData(QVariant(DELETE_ID)); // -------- SHRED - only one file /* if ( panel->func->files() ->getType() == filesystem:fileSystemM_NORMAL && !fileitem->isDir() && !multipleSelections ) addAction( i18n( "Shred" ) )->setData( QVariant( SHRED_ID ) );*/ // ---------- link handling // create new shortcut or redirect links - only on local directories: if (panel->func->files()->isLocal()) { addSeparator(); QMenu *linkMenu = new QMenu(this); linkMenu->addAction(i18n("New Symlink..."))->setData(QVariant(NEW_SYMLINK_ID)); linkMenu->addAction(i18n("New Hardlink..."))->setData(QVariant(NEW_LINK_ID)); if (file->isSymLink()) { linkMenu->addAction(i18n("Redirect Link..."))->setData(QVariant(REDIRECT_LINK_ID)); } QAction *linkAction = addMenu(linkMenu); linkAction->setText(i18n("Link Handling")); - linkAction->setIcon(krLoader->loadIcon("insert-link", KIconLoader::Small)); + linkAction->setIcon(Icon("insert-link")); } addSeparator(); // ---------- calculate space if (panel->func->files()->isLocal() && (file->isDir() || multipleSelections)) addAction(panel->gui->actions()->actCalculate); // ---------- mount/umount/eject if (panel->func->files()->isLocal() && file->isDir() && !multipleSelections) { const QString selectedDirectoryPath = file->getUrl().path(); if (krMtMan.getStatus(selectedDirectoryPath) == KMountMan::MOUNTED) addAction(i18n("Unmount"))->setData(QVariant(UNMOUNT_ID)); else if (krMtMan.getStatus(selectedDirectoryPath) == KMountMan::NOT_MOUNTED) addAction(i18n("Mount"))->setData(QVariant(MOUNT_ID)); if (krMtMan.ejectable(selectedDirectoryPath)) addAction(i18n("Eject"))->setData(QVariant(EJECT_ID)); } // --------- send by mail if (KrServices::supportedTools().contains("MAIL") && !file->isDir()) { - addAction(krLoader->loadIcon("mail-send", KIconLoader::Small), + addAction(Icon("mail-send"), i18n("Send by Email"))->setData(QVariant(SEND_BY_EMAIL_ID)); } // --------- empty trash if (trashOnly) { addAction(i18n("Restore"))->setData(QVariant(RESTORE_TRASHED_FILE_ID)); addAction(i18n("Empty Trash"))->setData(QVariant(EMPTY_TRASH_ID)); } #ifdef SYNCHRONIZER_ENABLED // --------- synchronize if (panel->view->numSelected()) { addAction(i18n("Synchronize Selected Files..."))->setData(QVariant(SYNC_SELECTED_ID)); } #endif // --------- copy/paste addSeparator(); addAction(panel->gui->actions()->actCut); addAction(panel->gui->actions()->actCopy); addAction(panel->gui->actions()->actPaste); addSeparator(); // --------- properties addAction(panel->gui->actions()->actProperties); } void PanelContextMenu::addEmptyMenuEntries() { addAction(panel->gui->actions()->actPaste); } void PanelContextMenu::addCreateNewMenu() { QMenu *createNewMenu = new QMenu(this); - createNewMenu->addAction(krLoader->loadIcon("folder", KIconLoader::Small), + createNewMenu->addAction(Icon("folder"), i18n("Folder..."))->setData(QVariant(MKDIR_ID)); - createNewMenu->addAction(krLoader->loadIcon("text-plain", KIconLoader::Small), + createNewMenu->addAction(Icon("text-plain"), i18n("Text File..."))->setData(QVariant(NEW_TEXT_FILE_ID)); QAction *newMenuAction = addMenu(createNewMenu); newMenuAction->setText(i18n("Create New")); - newMenuAction->setIcon(krLoader->loadIcon("document-new", KIconLoader::Small)); + newMenuAction->setIcon(Icon("document-new")); } void PanelContextMenu::performAction(int id) { const QUrl singleURL = _items.isEmpty() ? QUrl() : _items.first().url(); switch (id) { case - 1 : // the user clicked outside of the menu return; case OPEN_TAB_ID : // assuming only 1 file is selected (otherwise we won't get here) panel->manager()->newTab(singleURL, panel); break; case OPEN_ID : foreach(const KFileItem &fi, _items) panel->func->execute(fi.name()); break; case BROWSE_ID : panel->func->goInside(singleURL.fileName()); break; case COPY_ID : panel->func->copyFiles(); break; case MOVE_ID : panel->func->moveFiles(); break; case TRASH_ID : panel->func->deleteFiles(true); break; case DELETE_ID : panel->func->deleteFiles(false); break; case EJECT_ID : krMtMan.eject(singleURL.adjusted(QUrl::StripTrailingSlash).path()); break; // case SHRED_ID : // if ( KMessageBox::warningContinueCancel( krApp, // i18n("Do you really want to shred %1? Once shred, the file is gone forever.", item->name()), // QString(), KStandardGuiItem::cont(), KStandardGuiItem::cancel(), "Shred" ) == KMessageBox::Continue ) // KShred::shred( panel->func->files() ->getFile( item->name() ).adjusted(QUrl::RemoveTrailingSlash).path() ); // break; case OPEN_KONQ_ID : KToolInvocation::startServiceByDesktopName("konqueror", singleURL.toDisplayString(QUrl::PreferLocalFile)); break; case CHOOSE_ID : // open-with dialog panel->func->displayOpenWithDialog(_items.urlList()); break; case MOUNT_ID : krMtMan.mount(singleURL.adjusted(QUrl::StripTrailingSlash).path()); break; case NEW_LINK_ID : panel->func->krlink(false); break; case NEW_SYMLINK_ID : panel->func->krlink(true); break; case REDIRECT_LINK_ID : panel->func->redirectLink(); break; case EMPTY_TRASH_ID : KrTrashHandler::emptyTrash(); break; case RESTORE_TRASHED_FILE_ID : KrTrashHandler::restoreTrashedFiles(_items.urlList()); break; case UNMOUNT_ID : krMtMan.unmount(singleURL.adjusted(QUrl::StripTrailingSlash).path()); break; case SEND_BY_EMAIL_ID : { SLOTS->sendFileByEmail(_items.urlList()); break; } case MKDIR_ID : panel->func->mkdir(); break; case NEW_TEXT_FILE_ID: panel->func->editNew(); break; #ifdef SYNCHRONIZER_ENABLED case SYNC_SELECTED_ID : { QStringList selectedNames; for (const KFileItem item : _items) { selectedNames.append(item.name()); } KrViewItemList otherItems; panel->otherPanel()->view->getSelectedKrViewItems(&otherItems); for (KrViewItem *otherItem : otherItems) { const QString name = otherItem->name(); if (!selectedNames.contains(name)) { selectedNames.append(name); } } SLOTS->slotSynchronizeDirs(selectedNames); } break; #endif case OPEN_TERM_ID : SLOTS->runTerminal(singleURL.path()); break; } // check if something from the open-with-offered-services was selected if (id >= SERVICE_LIST_ID) { const QStringList names = panel->gui->getSelectedNames(); panel->func->runService(*(offers[ id - SERVICE_LIST_ID ]), panel->func->files()->getUrls(names)); } } diff --git a/krusader/Panel/sidebar.cpp b/krusader/Panel/sidebar.cpp index d354eb25..79c08694 100644 --- a/krusader/Panel/sidebar.cpp +++ b/krusader/Panel/sidebar.cpp @@ -1,289 +1,289 @@ /***************************************************************************** * Copyright (C) 2003 Shie Erlich * * Copyright (C) 2003 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 "sidebar.h" #include "krfiletreeview.h" #include "krpanel.h" #include "panelfunc.h" #include "viewactions.h" #include "../defaults.h" -#include "../kicons.h" +#include "../icon.h" #include "../Dialogs/krsqueezedtextlabel.h" #include "../FileSystem/fileitem.h" #include "../FileSystem/filesystem.h" #include "../KViewer/diskusageviewer.h" #include "../KViewer/panelviewer.h" #include "PanelView/krview.h" #include "PanelView/krviewitem.h" // QtCore #include #include // QtWidgets #include #include #include #include -#include + Sidebar::Sidebar(QWidget *parent) : QWidget(parent), stack(0), imageFilePreview(0), pjob(0) { QGridLayout * layout = new QGridLayout(this); layout->setContentsMargins(0, 0, 0, 0); // create the label+buttons setup dataLine = new KrSqueezedTextLabel(this); KConfigGroup lg(krConfig, "Look&Feel"); dataLine->setFont(lg.readEntry("Filelist Font", _FilelistFont)); // --- hack: setup colors to be the same as an inactive panel dataLine->setBackgroundRole(QPalette::Window); int sheight = QFontMetrics(dataLine->font()).height() + 4; dataLine->setMaximumHeight(sheight); btns = new QButtonGroup(this); btns->setExclusive(true); connect(btns, SIGNAL(buttonClicked(int)), this, SLOT(tabSelected(int))); treeBtn = new QToolButton(this); treeBtn->setToolTip(i18n("Tree Panel: a tree view of the local file system")); - treeBtn->setIcon(krLoader->loadIcon("view-list-tree", KIconLoader::Toolbar, 16)); + treeBtn->setIcon(Icon("view-list-tree")); treeBtn->setFixedSize(20, 20); treeBtn->setCheckable(true); btns->addButton(treeBtn, Tree); previewBtn = new QToolButton(this); previewBtn->setToolTip(i18n("Preview Panel: display a preview of the current file")); - previewBtn->setIcon(krLoader->loadIcon("view-preview", KIconLoader::Toolbar, 16)); + previewBtn->setIcon(Icon("view-preview")); previewBtn->setFixedSize(20, 20); previewBtn->setCheckable(true); btns->addButton(previewBtn, Preview); viewerBtn = new QToolButton(this); viewerBtn->setToolTip(i18n("View Panel: view the current file")); - viewerBtn->setIcon(krLoader->loadIcon("zoom-original", KIconLoader::Toolbar, 16)); + viewerBtn->setIcon(Icon("zoom-original")); viewerBtn->setFixedSize(20, 20); viewerBtn->setCheckable(true); btns->addButton(viewerBtn, View); duBtn = new QToolButton(this); duBtn->setToolTip(i18n("Disk Usage Panel: view the usage of a folder")); - duBtn->setIcon(krLoader->loadIcon("kr_diskusage", KIconLoader::Toolbar, 16)); + duBtn->setIcon(Icon("kr_diskusage")); duBtn->setFixedSize(20, 20); duBtn->setCheckable(true); btns->addButton(duBtn, DskUsage); layout->addWidget(dataLine, 0, 0); layout->addWidget(treeBtn, 0, 1); layout->addWidget(previewBtn, 0, 2); layout->addWidget(viewerBtn, 0, 3); layout->addWidget(duBtn, 0, 4); // create a widget stack on which to put the parts stack = new QStackedWidget(this); // create the tree part ---------- tree = new KrFileTreeView(stack); tree->setProperty("KrusaderWidgetId", QVariant(Tree)); stack->addWidget(tree); // NOTE: the F2 key press event is caught before it gets to the tree tree->setEditTriggers(QAbstractItemView::EditKeyPressed); // connecting signal to signal connect(tree, &KrFileTreeView::urlActivated, this, &Sidebar::urlActivated); // create the quickview part ------ imageFilePreview = new KImageFilePreview(stack); imageFilePreview->setProperty("KrusaderWidgetId", QVariant(Preview)); stack->addWidget(imageFilePreview); // create the panelview fileViewer = new PanelViewer(stack); fileViewer->setProperty("KrusaderWidgetId", QVariant(View)); // kparts demand too much width QSizePolicy sizePolicy = fileViewer->sizePolicy(); sizePolicy.setHorizontalPolicy(QSizePolicy::Ignored); fileViewer->setSizePolicy(sizePolicy); stack->addWidget(fileViewer); connect(fileViewer, &PanelViewer::openUrlRequest, this, &Sidebar::handleOpenUrlRequest); // create the disk usage view diskusage = new DiskUsageViewer(stack); diskusage->setStatusLabel(dataLine, i18n("Disk Usage:")); diskusage->setProperty("KrusaderWidgetId", QVariant(DskUsage)); stack->addWidget(diskusage); connect(diskusage, &DiskUsageViewer::openUrlRequest, this, &Sidebar::handleOpenUrlRequest); // -------- finish the layout (General one) layout->addWidget(stack, 1, 0, 1, 5); hide(); // for not to open the 3rd hand tool at start (selecting the last used tab) setCurrentPage(0); } Sidebar::~Sidebar() {} void Sidebar::saveSettings(KConfigGroup cfg) const { tree->saveSettings(cfg); } void Sidebar::restoreSettings(const KConfigGroup &cfg) { tree->restoreSettings(cfg); } void Sidebar::setCurrentPage(int id) { QAbstractButton * curr = btns->button(id); if (curr) { curr->click(); } } void Sidebar::show() { QWidget::show(); tabSelected(currentPage()); } void Sidebar::hide() { QWidget::hide(); if (currentPage() == View) fileViewer->closeUrl(); if (currentPage() == DskUsage) diskusage->closeUrl(); } void Sidebar::focusInEvent(QFocusEvent*) { switch (currentPage()) { case Preview: if (!isHidden()) imageFilePreview->setFocus(); break; case View: if (!isHidden() && fileViewer->part() && fileViewer->part()->widget()) fileViewer->part()->widget()->setFocus(); break; case DskUsage: if (!isHidden() && diskusage->getWidget() && diskusage->getWidget()->currentWidget()) diskusage->getWidget()->currentWidget()->setFocus(); break; case Tree: if (!isHidden()) tree->setFocus(); break; } } void Sidebar::handleOpenUrlRequest(const QUrl &url) { QMimeDatabase db; QMimeType mime = db.mimeTypeForUrl(url); if (mime.isValid() && mime.name() == "inode/directory") ACTIVE_PANEL->func->openUrl(url); } void Sidebar::tabSelected(int id) { QUrl url; const FileItem *fileitem = 0; if (ACTIVE_PANEL && ACTIVE_PANEL->view) fileitem = ACTIVE_PANEL->func->files()->getFileItem(ACTIVE_PANEL->view->getCurrentItem()); if(fileitem) url = fileitem->getUrl(); // if tab is tree, set something logical in the data line switch (id) { case Tree: stack->setCurrentWidget(tree); dataLine->setText(i18n("Tree:")); if (!isHidden()) tree->setFocus(); if (ACTIVE_PANEL) tree->setCurrentUrl(ACTIVE_PANEL->virtualPath()); break; case Preview: stack->setCurrentWidget(imageFilePreview); dataLine->setText(i18n("Preview:")); update(fileitem); break; case View: stack->setCurrentWidget(fileViewer); dataLine->setText(i18n("View:")); update(fileitem); if (!isHidden() && fileViewer->part() && fileViewer->part()->widget()) fileViewer->part()->widget()->setFocus(); break; case DskUsage: stack->setCurrentWidget(diskusage); dataLine->setText(i18n("Disk Usage:")); update(fileitem); if (!isHidden() && diskusage->getWidget() && diskusage->getWidget()->currentWidget()) diskusage->getWidget()->currentWidget()->setFocus(); break; } if (id != View) fileViewer->closeUrl(); } // decide which part to update, if at all void Sidebar::update(const FileItem *fileitem) { if (isHidden()) return; QUrl url; if(fileitem) url = fileitem->getUrl(); switch (currentPage()) { case Preview: imageFilePreview->showPreview(url); dataLine->setText(i18n("Preview: %1", url.fileName())); break; case View: if(fileitem && !fileitem->isDir() && fileitem->isReadable()) fileViewer->openUrl(fileitem->getUrl()); else fileViewer->closeUrl(); dataLine->setText(i18n("View: %1", url.fileName())); break; case DskUsage: { if(fileitem && !fileitem->isDir()) url = KIO::upUrl(url); dataLine->setText(i18n("Disk Usage: %1", url.fileName())); diskusage->openUrl(url); } break; case Tree: // nothing to do break; } } void Sidebar::onPanelPathChange(const QUrl &url) { switch (currentPage()) { case Tree: if (url.isLocalFile()) { tree->setCurrentUrl(url); // synchronize panel path with tree path } break; } } diff --git a/krusader/Search/krsearchdialog.cpp b/krusader/Search/krsearchdialog.cpp index 14dfa683..3b95a125 100644 --- a/krusader/Search/krsearchdialog.cpp +++ b/krusader/Search/krsearchdialog.cpp @@ -1,670 +1,670 @@ /***************************************************************************** * Copyright (C) 2001 Shie Erlich * * Copyright (C) 2001 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 "krsearchdialog.h" // QtCore #include #include // QtGui #include #include #include #include #include #include // QtWidgets #include #include #include #include #include #include #include #include #include "krsearchmod.h" #include "../Dialogs/krdialogs.h" #include "../Dialogs/krspecialwidgets.h" #include "../Dialogs/krsqueezedtextlabel.h" #include "../FileSystem/fileitem.h" #include "../FileSystem/krquery.h" #include "../FileSystem/virtualfilesystem.h" #include "../Filter/filtertabs.h" #include "../Filter/generalfilter.h" #include "../KViewer/krviewer.h" #include "../Panel/PanelView/krview.h" #include "../Panel/PanelView/krviewfactory.h" #include "../Panel/PanelView/krviewitem.h" #include "../Panel/krpanel.h" #include "../Panel/krsearchbar.h" #include "../Panel/panelfunc.h" #include "../defaults.h" -#include "../kicons.h" #include "../kractions.h" #include "../krglobal.h" +#include "../filelisticon.h" #include "../krservices.h" #include "../krslots.h" #include "../krusaderview.h" #include "../panelmanager.h" #define RESULTVIEW_TYPE 0 class SearchResultContainer : public DirListerInterface { public: explicit SearchResultContainer(QObject *parent) : DirListerInterface(parent) {} virtual ~SearchResultContainer() { clear(); } virtual QList fileItems() const Q_DECL_OVERRIDE { return _fileItems; } virtual unsigned long numFileItems() const Q_DECL_OVERRIDE { return _fileItems.count(); } virtual bool isRoot() const Q_DECL_OVERRIDE { return true; } void clear() { emit cleared(); foreach(FileItem *fileitem, _fileItems) delete fileitem; _fileItems.clear(); _foundText.clear(); } void addItem(const FileItem &file, const QString &foundText) { const QString path = file.getUrl().toDisplayString(QUrl::PreferLocalFile); FileItem *fileitem = FileItem::createCopy(file, path); _fileItems << fileitem; if(!foundText.isEmpty()) _foundText[fileitem] = foundText; emit addedFileItem(fileitem); } QString foundText(const FileItem *fileitem) { return _foundText[fileitem]; } private: QList _fileItems; QHash _foundText; }; KrSearchDialog *KrSearchDialog::SearchDialog = 0; QString KrSearchDialog::lastSearchText = QString('*'); int KrSearchDialog::lastSearchType = 0; bool KrSearchDialog::lastSearchForCase = false; bool KrSearchDialog::lastContainsWholeWord = false; bool KrSearchDialog::lastContainsWithCase = false; bool KrSearchDialog::lastSearchInSubDirs = true; bool KrSearchDialog::lastSearchInArchives = false; bool KrSearchDialog::lastFollowSymLinks = false; bool KrSearchDialog::lastContainsRegExp = false; // class starts here ///////////////////////////////////////// KrSearchDialog::KrSearchDialog(QString profile, QWidget* parent) : QDialog(parent), query(0), searcher(0), isBusy(false), closed(false) { KConfigGroup group(krConfig, "Search"); setWindowTitle(i18n("Krusader::Search")); - setWindowIcon(QIcon::fromTheme("system-search")); + setWindowIcon(Icon("system-search")); QGridLayout* searchBaseLayout = new QGridLayout(this); searchBaseLayout->setSpacing(6); searchBaseLayout->setContentsMargins(11, 11, 11, 11); // creating the dialog buttons ( Search, Stop, Close ) QHBoxLayout* buttonsLayout = new QHBoxLayout(); buttonsLayout->setSpacing(6); buttonsLayout->setContentsMargins(0, 0, 0, 0); profileManager = new ProfileManager("SearcherProfile", this); buttonsLayout->addWidget(profileManager); searchTextToClipboard = new QCheckBox(this); searchTextToClipboard->setText(i18n("Query to clipboard")); searchTextToClipboard->setToolTip(i18n("Place search text to clipboard when a found file is opened.")); searchTextToClipboard->setCheckState(static_cast(group.readEntry("QueryToClipboard", 0))); connect(searchTextToClipboard, &QCheckBox::stateChanged, this, [=](int state) { KConfigGroup group(krConfig, "Search"); group.writeEntry("QueryToClipboard", state); }); buttonsLayout->addWidget(searchTextToClipboard); QSpacerItem* spacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); buttonsLayout->addItem(spacer); mainFeedToListBoxBtn = new QPushButton(this); mainFeedToListBoxBtn->setText(i18n("Feed to listbox")); - mainFeedToListBoxBtn->setIcon(QIcon::fromTheme("list-add")); + mainFeedToListBoxBtn->setIcon(Icon("list-add")); mainFeedToListBoxBtn->setEnabled(false); buttonsLayout->addWidget(mainFeedToListBoxBtn); mainSearchBtn = new QPushButton(this); mainSearchBtn->setText(i18n("Search")); - mainSearchBtn->setIcon(QIcon::fromTheme("edit-find")); + mainSearchBtn->setIcon(Icon("edit-find")); mainSearchBtn->setDefault(true); buttonsLayout->addWidget(mainSearchBtn); mainStopBtn = new QPushButton(this); mainStopBtn->setEnabled(false); mainStopBtn->setText(i18n("Stop")); - mainStopBtn->setIcon(QIcon::fromTheme("process-stop")); + mainStopBtn->setIcon(Icon("process-stop")); buttonsLayout->addWidget(mainStopBtn); mainCloseBtn = new QPushButton(this); mainCloseBtn->setText(i18n("Close")); - mainCloseBtn->setIcon(QIcon::fromTheme("dialog-close")); + mainCloseBtn->setIcon(Icon("dialog-close")); buttonsLayout->addWidget(mainCloseBtn); searchBaseLayout->addLayout(buttonsLayout, 1, 0); // creating the searcher tabs searcherTabs = new QTabWidget(this); filterTabs = FilterTabs::addTo(searcherTabs, FilterTabs::Default); generalFilter = (GeneralFilter *)filterTabs->get("GeneralFilter"); QWidget* resultTab = new QWidget(searcherTabs); QGridLayout* resultLayout = new QGridLayout(resultTab); resultLayout->setSpacing(6); resultLayout->setContentsMargins(6, 6, 6, 6); // creating the result tab QHBoxLayout* resultLabelLayout = new QHBoxLayout(); resultLabelLayout->setSpacing(6); resultLabelLayout->setContentsMargins(0, 0, 0, 0); foundLabel = new QLabel(resultTab); QSizePolicy foundpolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); foundpolicy.setHeightForWidth(foundLabel->sizePolicy().hasHeightForWidth()); foundLabel->setSizePolicy(foundpolicy); foundLabel->setFrameShape(QLabel::StyledPanel); foundLabel->setFrameShadow(QLabel::Sunken); foundLabel->setText(i18n("Found 0 matches.")); resultLabelLayout->addWidget(foundLabel); searchingLabel = new KSqueezedTextLabel(resultTab); searchingLabel->setFrameShape(QLabel::StyledPanel); searchingLabel->setFrameShadow(QLabel::Sunken); searchingLabel->setText(""); resultLabelLayout->addWidget(searchingLabel); resultLayout->addLayout(resultLabelLayout, 2, 0); // creating the result list view result = new SearchResultContainer(this); // the view resultView = KrViewFactory::createView(RESULTVIEW_TYPE, resultTab, krConfig); resultView->init(false); resultView->restoreSettings(KConfigGroup(&group, "ResultView")); resultView->setMainWindow(this); resultView->prepareForActive(); resultView->refreshColors(); resultView->setFiles(result); resultView->refresh(); resultLayout->addWidget(resultView->widget(), 0, 0); // search bar searchBar = new KrSearchBar(resultView, this); searchBar->hide(); resultLayout->addWidget(searchBar, 1, 0); QHBoxLayout* foundTextLayout = new QHBoxLayout(); foundTextLayout->setSpacing(6); foundTextLayout->setContentsMargins(0, 0, 0, 0); QLabel *l1 = new QLabel(resultTab); QSizePolicy l1policy(QSizePolicy::Minimum, QSizePolicy::Minimum); l1policy.setHeightForWidth(l1->sizePolicy().hasHeightForWidth()); l1->setSizePolicy(l1policy); l1->setFrameShape(QLabel::StyledPanel); l1->setFrameShadow(QLabel::Sunken); l1->setText(i18n("Text found:")); foundTextLayout->addWidget(l1); foundTextLabel = new KrSqueezedTextLabel(resultTab); foundTextLabel->setFrameShape(QLabel::StyledPanel); foundTextLabel->setFrameShadow(QLabel::Sunken); foundTextLabel->setText(""); foundTextLayout->addWidget(foundTextLabel); resultLayout->addLayout(foundTextLayout, 3, 0); searcherTabs->addTab(resultTab, i18n("&Results")); searchBaseLayout->addWidget(searcherTabs, 0, 0); // signals and slots connections connect(mainSearchBtn, SIGNAL(clicked()), this, SLOT(startSearch())); connect(mainStopBtn, SIGNAL(clicked()), this, SLOT(stopSearch())); connect(mainCloseBtn, SIGNAL(clicked()), this, SLOT(closeDialog())); connect(mainFeedToListBoxBtn, SIGNAL(clicked()), this, SLOT(feedToListBox())); connect(profileManager, SIGNAL(loadFromProfile(QString)), filterTabs, SLOT(loadFromProfile(QString))); connect(profileManager, SIGNAL(saveToProfile(QString)), filterTabs, SLOT(saveToProfile(QString))); connect(resultView->op(), SIGNAL(currentChanged(KrViewItem*)), SLOT(currentChanged(KrViewItem*))); connect(resultView->op(), SIGNAL(executed(QString)), SLOT(executed(QString))); connect(resultView->op(), SIGNAL(contextMenu(QPoint)), SLOT(contextMenu(QPoint))); // tab order setTabOrder(mainSearchBtn, mainCloseBtn); setTabOrder(mainCloseBtn, mainStopBtn); setTabOrder(mainStopBtn, searcherTabs); setTabOrder(searcherTabs, resultView->widget()); sizeX = group.readEntry("Window Width", -1); sizeY = group.readEntry("Window Height", -1); if (sizeX != -1 && sizeY != -1) resize(sizeX, sizeY); if (group.readEntry("Window Maximized", false)) showMaximized(); else show(); generalFilter->searchFor->setFocus(); // finaly, load a profile of apply defaults: if (profile.isEmpty()) { // load the last used values generalFilter->searchFor->setEditText(lastSearchText); generalFilter->searchFor->lineEdit()->selectAll(); generalFilter->ofType->setCurrentIndex(lastSearchType); generalFilter->searchForCase->setChecked(lastSearchForCase); generalFilter->containsWholeWord->setChecked(lastContainsWholeWord); generalFilter->containsTextCase->setChecked(lastContainsWithCase); generalFilter->containsRegExp->setChecked(lastContainsRegExp); generalFilter->searchInDirs->setChecked(lastSearchInSubDirs); generalFilter->searchInArchives->setChecked(lastSearchInArchives); generalFilter->followLinks->setChecked(lastFollowSymLinks); // the path in the active panel should be the default search location generalFilter->searchIn->lineEdit()->setText(ACTIVE_PANEL->virtualPath().toDisplayString(QUrl::PreferLocalFile)); } else profileManager->loadProfile(profile); // important: call this _after_ you've connected profileManager ot the loadFromProfile!! } KrSearchDialog::~KrSearchDialog() { delete query; query = 0; delete resultView; resultView = 0; } void KrSearchDialog::closeDialog(bool isAccept) { if(isBusy) { closed = true; return; } // stop the search if it's on-going if (searcher != 0) { delete searcher; searcher = 0; } // saving the searcher state KConfigGroup group(krConfig, "Search"); group.writeEntry("Window Width", sizeX); group.writeEntry("Window Height", sizeY); group.writeEntry("Window Maximized", isMaximized()); resultView->saveSettings(KConfigGroup(&group, "ResultView")); lastSearchText = generalFilter->searchFor->currentText(); lastSearchType = generalFilter->ofType->currentIndex(); lastSearchForCase = generalFilter->searchForCase->isChecked(); lastContainsWholeWord = generalFilter->containsWholeWord->isChecked(); lastContainsWithCase = generalFilter->containsTextCase->isChecked(); lastContainsRegExp = generalFilter->containsRegExp->isChecked(); lastSearchInSubDirs = generalFilter->searchInDirs->isChecked(); lastSearchInArchives = generalFilter->searchInArchives->isChecked(); lastFollowSymLinks = generalFilter->followLinks->isChecked(); hide(); SearchDialog = 0; if (isAccept) QDialog::accept(); else QDialog::reject(); this->deleteLater(); } void KrSearchDialog::reject() { closeDialog(false); } void KrSearchDialog::resizeEvent(QResizeEvent *e) { if (!isMaximized()) { sizeX = e->size().width(); sizeY = e->size().height(); } } void KrSearchDialog::slotFound(const FileItem &file, const QString &foundText) { result->addItem(file, foundText); foundLabel->setText(i18np("Found %1 match.", "Found %1 matches.", result->numFileItems())); } bool KrSearchDialog::gui2query() { // prepare the query ... /////////////////// names, locations and greps if (query != 0) { delete query; query = 0; } query = new KRQuery(); return filterTabs->fillQuery(query); } void KrSearchDialog::startSearch() { if(isBusy) return; // prepare the query ///////////////////////////////////////////// if (!gui2query()) return; // first, informative messages if (query->searchInArchives()) { KMessageBox::information(this, i18n("Since you chose to also search in archives, " "note the following limitations:\n" "You cannot search for text (grep) while doing" " a search that includes archives."), 0, "searchInArchives"); } // prepare the gui /////////////////////////////////////////////// mainSearchBtn->setEnabled(false); mainCloseBtn->setEnabled(false); mainStopBtn->setEnabled(true); mainFeedToListBoxBtn->setEnabled(false); result->clear(); resultView->setSortMode(KrViewProperties::NoColumn, 0); searchingLabel->setText(""); foundLabel->setText(i18n("Found 0 matches.")); searcherTabs->setCurrentIndex(2); // show the results page foundTextLabel->setText(""); isBusy = true; qApp->processEvents(); // start the search. if (searcher != 0) abort(); searcher = new KRSearchMod(query); connect(searcher, SIGNAL(searching(QString)), searchingLabel, SLOT(setText(QString))); connect(searcher, &KRSearchMod::found, this, &KrSearchDialog::slotFound); connect(searcher, SIGNAL(finished()), this, SLOT(stopSearch())); searcher->start(); isBusy = false; delete searcher; searcher = 0; // gui stuff mainSearchBtn->setEnabled(true); mainCloseBtn->setEnabled(true); mainStopBtn->setEnabled(false); if (result->numFileItems()) mainFeedToListBoxBtn->setEnabled(true); searchingLabel->setText(i18n("Finished searching.")); if (closed) closeDialog(); } void KrSearchDialog::stopSearch() { if (searcher != 0) { searcher->stop(); disconnect(searcher, 0, 0, 0); } } void KrSearchDialog::executed(const QString &name) { // 'name' is (local) file path or complete URL QString path = name; QString fileName; if(!name.endsWith('/')) { // not a directory, split filename and path int idx = name.lastIndexOf("/"); fileName = name.mid(idx+1); path = name.left(idx); } QUrl url(path); if (url.scheme().isEmpty()) { url = QUrl::fromLocalFile(path); } ACTIVE_FUNC->openUrl(url, fileName); showMinimized(); } void KrSearchDialog::currentChanged(KrViewItem *item) { if(!item) return; QString text = result->foundText(item->getFileItem()); if(!text.isEmpty()) { // ugly hack: find the and in the text, then // use it to set the are which we don't want squeezed int idx = text.indexOf("") - 4; // take "" into account int length = text.indexOf("") - idx + 4; foundTextLabel->setText(text, idx, length); } } void KrSearchDialog::closeEvent(QCloseEvent *e) { /* if searching is in progress we must not close the window */ if (isBusy) /* because qApp->processEvents() is called by the searcher and */ { /* at window desruction, the searcher object will be deleted */ stopSearch(); /* instead we stop searching */ closed = true; /* and after stopping: startSearch can close the window */ e->ignore(); /* ignoring the close event */ } else QDialog::closeEvent(e); /* if no searching, let QDialog handle the event */ } void KrSearchDialog::keyPressEvent(QKeyEvent *e) { // TODO: don't use hardcoded shortcuts if (isBusy && e->key() == Qt::Key_Escape) { /* at searching we must not close the window */ stopSearch(); /* so we simply stop searching */ return; } if (resultView->widget()->hasFocus()) { if ((e->key() | e->modifiers()) == (Qt::CTRL | Qt::Key_I)) { searchBar->showBar(KrSearchBar::MODE_FILTER); } else if (e->key() == Qt::Key_F4) { tryPlaceSearchQueryToClipboard(); editCurrent(); return; } else if (e->key() == Qt::Key_F3) { tryPlaceSearchQueryToClipboard(); viewCurrent(); return; } else if (e->key() == Qt::Key_F10) { compareByContent(); return; } else if (KrGlobal::copyShortcut == QKeySequence(e->key() | e->modifiers())) { copyToClipBoard(); return; } } QDialog::keyPressEvent(e); } void KrSearchDialog::editCurrent() { KrViewItem *current = resultView->getCurrentKrViewItem(); if (current) KrViewer::edit(current->getFileItem()->getUrl(), this); } void KrSearchDialog::viewCurrent() { KrViewItem *current = resultView->getCurrentKrViewItem(); if (current) KrViewer::view(current->getFileItem()->getUrl(), this); } void KrSearchDialog::compareByContent() { KrViewItemList list; resultView->getSelectedKrViewItems(&list); if (list.count() != 2) return; SLOTS->compareContent(list[0]->getFileItem()->getUrl(),list[1]->getFileItem()->getUrl()); } void KrSearchDialog::contextMenu(const QPoint &pos) { // create the menu QMenu popup; popup.setTitle(i18n("Krusader Search")); QAction *actView = popup.addAction(i18n("View File (F3)")); QAction *actEdit = popup.addAction(i18n("Edit File (F4)")); QAction *actComp = popup.addAction(i18n("Compare by content (F10)")); if(resultView->numSelected() != 2) actComp->setEnabled(false); QAction *actClip = popup.addAction(i18n("Copy selected to clipboard")); QAction *result = popup.exec(pos); // check out the user's option if (result == actView) viewCurrent(); else if (result == actEdit) editCurrent(); else if (result == actClip) copyToClipBoard(); else if (result == actComp) compareByContent(); } void KrSearchDialog::feedToListBox() { VirtualFileSystem virtFilesystem; virtFilesystem.scanDir(QUrl::fromLocalFile("/")); KConfigGroup group(krConfig, "Search"); int listBoxNum = group.readEntry("Feed To Listbox Counter", 1); QString queryName; if(query) { QString where = KrServices::toStringList(query->searchInDirs()).join(", "); if(query->content().isEmpty()) queryName = i18n("Search results for \"%1\" in %2", query->nameFilter(), where); else queryName = i18n("Search results for \"%1\" containing \"%2\" in %3", query->nameFilter(), query->content(), where); } QString fileSystemName; do { fileSystemName = i18n("Search results") + QString(" %1").arg(listBoxNum++); } while (virtFilesystem.getFileItem(fileSystemName) != 0); group.writeEntry("Feed To Listbox Counter", listBoxNum); KConfigGroup ga(krConfig, "Advanced"); if (ga.readEntry("Confirm Feed to Listbox", _ConfirmFeedToListbox)) { bool ok; fileSystemName = QInputDialog::getText(this, i18n("Query name"), i18n("Here you can name the file collection"), QLineEdit::Normal, fileSystemName, &ok); if (! ok) return; } QList urlList; foreach(FileItem *fileitem, result->fileItems()) urlList.push_back(fileitem->getUrl()); mainSearchBtn->setEnabled(false); mainCloseBtn->setEnabled(false); mainFeedToListBoxBtn->setEnabled(false); isBusy = true; const QUrl url = QUrl(QString("virt:/") + fileSystemName); virtFilesystem.scanDir(url); virtFilesystem.addFiles(urlList); virtFilesystem.setMetaInformation(queryName); //ACTIVE_FUNC->openUrl(url); ACTIVE_MNG->slotNewTab(url); isBusy = false; closeDialog(); } void KrSearchDialog::copyToClipBoard() { QList urls; foreach(FileItem *fileitem, result->fileItems()) urls.push_back(fileitem->getUrl()); if (urls.count() == 0) return; QMimeData *mimeData = new QMimeData; - mimeData->setImageData(FL_LOADICON("file")); + mimeData->setImageData(FileListIcon("file").pixmap()); mimeData->setUrls(urls); QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard); } void KrSearchDialog::tryPlaceSearchQueryToClipboard() { if (searchTextToClipboard->isChecked() && !generalFilter->containsText->currentText().isEmpty() && QApplication::clipboard()->text() != generalFilter->containsText->currentText()) { QApplication::clipboard()->setText(generalFilter->containsText->currentText()); } } diff --git a/krusader/Synchronizer/synchronizedialog.cpp b/krusader/Synchronizer/synchronizedialog.cpp index b3e4f505..70ac6960 100644 --- a/krusader/Synchronizer/synchronizedialog.cpp +++ b/krusader/Synchronizer/synchronizedialog.cpp @@ -1,203 +1,204 @@ /***************************************************************************** * 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/]. * *****************************************************************************/ #include "synchronizedialog.h" #include "../FileSystem/krpermhandler.h" #include "../krglobal.h" +#include "../icon.h" #include "../defaults.h" // QtWidgets #include #include #include #include #include SynchronizeDialog::SynchronizeDialog(QWidget* parent, Synchronizer *sync, int pleftCopyNr, KIO::filesize_t pleftCopySize, int prightCopyNr, KIO::filesize_t prightCopySize, int pdeleteNr, KIO::filesize_t pdeleteSize, int parThreads) : QDialog(parent), synchronizer(sync), leftCopyNr(pleftCopyNr), leftCopySize(pleftCopySize), rightCopyNr(prightCopyNr), rightCopySize(prightCopySize), deleteNr(pdeleteNr), deleteSize(pdeleteSize), parallelThreads(parThreads), isPause(true), syncStarted(false) { setWindowTitle(i18n("Krusader::Synchronize")); setModal(true); QVBoxLayout *layout = new QVBoxLayout(this); layout->setContentsMargins(11, 11, 11, 11); layout->setSpacing(6); cbRightToLeft = new QCheckBox(i18np("Right to left: Copy 1 file", "Right to left: Copy %1 files", leftCopyNr) + ' ' + i18np("(1 byte)", "(%1 bytes)", KRpermHandler::parseSize(leftCopySize).trimmed().toInt()), this); cbRightToLeft->setChecked(leftCopyNr != 0); cbRightToLeft->setEnabled(leftCopyNr != 0); layout->addWidget(cbRightToLeft); lbRightToLeft = new QLabel(i18np("\tReady: %2/1 file, %3/%4", "\tReady: %2/%1 files, %3/%4", leftCopyNr, 0, 0, KRpermHandler::parseSize(leftCopySize).trimmed()), this); lbRightToLeft->setEnabled(leftCopyNr != 0); layout->addWidget(lbRightToLeft); cbLeftToRight = new QCheckBox(i18np("Left to right: Copy 1 file", "Left to right: Copy %1 files", rightCopyNr) + ' ' + i18np("(1 byte)", "(%1 bytes)", KRpermHandler::parseSize(rightCopySize).trimmed().toInt()), this); cbLeftToRight->setChecked(rightCopyNr != 0); cbLeftToRight->setEnabled(rightCopyNr != 0); layout->addWidget(cbLeftToRight); lbLeftToRight = new QLabel(i18np("\tReady: %2/1 file, %3/%4", "\tReady: %2/%1 files, %3/%4", rightCopyNr, 0, 0, KRpermHandler::parseSize(rightCopySize).trimmed()), this); lbLeftToRight->setEnabled(rightCopyNr != 0); layout->addWidget(lbLeftToRight); cbDeletable = new QCheckBox(i18np("Left: Delete 1 file", "Left: Delete %1 files", deleteNr) + ' ' + i18np("(1 byte)", "(%1 bytes)", KRpermHandler::parseSize(deleteSize).trimmed().toInt()), this); cbDeletable->setChecked(deleteNr != 0); cbDeletable->setEnabled(deleteNr != 0); layout->addWidget(cbDeletable); lbDeletable = new QLabel(i18np("\tReady: %2/1 file, %3/%4", "\tReady: %2/%1 files, %3/%4", deleteNr, 0, 0, KRpermHandler::parseSize(deleteSize).trimmed()), this); lbDeletable->setEnabled(deleteNr != 0); layout->addWidget(lbDeletable); progress = new QProgressBar(this); progress->setMaximum(1000); progress->setMinimum(0); progress->setValue(0); progress->setMinimumWidth(400); layout->addWidget(progress); QWidget *hboxWidget = new QWidget(this); QHBoxLayout * hbox = new QHBoxLayout(hboxWidget); hbox->setSpacing(6); cbOverwrite = new QCheckBox(i18n("Confirm overwrites"), this); KConfigGroup group(krConfig, "Synchronize"); cbOverwrite->setChecked(group.readEntry("Confirm overwrites", _ConfirmOverWrites)); layout->addWidget(cbOverwrite); QSpacerItem* spacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); hbox->addItem(spacer); btnStart = new QPushButton(hboxWidget); btnStart->setText(i18n("&Start")); - btnStart->setIcon(QIcon::fromTheme("media-playback-start")); + btnStart->setIcon(Icon("media-playback-start")); hbox->addWidget(btnStart); btnPause = new QPushButton(hboxWidget); btnPause->setEnabled(false); btnPause->setText(i18n("&Pause")); - btnPause->setIcon(QIcon::fromTheme("media-playback-pause")); + btnPause->setIcon(Icon("media-playback-pause")); hbox->addWidget(btnPause); QPushButton *btnClose = new QPushButton(hboxWidget); btnClose->setText(i18n("&Close")); - btnClose->setIcon(QIcon::fromTheme("dialog-close")); + btnClose->setIcon(Icon("dialog-close")); hbox->addWidget(btnClose); layout->addWidget(hboxWidget); connect(btnStart, SIGNAL(clicked()), this, SLOT(startSynchronization())); connect(btnPause, SIGNAL(clicked()), this, SLOT(pauseOrResume())); connect(btnClose, SIGNAL(clicked()), this, SLOT(reject())); exec(); } SynchronizeDialog::~SynchronizeDialog() { KConfigGroup group(krConfig, "Synchronize"); group.writeEntry("Confirm overwrites", cbOverwrite->isChecked()); } void SynchronizeDialog::startSynchronization() { btnStart->setEnabled(false); btnPause->setEnabled(syncStarted = true); connect(synchronizer, SIGNAL(synchronizationFinished()), this, SLOT(synchronizationFinished())); connect(synchronizer, SIGNAL(processedSizes(int,KIO::filesize_t,int,KIO::filesize_t,int,KIO::filesize_t)), this, SLOT(processedSizes(int,KIO::filesize_t,int,KIO::filesize_t,int,KIO::filesize_t))); connect(synchronizer, SIGNAL(pauseAccepted()), this, SLOT(pauseAccepted())); if (!cbRightToLeft->isChecked()) leftCopySize = 0; if (!cbLeftToRight->isChecked()) rightCopySize = 0; if (!cbDeletable->isChecked()) deleteSize = 0; synchronizer->synchronize(this, cbRightToLeft->isChecked(), cbLeftToRight->isChecked(), cbDeletable->isChecked(), !cbOverwrite->isChecked(), parallelThreads); } void SynchronizeDialog::synchronizationFinished() { QDialog::reject(); } void SynchronizeDialog::processedSizes(int leftNr, KIO::filesize_t leftSize, int rightNr, KIO::filesize_t rightSize, int delNr, KIO::filesize_t delSize) { lbRightToLeft->setText(i18np("\tReady: %2/1 file, %3/%4", "\tReady: %2/%1 files, %3/%4", leftCopyNr, leftNr, KRpermHandler::parseSize(leftSize).trimmed(), KRpermHandler::parseSize(leftCopySize).trimmed())); lbLeftToRight->setText(i18np("\tReady: %2/1 file, %3/%4", "\tReady: %2/%1 files, %3/%4", rightCopyNr, rightNr, KRpermHandler::parseSize(rightSize).trimmed(), KRpermHandler::parseSize(rightCopySize).trimmed())); lbDeletable->setText(i18np("\tReady: %2/1 file, %3/%4", "\tReady: %2/%1 files, %3/%4", deleteNr, delNr, KRpermHandler::parseSize(delSize).trimmed(), KRpermHandler::parseSize(deleteSize).trimmed())); KIO::filesize_t totalSum = leftCopySize + rightCopySize + deleteSize; KIO::filesize_t processedSum = leftSize + rightSize + delSize; if (totalSum == 0) totalSum++; progress->setValue((int)(((double)processedSum / (double)totalSum)*1000)); } void SynchronizeDialog::pauseOrResume() { if (isPause) { btnPause->setEnabled(false); synchronizer->pause(); } else { btnPause->setText(i18n("Pause")); synchronizer->resume(); isPause = true; } } void SynchronizeDialog::pauseAccepted() { btnPause->setText(i18n("Resume")); btnPause->setEnabled(true); isPause = false; } diff --git a/krusader/Synchronizer/synchronizergui.cpp b/krusader/Synchronizer/synchronizergui.cpp index a79b2183..bea9d295 100644 --- a/krusader/Synchronizer/synchronizergui.cpp +++ b/krusader/Synchronizer/synchronizergui.cpp @@ -1,1624 +1,1628 @@ /***************************************************************************** * 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/]. * *****************************************************************************/ #include "synchronizergui.h" #include "../krglobal.h" +#include "../filelisticon.h" #include "../defaults.h" #include "../krusaderview.h" #include "../Panel/listpanel.h" #include "../Panel/panelfunc.h" #include "../FileSystem/krpermhandler.h" #include "../KViewer/krviewer.h" #include "../Dialogs/krspwidgets.h" #include "../FileSystem/krquery.h" #include "../krservices.h" #include "../krslots.h" -#include "../kicons.h" #include "synchronizedialog.h" #include "feedtolistboxdialog.h" #include "synchronizercolors.h" // QtCore #include #include #include #include // QtGui #include #include #include #include #include #include #include // QtWidgets #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class SynchronizerListView : public KrTreeWidget { private: Synchronizer *synchronizer; bool isLeft; public: SynchronizerListView(Synchronizer * sync, QWidget * parent) : KrTreeWidget(parent), synchronizer(sync) { } void mouseMoveEvent(QMouseEvent * e) { isLeft = ((e->modifiers() & Qt::ShiftModifier) == 0); KrTreeWidget::mouseMoveEvent(e); } void startDrag(Qt::DropActions /* supportedActs */) { QList urls; unsigned ndx = 0; SynchronizerFileItem *currentItem; while ((currentItem = synchronizer->getItemAt(ndx++)) != 0) { SynchronizerGUI::SyncViewItem *viewItem = (SynchronizerGUI::SyncViewItem *)currentItem->userData(); if (!viewItem || !viewItem->isSelected() || viewItem->isHidden()) continue; SynchronizerFileItem *item = viewItem->synchronizerItemRef(); if (item) { if (isLeft && item->existsInLeft()) { QString leftDirName = item->leftDirectory().isEmpty() ? "" : item->leftDirectory() + '/'; QUrl leftURL = Synchronizer::fsUrl(synchronizer->leftBaseDirectory() + leftDirName + item->leftName()); urls.push_back(leftURL); } else if (!isLeft && item->existsInRight()) { QString rightDirName = item->rightDirectory().isEmpty() ? "" : item->rightDirectory() + '/'; QUrl rightURL = Synchronizer::fsUrl(synchronizer->rightBaseDirectory() + rightDirName + item->rightName()); urls.push_back(rightURL); } } } if (urls.count() == 0) return; QDrag *drag = new QDrag(this); QMimeData *mimeData = new QMimeData; - mimeData->setImageData(FL_LOADICON(isLeft ? "arrow-left-double" : "arrow-right-double")); + mimeData->setImageData(FileListIcon(isLeft ? "arrow-left-double" : "arrow-right-double").pixmap()); mimeData->setUrls(urls); drag->setMimeData(mimeData); drag->start(); } }; SynchronizerGUI::SynchronizerGUI(QWidget* parent, QUrl leftURL, QUrl rightURL, QStringList selList) : QDialog(parent) { initGUI(QString(), leftURL, rightURL, selList); } SynchronizerGUI::SynchronizerGUI(QWidget* parent, QString profile) : QDialog(parent) { initGUI(profile, QUrl(), QUrl(), QStringList()); } void SynchronizerGUI::initGUI(QString profileName, QUrl leftURL, QUrl rightURL, QStringList selList) { setAttribute(Qt::WA_DeleteOnClose); selectedFiles = selList; isComparing = wasClosed = wasSync = false; firstResize = true; sizeX = sizeY = -1; bool equalSizes = false; hasSelectedFiles = (selectedFiles.count() != 0); if (leftURL.isEmpty()) leftURL = QUrl::fromLocalFile(ROOT_DIR); if (rightURL.isEmpty()) rightURL = QUrl::fromLocalFile(ROOT_DIR); setWindowTitle(i18n("Krusader::Synchronize Folders")); QGridLayout *synchGrid = new QGridLayout(this); synchGrid->setSpacing(6); synchGrid->setContentsMargins(11, 11, 11, 11); synchronizerTabs = new QTabWidget(this); /* ============================== Compare groupbox ============================== */ QWidget *synchronizerTab = new QWidget(this); QGridLayout *synchronizerGrid = new QGridLayout(synchronizerTab); synchronizerGrid->setSpacing(6); synchronizerGrid->setContentsMargins(11, 11, 11, 11); QGroupBox *compareDirs = new QGroupBox(synchronizerTab); compareDirs->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); compareDirs->setTitle(i18n("Folder Comparison")); QGridLayout *grid = new QGridLayout(compareDirs); grid->setSpacing(6); grid->setContentsMargins(11, 11, 11, 11); leftDirLabel = new QLabel(compareDirs); leftDirLabel->setAlignment(Qt::AlignHCenter); grid->addWidget(leftDirLabel, 0 , 0); QLabel *filterLabel = new QLabel(compareDirs); filterLabel->setText(i18n("File &Filter:")); filterLabel->setAlignment(Qt::AlignHCenter); grid->addWidget(filterLabel, 0 , 1); rightDirLabel = new QLabel(compareDirs); rightDirLabel->setAlignment(Qt::AlignHCenter); grid->addWidget(rightDirLabel, 0 , 2); KConfigGroup group(krConfig, "Synchronize"); leftLocation = new KHistoryComboBox(false, compareDirs); leftLocation->setMaxCount(25); // remember 25 items leftLocation->setDuplicatesEnabled(false); leftLocation->setEditable(true); leftLocation->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); QStringList list = group.readEntry("Left Folder History", QStringList()); leftLocation->setHistoryItems(list); KUrlRequester *leftUrlReq = new KUrlRequester(leftLocation, compareDirs); leftUrlReq->setUrl(leftURL); leftUrlReq->setMode(KFile::Directory); leftUrlReq->setMinimumWidth(250); grid->addWidget(leftUrlReq, 1 , 0); leftLocation->setWhatsThis(i18n("The left base folder used during the synchronization process.")); leftUrlReq->setEnabled(!hasSelectedFiles); leftLocation->setEnabled(!hasSelectedFiles); leftDirLabel->setBuddy(leftLocation); fileFilter = new KHistoryComboBox(false, compareDirs); fileFilter->setMaxCount(25); // remember 25 items fileFilter->setDuplicatesEnabled(false); fileFilter->setMinimumWidth(100); fileFilter->setMaximumWidth(100); fileFilter->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); list = group.readEntry("File Filter", QStringList()); fileFilter->setHistoryItems(list); fileFilter->setEditText("*"); grid->addWidget(fileFilter, 1 , 1); filterLabel->setBuddy(fileFilter); QString wtFilter = "

" + i18n("

The filename filtering criteria is defined here.

You can make use of wildcards. Multiple patterns are separated by space (means logical OR) and patterns are excluded from the search using the pipe symbol.

If the pattern is ended with a slash (*pattern*/), that means that pattern relates to recursive search of folders.

  • pattern - means to search those files/folders that name is pattern, recursive search goes through all subfolders independently of the value of pattern
  • pattern/ - means to search all files/folders, but recursive search goes through/excludes the folders that name is pattern

It is allowed to use quotation marks for names that contain space. Filter \"Program Files\" searches out those files/folders that name is Program Files.

Examples:

  • *.o
  • *.h *.c\?\?
  • *.cpp *.h | *.moc.cpp
  • * | .svn/ .git/

Note: the search term 'text' is equivalent to '*text*'.

"); fileFilter->setWhatsThis(wtFilter); filterLabel->setWhatsThis(wtFilter); rightLocation = new KHistoryComboBox(compareDirs); rightLocation->setMaxCount(25); // remember 25 items rightLocation->setDuplicatesEnabled(false); rightLocation->setEditable(true); rightLocation->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); list = group.readEntry("Right Folder History", QStringList()); rightLocation->setHistoryItems(list); KUrlRequester *rightUrlReq = new KUrlRequester(rightLocation, compareDirs); rightUrlReq->setUrl(rightURL); rightUrlReq->setMode(KFile::Directory); rightUrlReq->setMinimumWidth(250); grid->addWidget(rightUrlReq, 1 , 2); rightLocation->setWhatsThis(i18n("The right base folder used during the synchronization process.")); rightUrlReq->setEnabled(!hasSelectedFiles); rightLocation->setEnabled(!hasSelectedFiles); rightDirLabel->setBuddy(rightLocation); QWidget *optionWidget = new QWidget(compareDirs); QHBoxLayout *optionBox = new QHBoxLayout(optionWidget); optionBox->setContentsMargins(0, 0, 0, 0); QWidget *optionGridWidget = new QWidget(optionWidget); QGridLayout *optionGrid = new QGridLayout(optionGridWidget); optionBox->addWidget(optionGridWidget); cbSubdirs = new QCheckBox(i18n("Recurse subfolders"), optionGridWidget); cbSubdirs->setChecked(group.readEntry("Recurse Subdirectories", _RecurseSubdirs)); optionGrid->addWidget(cbSubdirs, 0, 0); cbSubdirs->setWhatsThis(i18n("Compare not only the base folders but their subfolders as well.")); cbSymlinks = new QCheckBox(i18n("Follow symlinks"), optionGridWidget); cbSymlinks->setChecked(group.readEntry("Follow Symlinks", _FollowSymlinks)); cbSymlinks->setEnabled(cbSubdirs->isChecked()); optionGrid->addWidget(cbSymlinks, 0, 1); cbSymlinks->setWhatsThis(i18n("Follow symbolic links during the compare process.")); cbByContent = new QCheckBox(i18n("Compare by content"), optionGridWidget); cbByContent->setChecked(group.readEntry("Compare By Content", _CompareByContent)); optionGrid->addWidget(cbByContent, 0, 2); cbByContent->setWhatsThis(i18n("Compare duplicated files with same size by content.")); cbIgnoreDate = new QCheckBox(i18n("Ignore Date"), optionGridWidget); cbIgnoreDate->setChecked(group.readEntry("Ignore Date", _IgnoreDate)); optionGrid->addWidget(cbIgnoreDate, 1, 0); cbIgnoreDate->setWhatsThis(i18n("

Ignore date information during the compare process.

Note: useful if the files are located on network filesystems or in archives.

")); cbAsymmetric = new QCheckBox(i18n("Asymmetric"), optionGridWidget); cbAsymmetric->setChecked(group.readEntry("Asymmetric", _Asymmetric)); optionGrid->addWidget(cbAsymmetric, 1, 1); cbAsymmetric->setWhatsThis(i18n("

Asymmetric mode

The left side is the destination, the right is the source folder. Files existing only in the left folder will be deleted, the other differing ones will be copied from right to left.

Note: useful when updating a folder from a file server.

")); cbIgnoreCase = new QCheckBox(i18n("Ignore Case"), optionGridWidget); cbIgnoreCase->setChecked(group.readEntry("Ignore Case", _IgnoreCase)); optionGrid->addWidget(cbIgnoreCase, 1, 2); cbIgnoreCase->setWhatsThis(i18n("

Case insensitive filename compare.

Note: useful when synchronizing Windows filesystems.

")); /* =========================== Show options groupbox ============================= */ QGroupBox *showOptions = new QGroupBox(optionWidget); optionBox->addWidget(showOptions); showOptions->setTitle(i18n("S&how options")); showOptions->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); QGridLayout *showOptionsLayout = new QGridLayout(showOptions); showOptionsLayout->setSpacing(4); showOptionsLayout->setContentsMargins(11, 11, 11, 11); bool checked; QString description; checked = group.readEntry("LeftToRight Button", _BtnLeftToRight); description = i18n("Show files marked to Copy from left to right."); btnLeftToRight = - createButton(showOptions, "arrow-right", checked, Qt::CTRL + Qt::Key_L, description); + createButton(showOptions, "arrow-right", checked, Qt::CTRL + Qt::Key_L, description, ">"); showOptionsLayout->addWidget(btnLeftToRight, 0, 0); checked = group.readEntry("Equals Button", _BtnEquals); description = i18n("Show files considered to be identical."); btnEquals = createButton(showOptions, "equals", checked, Qt::CTRL + Qt::Key_E, description, "="); showOptionsLayout->addWidget(btnEquals, 0, 1); checked = group.readEntry("Differents Button", _BtnDifferents); description = i18n("Show excluded files."); btnDifferents = createButton(showOptions, "unequals", checked, Qt::CTRL + Qt::Key_D, description, "!="); showOptionsLayout->addWidget(btnDifferents, 0, 2); checked = group.readEntry("RightToLeft Button", _BtnRightToLeft); description = i18n("Show files marked to Copy from right to left."); btnRightToLeft = - createButton(showOptions, "arrow-left", checked, Qt::CTRL + Qt::Key_R, description); + createButton(showOptions, "arrow-left", checked, Qt::CTRL + Qt::Key_R, description, "<"); showOptionsLayout->addWidget(btnRightToLeft, 0, 3); checked = group.readEntry("Deletable Button", _BtnDeletable); description = i18n("Show files marked to delete."); btnDeletable = createButton(showOptions, "user-trash", checked, Qt::CTRL + Qt::Key_T, description); showOptionsLayout->addWidget(btnDeletable, 0, 4); checked = group.readEntry("Duplicates Button", _BtnDuplicates); description = i18n("Show files that exist on both sides."); btnDuplicates = createButton(showOptions, "arrow-up", checked, Qt::CTRL + Qt::Key_I, description, i18n("Duplicates"), true); showOptionsLayout->addWidget(btnDuplicates, 0, 5); checked = group.readEntry("Singles Button", _BtnSingles); description = i18n("Show files that exist on one side only."); btnSingles = createButton(showOptions, "arrow-down", checked, Qt::CTRL + Qt::Key_N, description, i18n("Singles"), true); showOptionsLayout->addWidget(btnSingles, 0, 6); grid->addWidget(optionWidget, 2, 0, 1, 3); synchronizerGrid->addWidget(compareDirs, 0, 0); /* ========================= Synchronization list view ========================== */ syncList = new SynchronizerListView(&synchronizer, synchronizerTab); // create the main container syncList->setWhatsThis(i18n("The compare results of the synchronizer (Ctrl+M).")); syncList->setAutoFillBackground(true); syncList->installEventFilter(this); KConfigGroup gl(krConfig, "Look&Feel"); syncList->setFont(gl.readEntry("Filelist Font", _FilelistFont)); syncList->setBackgroundRole(QPalette::Window); syncList->setAutoFillBackground(true); QStringList labels; labels << i18nc("@title:column file name", "Name"); labels << i18nc("@title:column", "Size"); labels << i18nc("@title:column", "Date"); labels << i18n("<=>"); labels << i18nc("@title:column", "Date"); labels << i18nc("@title:column", "Size"); labels << i18nc("@title:column file name", "Name"); syncList->setHeaderLabels(labels); syncList->header()->setSectionResizeMode(QHeaderView::Interactive); if (group.hasKey("State")) syncList->header()->restoreState(group.readEntry("State", QByteArray())); else { int i = QFontMetrics(syncList->font()).width("W"); int j = QFontMetrics(syncList->font()).width("0"); j = (i > j ? i : j); int typeWidth = j * 7 / 2; syncList->setColumnWidth(0, typeWidth * 4); syncList->setColumnWidth(1, typeWidth * 2); syncList->setColumnWidth(2, typeWidth * 3); syncList->setColumnWidth(3, typeWidth * 1); syncList->setColumnWidth(4, typeWidth * 3); syncList->setColumnWidth(5, typeWidth * 2); syncList->setColumnWidth(6, typeWidth * 4); equalSizes = true; } syncList->setAllColumnsShowFocus(true); syncList->setSelectionMode(QAbstractItemView::ExtendedSelection); syncList->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); syncList->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); syncList->header()->setSortIndicatorShown(false); syncList->setSortingEnabled(false); syncList->setRootIsDecorated(true); syncList->setIndentation(10); syncList->setDragEnabled(true); syncList->setAutoFillBackground(true); synchronizerGrid->addWidget(syncList, 1, 0); synchronizerTabs->addTab(synchronizerTab, i18n("&Synchronizer")); synchGrid->addWidget(synchronizerTabs, 0, 0); filterTabs = FilterTabs::addTo(synchronizerTabs, FilterTabs::HasDontSearchIn); generalFilter = (GeneralFilter *)filterTabs->get("GeneralFilter"); generalFilter->searchFor->setEditText(fileFilter->currentText()); generalFilter->searchForCase->setChecked(true); // creating the time shift, equality threshold, hidden files options QGroupBox *optionsGroup = new QGroupBox(generalFilter); optionsGroup->setTitle(i18n("&Options")); QGridLayout *optionsLayout = new QGridLayout(optionsGroup); optionsLayout->setAlignment(Qt::AlignTop); optionsLayout->setSpacing(6); optionsLayout->setContentsMargins(11, 11, 11, 11); QLabel * parallelThreadsLabel = new QLabel(i18n("Parallel threads:"), optionsGroup); optionsLayout->addWidget(parallelThreadsLabel, 0, 0); parallelThreadsSpinBox = new QSpinBox(optionsGroup); parallelThreadsSpinBox->setMinimum(1); parallelThreadsSpinBox->setMaximum(15); int parThreads = group.readEntry("Parallel Threads", 1); parallelThreadsSpinBox->setValue(parThreads); optionsLayout->addWidget(parallelThreadsSpinBox, 0, 1); QLabel * equalityLabel = new QLabel(i18n("Equality threshold:"), optionsGroup); optionsLayout->addWidget(equalityLabel, 1, 0); equalitySpinBox = new QSpinBox(optionsGroup); equalitySpinBox->setMaximum(9999); optionsLayout->addWidget(equalitySpinBox, 1, 1); equalityUnitCombo = new QComboBox(optionsGroup); equalityUnitCombo->addItem(i18n("sec")); equalityUnitCombo->addItem(i18n("min")); equalityUnitCombo->addItem(i18n("hour")); equalityUnitCombo->addItem(i18n("day")); optionsLayout->addWidget(equalityUnitCombo, 1, 2); QLabel * timeShiftLabel = new QLabel(i18n("Time shift (right-left):"), optionsGroup); optionsLayout->addWidget(timeShiftLabel, 2, 0); timeShiftSpinBox = new QSpinBox(optionsGroup); timeShiftSpinBox->setMinimum(-9999); timeShiftSpinBox->setMaximum(9999); optionsLayout->addWidget(timeShiftSpinBox, 2, 1); timeShiftUnitCombo = new QComboBox(optionsGroup); timeShiftUnitCombo->addItem(i18n("sec")); timeShiftUnitCombo->addItem(i18n("min")); timeShiftUnitCombo->addItem(i18n("hour")); timeShiftUnitCombo->addItem(i18n("day")); optionsLayout->addWidget(timeShiftUnitCombo, 2, 2); QFrame *line = new QFrame(optionsGroup); line->setFrameStyle(QFrame::HLine | QFrame::Sunken); optionsLayout->addWidget(line, 3, 0, 1, 3); ignoreHiddenFilesCB = new QCheckBox(i18n("Ignore hidden files"), optionsGroup); optionsLayout->addWidget(ignoreHiddenFilesCB, 4, 0, 1, 3); generalFilter->middleLayout->addWidget(optionsGroup); /* ================================== Buttons =================================== */ QHBoxLayout *buttons = new QHBoxLayout; buttons->setSpacing(6); buttons->setContentsMargins(0, 0, 0, 0); profileManager = new ProfileManager("SynchronizerProfile", this); profileManager->setShortcut(Qt::CTRL + Qt::Key_P); profileManager->setWhatsThis(i18n("Profile manager (Ctrl+P).")); buttons->addWidget(profileManager); btnSwapSides = new QPushButton(this); - btnSwapSides->setIcon(QIcon::fromTheme("document-swap")); + btnSwapSides->setIcon(Icon("document-swap")); btnSwapSides->setShortcut(Qt::CTRL + Qt::Key_S); btnSwapSides->setWhatsThis(i18n("Swap sides (Ctrl+S).")); buttons->addWidget(btnSwapSides); statusLabel = new QLabel(this); buttons->addWidget(statusLabel); QSpacerItem* spacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); buttons->addItem(spacer); btnCompareDirs = new QPushButton(this); btnCompareDirs->setText(i18n("Compare")); - btnCompareDirs->setIcon(QIcon::fromTheme("kr_comparedirs")); + btnCompareDirs->setIcon(Icon("kr_comparedirs")); btnCompareDirs->setDefault(true); buttons->addWidget(btnCompareDirs); btnScrollResults = new QPushButton(this); btnScrollResults->setCheckable(true); btnScrollResults->setChecked(group.readEntry("Scroll Results", _ScrollResults)); btnScrollResults->hide(); if (btnScrollResults->isChecked()) btnScrollResults->setText(i18n("Quiet")); else btnScrollResults->setText(i18n("Scroll Results")); buttons->addWidget(btnScrollResults); btnStopComparing = new QPushButton(this); btnStopComparing->setText(i18n("Stop")); - btnStopComparing->setIcon(QIcon::fromTheme("process-stop")); + btnStopComparing->setIcon(Icon("process-stop")); btnStopComparing->setEnabled(false); buttons->addWidget(btnStopComparing); btnFeedToListBox = new QPushButton(this); btnFeedToListBox->setText(i18n("Feed to listbox")); - btnFeedToListBox->setIcon(QIcon::fromTheme("list-add")); + btnFeedToListBox->setIcon(Icon("list-add")); btnFeedToListBox->setEnabled(false); btnFeedToListBox->hide(); buttons->addWidget(btnFeedToListBox); btnSynchronize = new QPushButton(this); btnSynchronize->setText(i18n("Synchronize")); - btnSynchronize->setIcon(QIcon::fromTheme("folder-sync")); + btnSynchronize->setIcon(Icon("folder-sync")); btnSynchronize->setEnabled(false); buttons->addWidget(btnSynchronize); QPushButton *btnCloseSync = new QPushButton(this); btnCloseSync->setText(i18n("Close")); - btnCloseSync->setIcon(QIcon::fromTheme("dialog-close")); + btnCloseSync->setIcon(Icon("dialog-close")); buttons->addWidget(btnCloseSync); synchGrid->addLayout(buttons, 1, 0); /* =============================== Connect table ================================ */ connect(syncList, SIGNAL(itemRightClicked(QTreeWidgetItem*,QPoint,int)), this, SLOT(rightMouseClicked(QTreeWidgetItem*,QPoint))); connect(syncList, SIGNAL(itemActivated(QTreeWidgetItem*,int)), this, SLOT(doubleClicked(QTreeWidgetItem*))); connect(profileManager, SIGNAL(loadFromProfile(QString)), this, SLOT(loadFromProfile(QString))); connect(profileManager, SIGNAL(saveToProfile(QString)), this, SLOT(saveToProfile(QString))); connect(btnSwapSides, SIGNAL(clicked()), this, SLOT(swapSides())); connect(btnCompareDirs, SIGNAL(clicked()), this, SLOT(compare())); connect(btnStopComparing, SIGNAL(clicked()), this, SLOT(stop())); connect(btnFeedToListBox, SIGNAL(clicked()), this, SLOT(feedToListBox())); connect(btnSynchronize, SIGNAL(clicked()), this, SLOT(synchronize())); connect(btnScrollResults, SIGNAL(toggled(bool)), this, SLOT(setScrolling(bool))); connect(btnCloseSync, SIGNAL(clicked()), this, SLOT(closeDialog())); connect(cbSubdirs, SIGNAL(toggled(bool)), this, SLOT(subdirsChecked(bool))); connect(cbAsymmetric, SIGNAL(toggled(bool)), this, SLOT(setPanelLabels())); connect(&synchronizer, SIGNAL(comparedFileData(SynchronizerFileItem*)), this, SLOT(addFile(SynchronizerFileItem*))); connect(&synchronizer, SIGNAL(markChanged(SynchronizerFileItem*,bool)), this, SLOT(markChanged(SynchronizerFileItem*,bool))); connect(&synchronizer, SIGNAL(statusInfo(QString)), this, SLOT(statusInfo(QString))); connect(btnLeftToRight, SIGNAL(toggled(bool)), this, SLOT(refresh())); connect(btnEquals, SIGNAL(toggled(bool)), this, SLOT(refresh())); connect(btnDifferents, SIGNAL(toggled(bool)), this, SLOT(refresh())); connect(btnRightToLeft, SIGNAL(toggled(bool)), this, SLOT(refresh())); connect(btnDeletable, SIGNAL(toggled(bool)), this, SLOT(refresh())); connect(btnDuplicates, SIGNAL(toggled(bool)), this, SLOT(refresh())); connect(btnSingles, SIGNAL(toggled(bool)), this, SLOT(refresh())); connect(fileFilter, SIGNAL(currentTextChanged(QString)), this, SLOT(connectFilters(QString))); connect(generalFilter->searchFor, SIGNAL(currentTextChanged(QString)), this, SLOT(connectFilters(QString))); connect(generalFilter->searchFor, SIGNAL(currentTextChanged(QString)), this, SLOT(setCompletion())); connect(generalFilter->dontSearchIn, SIGNAL(checkValidity(QString&,QString&)), this, SLOT(checkExcludeURLValidity(QString&,QString&))); connect(profileManager, SIGNAL(loadFromProfile(QString)), filterTabs, SLOT(loadFromProfile(QString))); connect(profileManager, SIGNAL(saveToProfile(QString)), filterTabs, SLOT(saveToProfile(QString))); setPanelLabels(); setCompletion(); /* =============================== Loading the colors ================================ */ KConfigGroup gc(krConfig, "Colors"); QString COLOR_NAMES[] = { "Equals", "Differs", "LeftCopy", "RightCopy", "Delete" }; QPalette defaultPalette = QGuiApplication::palette(); DECLARE_SYNCHRONIZER_BACKGROUND_DEFAULTS; DECLARE_SYNCHRONIZER_FOREGROUND_DEFAULTS; for (int clr = 0; clr != TT_MAX; clr ++) { QString colorName = clr > 4 ? "Equals" : COLOR_NAMES[ clr ]; QColor backgroundDefault = clr > 4 ? defaultPalette.color(QPalette::Active, QPalette::Base) : SYNCHRONIZER_BACKGROUND_DEFAULTS[ clr ]; QColor foregroundDefault = clr > 4 ? defaultPalette.color(QPalette::Active, QPalette::Text) : SYNCHRONIZER_FOREGROUND_DEFAULTS[ clr ]; QString foreEntry = QString("Synchronizer ") + colorName + QString(" Foreground"); QString bckgEntry = QString("Synchronizer ") + colorName + QString(" Background"); if (gc.readEntry(foreEntry, QString()) == "KDE default") foreGrounds[ clr ] = QColor(); else if (gc.readEntry(foreEntry, QString()).isEmpty()) // KDE4 workaround, default color doesn't work foreGrounds[ clr ] = foregroundDefault; else foreGrounds[ clr ] = gc.readEntry(foreEntry, foregroundDefault); if (gc.readEntry(bckgEntry, QString()) == "KDE default") backGrounds[ clr ] = QColor(); else if (gc.readEntry(foreEntry, QString()).isEmpty()) // KDE4 workaround, default color doesn't work backGrounds[ clr ] = backgroundDefault; else backGrounds[ clr ] = gc.readEntry(bckgEntry, backgroundDefault); } if (backGrounds[ TT_EQUALS ].isValid()) { QPalette pal = syncList->palette(); pal.setColor(QPalette::Base, backGrounds[ TT_EQUALS ]); syncList->setPalette(pal); } int sx = group.readEntry("Window Width", -1); int sy = group.readEntry("Window Height", -1); if (sx != -1 && sy != -1) resize(sx, sy); if (group.readEntry("Window Maximized", false)) { setWindowState(windowState() | Qt::WindowMaximized); } if (equalSizes) { int newSize6 = syncList->header()->sectionSize(6); int newSize0 = syncList->header()->sectionSize(0); int delta = newSize6 - newSize0 + (newSize6 & 1); newSize0 += (delta / 2); if (newSize0 > 20) syncList->header()->resizeSection(0, newSize0); } if (!profileName.isNull()) profileManager->loadProfile(profileName); synchronizer.setParentWidget(this); } SynchronizerGUI::~SynchronizerGUI() { syncList->clear(); // for sanity: deletes the references to the synchronizer list } void SynchronizerGUI::setPanelLabels() { if (hasSelectedFiles && cbAsymmetric->isChecked()) { leftDirLabel->setText(i18n("Selected files from targ&et folder:")); rightDirLabel->setText(i18n("Selected files from sou&rce folder:")); } else if (hasSelectedFiles && !cbAsymmetric->isChecked()) { leftDirLabel->setText(i18n("Selected files from &left folder:")); rightDirLabel->setText(i18n("Selected files from &right folder:")); } else if (cbAsymmetric->isChecked()) { leftDirLabel->setText(i18n("Targ&et folder:")); rightDirLabel->setText(i18n("Sou&rce folder:")); } else { leftDirLabel->setText(i18n("&Left folder:")); rightDirLabel->setText(i18n("&Right folder:")); } } void SynchronizerGUI::setCompletion() { generalFilter->dontSearchIn->setCompletionDir(Synchronizer::fsUrl(rightLocation->currentText())); } void SynchronizerGUI::checkExcludeURLValidity(QString &text, QString &error) { QUrl url = Synchronizer::fsUrl(text); if (url.isRelative()) return; QString leftBase = leftLocation->currentText(); if (!leftBase.endsWith('/')) leftBase += '/'; QUrl leftBaseURL = Synchronizer::fsUrl(leftBase); if (leftBaseURL.isParentOf(url) && !url.isParentOf(leftBaseURL)) { text = QDir(leftBaseURL.path()).relativeFilePath(url.path()); return; } QString rightBase = rightLocation->currentText(); if (!rightBase.endsWith('/')) rightBase += '/'; QUrl rightBaseURL = Synchronizer::fsUrl(rightBase); if (rightBaseURL.isParentOf(url) && !url.isParentOf(rightBaseURL)) { text = QDir(rightBaseURL.path()).relativeFilePath(url.path()); return; } error = i18n("URL must be the descendant of either the left or the right base URL."); } void SynchronizerGUI::doubleClicked(QTreeWidgetItem *itemIn) { if (!itemIn) return; SyncViewItem *syncItem = (SyncViewItem *)itemIn; SynchronizerFileItem *item = syncItem->synchronizerItemRef(); if (item && item->existsInLeft() && item->existsInRight() && !item->isDir()) { QString leftDirName = item->leftDirectory().isEmpty() ? "" : item->leftDirectory() + '/'; QString rightDirName = item->rightDirectory().isEmpty() ? "" : item->rightDirectory() + '/'; QUrl leftURL = Synchronizer::fsUrl(synchronizer.leftBaseDirectory() + leftDirName + item->leftName()); QUrl rightURL = Synchronizer::fsUrl(synchronizer.rightBaseDirectory() + rightDirName + item->rightName()); SLOTS->compareContent(leftURL,rightURL); } else if (item && item->isDir()) { itemIn->setExpanded(!itemIn->isExpanded()); } } void SynchronizerGUI::rightMouseClicked(QTreeWidgetItem *itemIn, const QPoint &pos) { // these are the values that will exist in the menu #define EXCLUDE_ID 90 #define RESTORE_ID 91 #define COPY_TO_LEFT_ID 92 #define COPY_TO_RIGHT_ID 93 #define REVERSE_DIR_ID 94 #define DELETE_ID 95 #define VIEW_LEFT_FILE_ID 96 #define VIEW_RIGHT_FILE_ID 97 #define COMPARE_FILES_ID 98 #define SELECT_ITEMS_ID 99 #define DESELECT_ITEMS_ID 100 #define INVERT_SELECTION_ID 101 #define SYNCH_WITH_KGET_ID 102 #define COPY_CLPBD_LEFT_ID 103 #define COPY_CLPBD_RIGHT_ID 104 ////////////////////////////////////////////////////////// if (!itemIn) return; SyncViewItem *syncItem = (SyncViewItem *)itemIn; if (syncItem == 0) return; SynchronizerFileItem *item = syncItem->synchronizerItemRef(); bool isDuplicate = item->existsInLeft() && item->existsInRight(); bool isDir = item->isDir(); // create the menu QMenu popup; QAction *myact; QHash< QAction *, int > actHash; popup.setTitle(i18n("Synchronize Folders")); myact = popup.addAction(i18n("E&xclude")); actHash[ myact ] = EXCLUDE_ID; myact = popup.addAction(i18n("Restore ori&ginal operation")); actHash[ myact ] = RESTORE_ID; myact = popup.addAction(i18n("Re&verse direction")); actHash[ myact ] = REVERSE_DIR_ID; myact = popup.addAction(i18n("Copy from &right to left")); actHash[ myact ] = COPY_TO_LEFT_ID; myact = popup.addAction(i18n("Copy from &left to right")); actHash[ myact ] = COPY_TO_RIGHT_ID; myact = popup.addAction(i18n("&Delete (left single)")); actHash[ myact ] = DELETE_ID; popup.addSeparator(); myact = popup.addAction(i18n("V&iew left file")); myact->setEnabled(!isDir && item->existsInLeft()); actHash[ myact ] = VIEW_LEFT_FILE_ID; myact = popup.addAction(i18n("Vi&ew right file")); myact->setEnabled(!isDir && item->existsInRight()); actHash[ myact ] = VIEW_RIGHT_FILE_ID; myact = popup.addAction(i18n("&Compare Files")); myact->setEnabled(!isDir && isDuplicate); actHash[ myact ] = COMPARE_FILES_ID; popup.addSeparator(); myact = popup.addAction(i18n("C&opy selected to clipboard (left)")); actHash[ myact ] = COPY_CLPBD_LEFT_ID; myact = popup.addAction(i18n("Co&py selected to clipboard (right)")); actHash[ myact ] = COPY_CLPBD_RIGHT_ID; popup.addSeparator(); myact = popup.addAction(i18n("&Select items")); actHash[ myact ] = SELECT_ITEMS_ID; myact = popup.addAction(i18n("Deselec&t items")); actHash[ myact ] = DESELECT_ITEMS_ID; myact = popup.addAction(i18n("I&nvert selection")); actHash[ myact ] = INVERT_SELECTION_ID; QUrl leftBDir = Synchronizer::fsUrl(synchronizer.leftBaseDirectory()); QUrl rightBDir = Synchronizer::fsUrl(synchronizer.rightBaseDirectory()); if (KrServices::cmdExist("kget") && ((!leftBDir.isLocalFile() && rightBDir.isLocalFile() && btnLeftToRight->isChecked()) || (leftBDir.isLocalFile() && !rightBDir.isLocalFile() && btnRightToLeft->isChecked()))) { popup.addSeparator(); myact = popup.addAction(i18n("Synchronize with &KGet")); actHash[ myact ] = SYNCH_WITH_KGET_ID; } QAction * res = popup.exec(pos); int result = -1; if (actHash.contains(res)) result = actHash[ res ]; if (result != -1) executeOperation(item, result); } void SynchronizerGUI::executeOperation(SynchronizerFileItem *item, int op) { // check out the user's option QString leftDirName = item->leftDirectory().isEmpty() ? "" : item->leftDirectory() + '/'; QString rightDirName = item->rightDirectory().isEmpty() ? "" : item->rightDirectory() + '/'; QUrl leftURL = Synchronizer::fsUrl(synchronizer.leftBaseDirectory() + leftDirName + item->leftName()); QUrl rightURL = Synchronizer::fsUrl(synchronizer.rightBaseDirectory() + rightDirName + item->rightName()); switch (op) { case EXCLUDE_ID: case RESTORE_ID: case COPY_TO_LEFT_ID: case COPY_TO_RIGHT_ID: case REVERSE_DIR_ID: case DELETE_ID: { unsigned ndx = 0; SynchronizerFileItem *currentItem; while ((currentItem = synchronizer.getItemAt(ndx++)) != 0) { SyncViewItem *viewItem = (SyncViewItem *)currentItem->userData(); if (!viewItem || !viewItem->isSelected() || viewItem->isHidden()) continue; switch (op) { case EXCLUDE_ID: synchronizer.exclude(viewItem->synchronizerItemRef()); break; case RESTORE_ID: synchronizer.restore(viewItem->synchronizerItemRef()); break; case REVERSE_DIR_ID: synchronizer.reverseDirection(viewItem->synchronizerItemRef()); break; case COPY_TO_LEFT_ID: synchronizer.copyToLeft(viewItem->synchronizerItemRef()); break; case COPY_TO_RIGHT_ID: synchronizer.copyToRight(viewItem->synchronizerItemRef()); break; case DELETE_ID: synchronizer.deleteLeft(viewItem->synchronizerItemRef()); break; } } refresh(); } break; case VIEW_LEFT_FILE_ID: KrViewer::view(leftURL, this); // view the file break; case VIEW_RIGHT_FILE_ID: KrViewer::view(rightURL, this); // view the file break; case COMPARE_FILES_ID: SLOTS->compareContent(leftURL,rightURL); break; case SELECT_ITEMS_ID: case DESELECT_ITEMS_ID: { KRQuery query = KRSpWidgets::getMask((op == SELECT_ITEMS_ID ? i18n("Select items") : i18n("Deselect items")), true, this); if (query.isNull()) break; unsigned ndx = 0; SynchronizerFileItem *currentItem; while ((currentItem = synchronizer.getItemAt(ndx++)) != 0) { SyncViewItem *viewItem = (SyncViewItem *)currentItem->userData(); if (!viewItem || viewItem->isHidden()) continue; if (query.match(currentItem->leftName()) || query.match(currentItem->rightName())) viewItem->setSelected(op == SELECT_ITEMS_ID); } } break; case INVERT_SELECTION_ID: { unsigned ndx = 0; SynchronizerFileItem *currentItem; while ((currentItem = synchronizer.getItemAt(ndx++)) != 0) { SyncViewItem *viewItem = (SyncViewItem *)currentItem->userData(); if (!viewItem || viewItem->isHidden()) continue; viewItem->setSelected(!viewItem->isSelected()); } } break; case SYNCH_WITH_KGET_ID: synchronizer.synchronizeWithKGet(); closeDialog(); break; case COPY_CLPBD_LEFT_ID: copyToClipboard(true); break; case COPY_CLPBD_RIGHT_ID: copyToClipboard(false); break; case -1 : return; // the user clicked outside of the menu } } void SynchronizerGUI::closeDialog() { if (isComparing) { stop(); wasClosed = true; return; } KConfigGroup group(krConfig, "Synchronize"); QStringList list; foreach(const QString &item, leftLocation->historyItems()) { QUrl url(item); // make sure no passwords are saved in config url.setPassword(QString()); list << url.toDisplayString(QUrl::PreferLocalFile); } group.writeEntry("Left Folder History", list); list.clear(); foreach(const QString &item, rightLocation->historyItems()) { QUrl url(item); // make sure no passwords are saved in config url.setPassword(QString()); list << url.toDisplayString(QUrl::PreferLocalFile); } group.writeEntry("Right Folder History", list); list = fileFilter->historyItems(); group.writeEntry("File Filter", list); group.writeEntry("Recurse Subdirectories", cbSubdirs->isChecked()); group.writeEntry("Follow Symlinks", cbSymlinks->isChecked()); group.writeEntry("Compare By Content", cbByContent->isChecked()); group.writeEntry("Ignore Date", cbIgnoreDate->isChecked()); group.writeEntry("Asymmetric", cbAsymmetric->isChecked()); group.writeEntry("Ignore Case", cbIgnoreCase->isChecked()); group.writeEntry("LeftToRight Button", btnLeftToRight->isChecked()); group.writeEntry("Equals Button", btnEquals->isChecked()); group.writeEntry("Differents Button", btnDifferents->isChecked()); group.writeEntry("RightToLeft Button", btnRightToLeft->isChecked()); group.writeEntry("Deletable Button", btnDeletable->isChecked()); group.writeEntry("Duplicates Button", btnDuplicates->isChecked()); group.writeEntry("Singles Button", btnSingles->isChecked()); group.writeEntry("Scroll Results", btnScrollResults->isChecked()); group.writeEntry("Parallel Threads", parallelThreadsSpinBox->value()); group.writeEntry("Window Width", sizeX); group.writeEntry("Window Height", sizeY); group.writeEntry("Window Maximized", isMaximized()); group.writeEntry("State", syncList->header()->saveState()); QDialog::reject(); this->deleteLater(); if (wasSync) { LEFT_PANEL->func->refresh(); RIGHT_PANEL->func->refresh(); ACTIVE_PANEL->gui->slotFocusOnMe(); } } void SynchronizerGUI::compare() { KRQuery query; if (!filterTabs->fillQuery(&query)) return; // perform some previous tests QString leftLocationTrimmed = leftLocation->currentText().trimmed(); QString rightLocationTrimmed = rightLocation->currentText().trimmed(); if (leftLocationTrimmed.isEmpty()) { KMessageBox::error(this, i18n("The target folder must not be empty.")); leftLocation->setFocus(); return; } if (rightLocationTrimmed.isEmpty()) { KMessageBox::error(this, i18n("The source folder must not be empty.")); rightLocation->setFocus(); return; } if (leftLocationTrimmed == rightLocationTrimmed) { if (KMessageBox::warningContinueCancel(this, i18n("Warning: The left and the right side are showing the same folder.")) != KMessageBox::Continue) { return; } } query.setNameFilter(fileFilter->currentText(), query.isCaseSensitive()); synchronizerTabs->setCurrentIndex(0); syncList->clear(); lastItem = 0; leftLocation->addToHistory(leftLocation->currentText()); rightLocation->addToHistory(rightLocation->currentText()); fileFilter->addToHistory(fileFilter->currentText()); setMarkFlags(); btnCompareDirs->setEnabled(false); profileManager->setEnabled(false); btnSwapSides->setEnabled(false); btnStopComparing->setEnabled(isComparing = true); btnStopComparing->show(); btnFeedToListBox->setEnabled(false); btnFeedToListBox->hide(); btnSynchronize->setEnabled(false); btnCompareDirs->hide(); btnScrollResults->show(); disableMarkButtons(); int fileCount = synchronizer.compare(leftLocation->currentText(), rightLocation->currentText(), &query, cbSubdirs->isChecked(), cbSymlinks->isChecked(), cbIgnoreDate->isChecked(), cbAsymmetric->isChecked(), cbByContent->isChecked(), cbIgnoreCase->isChecked(), btnScrollResults->isChecked(), selectedFiles, convertToSeconds(equalitySpinBox->value(), equalityUnitCombo->currentIndex()), convertToSeconds(timeShiftSpinBox->value(), timeShiftUnitCombo->currentIndex()), parallelThreadsSpinBox->value(), ignoreHiddenFilesCB->isChecked()); enableMarkButtons(); btnStopComparing->setEnabled(isComparing = false); btnStopComparing->hide(); btnFeedToListBox->show(); btnCompareDirs->setEnabled(true); profileManager->setEnabled(true); btnSwapSides->setEnabled(true); btnCompareDirs->show(); btnScrollResults->hide(); if (fileCount) { btnSynchronize->setEnabled(true); btnFeedToListBox->setEnabled(true); } syncList->setFocus(); if (wasClosed) closeDialog(); } void SynchronizerGUI::stop() { synchronizer.stop(); } void SynchronizerGUI::feedToListBox() { FeedToListBoxDialog listBox(this, &synchronizer, syncList, btnEquals->isChecked()); if (listBox.isAccepted()) closeDialog(); } void SynchronizerGUI::reject() { closeDialog(); } void SynchronizerGUI::addFile(SynchronizerFileItem *item) { QString leftName = "", rightName = "", leftDate = "", rightDate = "", leftSize = "", rightSize = ""; bool isDir = item->isDir(); QColor textColor = foreGrounds[ item->task()]; QColor baseColor = backGrounds[ item->task()]; if (item->existsInLeft()) { leftName = item->leftName(); leftSize = isDir ? dirLabel() + ' ' : KRpermHandler::parseSize(item->leftSize()); leftDate = SynchronizerGUI::convertTime(item->leftDate()); } if (item->existsInRight()) { rightName = item->rightName(); rightSize = isDir ? dirLabel() + ' ' : KRpermHandler::parseSize(item->rightSize()); rightDate = SynchronizerGUI::convertTime(item->rightDate()); } SyncViewItem *listItem = 0; SyncViewItem *dirItem; if (item->parent() == 0) { listItem = new SyncViewItem(item, textColor, baseColor, syncList, lastItem, leftName, leftSize, leftDate, Synchronizer::getTaskTypeName(item->task()), rightDate, rightSize, rightName); lastItem = listItem; } else { dirItem = (SyncViewItem *)item->parent()->userData(); if (dirItem) { dirItem->setExpanded(true); listItem = new SyncViewItem(item, textColor, baseColor, dirItem, dirItem->lastItem(), leftName, leftSize, leftDate, Synchronizer::getTaskTypeName(item->task()), rightDate, rightSize, rightName); dirItem->setLastItem(listItem); } } if (listItem) { - listItem->setIcon(0, QIcon::fromTheme(isDir ? "folder" : "document-new")); + listItem->setIcon(0, Icon(isDir ? "folder" : "document-new")); if (!item->isMarked()) listItem->setHidden(true); else syncList->scrollTo(syncList->indexOf(listItem)); } } void SynchronizerGUI::markChanged(SynchronizerFileItem *item, bool ensureVisible) { SyncViewItem *listItem = (SyncViewItem *)item->userData(); if (listItem) { if (!item->isMarked()) { listItem->setHidden(true); } else { QString leftName = "", rightName = "", leftDate = "", rightDate = "", leftSize = "", rightSize = ""; bool isDir = item->isDir(); if (item->existsInLeft()) { leftName = item->leftName(); leftSize = isDir ? dirLabel() + ' ' : KRpermHandler::parseSize(item->leftSize()); leftDate = SynchronizerGUI::convertTime(item->leftDate()); } if (item->existsInRight()) { rightName = item->rightName(); rightSize = isDir ? dirLabel() + ' ' : KRpermHandler::parseSize(item->rightSize()); rightDate = SynchronizerGUI::convertTime(item->rightDate()); } listItem->setHidden(false); listItem->setText(0, leftName); listItem->setText(1, leftSize); listItem->setText(2, leftDate); listItem->setText(3, Synchronizer::getTaskTypeName(item->task())); listItem->setText(4, rightDate); listItem->setText(5, rightSize); listItem->setText(6, rightName); listItem->setColors(foreGrounds[ item->task()], backGrounds[ item->task()]); if (ensureVisible) syncList->scrollTo(syncList->indexOf(listItem)); } } } void SynchronizerGUI::subdirsChecked(bool isOn) { cbSymlinks->setEnabled(isOn); } void SynchronizerGUI::disableMarkButtons() { btnLeftToRight->setEnabled(false); btnEquals->setEnabled(false); btnDifferents->setEnabled(false); btnRightToLeft->setEnabled(false); btnDeletable->setEnabled(false); btnDuplicates->setEnabled(false); btnSingles->setEnabled(false); } void SynchronizerGUI::enableMarkButtons() { btnLeftToRight->setEnabled(true); btnEquals->setEnabled(true); btnDifferents->setEnabled(true); btnRightToLeft->setEnabled(true); btnDeletable->setEnabled(true); btnDuplicates->setEnabled(true); btnSingles->setEnabled(true); } QString SynchronizerGUI::convertTime(time_t time) const { // convert the time_t to struct tm struct tm* t = localtime((time_t *) & time); QDateTime tmp(QDate(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday), QTime(t->tm_hour, t->tm_min)); return QLocale().toString(tmp, QLocale::ShortFormat); } void SynchronizerGUI::setMarkFlags() { synchronizer.setMarkFlags(btnRightToLeft->isChecked(), btnEquals->isChecked(), btnDifferents->isChecked(), btnLeftToRight->isChecked(), btnDuplicates->isChecked(), btnSingles->isChecked(), btnDeletable->isChecked()); } void SynchronizerGUI::refresh() { if (!isComparing) { syncList->clearSelection(); setMarkFlags(); btnCompareDirs->setEnabled(false); profileManager->setEnabled(false); btnSwapSides->setEnabled(false); btnSynchronize->setEnabled(false); btnFeedToListBox->setEnabled(false); disableMarkButtons(); int fileCount = synchronizer.refresh(); enableMarkButtons(); btnCompareDirs->setEnabled(true); profileManager->setEnabled(true); btnSwapSides->setEnabled(true); if (fileCount) { btnFeedToListBox->setEnabled(true); btnSynchronize->setEnabled(true); } } } void SynchronizerGUI::synchronize() { int copyToLeftNr, copyToRightNr, deleteNr; KIO::filesize_t copyToLeftSize, copyToRightSize, deleteSize; if (!synchronizer.totalSizes(©ToLeftNr, ©ToLeftSize, ©ToRightNr, ©ToRightSize, &deleteNr, &deleteSize)) { KMessageBox::sorry(parentWidget(), i18n("Synchronizer has nothing to do.")); return; } SynchronizeDialog *sd = new SynchronizeDialog(this, &synchronizer, copyToLeftNr, copyToLeftSize, copyToRightNr, copyToRightSize, deleteNr, deleteSize, parallelThreadsSpinBox->value()); wasSync = sd->wasSyncronizationStarted(); delete sd; if (wasSync) closeDialog(); } void SynchronizerGUI::resizeEvent(QResizeEvent *e) { if (!isMaximized()) { sizeX = e->size().width(); sizeY = e->size().height(); } if (!firstResize) { int delta = e->size().width() - e->oldSize().width() + (e->size().width() & 1); int newSize = syncList->header()->sectionSize(0) + delta / 2; if (newSize > 20) syncList->header()->resizeSection(0, newSize); } firstResize = false; QDialog::resizeEvent(e); } void SynchronizerGUI::statusInfo(QString info) { statusLabel->setText(info); qApp->processEvents(); } void SynchronizerGUI::swapSides() { if (btnCompareDirs->isEnabled()) { QString leftCurrent = leftLocation->currentText(); leftLocation->lineEdit()->setText(rightLocation->currentText()); rightLocation->lineEdit()->setText(leftCurrent); synchronizer.swapSides(); refresh(); } } void SynchronizerGUI::keyPressEvent(QKeyEvent *e) { switch (e->key()) { case Qt::Key_M : { if (e->modifiers() == Qt::ControlModifier) { syncList->setFocus(); e->accept(); } break; } case Qt::Key_F3 : case Qt::Key_F4 : { e->accept(); syncList->setFocus(); QTreeWidgetItem *listItem = syncList->currentItem(); if (listItem == 0) break; bool isedit = e->key() == Qt::Key_F4; SynchronizerFileItem *item = ((SyncViewItem *)listItem)->synchronizerItemRef(); QString leftDirName = item->leftDirectory().isEmpty() ? "" : item->leftDirectory() + '/'; QString rightDirName = item->rightDirectory().isEmpty() ? "" : item->rightDirectory() + '/'; if (item->isDir()) return; if (e->modifiers() == Qt::ShiftModifier && item->existsInRight()) { QUrl rightURL = Synchronizer::fsUrl(synchronizer.rightBaseDirectory() + rightDirName + item->rightName()); if (isedit) KrViewer::edit(rightURL, this); // view the file else KrViewer::view(rightURL, this); // view the file return; } else if (e->modifiers() == 0 && item->existsInLeft()) { QUrl leftURL = Synchronizer::fsUrl(synchronizer.leftBaseDirectory() + leftDirName + item->leftName()); if (isedit) KrViewer::edit(leftURL, this); // view the file else KrViewer::view(leftURL, this); // view the file return; } } break; case Qt::Key_U : if (e->modifiers() != Qt::ControlModifier) break; e->accept(); swapSides(); return; case Qt::Key_Escape: if (!btnStopComparing->isHidden() && btnStopComparing->isEnabled()) { // is it comparing? e->accept(); btnStopComparing->animateClick(); // just click the stop button } else { e->accept(); if (syncList->topLevelItemCount() != 0) { int result = KMessageBox::warningYesNo(this, i18n("The synchronizer window contains data from a previous compare. If you exit, this data will be lost. Do you really want to exit?"), i18n("Krusader::Synchronize Folders"), KStandardGuiItem::yes(), KStandardGuiItem::no(), "syncGUIexit"); if (result != KMessageBox::Yes) return; } QDialog::reject(); } return; } QDialog::keyPressEvent(e); } bool SynchronizerGUI::eventFilter(QObject * /* watched */, QEvent * e) { if (e->type() == QEvent::KeyPress) { QKeyEvent* ke = (QKeyEvent*) e; switch (ke->key()) { case Qt::Key_Down: case Qt::Key_Left: case Qt::Key_Right: case Qt::Key_Up: case Qt::Key_Delete: case Qt::Key_W: { if (ke->key() == Qt::Key_W) { if (ke->modifiers() != Qt::ControlModifier) return false; } else if (ke->modifiers() != Qt::AltModifier) return false; int op = -1; switch (ke->key()) { case Qt::Key_Down: op = EXCLUDE_ID; break; case Qt::Key_Left: op = COPY_TO_LEFT_ID; break; case Qt::Key_Right: op = COPY_TO_RIGHT_ID; break; case Qt::Key_Up: op = RESTORE_ID; break; case Qt::Key_Delete: op = DELETE_ID; break; case Qt::Key_W: op = REVERSE_DIR_ID; break; } ke->accept(); QTreeWidgetItem *listItem = syncList->currentItem(); if (listItem == 0) return true; SynchronizerFileItem *item = ((SyncViewItem *)listItem)->synchronizerItemRef(); bool hasSelected = false; QList selected = syncList->selectedItems(); for (int i = 0; i != selected.count(); i++) if (selected[ i ]->isSelected() && !selected[ i ]->isHidden()) hasSelected = true; if (!hasSelected) listItem->setSelected(true); executeOperation(item, op); return true; } } } return false; } void SynchronizerGUI::loadFromProfile(QString profile) { syncList->clear(); synchronizer.reset(); isComparing = wasClosed = false; btnSynchronize->setEnabled(false); btnFeedToListBox->setEnabled(false); KConfigGroup pg(krConfig, profile); if (!hasSelectedFiles) { leftLocation->lineEdit()->setText(pg.readEntry("Left Location", QString())); rightLocation->lineEdit()->setText(pg.readEntry("Right Location", QString())); } fileFilter->lineEdit()->setText(pg.readEntry("Search For", QString())); cbSubdirs-> setChecked(pg.readEntry("Recurse Subdirectories", true)); cbSymlinks-> setChecked(pg.readEntry("Follow Symlinks", false)); cbByContent-> setChecked(pg.readEntry("Compare By Content", false)); cbIgnoreDate->setChecked(pg.readEntry("Ignore Date", false)); cbAsymmetric->setChecked(pg.readEntry("Asymmetric", false)); cbIgnoreCase->setChecked(pg.readEntry("Ignore Case", false)); btnScrollResults->setChecked(pg.readEntry("Scroll Results", false)); btnLeftToRight->setChecked(pg.readEntry("Show Left To Right", true)); btnEquals ->setChecked(pg.readEntry("Show Equals", true)); btnDifferents ->setChecked(pg.readEntry("Show Differents", true)); btnRightToLeft->setChecked(pg.readEntry("Show Right To Left", true)); btnDeletable ->setChecked(pg.readEntry("Show Deletable", true)); btnDuplicates ->setChecked(pg.readEntry("Show Duplicates", true)); btnSingles ->setChecked(pg.readEntry("Show Singles", true)); int equalityThreshold = pg.readEntry("Equality Threshold", 0); int equalityCombo = 0; convertFromSeconds(equalityThreshold, equalityCombo, equalityThreshold); equalitySpinBox->setValue(equalityThreshold); equalityUnitCombo->setCurrentIndex(equalityCombo); int timeShift = pg.readEntry("Time Shift", 0); int timeShiftCombo = 0; convertFromSeconds(timeShift, timeShiftCombo, timeShift); timeShiftSpinBox->setValue(timeShift); timeShiftUnitCombo->setCurrentIndex(timeShiftCombo); int parallelThreads = pg.readEntry("Parallel Threads", 1); parallelThreadsSpinBox->setValue(parallelThreads); bool ignoreHidden = pg.readEntry("Ignore Hidden Files", false); ignoreHiddenFilesCB->setChecked(ignoreHidden); refresh(); } void SynchronizerGUI::saveToProfile(QString profile) { KConfigGroup group(krConfig, profile); group.writeEntry("Left Location", leftLocation->currentText()); group.writeEntry("Search For", fileFilter->currentText()); group.writeEntry("Right Location", rightLocation->currentText()); group.writeEntry("Recurse Subdirectories", cbSubdirs->isChecked()); group.writeEntry("Follow Symlinks", cbSymlinks->isChecked()); group.writeEntry("Compare By Content", cbByContent->isChecked()); group.writeEntry("Ignore Date", cbIgnoreDate->isChecked()); group.writeEntry("Asymmetric", cbAsymmetric->isChecked()); group.writeEntry("Ignore Case", cbIgnoreCase->isChecked()); group.writeEntry("Scroll Results", btnScrollResults->isChecked()); group.writeEntry("Show Left To Right", btnLeftToRight->isChecked()); group.writeEntry("Show Equals", btnEquals->isChecked()); group.writeEntry("Show Differents", btnDifferents->isChecked()); group.writeEntry("Show Right To Left", btnRightToLeft->isChecked()); group.writeEntry("Show Deletable", btnDeletable->isChecked()); group.writeEntry("Show Duplicates", btnDuplicates->isChecked()); group.writeEntry("Show Singles", btnSingles->isChecked()); group.writeEntry("Equality Threshold", convertToSeconds(equalitySpinBox->value(), equalityUnitCombo->currentIndex())); group.writeEntry("Time Shift", convertToSeconds(timeShiftSpinBox->value(), timeShiftUnitCombo->currentIndex())); group.writeEntry("Parallel Threads", parallelThreadsSpinBox->value()); group.writeEntry("Ignore Hidden Files", ignoreHiddenFilesCB->isChecked()); } void SynchronizerGUI::connectFilters(const QString &newString) { if (synchronizerTabs->currentIndex()) fileFilter->setEditText(newString); else generalFilter->searchFor->setEditText(newString); } void SynchronizerGUI::setScrolling(bool isOn) { if (isOn) btnScrollResults->setText(i18n("Quiet")); else btnScrollResults->setText(i18n("Scroll Results")); synchronizer.setScrolling(isOn); } int SynchronizerGUI::convertToSeconds(int time, int unit) { switch (unit) { case 1: return time * 60; case 2: return time * 3600; case 3: return time * 86400; default: return time; } } void SynchronizerGUI::convertFromSeconds(int &time, int &unit, int second) { unit = 0; time = second; int absTime = (time < 0) ? -time : time; if (absTime >= 86400 && (absTime % 86400) == 0) { time /= 86400; unit = 3; } else if (absTime >= 3600 && (absTime % 3600) == 0) { time /= 3600; unit = 2; } else if (absTime >= 60 && (absTime % 60) == 0) { time /= 60; unit = 1; } } QPushButton *SynchronizerGUI::createButton(QWidget *parent, const QString &iconName, bool checked, const QKeySequence &shortCut, const QString &description, const QString &text, bool textAndIcon) { QPushButton *button = new QPushButton(parent); - if (!text.isEmpty() && (textAndIcon || !QIcon::hasThemeIcon(iconName))) + bool iconExists = Icon::exists(iconName); + if (!text.isEmpty() && (textAndIcon || !iconExists)) { button->setText(text); - button->setIcon(QIcon::fromTheme(iconName)); + } + if (iconExists) { + button->setIcon(Icon(iconName)); + } button->setCheckable(true); button->setChecked(checked); button->setShortcut(shortCut); const QString infoText = QString("%1 (%2)").arg(description, shortCut.toString(QKeySequence::NativeText)); button->setWhatsThis(infoText); button->setToolTip(infoText); return button; } void SynchronizerGUI::copyToClipboard(bool isLeft) { QList urls; unsigned ndx = 0; SynchronizerFileItem *currentItem; while ((currentItem = synchronizer.getItemAt(ndx++)) != 0) { SynchronizerGUI::SyncViewItem *viewItem = (SynchronizerGUI::SyncViewItem *)currentItem->userData(); if (!viewItem || !viewItem->isSelected() || viewItem->isHidden()) continue; SynchronizerFileItem *item = viewItem->synchronizerItemRef(); if (item) { if (isLeft && item->existsInLeft()) { QString leftDirName = item->leftDirectory().isEmpty() ? "" : item->leftDirectory() + '/'; QUrl leftURL = Synchronizer::fsUrl(synchronizer.leftBaseDirectory() + leftDirName + item->leftName()); urls.push_back(leftURL); } else if (!isLeft && item->existsInRight()) { QString rightDirName = item->rightDirectory().isEmpty() ? "" : item->rightDirectory() + '/'; QUrl rightURL = Synchronizer::fsUrl(synchronizer.rightBaseDirectory() + rightDirName + item->rightName()); urls.push_back(rightURL); } } } if (urls.count() == 0) return; QMimeData *mimeData = new QMimeData; - mimeData->setImageData(FL_LOADICON(isLeft ? "arrow-left-double" : "arrow-right-double")); + mimeData->setImageData(FileListIcon(isLeft ? "arrow-left-double" : "arrow-right-double").pixmap()); mimeData->setUrls(urls); QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard); } QString SynchronizerGUI::dirLabel() { //HACK add <> brackets AFTER translating - otherwise KUIT thinks it's a tag static QString label = QString("<") + i18nc("Show the string 'DIR' instead of file size in detailed view (for folders)", "DIR") + '>'; return label; } diff --git a/krusader/UserAction/kraction.cpp b/krusader/UserAction/kraction.cpp index 60c3185a..6deb91b5 100644 --- a/krusader/UserAction/kraction.cpp +++ b/krusader/UserAction/kraction.cpp @@ -1,699 +1,700 @@ /***************************************************************************** * Copyright (C) 2004 Shie Erlich * * Copyright (C) 2004 Rafi Yanai * * Copyright (C) 2006 Jonas Bähr * * 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 "kraction.h" // QtCore #include #include #include #include #include #include #include // QtGui #include // QtWidgets #include #include #include #include #include #include #include #include #include // QtXml #include #include #include #include #include #include #include #include "expander.h" #include "useraction.h" #include "../GUI/terminaldock.h" #include "../krglobal.h" +#include "../icon.h" #include "../krusaderview.h" #include "../krservices.h" #include "../defaults.h" // KrActionProcDlg KrActionProcDlg::KrActionProcDlg(QString caption, bool enableStderr, QWidget *parent) : QDialog(parent), _stdout(0), _stderr(0), _currentTextEdit(0) { setWindowTitle(caption); setWindowModality(Qt::NonModal); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); // do we need to separate stderr and stdout? if (enableStderr) { QSplitter *splitt = new QSplitter(Qt::Horizontal, this); mainLayout->addWidget(splitt); // create stdout QWidget *stdoutWidget = new QWidget(splitt); QVBoxLayout *stdoutBox = new QVBoxLayout(stdoutWidget); stdoutBox->addWidget(new QLabel(i18n("Standard Output (stdout)"), stdoutWidget)); _stdout = new KTextEdit(stdoutWidget); _stdout->setReadOnly(true); stdoutBox->addWidget(_stdout); // create stderr QWidget *stderrWidget = new QWidget(splitt); QVBoxLayout *stderrBox = new QVBoxLayout(stderrWidget); stderrBox->addWidget(new QLabel(i18n("Standard Error (stderr)"), stderrWidget)); _stderr = new KTextEdit(stderrWidget); _stderr->setReadOnly(true); stderrBox->addWidget(_stderr); } else { // create stdout mainLayout->addWidget(new QLabel(i18n("Output"))); _stdout = new KTextEdit; _stdout->setReadOnly(true); mainLayout->addWidget(_stdout); } _currentTextEdit = _stdout; connect(_stdout, SIGNAL(textChanged()), SLOT(currentTextEditChanged())); if (_stderr) connect(_stderr, SIGNAL(textChanged()), SLOT(currentTextEditChanged())); KConfigGroup group(krConfig, "UserActions"); normalFont = group.readEntry("Normal Font", _UserActions_NormalFont); fixedFont = group.readEntry("Fixed Font", _UserActions_FixedFont); bool startupState = group.readEntry("Use Fixed Font", _UserActions_UseFixedFont); toggleFixedFont(startupState); QHBoxLayout *hbox = new QHBoxLayout; QCheckBox* useFixedFont = new QCheckBox(i18n("Use font with fixed width")); useFixedFont->setChecked(startupState); hbox->addWidget(useFixedFont); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); hbox->addWidget(buttonBox); mainLayout->addLayout(hbox); closeButton = buttonBox->button(QDialogButtonBox::Close); closeButton->setEnabled(false); QPushButton *saveAsButton = new QPushButton; KGuiItem::assign(saveAsButton, KStandardGuiItem::saveAs()); buttonBox->addButton(saveAsButton, QDialogButtonBox::ActionRole); killButton = new QPushButton(i18n("Kill")); killButton->setToolTip(i18n("Kill the running process")); killButton->setDefault(true); buttonBox->addButton(killButton, QDialogButtonBox::ActionRole); connect(killButton, SIGNAL(clicked()), this, SIGNAL(killClicked())); connect(saveAsButton, SIGNAL(clicked()), this, SLOT(slotSaveAs())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); connect(useFixedFont, SIGNAL(toggled(bool)), SLOT(toggleFixedFont(bool))); resize(sizeHint() * 2); } void KrActionProcDlg::addStderr(const QString& str) { if (_stderr) _stderr->append(str); else { _stdout->setFontItalic(true); _stdout->append(str); _stdout->setFontItalic(false); } } void KrActionProcDlg::addStdout(const QString& str) { _stdout->append(str); } void KrActionProcDlg::toggleFixedFont(bool state) { if (state) { _stdout->setFont(fixedFont); if (_stderr) _stderr->setFont(fixedFont); } else { _stdout->setFont(normalFont); if (_stderr) _stderr->setFont(normalFont); } } void KrActionProcDlg::slotSaveAs() { QString filename = QFileDialog::getSaveFileName(this, QString(), QString(), i18n("*.txt|Text files\n*|All files")); if (filename.isEmpty()) return; QFile file(filename); int answer = KMessageBox::Yes; if (file.exists()) answer = KMessageBox::warningYesNoCancel(this, //parent i18n("This file already exists.\nDo you want to overwrite it or append the output?"), //text i18n("Overwrite or append?"), //caption KStandardGuiItem::overwrite(), //label for Yes-Button KGuiItem(i18n("Append")) //label for No-Button ); if (answer == KMessageBox::Cancel) return; bool open; if (answer == KMessageBox::No) // this means to append open = file.open(QIODevice::WriteOnly | QIODevice::Append); else open = file.open(QIODevice::WriteOnly); if (! open) { KMessageBox::error(this, i18n("Cannot open %1 for writing.\nNothing exported.", filename), i18n("Export failed") ); return; } QTextStream stream(&file); stream << _currentTextEdit->toPlainText(); file.close(); } void KrActionProcDlg::slotProcessFinished() { closeButton->setEnabled(true); killButton->setEnabled(false); } void KrActionProcDlg::currentTextEditChanged() { if (_stderr && _stderr->hasFocus()) _currentTextEdit = _stderr; else _currentTextEdit = _stdout; } // KrActionProc KrActionProc::KrActionProc(KrActionBase* action) : QObject(), _action(action), _proc(0), _output(0) { } KrActionProc::~KrActionProc() { delete _proc; } void KrActionProc::start(QString cmdLine) { QStringList list; list << cmdLine; start(list); } void KrActionProc::start(QStringList cmdLineList) { QString cmd; // this is the command which is really executed (with maybe kdesu, maybe konsole, ...) // in case no specific working directory has been requested, execute in a relatively safe place QString workingDir = QDir::tempPath(); if (! _action->startpath().isEmpty()) workingDir = _action->startpath(); if (!_action->user().isEmpty()) { if (!KrServices::isExecutable(KDESU_PATH)) { KMessageBox::sorry(0, i18n("Cannot run user action, %1 not found or not executable. " "Please verify that kde-cli-tools are installed.", QString(KDESU_PATH))); return; } } if (_action->execType() == KrAction::RunInTE && (! MAIN_VIEW->terminalDock()->initialise())) { KMessageBox::sorry(0, i18n("Embedded terminal emulator does not work, using output collection instead.")); } for (QStringList::Iterator it = cmdLineList.begin(); it != cmdLineList.end(); ++it) { if (! cmd.isEmpty()) cmd += " ; "; //TODO make this separator configurable (users may want && or ||) //TODO: read header fom config or action-properties and place it on top of each command if (cmdLineList.count() > 1) cmd += "echo --------------------------------------- ; "; cmd += *it; } // make sure the command gets executed in the right directory cmd = "(cd " + KrServices::quote(workingDir) + " && (" + cmd + "))"; if (_action->execType() == KrAction::RunInTE && MAIN_VIEW->terminalDock()->isInitialised()) { //send the commandline contents to the terminal emulator if (!_action->user().isEmpty()) { // "-t" is necessary that kdesu displays the terminal-output of the command cmd = KrServices::quote(KDESU_PATH) + " -t -u " + _action->user() + " -c " + KrServices::quote(cmd); } MAIN_VIEW->terminalDock()->sendInput(cmd + '\n'); deleteLater(); } else { // will start a new process _proc = new KProcess(this); _proc->clearProgram(); // this clears the arglist too _proc->setWorkingDirectory(workingDir); connect(_proc, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(processExited(int,QProcess::ExitStatus))); if (_action->execType() == KrAction::Normal || _action->execType() == KrAction::Terminal) { // not collect output if (_action->execType() == KrAction::Terminal) { // run in terminal KConfigGroup group(krConfig, "UserActions"); QString term = group.readEntry("Terminal", _UserActions_Terminal); QStringList termArgs = KShell::splitArgs(term, KShell::TildeExpand); if (termArgs.isEmpty()) { KMessageBox::error(0, i18nc("Arg is a string containing the bad quoting.", "Bad quoting in terminal command:\n%1", term)); deleteLater(); return; } for (int i = 0; i != termArgs.size(); i++) { if (termArgs[i] == "%t") termArgs[i] = cmdLineList.join(" ; "); else if (termArgs[i] == "%d") termArgs[i] = workingDir; } termArgs << "sh" << "-c" << cmd; cmd = KrServices::quote(termArgs).join(" "); } if (!_action->user().isEmpty()) { cmd = KrServices::quote(KDESU_PATH) + " -u " + _action->user() + " -c " + KrServices::quote(cmd); } } else { // collect output bool separateStderr = false; if (_action->execType() == KrAction::CollectOutputSeparateStderr) separateStderr = true; _output = new KrActionProcDlg(_action->text(), separateStderr); // connect the output to the dialog _proc->setOutputChannelMode(KProcess::SeparateChannels); connect(_proc, SIGNAL(readyReadStandardError()), SLOT(addStderr())); connect(_proc, SIGNAL(readyReadStandardOutput()), SLOT(addStdout())); connect(_output, SIGNAL(killClicked()), this, SLOT(kill())); _output->show(); if (!_action->user().isEmpty()) { // "-t" is necessary that kdesu displays the terminal-output of the command cmd = KrServices::quote(KDESU_PATH) + " -t -u " + _action->user() + " -c " + KrServices::quote(cmd); } } //printf("cmd: %s\n", cmd.toAscii().data()); _proc->setShellCommand(cmd); _proc->start(); } } void KrActionProc::processExited(int /*exitCode*/, QProcess::ExitStatus /*exitStatus*/) { // enable the 'close' button on the dialog (if active), disable 'kill' button if (_output) { // TODO tell the user the program exit code _output->slotProcessFinished(); } delete this; // banzai!! } void KrActionProc::addStderr() { if (_output) { _output->addStderr(QString::fromLocal8Bit(_proc->readAllStandardError().data())); } } void KrActionProc::addStdout() { if (_output) { _output->addStdout(QString::fromLocal8Bit(_proc->readAllStandardOutput().data())); } } // KrAction KrAction::KrAction(KActionCollection *parent, QString name) : QAction((QObject *)parent) { _actionCollection = parent; setObjectName(name); parent->addAction(name, this); connect(this, SIGNAL(triggered()), this, SLOT(exec())); } KrAction::~KrAction() { foreach(QWidget *w, associatedWidgets()) w->removeAction(this); krUserAction->removeKrAction(this); // Importent! Else Krusader will crash when writing the actions to file } bool KrAction::isAvailable(const QUrl ¤tURL) { bool available = true; //show per default (FIXME: make the default an attribute of ) //check protocol if (! _showonlyProtocol.empty()) { available = false; for (QStringList::Iterator it = _showonlyProtocol.begin(); it != _showonlyProtocol.end(); ++it) { //qDebug() << "KrAction::isAvailable currendProtocol: " << currentURL.scheme() << " =?= " << *it; if (currentURL.scheme() == *it) { // FIXME remove trailing slashes at the xml-parsing (faster because done only once) available = true; break; } } } //check protocol: done //check the Path-list: if (available && ! _showonlyPath.empty()) { available = false; for (QStringList::Iterator it = _showonlyPath.begin(); it != _showonlyPath.end(); ++it) { if ((*it).right(1) == "*") { if (currentURL.path().indexOf((*it).left((*it).length() - 1)) == 0) { available = true; break; } } else if (currentURL.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path() == *it) { // FIXME remove trailing slashes at the xml-parsing (faster because done only once) available = true; break; } } } //check the Path-list: done //check mime-type if (available && ! _showonlyMime.empty()) { available = false; QMimeDatabase db; QMimeType mime = db.mimeTypeForUrl(currentURL); if (mime.isValid()) { for (QStringList::Iterator it = _showonlyMime.begin(); it != _showonlyMime.end(); ++it) { if ((*it).contains("/")) { if (mime.inherits(*it)) { // don't use ==; use 'inherits()' instead, which is aware of inheritence (ie: text/x-makefile is also text/plain) available = true; break; } } else { if (mime.name().indexOf(*it) == 0) { // 0 is the beginning, -1 is not found available = true; break; } } } //for } } //check the mime-type: done //check filename if (available && ! _showonlyFile.empty()) { available = false; for (QStringList::Iterator it = _showonlyFile.begin(); it != _showonlyFile.end(); ++it) { QRegExp regex = QRegExp(*it, Qt::CaseInsensitive, QRegExp::Wildcard); // case-sensitive = false; wildcards = true if (regex.exactMatch(currentURL.fileName())) { available = true; break; } } } //check the filename: done return available; } bool KrAction::xmlRead(const QDomElement& element) { /* This has to be done elsewhere!! if ( element.tagName() != "action" ) return false; Also the name has to be checked before the action is created! setName( element.attribute( "name" ).toLatin1() ); */ QString attr; attr = element.attribute("enabled", "true"); // default: "true" if (attr == "false") { setEnabled(false); setVisible(false); } for (QDomNode node = element.firstChild(); !node.isNull(); node = node.nextSibling()) { QDomElement e = node.toElement(); if (e.isNull()) continue; // this should skip nodes which are not elements ( i.e. comments, , or text nodes) if (e.tagName() == "title") setText(i18n(e.text().toUtf8().constData())); else if (e.tagName() == "tooltip") setToolTip(i18n(e.text().toUtf8().constData())); else if (e.tagName() == "icon") - setIcon(QIcon::fromTheme(_iconName = e.text())); + setIcon(Icon(_iconName = e.text())); else if (e.tagName() == "category") setCategory(i18n(e.text().toUtf8().constData())); else if (e.tagName() == "description") setWhatsThis(i18n(e.text().toUtf8().constData())); else if (e.tagName() == "command") readCommand(e); else if (e.tagName() == "startpath") setStartpath(e.text()); else if (e.tagName() == "availability") readAvailability(e); else if (e.tagName() == "defaultshortcut") _actionCollection->setDefaultShortcut(this, QKeySequence(e.text())); else // unknown but not empty if (! e.tagName().isEmpty()) qWarning() << "KrAction::xmlRead() - unrecognized tag found: <" << e.tagName() << ">"; } // for ( QDomNode node = action->firstChild(); !node.isNull(); node = node.nextSibling() ) return true; } //KrAction::xmlRead QDomElement KrAction::xmlDump(QDomDocument& doc) const { QDomElement actionElement = doc.createElement("action"); actionElement.setAttribute("name", objectName()); if (! isVisible()) { actionElement.setAttribute("enabled", "false"); } #define TEXT_ELEMENT( TAGNAME, TEXT ) \ { \ QDomElement e = doc.createElement( TAGNAME ); \ e.appendChild( doc.createTextNode( TEXT ) ); \ actionElement.appendChild( e ); \ } TEXT_ELEMENT("title", text()) if (! toolTip().isEmpty()) TEXT_ELEMENT("tooltip", toolTip()) if (! _iconName.isEmpty()) TEXT_ELEMENT("icon", _iconName) if (! category().isEmpty()) TEXT_ELEMENT("category", category()) if (! whatsThis().isEmpty()) TEXT_ELEMENT("description", whatsThis()) actionElement.appendChild(dumpCommand(doc)); if (! startpath().isEmpty()) TEXT_ELEMENT("startpath", startpath()) QDomElement availabilityElement = dumpAvailability(doc); if (availabilityElement.hasChildNodes()) actionElement.appendChild(availabilityElement); if (! shortcut().isEmpty()) TEXT_ELEMENT("defaultshortcut", shortcut().toString()) //.toString() would return a localised string which can't be read again return actionElement; } //KrAction::xmlDump void KrAction::readCommand(const QDomElement& element) { QString attr; attr = element.attribute("executionmode", "normal"); // default: "normal" if (attr == "normal") setExecType(Normal); else if (attr == "terminal") setExecType(Terminal); else if (attr == "collect_output") setExecType(CollectOutput); else if (attr == "collect_output_separate_stderr") setExecType(CollectOutputSeparateStderr); else if (attr == "embedded_terminal") setExecType(RunInTE); else qWarning() << "KrAction::readCommand() - unrecognized attribute value found: , or text nodes) QStringList* showlist = 0; if (e.tagName() == "protocol") showlist = &_showonlyProtocol; else if (e.tagName() == "path") showlist = &_showonlyPath; else if (e.tagName() == "mimetype") showlist = & _showonlyMime; else if (e.tagName() == "filename") showlist = & _showonlyFile; else { qWarning() << "KrAction::readAvailability() - unrecognized element found: <" << e.tagName() << ">"; showlist = 0; } if (showlist) { for (QDomNode subnode = e.firstChild(); ! subnode.isNull(); subnode = subnode.nextSibling()) { QDomElement subelement = subnode.toElement(); if (subelement.tagName() == "show") showlist->append(subelement.text()); } // for } // if ( showlist ) } // for } //KrAction::readAvailability QDomElement KrAction::dumpAvailability(QDomDocument& doc) const { QDomElement availabilityElement = doc.createElement("availability"); # define LIST_ELEMENT( TAGNAME, LIST ) \ { \ QDomElement e = doc.createElement( TAGNAME ); \ for ( QStringList::const_iterator it = LIST.constBegin(); it != LIST.constEnd(); ++it ) { \ QDomElement show = doc.createElement( "show" ); \ show.appendChild( doc.createTextNode( *it ) ); \ e.appendChild( show ); \ } \ availabilityElement.appendChild( e ); \ } if (! _showonlyProtocol.isEmpty()) LIST_ELEMENT("protocol", _showonlyProtocol) if (! _showonlyPath.isEmpty()) LIST_ELEMENT("path", _showonlyPath) if (! _showonlyMime.isEmpty()) LIST_ELEMENT("mimetype", _showonlyMime) if (! _showonlyFile.isEmpty()) LIST_ELEMENT("filename", _showonlyFile) return availabilityElement; } //KrAction::dumpAvailability diff --git a/krusader/actionsbase.cpp b/krusader/actionsbase.cpp index 13583869..e37b38ca 100644 --- a/krusader/actionsbase.cpp +++ b/krusader/actionsbase.cpp @@ -1,118 +1,119 @@ /***************************************************************************** * Copyright (C) 2010 Jan Lepper * * Copyright (C) 2010-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 "actionsbase.h" #include "krmainwindow.h" +#include "icon.h" // QtWidgets #include #include #include void ActionsBase::ActionGroup::reconnect(QObject *recv) { foreach(QAction *action, _slots.keys()) { disconnect(action, 0, 0, 0); connect(action, SIGNAL(triggered(bool)), recv, _slots[action]); } } void ActionsBase::ActionGroup::addAction(QAction *action, const char *slot) { _slots.insert(action, slot); } QAction *ActionsBase::createAction(QString text, QString icon, bool isToggleAction) { if(isToggleAction) { if (icon == 0) return (QAction *)(new KToggleAction(text, this)); else - return (QAction *)(new KToggleAction(QIcon::fromTheme(icon), text, this)); + return (QAction *)(new KToggleAction(Icon(icon), text, this)); } else { if (icon == 0) return new QAction(text, this); else - return new QAction(QIcon::fromTheme(icon), text, this); + return new QAction(Icon(icon), text, this); } } QAction *ActionsBase::action(QString text, QString icon, QKeySequence shortcut, QObject *recv, const char *slot, QString name, bool isToggleAction) { QAction *a = createAction(text, icon, isToggleAction); connect(a, SIGNAL(triggered(bool)), recv, slot); _mainWindow->actions()->addAction(name, a); _mainWindow->actions()->setDefaultShortcut(a, shortcut); return a; } QAction *ActionsBase::action(QString text, QString icon, const QList &shortcuts, QObject *recv, const char *slot, QString name, bool isToggleAction) { QAction *a = createAction(text, icon, isToggleAction); connect(a, SIGNAL(triggered(bool)), recv, slot); _mainWindow->actions()->addAction(name, a); _mainWindow->actions()->setDefaultShortcuts(a, shortcuts); return a; } QAction *ActionsBase::action(QString text, QString icon, QKeySequence shortcut, ActionGroup &group, const char *slot, QString name, bool isToggleAction) { QAction *action = createAction(text, icon, isToggleAction); group.addAction(action, slot); _mainWindow->actions()->addAction(name, action); _mainWindow->actions()->setDefaultShortcut(action, shortcut); return action; } KToggleAction *ActionsBase::toggleAction(QString text, QString icon, QKeySequence shortcut, QObject *recv, const char *slot, QString name) { return (KToggleAction *)(action(text, icon, shortcut, recv, slot, name, true)); } KToggleAction *ActionsBase::toggleAction(QString text, QString icon, QKeySequence shortcut, ActionGroup &group, const char *slot, QString name) { return (KToggleAction *)(action(text, icon, shortcut, group, slot, name, true)); } QAction *ActionsBase::stdAction(KStandardAction::StandardAction id, QObject *recv, const char *slot) { return KStandardAction::create(id, recv, slot, _mainWindow->actions()); } QAction *ActionsBase::stdAction(KStandardAction::StandardAction id, ActionGroup &group, const char *slot) { QAction *action = KStandardAction::create(id, 0, 0, _mainWindow->actions()); group.addAction(action, slot); return action; } diff --git a/krusader/kicons.cpp b/krusader/filelisticon.cpp similarity index 70% rename from krusader/kicons.cpp rename to krusader/filelisticon.cpp index 5f5a296b..3ba4aeeb 100644 --- a/krusader/kicons.cpp +++ b/krusader/filelisticon.cpp @@ -1,41 +1,38 @@ /***************************************************************************** - * Copyright (C) 2000 Shie Erlich * - * Copyright (C) 2000 Rafi Yanai * - * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * + * Copyright (C) 2018 Nikita Melnichenko * + * Copyright (C) 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 "kicons.h" +#include "filelisticon.h" + #include "krglobal.h" #include "defaults.h" -// QtCore -#include -// QtGui -#include -// QtWidgets -#include - #include -#include -QPixmap FL_LOADICON(QString name) + +QSize FileListIcon::size() const +{ + int linearSize = KConfigGroup(krConfig, "Look&Feel").readEntry("Filelist Icon Size", _FilelistIconSize).toInt(); + return QSize(linearSize, linearSize); +} + +QPixmap FileListIcon::pixmap() const { - KConfigGroup group(krConfig, "Look&Feel"); - int size = (group.readEntry("Filelist Icon Size", _FilelistIconSize)).toInt(); - return krLoader->loadIcon(name, KIconLoader::Desktop, size); + return QIcon::pixmap(size()); } diff --git a/krusader/kicons.h b/krusader/filelisticon.h similarity index 74% rename from krusader/kicons.h rename to krusader/filelisticon.h index 3f3cfd1e..f0a46d70 100644 --- a/krusader/kicons.h +++ b/krusader/filelisticon.h @@ -1,31 +1,42 @@ /***************************************************************************** - * Copyright (C) 2000 Shie Erlich * - * Copyright (C) 2000 Rafi Yanai * - * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * + * Copyright (C) 2018 Nikita Melnichenko * + * Copyright (C) 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 KICONS_H -#define KICONS_H +#ifndef FILELISTICON_H +#define FILELISTICON_H + +#include "icon.h" // QtGui #include -// used only for calls within the kfilelist framework, handles icon sizes -QPixmap FL_LOADICON(QString name); -#endif +class FileListIcon : public Icon +{ +public: + explicit FileListIcon(QString name) : Icon(name) {} + + /// Load pixmap of standard file list icon size + QPixmap pixmap() const; + + /// Get icon size as configured by user + QSize size() const; +}; + +#endif // FILELISTICON_H diff --git a/krusader/icon.cpp b/krusader/icon.cpp new file mode 100644 index 00000000..d7e259d6 --- /dev/null +++ b/krusader/icon.cpp @@ -0,0 +1,310 @@ +/***************************************************************************** + * Copyright (C) 2018 Nikita Melnichenko * + * Copyright (C) 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 "icon.h" + +#include "krglobal.h" + +// QtCore +#include +#include +#include +#include +// QtGui +#include +#include +#include + +#include +#include + + +static const int cacheSize = 500; +static const char *missingIconPath = ":/icons/icon-missing.svgz"; + + +static inline QStringList getThemeFallbackList() +{ + QStringList themes; + + // add user fallback theme if set + if (krConfig) { + const KConfigGroup group(krConfig, QStringLiteral("Startup")); + QString userFallbackTheme = group.readEntry("Fallback Icon Theme", QString()); + if (!userFallbackTheme.isEmpty()) { + themes << userFallbackTheme; + } + } + + // Breeze and Oxygen are weak dependencies of Krusader, + // i.e. each of the themes provide a complete set of icons used in the interface + const QString breeze(Icon::isLightWindowThemeActive() ? "breeze" : "breeze-dark"); + themes << breeze << "oxygen"; + + return themes; +} + + +class IconEngine : public QIconEngine +{ +public: + IconEngine(QString iconName, QIcon fallbackIcon, QStringList overlays = QStringList()) : + _iconName(iconName), _fallbackIcon(fallbackIcon), _overlays(overlays) + { + _themeFallbackList = getThemeFallbackList(); + } + + virtual void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override; + virtual QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override; + + virtual IconEngine *clone() const override + { + return new IconEngine(*this); + } + +private: + QString _iconName; + QStringList _themeFallbackList; + QIcon _fallbackIcon; + QStringList _overlays; +}; + +Icon::Icon() : QIcon() +{ +} + +Icon::Icon(QString name, QStringList overlays) : + QIcon(new IconEngine(name, QIcon(missingIconPath), overlays)) +{ +} + +Icon::Icon(QString name, QIcon fallbackIcon, QStringList overlays) : + QIcon(new IconEngine(name, fallbackIcon, overlays)) +{ +} + +struct IconSearchResult +{ + QIcon icon; ///< icon returned by search; null icon if not found + QString originalThemeName; ///< original theme name if theme is modified by search + + IconSearchResult(QIcon icon, QString originalThemeName) : + icon(icon), originalThemeName(originalThemeName) {} +}; + +// Search icon in the configured themes. +// If this call modifies active theme, the original theme name will be specified in the result. +static inline IconSearchResult searchIcon(QString iconName, QStringList themeFallbackList) +{ + if (QDir::isAbsolutePath(iconName)) { + // a path is used - directly load the icon + return IconSearchResult(QIcon(iconName), QString()); + } else if (QIcon::hasThemeIcon(iconName)) { + // current theme has the icon - load seamlessly + return IconSearchResult(QIcon::fromTheme(iconName), QString()); + } else if (KIconLoader::global()->hasIcon(iconName)) { + // KF icon loader does a wider search and helps with mime icons + return IconSearchResult(KDE::icon(iconName), QString()); + } else { + // search the icon in fallback themes + auto currentTheme = QIcon::themeName(); + for (auto fallbackThemeName : themeFallbackList) { + QIcon::setThemeName(fallbackThemeName); + if (QIcon::hasThemeIcon(iconName)) { + return IconSearchResult(QIcon::fromTheme(iconName), currentTheme); + } + } + QIcon::setThemeName(currentTheme); + + // not found + return IconSearchResult(QIcon(), QString()); + } +} + +bool Icon::exists(QString iconName) +{ + static QCache cache(cacheSize); + static QString cachedTheme; + + // invalidate cache if system theme is changed + if (cachedTheme != QIcon::themeName()) { + cache.clear(); + cachedTheme = QIcon::themeName(); + } + + // return cached result when possible + if (cache.contains(iconName)) { + return *cache.object(iconName); + } + + auto searchResult = searchIcon(iconName, getThemeFallbackList()); + if (!searchResult.originalThemeName.isNull()) { + QIcon::setThemeName(searchResult.originalThemeName); + } + + bool *result = new bool(!searchResult.icon.isNull()); + + // update the cache; the cache takes ownership over the result + cache.insert(iconName, result); + + return *result; +} + +void Icon::applyOverlays(QPixmap *pixmap, QStringList overlays) +{ + auto iconLoader = KIconLoader::global(); + + // Since KIconLoader loadIcon is not virtual method, we can't redefine loadIcon + // that is called by drawOverlays. The best we can do is to go over the overlays + // and ensure they exist from the icon loader point of view. + // If not, we replace the overlay with "emblem-unreadable" which should be available + // per freedesktop icon name specification: + // https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html + QStringList fixedOverlays; + for (auto overlay : overlays) { + if (overlay.isEmpty() || iconLoader->hasIcon(overlay)) { + fixedOverlays << overlay; + } else { + fixedOverlays << "emblem-unreadable"; + } + } + + iconLoader->drawOverlays(fixedOverlays, *pixmap, KIconLoader::Desktop); +} + +bool Icon::isLightWindowThemeActive() +{ + const QColor textColor = QPalette().brush(QPalette::Text).color(); + return (textColor.red() + textColor.green() + textColor.blue()) / 3 < 128; +} + + +class IconCacheKey +{ +public: + IconCacheKey(const QString &name, QStringList overlays, + const QSize &size, QIcon::Mode mode, QIcon::State state) : + name(name), overlays(overlays), size(size), mode(mode), state(state) + { + + auto repr = QString("%1 [%2] %3x%4 %5 %6").arg(name).arg(overlays.join(';')) + .arg(size.width()).arg(size.height()) + .arg((int)mode).arg((int)state); + _hash = qHash(repr); + } + + bool operator ==(const IconCacheKey &x) const + { + return name == x.name && overlays == x.overlays + && size == x.size && mode == x.mode && state == x.state; + } + + uint hash() const + { + return _hash; + } + + QString name; + QStringList overlays; + QSize size; + QIcon::Mode mode; + QIcon::State state; + +private: + uint _hash; +}; + +uint qHash(const IconCacheKey &key) +{ + return key.hash(); +} + +QPixmap IconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) +{ + static QCache cache(cacheSize); + static QString cachedTheme; + + QString systemTheme = QIcon::themeName(); + + // [WORKAROUND] If system theme is Breeze, pick light or dark variant of the theme explicitly + // This type of selection works implicitly when QIcon::fromTheme is used, + // however after QIcon::setThemeName it stops working for unknown reason. + if (systemTheme == "breeze" || systemTheme == "breeze-dark") { + const QString pickedSystemTheme(Icon::isLightWindowThemeActive() ? "breeze" : "breeze-dark"); + if (systemTheme != pickedSystemTheme) { + qDebug() << "System icon theme variant changed:" << systemTheme << "->" << pickedSystemTheme; + systemTheme = pickedSystemTheme; + QIcon::setThemeName(systemTheme); + } + } + + // invalidate cache if system theme is changed + if (cachedTheme != systemTheme) { + if (!cachedTheme.isEmpty()) { + qDebug() << "System icon theme changed:" << cachedTheme << "->" << systemTheme; + } + + cache.clear(); + cachedTheme = systemTheme; + } + + // an empty icon name is a special case - we don't apply any fallback + if (_iconName.isEmpty()) { + return QPixmap(); + } + + auto key = IconCacheKey(_iconName, _overlays, size, mode, state); + + // return cached icon when possible + if (cache.contains(key)) { + return *cache.object(key); + } + + // search icon and extract pixmap + auto pixmap = new QPixmap; + auto searchResult = searchIcon(_iconName, _themeFallbackList); + if (!searchResult.icon.isNull()) { + *pixmap = searchResult.icon.pixmap(size, mode, state); + } + if (!searchResult.originalThemeName.isNull()) { + QIcon::setThemeName(searchResult.originalThemeName); + } + + // can't find the icon neither in system theme nor in fallback themes - load fallback icon + if (pixmap->isNull()) { + qWarning() << "Unable to find icon" << _iconName << "of size" << size << "in any configured theme"; + *pixmap = _fallbackIcon.pixmap(size, mode, state); + } + + // apply overlays in a safe manner + Icon::applyOverlays(pixmap, _overlays); + + // update the cache; the cache takes ownership over the pixmap + cache.insert(key, pixmap); + + return *pixmap; +} + +void IconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) +{ + QSize pixmapSize = rect.size(); + QPixmap px = pixmap(pixmapSize, mode, state); + painter->drawPixmap(rect, px); +} diff --git a/krusader/GUI/krremoteencodingmenu.h b/krusader/icon.h similarity index 54% copy from krusader/GUI/krremoteencodingmenu.h copy to krusader/icon.h index 28542e4d..58d32949 100644 --- a/krusader/GUI/krremoteencodingmenu.h +++ b/krusader/icon.h @@ -1,63 +1,55 @@ /***************************************************************************** - * Copyright (C) 2005 Csaba Karai * - * Copyright (C) 2005-2018 Krusader Krew [https://krusader.org] * - * * - * Based on KRemoteEncodingPlugin from Dawit Alemayehu * + * Copyright (C) 2018 Nikita Melnichenko * + * Copyright (C) 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 KRREMOTEENCODINGMENU_H -#define KRREMOTEENCODINGMENU_H - -// QtCore -#include -// QtWidgets -#include - -# include - -class KActionCollection; - -class KrRemoteEncodingMenu: public KActionMenu +#ifndef ICON_H +#define ICON_H + +// QtGui +#include +#include + +/** + * @class Icon + * + * Universal icon class for Krusader. + * + * There is a list of configured themes that Icon searches in. + * The order of themes is the following: active theme, theme specified by user, + * fallback themes that provide complete icon set for Krusader. + * If icon is not found in any configured theme, the fallback icon is used. + */ +class Icon : public QIcon { - Q_OBJECT public: - KrRemoteEncodingMenu(const QString &text, const QString &icon, KActionCollection *parent = 0); - -protected slots: - - void slotAboutToShow(); - - void slotReload(); - void slotTriggered(QAction *); - - virtual void chooseDefault(); - virtual void chooseEncoding(QString encoding); - -protected: - virtual QString currentCharacterSet(); + Icon(); + explicit Icon(QString name, QStringList overlays = QStringList()); + explicit Icon(QString name, QIcon fallbackIcon, QStringList overlays = QStringList()); -private: + /// Check if icon exists in any configured theme + static bool exists(QString iconName); - void loadSettings(); - void updateKIOSlaves(); + /// Apply overlays to the pixmap with fallbacks to standard emblems + static void applyOverlays(QPixmap *pixmap, QStringList overlays); - QStringList encodingNames; - bool settingsLoaded; + /// Determine if light window theme is currently enabled + static bool isLightWindowThemeActive(); }; -#endif /* REMOTEENCODING_MENU_H */ +#endif // ICON_H diff --git a/krusader/icons/icon-missing.svgz b/krusader/icons/icon-missing.svgz new file mode 100644 index 00000000..54690022 Binary files /dev/null and b/krusader/icons/icon-missing.svgz differ diff --git a/krusader/kractions.cpp b/krusader/kractions.cpp index f06cd378..e2802ad5 100644 --- a/krusader/kractions.cpp +++ b/krusader/kractions.cpp @@ -1,324 +1,325 @@ /***************************************************************************** * Copyright (C) 2000 Shie Erlich * * 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 "kractions.h" // QtWidgets #include #include #include #include #include #include #include #include #include "defaults.h" #include "krusader.h" +#include "icon.h" #include "krusaderview.h" #include "krslots.h" #include "krtrashhandler.h" #include "Dialogs/popularurls.h" #include "GUI/krremoteencodingmenu.h" #include "JobMan/jobman.h" #include "MountMan/kmountman.h" #include "Panel/PanelView/krviewfactory.h" #include "UserAction/useraction.h" QAction *KrActions::actCompare = 0; QAction *KrActions::actDiskUsage = 0; QAction *KrActions::actHomeTerminal = 0; QAction *KrActions::actRemoteEncoding = 0; QAction *KrActions::actProfiles = 0; QAction *KrActions::actMultiRename = 0; QAction *KrActions::actMountMan = 0; QAction *KrActions::actNewTool = 0; QAction *KrActions::actKonfigurator = 0; QAction *KrActions::actToolsSetup = 0; QAction *KrActions::actSwapPanels = 0; QAction *KrActions::actSwapSides = 0; QAction *KrActions::actFind = 0; QAction *KrActions::actLocate = 0; QAction *KrActions::actSwitchFullScreenTE = 0; QAction *KrActions::actAddBookmark = 0; QAction *KrActions::actSavePosition = 0; QAction *KrActions::actSelectColorMask = 0; QAction *KrActions::actOpenLeftBm = 0; QAction *KrActions::actOpenRightBm = 0; QAction *KrActions::actCmdlinePopup = 0; QAction *KrActions::actSplit = 0; QAction *KrActions::actCombine = 0; QAction *KrActions::actUserMenu = 0; QAction *KrActions::actManageUseractions = 0; #ifdef SYNCHRONIZER_ENABLED QAction *KrActions::actSyncDirs = 0; #endif QAction *KrActions::actF10Quit = 0; QAction *KrActions::actEmptyTrash = 0; QAction *KrActions::actTrashBin = 0; QAction *KrActions::actPopularUrls = 0; KToggleAction *KrActions::actToggleTerminal = 0; QAction *KrActions::actVerticalMode = 0; QAction *KrActions::actSelectNewerAndSingle = 0; QAction *KrActions::actSelectSingle = 0; QAction *KrActions::actSelectNewer = 0; QAction *KrActions::actSelectDifferentAndSingle = 0; QAction *KrActions::actSelectDifferent = 0; QAction **KrActions::compareArray[] = {&actSelectNewerAndSingle, &actSelectNewer, &actSelectSingle, &actSelectDifferentAndSingle, &actSelectDifferent, 0 }; QAction *KrActions::actExecStartAndForget = 0; QAction *KrActions::actExecCollectSeparate = 0; QAction *KrActions::actExecCollectTogether = 0; QAction *KrActions::actExecTerminalExternal = 0; QAction *KrActions::actExecTerminalEmbedded = 0; QAction **KrActions::execTypeArray[] = {&actExecStartAndForget, &actExecCollectSeparate, &actExecCollectTogether, &actExecTerminalExternal, &actExecTerminalEmbedded, 0 }; KToggleAction *KrActions::actToggleFnkeys = 0; KToggleAction *KrActions::actToggleCmdline = 0; KToggleAction *KrActions::actShowStatusBar = 0; KToggleAction *KrActions::actToggleHidden = 0; KToggleAction *KrActions::actCompareDirs = 0; QAction *KrActions::actJobProgress = 0; QAction *KrActions::actJobControl = 0; QAction *KrActions::actJobMode = 0; QAction *KrActions::actJobUndo = 0; #ifdef __KJSEMBED__ static QAction *actShowJSConsole; #endif -QAction *createAction(QString text, QString icon, QKeySequence shortcut, +QAction *createAction(QString text, QString iconName, QKeySequence shortcut, QObject *recv, const char *slot, QString name, Krusader *krusaderApp) { QAction *a; - if (icon.isEmpty()) + if (iconName.isEmpty()) a = new QAction(text, krusaderApp); else - a = new QAction(QIcon::fromTheme(icon), text, krusaderApp); + a = new QAction(Icon(iconName), text, krusaderApp); krusaderApp->connect(a, SIGNAL(triggered(bool)), recv, slot); krusaderApp->actionCollection()->addAction(name, a); krusaderApp->actionCollection()->setDefaultShortcut(a, shortcut); return a; } -QAction *createAction(QString text, QString icon, QList shortcuts, +QAction *createAction(QString text, QString iconName, QList shortcuts, QObject *recv, const char *slot, QString name, Krusader *krusaderApp) { QAction *a; - if (icon.isEmpty()) + if (iconName.isEmpty()) a = new QAction(text, krusaderApp); else - a = new QAction(QIcon::fromTheme(icon), text, krusaderApp); + a = new QAction(Icon(iconName), text, krusaderApp); krusaderApp->connect(a, SIGNAL(triggered(bool)), recv, slot); krusaderApp->actionCollection()->addAction(name, a); krusaderApp->actionCollection()->setDefaultShortcuts(a, shortcuts); return a; } -KToggleAction *createToggleAction(QString text, QString icon, QKeySequence shortcut, +KToggleAction *createToggleAction(QString text, QString iconName, QKeySequence shortcut, QObject *recv, const char *slot, QString name, Krusader *krusaderApp) { KToggleAction *a; - if (icon == 0) + if (iconName == 0) a = new KToggleAction(text, krusaderApp); else - a = new KToggleAction(QIcon::fromTheme(icon), text, krusaderApp); + a = new KToggleAction(Icon(iconName), text, krusaderApp); krusaderApp->connect(a, SIGNAL(triggered(bool)), recv, slot); krusaderApp->actionCollection()->addAction(name, a); krusaderApp->actionCollection()->setDefaultShortcut(a, shortcut); return a; } void KrActions::setupActions(Krusader *krusaderApp) { #define NEW_KACTION(VAR, TEXT, ICON_NAME, SHORTCUT, RECV_OBJ, SLOT_NAME, NAME) \ VAR = createAction(TEXT, ICON_NAME, SHORTCUT, RECV_OBJ, SLOT_NAME, NAME, krusaderApp); #define NEW_KTOGGLEACTION(VAR, TEXT, ICON_NAME, SHORTCUT, RECV_OBJ, SLOT_NAME, NAME) \ VAR = createToggleAction(TEXT, ICON_NAME, SHORTCUT, RECV_OBJ, SLOT_NAME, NAME, krusaderApp); // first come the TODO actions //actSync = 0;//new QAction(i18n("S&ynchronize Dirs"), 0, krusaderApp, 0, actionCollection(), "sync dirs"); //actNewTool = 0;//new QAction(i18n("&Add a new tool"), 0, krusaderApp, 0, actionCollection(), "add tool"); //actToolsSetup = 0;//new QAction(i18n("&Tools Menu Setup"), 0, 0, krusaderApp, 0, actionCollection(), "tools setup"); //KStandardAction::print(SLOTS, 0,actionCollection(),"std_print"); //KStandardAction::showMenubar( SLOTS, SLOT(showMenubar()), actionCollection(), "std_menubar" ); /* Shortcut disabled because of the Terminal Emulator bug. */ KConfigGroup group(krConfig, "Private"); int compareMode = group.readEntry("Compare Mode", 0); int cmdExecMode = group.readEntry("Command Execution Mode", 0); QAction *tmp; Q_UNUSED(tmp); NEW_KACTION(tmp, i18n("Tab-Switch panel"), 0, Qt::Key_Tab, MAIN_VIEW, SLOT(panelSwitch()), "tab"); KToggleToolBarAction *actShowToolBar = new KToggleToolBarAction(krusaderApp->toolBar(), i18n("Show Main Toolbar"), krusaderApp); krusaderApp->actionCollection()->addAction(KStandardAction::name(KStandardAction::ShowToolbar), actShowToolBar); KToggleToolBarAction *actShowJobToolBar = new KToggleToolBarAction(krusaderApp->toolBar("jobToolBar"), i18n("Show Job Toolbar"), krusaderApp); krusaderApp->actionCollection()->addAction("toggle show jobbar", actShowJobToolBar); KToggleToolBarAction *actShowActionsToolBar = new KToggleToolBarAction(krusaderApp->toolBar("actionsToolBar"), i18n("Show Actions Toolbar"), krusaderApp); krusaderApp->actionCollection()->addAction("toggle actions toolbar", actShowActionsToolBar); actShowStatusBar = KStandardAction::showStatusbar(SLOTS, SLOT(updateStatusbarVisibility()), krusaderApp->actionCollection()); KStandardAction::quit(krusaderApp, SLOT(quit()), krusaderApp->actionCollection()); KStandardAction::configureToolbars(krusaderApp, SLOT(configureToolbars()), krusaderApp->actionCollection()); KStandardAction::keyBindings(krusaderApp->guiFactory(), SLOT(configureShortcuts()), krusaderApp->actionCollection()); // the toggle actions NEW_KTOGGLEACTION(actToggleFnkeys, i18n("Show &FN Keys Bar"), 0, 0, SLOTS, SLOT(toggleFnkeys()), "toggle fn bar"); NEW_KTOGGLEACTION(actToggleCmdline, i18n("Show &Command Line"), 0, 0, SLOTS, SLOT(toggleCmdline()), "toggle command line"); NEW_KTOGGLEACTION(actToggleTerminal, i18n("Show &Embedded Terminal"), 0, Qt::ALT + Qt::CTRL + Qt::Key_T, SLOTS, SLOT(toggleTerminal()), "toggle terminal emulator"); NEW_KTOGGLEACTION(actToggleHidden, i18n("Show &Hidden Files"), 0, Qt::ALT + Qt::Key_Period, SLOTS, SLOT(showHiddenFiles(bool)), "toggle hidden files"); NEW_KACTION(actSwapPanels, i18n("S&wap Panels"), 0, Qt::CTRL + Qt::Key_U, SLOTS, SLOT(swapPanels()), "swap panels"); NEW_KACTION(actEmptyTrash, i18n("Empty Trash"), "trash-empty", 0, SLOTS, SLOT(emptyTrash()), "emptytrash"); - NEW_KACTION(actTrashBin, i18n("Trash Popup Menu"), KrTrashHandler::trashIcon(), 0, SLOTS, SLOT(trashPopupMenu()), "trashbin"); + NEW_KACTION(actTrashBin, i18n("Trash Popup Menu"), KrTrashHandler::trashIconName(), 0, SLOTS, SLOT(trashPopupMenu()), "trashbin"); NEW_KACTION(actSwapSides, i18n("Sw&ap Sides"), 0, Qt::CTRL + Qt::SHIFT + Qt::Key_U, SLOTS, SLOT(toggleSwapSides()), "toggle swap sides"); actToggleHidden->setChecked(KConfigGroup(krConfig, "Look&Feel").readEntry("Show Hidden", _ShowHidden)); // and then the DONE actions NEW_KACTION(actCmdlinePopup, i18n("popup cmdline"), 0, Qt::CTRL + Qt::Key_Slash, SLOTS, SLOT(cmdlinePopup()), "cmdline popup"); NEW_KACTION(tmp, i18n("Start &Root Mode Krusader"), "krusader_root", Qt::ALT + Qt::SHIFT + Qt::Key_K, SLOTS, SLOT(rootKrusader()), "root krusader"); NEW_KACTION(actProfiles, i18n("Pro&files"), "user-identity", Qt::ALT + Qt::SHIFT + Qt::Key_L, MAIN_VIEW, SLOT(profiles()), "profile"); NEW_KACTION(actSplit, i18n("Sp&lit File..."), "split", Qt::CTRL + Qt::Key_P, SLOTS, SLOT(slotSplit()), "split"); NEW_KACTION(actCombine, i18n("Com&bine Files..."), "kr_combine", 0, SLOTS, SLOT(slotCombine()), "combine"); NEW_KACTION(actSelectNewerAndSingle, i18n("&Select Newer and Single"), 0, 0, SLOTS, SLOT(compareSetup()), "select_newer_and_single"); NEW_KACTION(actSelectNewer, i18n("Select &Newer"), 0, 0, SLOTS, SLOT(compareSetup()), "select_newer"); NEW_KACTION(actSelectSingle, i18n("Select &Single"), 0, 0, SLOTS, SLOT(compareSetup()), "select_single"); NEW_KACTION(actSelectDifferentAndSingle, i18n("Select Different &and Single"), 0, 0, SLOTS, SLOT(compareSetup()), "select_different_and_single"); NEW_KACTION(actSelectDifferent, i18n("Select &Different"), 0, 0, SLOTS, SLOT(compareSetup()), "select_different"); actSelectNewerAndSingle->setCheckable(true); actSelectNewer->setCheckable(true); actSelectSingle->setCheckable(true); actSelectDifferentAndSingle->setCheckable(true); actSelectDifferent->setCheckable(true); QActionGroup *selectGroup = new QActionGroup(krusaderApp); selectGroup->setExclusive(true); selectGroup->addAction(actSelectNewerAndSingle); selectGroup->addAction(actSelectNewer); selectGroup->addAction(actSelectSingle); selectGroup->addAction(actSelectDifferentAndSingle); selectGroup->addAction(actSelectDifferent); if (compareMode < (int)(sizeof(compareArray) / sizeof(QAction **)) - 1) (*compareArray[ compareMode ])->setChecked(true); NEW_KACTION(actExecStartAndForget, i18n("Start and &Forget"), 0, 0, SLOTS, SLOT(execTypeSetup()), "exec_start_and_forget"); NEW_KACTION(actExecCollectSeparate, i18n("Display &Separated Standard and Error Output"), 0, 0, SLOTS, SLOT(execTypeSetup()), "exec_collect_separate"); NEW_KACTION(actExecCollectTogether, i18n("Display &Mixed Standard and Error Output"), 0, 0, SLOTS, SLOT(execTypeSetup()), "exec_collect_together"); NEW_KACTION(actExecTerminalExternal, i18n("Start in &New Terminal"), 0, 0, SLOTS, SLOT(execTypeSetup()), "exec_terminal_external"); NEW_KACTION(actExecTerminalEmbedded, i18n("Send to &Embedded Terminal Emulator"), 0, 0, SLOTS, SLOT(execTypeSetup()), "exec_terminal_embedded"); actExecStartAndForget->setCheckable(true); actExecCollectSeparate->setCheckable(true); actExecCollectTogether->setCheckable(true); actExecTerminalExternal->setCheckable(true); actExecTerminalEmbedded->setCheckable(true); QActionGroup *actionGroup = new QActionGroup(krusaderApp); actionGroup->setExclusive(true); actionGroup->addAction(actExecStartAndForget); actionGroup->addAction(actExecCollectSeparate); actionGroup->addAction(actExecCollectTogether); actionGroup->addAction(actExecTerminalExternal); actionGroup->addAction(actExecTerminalEmbedded); if (cmdExecMode < (int)(sizeof(execTypeArray) / sizeof(QAction **)) - 1) (*execTypeArray[ cmdExecMode ])->setChecked(true); NEW_KACTION(actHomeTerminal, i18n("Start &Terminal"), "utilities-terminal", 0, SLOTS, SLOT(homeTerminal()), "terminal@home"); actMountMan = krMtMan.action(); krusaderApp->actionCollection()->addAction("mountman", actMountMan); krusaderApp->actionCollection()->setDefaultShortcut(actMountMan, Qt::ALT + Qt::Key_Slash); NEW_KACTION(actFind, i18n("&Search..."), "system-search", Qt::CTRL + Qt::Key_S, SLOTS, SLOT(search()), "find"); NEW_KACTION(actLocate, i18n("&Locate..."), "edit-find", Qt::SHIFT + Qt::CTRL + Qt::Key_L, SLOTS, SLOT(locate()), "locate"); #ifdef SYNCHRONIZER_ENABLED NEW_KACTION(actSyncDirs, i18n("Synchronize Fol&ders..."), "folder-sync", Qt::CTRL + Qt::Key_Y, SLOTS, SLOT(slotSynchronizeDirs()), "sync dirs"); #endif NEW_KACTION(actDiskUsage, i18n("D&isk Usage..."), "kr_diskusage", Qt::ALT + Qt::SHIFT + Qt::Key_S, SLOTS, SLOT(slotDiskUsage()), "disk usage"); NEW_KACTION(actKonfigurator, i18n("Configure &Krusader..."), "configure", 0, SLOTS, SLOT(startKonfigurator()), "konfigurator"); NEW_KACTION(actSavePosition, i18n("Save &Position"), 0, 0, krusaderApp, SLOT(savePosition()), "save position"); NEW_KACTION(actCompare, i18n("Compare b&y Content..."), "kr_comparedirs", 0, SLOTS, SLOT(compareContent()), "compare"); NEW_KACTION(actMultiRename, i18n("Multi &Rename..."), "edit-rename", Qt::SHIFT + Qt::Key_F2, SLOTS, SLOT(multiRename()), "multirename"); NEW_KACTION(actAddBookmark, i18n("Add Bookmark"), "bookmark-new", KStandardShortcut::addBookmark(), SLOTS, SLOT(addBookmark()), "add bookmark"); NEW_KACTION(actVerticalMode, i18n("Vertical Mode"), "view-split-top-bottom", Qt::ALT + Qt::CTRL + Qt::Key_R, MAIN_VIEW, SLOT(toggleVerticalMode()), "toggle vertical mode"); actUserMenu = new KActionMenu(i18n("User&actions"), krusaderApp); krusaderApp->actionCollection()->addAction("useractionmenu", actUserMenu); NEW_KACTION(actManageUseractions, i18n("Manage User Actions..."), 0, 0, SLOTS, SLOT(manageUseractions()), "manage useractions"); actRemoteEncoding = new KrRemoteEncodingMenu(i18n("Select Remote Charset"), "character-set", krusaderApp->actionCollection()); NEW_KACTION(actF10Quit, i18n("Quit"), 0, Qt::Key_F10, krusaderApp, SLOT(quit()) , "F10_Quit"); actF10Quit->setToolTip(i18n("Quit Krusader.")); NEW_KACTION(actPopularUrls, i18n("Popular URLs..."), 0, Qt::CTRL + Qt::Key_Z, krusaderApp->popularUrls(), SLOT(showDialog()), "Popular_Urls"); NEW_KACTION(actSwitchFullScreenTE, i18n("Toggle Fullscreen Embedded Terminal"), 0, Qt::CTRL + Qt::ALT + Qt::Key_F, MAIN_VIEW, SLOT(toggleFullScreenTerminalEmulator()), "switch_fullscreen_te"); NEW_KACTION(tmp, i18n("Move Focus Up"), 0, Qt::CTRL + Qt::SHIFT + Qt::Key_Up, MAIN_VIEW, SLOT(focusUp()), "move_focus_up"); NEW_KACTION(tmp, i18n("Move Focus Down"), 0, Qt::CTRL + Qt::SHIFT + Qt::Key_Down, MAIN_VIEW, SLOT(focusDown()), "move_focus_down"); // job manager actions actJobControl = krJobMan->controlAction(); krusaderApp->actionCollection()->addAction("job control", actJobControl); krusaderApp->actionCollection()->setDefaultShortcut(actJobControl, Qt::CTRL + Qt::ALT + Qt::Key_P); actJobProgress = krJobMan->progressAction(); krusaderApp->actionCollection()->addAction("job progress", actJobProgress); actJobMode = krJobMan->modeAction(); krusaderApp->actionCollection()->addAction("job mode", actJobMode); actJobUndo = krJobMan->undoAction(); krusaderApp->actionCollection()->addAction("job undo", actJobUndo); krusaderApp->actionCollection()->setDefaultShortcut(actJobUndo, Qt::CTRL + Qt::ALT + Qt::Key_Z); // and at last we can set the tool-tips actKonfigurator->setToolTip(i18n("Setup Krusader the way you like it")); actFind->setToolTip(i18n("Search for files")); // setup all UserActions krUserAction = new UserAction(); #ifdef __KJSEMBED__ actShowJSConsole = new QAction(i18n("JavaScript Console..."), Qt::ALT + Qt::CTRL + Qt::Key_J, SLOTS, SLOT(jsConsole()), krusaderApp->actionCollection(), "JS_Console"); #endif } diff --git a/krusader/krglobal.cpp b/krusader/krglobal.cpp index 8048c1b2..6b49fbbf 100644 --- a/krusader/krglobal.cpp +++ b/krusader/krglobal.cpp @@ -1,63 +1,62 @@ /***************************************************************************** * Copyright (C) 2000 Shie Erlich * * 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 "krglobal.h" #include "krusader.h" #include "krusaderview.h" // QtCore #include #include KConfig *KrGlobal::config = 0; KMountMan *KrGlobal::mountMan = 0; KrBookmarkHandler *KrGlobal::bookman = 0; KRslots* KrGlobal::slot = 0; -KIconLoader *KrGlobal::iconLoader = 0; KrusaderView *KrGlobal::mainView = 0; QWidget *KrGlobal::mainWindow = 0; UserAction *KrGlobal::userAction = 0; JobMan *KrGlobal::jobMan = 0; // ListPanel *KrGlobal::activePanel = 0; QKeySequence KrGlobal::copyShortcut; const int KrGlobal::sConfigVersion; int KrGlobal::sCurrentConfigVersion; KrPanel *KrGlobal::activePanel() { return mainView->activePanel(); } // void KrGlobal::enableAction(const char *name, bool enable) // { // getAction(name)->setEnabled(enable); // } // // QAction* KrGlobal::getAction(const char *name) // { // QAction *act = krApp->actionCollection()->action(name); // if(!act) // qFatal("no such action: %s", name); // return act; // } diff --git a/krusader/krglobal.h b/krusader/krglobal.h index fad27e60..2bfa2c80 100644 --- a/krusader/krglobal.h +++ b/krusader/krglobal.h @@ -1,96 +1,93 @@ /***************************************************************************** * Copyright (C) 2000 Shie Erlich * * 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/]. * *****************************************************************************/ #ifndef KRGLOBAL_H #define KRGLOBAL_H // QtGui #include #include class KConfig; class KMountMan; class KrBookmarkHandler; class KRslots; -class KIconLoader; class KrusaderView; class UserAction; class JobMan; class QWidget; class KrPanel; // global references to frequently used objects class KrGlobal { public: static KConfig *config; // allow everyone to access the config static KMountMan *mountMan; // krusader's Mount Manager static KrBookmarkHandler *bookman; static KRslots *slot; - static KIconLoader *iconLoader; // the app's icon loader static KrusaderView *mainView; // The GUI static QWidget *mainWindow; static UserAction *userAction; static JobMan *jobMan; // static ListPanel *activePanel; static KrPanel *activePanel(); //HACK - used by [ListerTextArea|KrSearchDialog|LocateDlg]:keyPressEvent() static QKeySequence copyShortcut; // static void enableAction(const char *name, bool enable); // static QAction *getAction(const char *name); /** Version of saved configuration. Use this to detect configuration updates. */ static const int sConfigVersion = 1; static int sCurrentConfigVersion; }; #define krConfig KrGlobal::config #define krMtMan (*(KrGlobal::mountMan)) #define krBookMan KrGlobal::bookman #define SLOTS KrGlobal::slot -#define krLoader KrGlobal::iconLoader #define MAIN_VIEW KrGlobal::mainView #define krMainWindow KrGlobal::mainWindow #define krUserAction KrGlobal::userAction #define krJobMan KrGlobal::jobMan #define ACTIVE_PANEL (KrGlobal::activePanel()) #define ACTIVE_MNG (MAIN_VIEW->activeManager()) #define ACTIVE_FUNC (ACTIVE_PANEL->func) #define OTHER_MNG (MAIN_VIEW->inactiveManager()) #define OTHER_PANEL (ACTIVE_PANEL->otherPanel()) #define OTHER_FUNC (OTHER_PANEL->func) #define LEFT_PANEL (MAIN_VIEW->leftPanel()) #define LEFT_FUNC (LEFT_PANEL->func) #define LEFT_MNG (MAIN_VIEW->leftManager()) #define RIGHT_PANEL (MAIN_VIEW->rightPanel()) #define RIGHT_FUNC (RIGHT_PANEL->func) #define RIGHT_MNG (MAIN_VIEW->rightManager()) // #define krEnableAction(name, enable) (KrGlobal::enableAction(#name, (enable))) // #define krGetAction(name) (KrGlobal::getAction(#name)) #endif diff --git a/krusader/krslots.cpp b/krusader/krslots.cpp index b561144f..66a0a3e7 100644 --- a/krusader/krslots.cpp +++ b/krusader/krslots.cpp @@ -1,747 +1,747 @@ /***************************************************************************** * Copyright (C) 2001 Shie Erlich * * Copyright (C) 2001 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 "krslots.h" // QtCore #include #include #include #include #include #include // QtGui #include #include // QtWidgets #include #include #include #include -#include #include #include #ifdef __KJSEMBED__ #include #include "KrJS/krjs.h" #endif #include "defaults.h" +#include "icon.h" #include "kractions.h" #include "krservices.h" #include "krtrashhandler.h" #include "krusader.h" #include "krusaderview.h" #include "panelmanager.h" #include "ActionMan/actionman.h" #include "BookMan/krbookmarkbutton.h" #include "BookMan/krbookmarkhandler.h" #include "Dialogs/krdialogs.h" #include "Dialogs/krspecialwidgets.h" #include "Dialogs/krspwidgets.h" #include "DiskUsage/diskusagegui.h" #include "FileSystem/fileitem.h" #include "FileSystem/filesystem.h" #include "FileSystem/krquery.h" #include "GUI/dirhistorybutton.h" #include "GUI/kcmdline.h" #include "GUI/kfnkeys.h" #include "GUI/krusaderstatus.h" #include "GUI/mediabutton.h" #include "GUI/terminaldock.h" #include "KViewer/krviewer.h" #include "Konfigurator/konfigurator.h" #include "Locate/locate.h" #include "MountMan/kmountman.h" #include "Panel/PanelView/krselectionmode.h" #include "Panel/PanelView/krview.h" #include "Panel/PanelView/krviewfactory.h" #include "Panel/PanelView/krviewitem.h" #include "Panel/listpanel.h" #include "Panel/panelfunc.h" #include "Panel/sidebar.h" #include "Search/krsearchdialog.h" #include "Search/krsearchmod.h" #include "Splitter/combiner.h" #include "Splitter/splitter.h" #include "Splitter/splittergui.h" #ifdef SYNCHRONIZER_ENABLED #include "Synchronizer/synchronizergui.h" #endif #define ACTIVE_VIEW _mainWindow->activeView() KRslots::KRslots(QObject *parent) : QObject(parent), _mainWindow(krApp) { } void KRslots::sendFileByEmail(const QList &urls) { if (urls.count() == 0) { KMessageBox::error(0, i18n("No selected files to send.")); return; } QString mailProg; QStringList lst = KrServices::supportedTools(); if (lst.contains("MAIL")) mailProg = lst[lst.indexOf("MAIL") + 1]; else { KMessageBox::error(0, i18n("Krusader cannot find a supported mail client. Please install one to your path. Hint: Krusader supports KMail.")); return; } QString subject, separator; foreach(const QUrl &url, urls) { subject += separator + url.fileName(); separator = ','; } subject = i18np("Sending file: %2", "Sending files: %2", urls.count(), subject); KProcess proc; QString executable = QUrl::fromLocalFile(mailProg).fileName(); if (executable == QStringLiteral("kmail")) { proc << mailProg << "--subject" << subject; foreach(const QUrl &url2, urls) proc << "--attach" << url2.toDisplayString(); } else if (executable == QStringLiteral("thunderbird")) { QString param = "attachment=\'"; separator = ""; foreach(const QUrl &url2, urls) { param += separator + url2.toDisplayString(); separator = ','; } param += "\',subject=\'" + subject + "\'"; proc << mailProg << "--compose" << param; } else if (executable == QStringLiteral("evolution")) { QString param = "mailto:?cc=&subject=" + subject + "&attach="; separator = ""; foreach(const QUrl &url2, urls) { param += separator + url2.toDisplayString(); separator = "&attach="; } proc << mailProg << param + ""; } if (!proc.startDetached()) KMessageBox::error(0, i18n("Error executing %1.", mailProg)); } void KRslots::compareContent() { const QStringList lstLeft = LEFT_PANEL->getSelectedNames(); const QStringList lstRight = RIGHT_PANEL->getSelectedNames(); const QStringList lstActive = ACTIVE_PANEL->gui->isLeft() ? lstLeft : lstRight; QUrl name1, name2; if (lstLeft.count() == 1 && lstRight.count() == 1) { // first, see if we've got exactly 1 selected file in each panel: name1 = LEFT_PANEL->func->files()->getUrl(lstLeft[0]); name2 = RIGHT_PANEL->func->files()->getUrl(lstRight[0]); } else if (lstActive.count() == 2) { // next try: are in the current panel exacty 2 files selected? name1 = ACTIVE_PANEL->func->files()->getUrl(lstActive[0]); name2 = ACTIVE_PANEL->func->files()->getUrl(lstActive[1]); } else if (ACTIVE_PANEL->otherPanel()->func->files()->getFileItem(ACTIVE_VIEW->getCurrentItem())) { // next try: is in the other panel a file with the same name? name1 = ACTIVE_PANEL->func->files()->getUrl(ACTIVE_VIEW->getCurrentItem()); name2 = ACTIVE_PANEL->otherPanel()->func->files()->getUrl(ACTIVE_VIEW->getCurrentItem()); } else { // if we got here, then we can't be sure what file to diff KMessageBox::detailedError(0, i18n("Do not know which files to compare."), "" + i18n("To compare two files by content, you can either:
  • Select one file in the left panel, and one in the right panel.
  • Select exactly two files in the active panel.
  • Make sure there is a file in the other panel, with the same name as the current file in the active panel.
") + "
"); return; } // else implied: all ok, let's call an external program to compare files // but if any of the files isn't local, download it first compareContent(name1, name2); } bool downloadToTemp(const QUrl &url, QString &dest) { QTemporaryFile tmpFile; tmpFile.setAutoRemove(false); if (tmpFile.open()) { dest = tmpFile.fileName(); KIO::Job* job = KIO::file_copy(url, QUrl::fromLocalFile(dest), -1, KIO::Overwrite | KIO::HideProgressInfo); if(!job->exec()) { KMessageBox::error(krApp, i18n("Krusader is unable to download %1", url.fileName())); return false; } return true; } return false; } void KRslots::compareContent(QUrl url1, QUrl url2) { QString diffProg; QStringList lst = KrServices::supportedTools(); if (lst.contains("DIFF")) diffProg = lst[lst.indexOf("DIFF") + 1]; else { KMessageBox::error(0, i18n("Krusader cannot find any of the supported diff-frontends. Please install one to your path. Hint: Krusader supports Kompare, KDiff3 and Xxdiff.")); return; } QString tmp1; QString tmp2; // kdiff3 sucks with spaces if (QUrl::fromLocalFile(diffProg).fileName() == "kdiff3" && !url1.toDisplayString().contains(" ") && !url2.toDisplayString().contains(" ")) { tmp1 = url1.toDisplayString(); tmp2 = url2.toDisplayString(); } else { if (!url1.isLocalFile()) { if (!downloadToTemp(url1, tmp1)) { return; } } else tmp1 = url1.path(); if (!url2.isLocalFile()) { if (!downloadToTemp(url2, tmp2)) { if (tmp1 != url1.path()) QFile::remove(tmp1); return; } } else tmp2 = url2.path(); } KrProcess *p = new KrProcess(tmp1 != url1.path() ? tmp1 : QString(), tmp2 != url2.path() ? tmp2 : QString()); *p << diffProg << tmp1 << tmp2; p->start(); if (!p->waitForStarted()) KMessageBox::error(0, i18n("Error executing %1.", diffProg)); } // GUI toggle slots void KRslots::toggleFnkeys() { if (MAIN_VIEW->fnKeys()->isVisible()) MAIN_VIEW->fnKeys()->hide(); else MAIN_VIEW->fnKeys()->show(); } void KRslots::toggleCmdline() { if (MAIN_VIEW->cmdLine()->isVisible()) MAIN_VIEW->cmdLine()->hide(); else MAIN_VIEW->cmdLine()->show(); } void KRslots::updateStatusbarVisibility() { krApp->statusBar()->setVisible(KrActions::actShowStatusBar->isChecked()); } void KRslots::toggleTerminal() { MAIN_VIEW->setTerminalEmulator(KrActions::actToggleTerminal->isChecked()); } void KRslots::insertFileName(bool fullPath) { QString filename = ACTIVE_VIEW->getCurrentItem(); if (filename.isEmpty()) { return; } if (fullPath) { const QString path = FileSystem::ensureTrailingSlash(ACTIVE_PANEL->virtualPath()) .toDisplayString(QUrl::PreferLocalFile); filename = path + filename; } filename = KrServices::quote(filename); if (MAIN_VIEW->cmdLine()->isVisible() || !MAIN_VIEW->terminalDock()->isTerminalVisible()) { QString current = MAIN_VIEW->cmdLine()->text(); if (current.length() != 0 && !current.endsWith(' ')) current += ' '; MAIN_VIEW->cmdLine()->setText(current + filename); MAIN_VIEW->cmdLine()->setFocus(); } else if (MAIN_VIEW->terminalDock()->isTerminalVisible()) { filename = ' ' + filename + ' '; MAIN_VIEW->terminalDock()->sendInput(filename, false); MAIN_VIEW->terminalDock()->setFocus(); } } void KRslots::refresh(const QUrl &u) { ACTIVE_FUNC->openUrl(u); } void KRslots::runKonfigurator(bool firstTime) { Konfigurator *konfigurator = new Konfigurator(firstTime); connect(konfigurator, SIGNAL(configChanged(bool)), SLOT(configChanged(bool))); //FIXME - no need to exec konfigurator->exec(); delete konfigurator; } void KRslots::configChanged(bool isGUIRestartNeeded) { krConfig->sync(); if (isGUIRestartNeeded) { krApp->setUpdatesEnabled(false); KConfigGroup group(krConfig, "Look&Feel"); FileItem::loadUserDefinedFolderIcons(group.readEntry("Load User Defined Folder Icons", _UserDefinedFolderIcons)); bool leftActive = ACTIVE_PANEL->gui->isLeft(); MAIN_VIEW->leftManager()->slotRecreatePanels(); MAIN_VIEW->rightManager()->slotRecreatePanels(); if(leftActive) LEFT_PANEL->slotFocusOnMe(); else RIGHT_PANEL->slotFocusOnMe(); MAIN_VIEW->fnKeys()->updateShortcuts(); KrSelectionMode::resetSelectionHandler(); krApp->setUpdatesEnabled(true); } krApp->setTray(); // really ugly, but reload the Fn keys just in case - csaba: any better idea? MAIN_VIEW->fnKeys()->updateShortcuts(); const bool showHidden = KConfigGroup(krConfig, "Look&Feel") .readEntry("Show Hidden", KrActions::actToggleHidden->isChecked()); if (showHidden != KrActions::actToggleHidden->isChecked()) { KrActions::actToggleHidden->setChecked(showHidden); MAIN_VIEW->leftManager()->reloadConfig(); MAIN_VIEW->rightManager()->reloadConfig(); } } void KRslots::showHiddenFiles(bool show) { KConfigGroup group(krConfig, "Look&Feel"); group.writeEntry("Show Hidden", show); MAIN_VIEW->leftManager()->reloadConfig(); MAIN_VIEW->rightManager()->reloadConfig(); } void KRslots::swapPanels() { QUrl leftURL = LEFT_PANEL->virtualPath(); QUrl rightURL = RIGHT_PANEL->virtualPath(); LEFT_PANEL->func->openUrl(rightURL); RIGHT_PANEL->func->openUrl(leftURL); } void KRslots::toggleSwapSides() { MAIN_VIEW->swapSides(); } void KRslots::search() { if (KrSearchDialog::SearchDialog != 0) { KConfigGroup group(krConfig, "Search"); if (group.readEntry("Window Maximized", false)) KrSearchDialog::SearchDialog->showMaximized(); else KrSearchDialog::SearchDialog->showNormal(); KrSearchDialog::SearchDialog->raise(); KrSearchDialog::SearchDialog->activateWindow(); } else KrSearchDialog::SearchDialog = new KrSearchDialog(); } void KRslots::locate() { if (!KrServices::cmdExist("locate")) { KMessageBox::error(krApp, i18n("Cannot find the 'locate' command. Please install the " "findutils-locate package of GNU, or set its dependencies in " "Konfigurator")); return; } if (LocateDlg::LocateDialog != 0) { LocateDlg::LocateDialog->showNormal(); LocateDlg::LocateDialog->raise(); LocateDlg::LocateDialog->activateWindow(); LocateDlg::LocateDialog->reset(); } else LocateDlg::LocateDialog = new LocateDlg(); } void KRslots::runTerminal(const QString & dir) { KProcess proc; proc.setWorkingDirectory(dir); KConfigGroup group(krConfig, "General"); QString term = group.readEntry("Terminal", _Terminal); QStringList sepdArgs = KShell::splitArgs(term, KShell::TildeExpand); if (sepdArgs.isEmpty()) { KMessageBox::error(krMainWindow, i18nc("Arg is a string containing the bad quoting.", "Bad quoting in terminal command:\n%1", term)); return; } for (int i = 0; i < sepdArgs.size(); i++) { if (sepdArgs[i] == "%d") { sepdArgs[i] = dir; } } proc << sepdArgs; if (!proc.startDetached()) KMessageBox::sorry(krApp, i18n("Error executing %1.", term)); } void KRslots::homeTerminal() { runTerminal(QDir::homePath()); } void KRslots::multiRename() { QStringList lst = KrServices::supportedTools(); int i = lst.indexOf("RENAME"); if (i == -1) { KMessageBox::sorry(krApp, i18n("Cannot find a batch rename tool.\nYou can get KRename at http://www.krename.net")); return; } QString pathToRename = lst[i+1]; const QStringList names = ACTIVE_PANEL->gui->getSelectedNames(); if (names.isEmpty()) { return; } KProcess proc; proc << pathToRename; for (const QString name: names) { FileItem *file = ACTIVE_FUNC->files()->getFileItem(name); if (!file) continue; const QUrl url = file->getUrl(); // KRename only supports the recursive option combined with a local directory path if (file->isDir() && url.scheme() == "file") { proc << "-r" << url.path(); } else { proc << url.toString(); } } if (!proc.startDetached()) KMessageBox::error(0, i18n("Error executing '%1'.", proc.program().join(" "))); } void KRslots::rootKrusader() { if (KMessageBox::warningContinueCancel( krApp, i18n("Improper operations in root mode can damage your operating system. " "

Furthermore, running UI applications as root is insecure and can " "allow attackers to gain root access."), QString(), KStandardGuiItem::cont(), KStandardGuiItem::cancel(), "Confirm Root Mode", KMessageBox::Notify | KMessageBox::Dangerous) != KMessageBox::Continue) return; if (!KrServices::isExecutable(KDESU_PATH)) { KMessageBox::sorry(krApp, i18n("Cannot start root mode Krusader, %1 not found or not executable. " "Please verify that kde-cli-tools are installed.", QString(KDESU_PATH))); return; } KProcess proc; proc << KDESU_PATH << "-c" << QApplication::instance()->applicationFilePath() + " --left=" + KrServices::quote(LEFT_PANEL->virtualPath().toDisplayString(QUrl::PreferLocalFile)) + " --right=" + KrServices::quote(RIGHT_PANEL->virtualPath().toDisplayString(QUrl::PreferLocalFile)); if (!proc.startDetached()) KMessageBox::error(0, i18n("Error executing %1.", proc.program()[0])); } void KRslots::slotSplit() { const QStringList list = ACTIVE_PANEL->gui->getSelectedNames(); QString name; // first, see if we've got exactly 1 selected file, if not, try the current one if (list.count() == 1) name = list[0]; if (name.isEmpty()) { // if we got here, then one of the panel can't be sure what file to diff KMessageBox::error(0, i18n("Do not know which file to split.")); return; } QUrl fileURL = ACTIVE_FUNC->files()->getUrl(name); if (fileURL.isEmpty()) return; if (ACTIVE_FUNC->files()->getFileItem(name)->isDir()) { KMessageBox::sorry(krApp, i18n("You cannot split a folder.")); return; } const QUrl destDir = ACTIVE_PANEL->otherPanel()->virtualPath(); SplitterGUI splitterGUI(MAIN_VIEW, fileURL, destDir); if (splitterGUI.exec() == QDialog::Accepted) { bool splitToOtherPanel = splitterGUI.getDestinationDir().matches(ACTIVE_PANEL->otherPanel()->virtualPath(), QUrl::StripTrailingSlash); Splitter split(MAIN_VIEW, fileURL, splitterGUI.getDestinationDir(), splitterGUI.overWriteFiles()); split.split(splitterGUI.getSplitSize()); if (splitToOtherPanel) ACTIVE_PANEL->otherPanel()->func->refresh(); } } void KRslots::slotCombine() { const QStringList list = ACTIVE_PANEL->gui->getSelectedNames(); if (list.isEmpty()) { KMessageBox::error(0, i18n("Do not know which files to combine.")); return; } QUrl baseURL; bool unixStyle = false; bool windowsStyle = false; QString commonName; int commonLength = 0; /* checking splitter names */ for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) { QUrl url = ACTIVE_FUNC->files()->getUrl(*it); if (url.isEmpty()) return; if (ACTIVE_FUNC->files()->getFileItem(*it)->isDir()) { KMessageBox::sorry(krApp, i18n("You cannot combine a folder.")); return; } if (!unixStyle) { QString name = url.fileName(); int extPos = name.lastIndexOf('.'); QString ext = name.mid(extPos + 1); name.truncate(extPos); url = url.adjusted(QUrl::RemoveFilename); url.setPath(url.path() + name); bool isExtInt; ext.toInt(&isExtInt, 10); if (extPos < 1 || ext.isEmpty() || (ext != "crc" && !isExtInt)) { if (windowsStyle) { KMessageBox::error(0, i18n("Not a split file: %1.", url.toDisplayString(QUrl::PreferLocalFile))); return; } unixStyle = true; } else { if (ext != "crc") windowsStyle = true; if (baseURL.isEmpty()) baseURL = url; else if (baseURL != url) { KMessageBox::error(0, i18n("Select only one split file.")); return; } } } if (unixStyle) { bool error = true; do { QString shortName = *it; QChar lastChar = shortName.at(shortName.length() - 1); if (lastChar.isLetter()) { char fillLetter = (lastChar.toUpper() == lastChar) ? 'A' : 'a'; if (commonName.isNull()) { commonLength = shortName.length(); commonName = shortName; while (commonName.length()) { QString shorter = commonName.left(commonName.length() - 1); QString testFile = shorter.leftJustified(commonLength, fillLetter); if (ACTIVE_FUNC->files()->getFileItem(testFile) == 0) break; else { commonName = shorter; baseURL = ACTIVE_PANEL->virtualPath().adjusted(QUrl::StripTrailingSlash); baseURL.setPath(baseURL.path() + '/' + (testFile)); } } error = (commonName == shortName); } else if (commonLength == shortName.length() && shortName.startsWith(commonName)) error = false; } } while (false); if (error) { KMessageBox::error(0, i18n("Not a split file: %1.", url.toDisplayString(QUrl::PreferLocalFile))); return; } } } // ask the user for the copy dest QUrl dest = KChooseDir::getDir(i18n("Combining %1.* to folder:", baseURL.toDisplayString(QUrl::PreferLocalFile)), ACTIVE_PANEL->otherPanel()->virtualPath(), ACTIVE_PANEL->virtualPath()); if (dest.isEmpty()) return ; // the user canceled bool combineToOtherPanel = (dest.matches(ACTIVE_PANEL->otherPanel()->virtualPath(), QUrl::StripTrailingSlash)); Combiner combine(MAIN_VIEW, baseURL, dest, unixStyle); combine.combine(); if (combineToOtherPanel) ACTIVE_PANEL->otherPanel()->func->refresh(); } void KRslots::manageUseractions() { ActionMan actionMan(MAIN_VIEW); } #ifdef SYNCHRONIZER_ENABLED void KRslots::slotSynchronizeDirs(QStringList selected) { SynchronizerGUI *synchronizerDialog = new SynchronizerGUI(MAIN_VIEW, LEFT_PANEL->virtualPath(), RIGHT_PANEL->virtualPath(), selected); synchronizerDialog->show(); // destroyed on close } #endif void KRslots::compareSetup() { for (int i = 0; KrActions::compareArray[i] != 0; i++) if ((*KrActions::compareArray[i])->isChecked()) { KConfigGroup group(krConfig, "Private"); group.writeEntry("Compare Mode", i); break; } } /** called by actions actExec* to choose the built-in command line mode */ void KRslots::execTypeSetup() { for (int i = 0; KrActions::execTypeArray[i] != 0; i++) if ((*KrActions::execTypeArray[i])->isChecked()) { if (*KrActions::execTypeArray[i] == KrActions::actExecTerminalEmbedded) { // if commands are to be executed in the TE, it must be loaded MAIN_VIEW->terminalDock()->initialise(); } KConfigGroup grp(krConfig, "Private"); grp.writeEntry("Command Execution Mode", i); break; } } void KRslots::slotDiskUsage() { DiskUsageGUI *diskUsageDialog = new DiskUsageGUI(ACTIVE_PANEL->virtualPath()); diskUsageDialog->askDirAndShow(); } void KRslots::applicationStateChanged() { if (MAIN_VIEW == 0) { /* CRASH FIX: it's possible that the method is called after destroying the main view */ return; } if(qApp->applicationState() == Qt::ApplicationActive || qApp->applicationState() == Qt::ApplicationInactive) { LEFT_PANEL->panelVisible(); RIGHT_PANEL->panelVisible(); } else { LEFT_PANEL->panelHidden(); RIGHT_PANEL->panelHidden(); } } void KRslots::emptyTrash() { KrTrashHandler::emptyTrash(); } #define OPEN_ID 100001 #define EMPTY_TRASH_ID 100002 void KRslots::trashPopupMenu() { QMenu trashMenu(krApp); - QAction * act = trashMenu.addAction(krLoader->loadIcon("document-open", KIconLoader::Panel), i18n("Open trash bin")); + QAction * act = trashMenu.addAction(Icon("document-open"), i18n("Open trash bin")); act->setData(QVariant(OPEN_ID)); - act = trashMenu.addAction(krLoader->loadIcon("trash-empty", KIconLoader::Panel), i18n("Empty trash bin")); + act = trashMenu.addAction(Icon("trash-empty"), i18n("Empty trash bin")); act->setData(QVariant(EMPTY_TRASH_ID)); int result = -1; QAction *res = trashMenu.exec(QCursor::pos()); if (res && res->data().canConvert ()) result = res->data().toInt(); if (result == OPEN_ID) { ACTIVE_FUNC->openUrl(QUrl(QStringLiteral("trash:/"))); } else if (result == EMPTY_TRASH_ID) { KrTrashHandler::emptyTrash(); } } //shows the JavaScript-Console void KRslots::jsConsole() { #ifdef __KJSEMBED__ if (! krJS) krJS = new KrJS(); krJS->view()->show(); #endif } void KRslots::addBookmark() { krBookMan->bookmarkCurrent(ACTIVE_PANEL->virtualPath()); } void KRslots::cmdlinePopup() { MAIN_VIEW->cmdLine()->popup(); } diff --git a/krusader/krusader.cpp b/krusader/krusader.cpp index bd116061..eeed2416 100644 --- a/krusader/krusader.cpp +++ b/krusader/krusader.cpp @@ -1,645 +1,639 @@ /***************************************************************************** * Copyright (C) 2000 Shie Erlich * * 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 "krusader.h" // QtCore #include #include #include #include // QtGui #include #include // QtWidgets #include #include #include // QtDBus #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include #include "defaults.h" -#include "kicons.h" #include "kractions.h" #include "krglobal.h" #include "krservices.h" #include "krslots.h" #include "krtrashhandler.h" #include "krusaderversion.h" #include "krusaderview.h" #include "panelmanager.h" #include "tabactions.h" #include "BookMan/krbookmarkhandler.h" #include "Dialogs/checksumdlg.h" #include "Dialogs/krpleasewait.h" #include "Dialogs/popularurls.h" #include "FileSystem/fileitem.h" #include "FileSystem/krpermhandler.h" #include "GUI/kcmdline.h" #include "GUI/kfnkeys.h" #include "GUI/krremoteencodingmenu.h" #include "GUI/krusaderstatus.h" #include "GUI/terminaldock.h" #include "JobMan/jobman.h" #include "KViewer/krviewer.h" #include "Konfigurator/kgprotocols.h" #include "MountMan/kmountman.h" #include "Panel/PanelView/krview.h" #include "Panel/PanelView/krviewfactory.h" #include "Panel/krcolorcache.h" #include "Panel/krpanel.h" #include "Panel/listpanelactions.h" #include "Panel/viewactions.h" #include "UserAction/expander.h" // This makes gcc-4.1 happy. Warning about possible problem with KrAction's dtor not called #include "UserAction/kraction.h" #include "UserAction/useraction.h" #ifdef __KJSEMBED__ #include "KrJS/krjs.h" #endif // define the static members Krusader *Krusader::App = 0; QString Krusader::AppName; // KrBookmarkHandler *Krusader::bookman = 0; //QTextOStream *Krusader::_krOut = QTextOStream(::stdout); #ifdef __KJSEMBED__ KrJS *Krusader::js = 0; QAction *Krusader::actShowJSConsole = 0; #endif // construct the views, statusbar and menu bars and prepare Krusader to start Krusader::Krusader(const QCommandLineParser &parser) : KParts::MainWindow(0, Qt::Window | Qt::WindowTitleHint | Qt::WindowContextHelpButtonHint), _listPanelActions(0), isStarting(true), isExiting(false), _quit(false) { // create the "krusader" App = this; krMainWindow = this; SLOTS = new KRslots(this); setXMLFile("krusaderui.rc"); // kpart-related xml file plzWait = new KRPleaseWaitHandler(this); const bool runKonfig = versionControl(); QString message; switch (krConfig->accessMode()) { case KConfigBase::NoAccess : message = "Krusader's configuration file can't be found. Default values will be used."; break; case KConfigBase::ReadOnly : message = "Krusader's configuration file is in READ ONLY mode (why is that!?) Changed values will not be saved"; break; case KConfigBase::ReadWrite : message = ""; break; } if (!message.isEmpty()) { KMessageBox::error(krApp, message); } - // create an icon loader - krLoader = KIconLoader::global(); -// iconLoader->addExtraDesktopThemes(); - // create MountMan KrGlobal::mountMan = new KMountMan(this); connect(KrGlobal::mountMan, SIGNAL(refreshPanel(QUrl)), SLOTS, SLOT(refresh(QUrl))); // create popular URLs container _popularUrls = new PopularUrls(this); // create bookman krBookMan = new KrBookmarkHandler(this); // create job manager krJobMan = new JobMan(this); // create the main view MAIN_VIEW = new KrusaderView(this); // setup all the krusader's actions setupActions(); // init the permission handler class KRpermHandler::init(); // init the protocol handler KgProtocols::init(); const KConfigGroup lookFeelGroup(krConfig, "Look&Feel"); FileItem::loadUserDefinedFolderIcons(lookFeelGroup.readEntry("Load User Defined Folder Icons", _UserDefinedFolderIcons)); const KConfigGroup startupGroup(krConfig, "Startup"); QString startProfile = startupGroup.readEntry("Starter Profile Name", QString()); QList leftTabs; QList rightTabs; // get command-line arguments if (parser.isSet("left")) { leftTabs = KrServices::toUrlList(parser.value("left").split(',')); startProfile.clear(); } if (parser.isSet("right")) { rightTabs = KrServices::toUrlList(parser.value("right").split(',')); startProfile.clear(); } if (parser.isSet("profile")) startProfile = parser.value("profile"); if (!startProfile.isEmpty()) { leftTabs.clear(); rightTabs.clear(); } // starting the panels MAIN_VIEW->start(startupGroup, startProfile.isEmpty(), leftTabs, rightTabs); // create a status bar KrusaderStatus *status = new KrusaderStatus(this); setStatusBar(status); status->setWhatsThis(i18n("Statusbar will show basic information " "about file below mouse pointer.")); // create tray icon (if needed) const bool startToTray = startupGroup.readEntry("Start To Tray", _StartToTray); setTray(startToTray); setCentralWidget(MAIN_VIEW); // manage our keyboard short-cuts //KAcceleratorManager::manage(this,true); setCursor(Qt::ArrowCursor); if (! startProfile.isEmpty()) MAIN_VIEW->profiles(startProfile); // restore gui settings { // now, check if we need to create a konsole_part // call the XML GUI function to draw the UI createGUI(MAIN_VIEW->terminalDock()->part()); // this needs to be called AFTER createGUI() !!! updateUserActions(); _listPanelActions->guiUpdated(); // not using this. See savePosition() //applyMainWindowSettings(); const KConfigGroup cfgToolbar(krConfig, "Main Toolbar"); toolBar()->applySettings(cfgToolbar); const KConfigGroup cfgJobBar(krConfig, "Job Toolbar"); toolBar("jobToolBar")->applySettings(cfgJobBar); const KConfigGroup cfgActionsBar(krConfig, "Actions Toolbar"); toolBar("actionsToolBar")->applySettings(cfgActionsBar); // restore toolbars position and visibility restoreState(startupGroup.readEntry("State", QByteArray())); statusBar()->setVisible(startupGroup.readEntry("Show status bar", _ShowStatusBar)); MAIN_VIEW->updateGUI(startupGroup); // popular urls _popularUrls->load(); } if (runKonfig) SLOTS->runKonfigurator(true); KConfigGroup viewerModuleGrp(krConfig, "ViewerModule"); if (viewerModuleGrp.readEntry("FirstRun", true)) { KrViewer::configureDeps(); viewerModuleGrp.writeEntry("FirstRun", false); } if (!runKonfig) { KConfigGroup cfg(krConfig, "Private"); move(cfg.readEntry("Start Position", _StartPosition)); resize(cfg.readEntry("Start Size", _StartSize)); } // view initialized; show window or only tray if (!startToTray) { show(); } KrTrashHandler::startWatcher(); isStarting = false; //HACK - used by [ListerTextArea|KrSearchDialog|LocateDlg]:keyPressEvent() KrGlobal::copyShortcut = _listPanelActions->actCopy->shortcut(); //HACK: make sure the active view becomes focused // for some reason sometimes the active view cannot be focused immediately at this point, // so queue it for the main loop QTimer::singleShot(0, ACTIVE_PANEL->view->widget(), SLOT(setFocus())); _openUrlTimer.setSingleShot(true); connect(&_openUrlTimer, SIGNAL(timeout()), SLOT(doOpenUrl())); KStartupInfo *startupInfo = new KStartupInfo(0, this); connect(startupInfo, &KStartupInfo::gotNewStartup, this, &Krusader::slotGotNewStartup); connect(startupInfo, &KStartupInfo::gotRemoveStartup, this, &Krusader::slotGotRemoveStartup); } Krusader::~Krusader() { KrTrashHandler::stopWatcher(); if (!isExiting) // save the settings if it was not saved (SIGTERM received) saveSettings(); delete MAIN_VIEW; MAIN_VIEW = 0; App = 0; } void Krusader::setTray(bool forceCreation) { const bool trayIsNeeded = forceCreation || KConfigGroup(krConfig, "Look&Feel") .readEntry("Minimize To Tray", _ShowTrayIcon); if (!sysTray && trayIsNeeded) { sysTray = new KStatusNotifierItem(this); - sysTray->setIconByName(privIcon()); + sysTray->setIconByName(appIconName()); // we have our own "quit" method, re-connect QAction *quitAction = sysTray->action(QStringLiteral("quit")); if (quitAction) { disconnect(quitAction, &QAction::triggered, nullptr, nullptr); connect(quitAction, &QAction::triggered, this, &Krusader::quit); } } else if (sysTray && !trayIsNeeded) { // user does not want tray anymore :( sysTray->deleteLater(); } } bool Krusader::versionControl() { // create config file krConfig = KSharedConfig::openConfig().data(); KConfigGroup nogroup(krConfig, QString()); const bool firstRun = nogroup.readEntry("First Time", true); KrGlobal::sCurrentConfigVersion = nogroup.readEntry("Config Version", -1); // first installation of krusader if (firstRun) { KMessageBox::information( krApp, i18n("Welcome to Krusader.

As this is your first run, your machine " "will now be checked for external applications. Then the Konfigurator will " "be launched where you can customize Krusader to your needs.

")); } nogroup.writeEntry("Version", VERSION); nogroup.writeEntry("First Time", false); krConfig->sync(); QDir().mkpath(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/krusader/")); return firstRun; } void Krusader::statusBarUpdate(const QString& mess) { // change the message on the statusbar for 5 seconds if (statusBar()->isVisible()) statusBar()->showMessage(mess, 5000); } bool Krusader::event(QEvent *e) { if(e->type() == QEvent::ApplicationPaletteChange) { KrColorCache::getColorCache().refreshColors(); } return KParts::MainWindow::event(e); } // Moving from Pixmap actions to generic filenames - thanks to Carsten Pfeiffer void Krusader::setupActions() { QAction *bringToTopAct = new QAction(i18n("Bring Main Window to Top"), this); actionCollection()->addAction("bring_main_window_to_top", bringToTopAct); connect(bringToTopAct, SIGNAL(triggered()), SLOT(moveToTop())); KrActions::setupActions(this); _krActions = new KrActions(this); _viewActions = new ViewActions(this, this); _listPanelActions = new ListPanelActions(this, this); _tabActions = new TabActions(this, this); } /////////////////////////////////////////////////////////////////////////// //////////////////// implementation of slots ////////////////////////////// /////////////////////////////////////////////////////////////////////////// void Krusader::savePosition() { KConfigGroup cfg(krConfig, "Private"); cfg.writeEntry("Start Position", pos()); cfg.writeEntry("Start Size", size()); cfg = krConfig->group("Startup"); MAIN_VIEW->saveSettings(cfg); // NOTE: this would save current window state/size, statusbar and settings for each toolbar. // We are not using this and saving everything manually because // - it does not save window position // - window size save/restore does sometimes not work (multi-monitor setup) // - saving the statusbar visibility should be independent from window position and restoring it // does not work properly. //KConfigGroup cfg = KConfigGroup(&cfg, "MainWindowSettings"); //saveMainWindowSettings(cfg); //statusBar()->setVisible(cfg.readEntry("StatusBar", "Enabled") != "Disabled"); krConfig->sync(); } void Krusader::saveSettings() { // workaround: revert terminal fullscreen mode before saving widget and toolbar visibility if (MAIN_VIEW->isTerminalEmulatorFullscreen()) { MAIN_VIEW->setTerminalEmulator(false, true); } KConfigGroup noGroup(krConfig, QString()); noGroup.writeEntry("Config Version", KrGlobal::sConfigVersion); // save toolbar settings KConfigGroup cfg(krConfig, "Main Toolbar"); toolBar()->saveSettings(cfg); cfg = krConfig->group("Job Toolbar"); toolBar("jobToolBar")->saveSettings(cfg); cfg = krConfig->group("Actions Toolbar"); toolBar("actionsToolBar")->saveSettings(cfg); cfg = krConfig->group("Startup"); // save toolbar visibility and position cfg.writeEntry("State", saveState()); cfg.writeEntry("Show status bar", statusBar()->isVisible()); // save panel and window settings if (cfg.readEntry("Remember Position", _RememberPos)) savePosition(); // save the gui components visibility if (cfg.readEntry("UI Save Settings", _UiSave)) { cfg.writeEntry("Show FN Keys", KrActions::actToggleFnkeys->isChecked()); cfg.writeEntry("Show Cmd Line", KrActions::actToggleCmdline->isChecked()); cfg.writeEntry("Show Terminal Emulator", KrActions::actToggleTerminal->isChecked()); } // save popular links _popularUrls->save(); krConfig->sync(); } void Krusader::closeEvent(QCloseEvent *event) { if (!sysTray || _quit) { _quit = false; // in case quit will be aborted KParts::MainWindow::closeEvent(event); // (may) quit, continues with queryClose()... } else { // close window to tray event->ignore(); hide(); } } void Krusader::showEvent(QShowEvent *event) { const KConfigGroup lookFeelGroup(krConfig, "Look&Feel"); if (sysTray && !lookFeelGroup.readEntry("Minimize To Tray", _ShowTrayIcon)) { // restoring from "start to tray", tray icon is not needed anymore sysTray->deleteLater(); } KParts::MainWindow::showEvent(event); } bool Krusader::queryClose() { if (isStarting || isExiting) return false; if (qApp->isSavingSession()) { // KDE is logging out, accept the close acceptClose(); return true; } const KConfigGroup cfg = krConfig->group("Look&Feel"); const bool confirmExit = cfg.readEntry("Warn On Exit", _WarnOnExit); // ask user and wait until all KIO::job operations are terminated. Krusader won't exit before // that anyway if (!krJobMan->waitForJobs(confirmExit)) return false; /* First try to close the child windows, because it's the safer way to avoid crashes, then close the main window. If closing a child is not successful, then we cannot let the main window close. */ for (;;) { QWidgetList list = QApplication::topLevelWidgets(); QWidget *activeModal = QApplication::activeModalWidget(); QWidget *w = list.at(0); if (activeModal && activeModal != this && activeModal != menuBar() && list.contains(activeModal) && !activeModal->isHidden()) { w = activeModal; } else { int i = 1; for (; i < list.count(); ++i) { w = list.at(i); if (!(w && (w == this || w->isHidden() || w == menuBar()))) break; } if (i == list.count()) w = 0; } if (!w) break; if (!w->close()) { if (w->inherits("QDialog")) { fprintf(stderr, "Failed to close: %s\n", w->metaObject()->className()); } return false; } } acceptClose(); return true; } void Krusader::acceptClose() { saveSettings(); emit shutdown(); // Removes the DBUS registration of the application. Single instance mode requires unique appid. // As Krusader is exiting, we release that unique appid, so new Krusader instances // can be started. QDBusConnection dbus = QDBusConnection::sessionBus(); dbus.unregisterObject("/Instances/" + Krusader::AppName); isExiting = true; } // the please wait dialog functions void Krusader::startWaiting(QString msg, int count , bool cancel) { plzWait->startWaiting(msg , count, cancel); } bool Krusader::wasWaitingCancelled() const { return plzWait->wasCancelled(); } void Krusader::stopWait() { plzWait->stopWait(); } void Krusader::updateUserActions() { KActionMenu *userActionMenu = (KActionMenu *) KrActions::actUserMenu; if (userActionMenu) { userActionMenu->menu()->clear(); userActionMenu->addAction(KrActions::actManageUseractions); userActionMenu->addSeparator(); krUserAction->populateMenu(userActionMenu, NULL); } } -const char* Krusader::privIcon() { +const char* Krusader::appIconName() { if (geteuid()) return "krusader_user"; else return "krusader_root"; } void Krusader::quit() { _quit = true; // remember that we want to quit and not close to tray close(); // continues with closeEvent()... } void Krusader::moveToTop() { if (isHidden()) show(); KWindowSystem::forceActiveWindow(winId()); } bool Krusader::isRunning() { moveToTop(); //FIXME - doesn't belong here return true; } bool Krusader::isLeftActive() { return MAIN_VIEW->isLeftActive(); } bool Krusader::openUrl(QString url) { _urlToOpen = url; _openUrlTimer.start(0); return true; } void Krusader::doOpenUrl() { QUrl url = QUrl::fromUserInput(_urlToOpen, QDir::currentPath(), QUrl::AssumeLocalFile); _urlToOpen.clear(); int tab = ACTIVE_MNG->findTab(url); if(tab >= 0) ACTIVE_MNG->setActiveTab(tab); else if((tab = OTHER_MNG->findTab(url)) >= 0) { OTHER_MNG->setActiveTab(tab); OTHER_MNG->currentPanel()->view->widget()->setFocus(); } else ACTIVE_MNG->slotNewTab(url); } void Krusader::slotGotNewStartup(const KStartupInfoId &id, const KStartupInfoData &data) { Q_UNUSED(id) Q_UNUSED(data) // This is here to show busy mouse cursor when _other_ applications are launched, not for krusader itself. qApp->setOverrideCursor(Qt::BusyCursor); } void Krusader::slotGotRemoveStartup(const KStartupInfoId &id, const KStartupInfoData &data) { Q_UNUSED(id) Q_UNUSED(data) qApp->restoreOverrideCursor(); } KrView *Krusader::activeView() { return ACTIVE_PANEL->view; } AbstractPanelManager *Krusader::activeManager() { return MAIN_VIEW->activeManager(); } AbstractPanelManager *Krusader::leftManager() { return MAIN_VIEW->leftManager(); } AbstractPanelManager *Krusader::rightManager() { return MAIN_VIEW->rightManager(); } diff --git a/krusader/krusader.h b/krusader/krusader.h index c6e3ea6a..8c10ec8e 100644 --- a/krusader/krusader.h +++ b/krusader/krusader.h @@ -1,186 +1,188 @@ /***************************************************************************** * Copyright (C) 2000 Shie Erlich * * 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/]. * *****************************************************************************/ #ifndef KRUSADER_H #define KRUSADER_H #ifdef HAVE_CONFIG_H #include #endif #include "krmainwindow.h" // QtCore #include #include #include #include #include // QtGui #include #include #include #include // QtWidgets #include #include #include #include #include #include #ifdef __KJSEMBED__ class KrJS; #endif class KStartupInfoData; class KStartupInfoId; class KrusaderStatus; class KRPleaseWaitHandler; class PopularUrls; class ViewActions; class ListPanelActions; class TabActions; class KrView; /** * @brief The main window of this file manager */ class Krusader : public KParts::MainWindow, public KrMainWindow { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.krusader.Instance") public: explicit Krusader(const QCommandLineParser &parser); virtual ~Krusader(); void setTray(bool forceCreation = false); // KrMainWindow implementation virtual QWidget *widget() Q_DECL_OVERRIDE { return this; } virtual KrView *activeView() Q_DECL_OVERRIDE; ViewActions *viewActions() { return _viewActions; } virtual KActionCollection *actions() { return actionCollection(); } virtual AbstractPanelManager *activeManager() Q_DECL_OVERRIDE; virtual AbstractPanelManager *leftManager() Q_DECL_OVERRIDE; virtual AbstractPanelManager *rightManager() Q_DECL_OVERRIDE; virtual PopularUrls *popularUrls() Q_DECL_OVERRIDE { return _popularUrls; } virtual KrActions *krActions() Q_DECL_OVERRIDE { return _krActions; } virtual ListPanelActions *listPanelActions() Q_DECL_OVERRIDE { return _listPanelActions; } virtual TabActions *tabActions() Q_DECL_OVERRIDE { return _tabActions; } virtual void plugActionList(const char *name, QList &list) Q_DECL_OVERRIDE { KParts::MainWindow::plugActionList(name, list); } + /** - * This returns a defferent icon if krusader runs with root-privileges - * @return a character string with the specitif icon-name + * Icon name that depends on whether krusader runs with root-privileges or not + * + * @return icon name */ - static const char* privIcon(); + static const char* appIconName(); public slots: void quit(); void moveToTop(); void statusBarUpdate(const QString& mess); // in use by Krusader only void saveSettings(); void savePosition(); void updateUserActions(); protected slots: void doOpenUrl(); void slotGotNewStartup(const KStartupInfoId &id, const KStartupInfoData &data); void slotGotRemoveStartup(const KStartupInfoId &id, const KStartupInfoData &data); protected: void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE; void showEvent(QShowEvent *event) Q_DECL_OVERRIDE; bool queryClose() Q_DECL_OVERRIDE; void setupActions(); bool versionControl(); // handle version differences in krusaderrc bool event(QEvent *) Q_DECL_OVERRIDE; public Q_SLOTS: Q_SCRIPTABLE bool isRunning(); Q_SCRIPTABLE bool isLeftActive(); Q_SCRIPTABLE bool openUrl(QString url); public: static Krusader *App; // a kApp style pointer static QString AppName; // the name of the application PopularUrls *_popularUrls; // holds a sorted list of the most popular urls visited // the internal progress bar variales + functions KRPleaseWaitHandler* plzWait; void startWaiting(QString msg = "Please Wait", int count = 0 , bool cancel = false); void stopWait(); bool wasWaitingCancelled() const; #ifdef __KJSEMBED__ static KrJS *js; #endif signals: void changeMessage(QString); // emitted when we are about to quit void shutdown(); private: void acceptClose(); private: KrActions *_krActions; ViewActions *_viewActions; ListPanelActions *_listPanelActions; TabActions *_tabActions; QPointer sysTray; bool isStarting; bool isExiting; QTimer _openUrlTimer; QString _urlToOpen; bool _quit; }; // main modules #define krApp Krusader::App #ifdef __KJSEMBED__ #define krJS Krusader::App->js #endif #endif diff --git a/krusader/krusaderview.cpp b/krusader/krusaderview.cpp index edc6a578..8e468613 100644 --- a/krusader/krusaderview.cpp +++ b/krusader/krusaderview.cpp @@ -1,529 +1,530 @@ /***************************************************************************** * Copyright (C) 2000 Shie Erlich * * 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 "krusaderview.h" // QtCore #include #include #include // QtGui #include #include // QtWidgets #include #include #include #include #include #include #include #include "krusader.h" +#include "icon.h" #include "kractions.h" #include "krslots.h" #include "defaults.h" #include "Panel/listpanel.h" #include "Panel/panelfunc.h" #include "GUI/kcmdline.h" #include "GUI/kfnkeys.h" #include "GUI/terminaldock.h" #include "panelmanager.h" #include "GUI/profilemanager.h" #include "Dialogs/percentalsplitter.h" #include "krservices.h" KrusaderView::KrusaderView(QWidget *parent) : QWidget(parent), activeMng(0) { } void KrusaderView::start(const KConfigGroup &cfg, bool restoreSettings, const QList &leftTabs, const QList &rightTabs) { //////////////////////////////// // make a 1x1 mainLayout, it will auto-expand: mainLayout = new QGridLayout(this); mainLayout->setContentsMargins(0, 0, 0, 0); mainLayout->setSpacing(0); // vertical splitter vert_splitter = new QSplitter(this); // splits between panels and terminal/cmdline vert_splitter->setOrientation(Qt::Vertical); // horizontal splitter horiz_splitter = new PercentalSplitter(vert_splitter); (_terminalDock = new TerminalDock(vert_splitter, krApp))->hide(); // create it hidden // create a command line thing _cmdLine = new KCMDLine(this); // add a panel manager for each side of the splitter leftMng = createManager(true); rightMng = createManager(false); leftMng->setOtherManager(rightMng); rightMng->setOtherManager(leftMng); // make the left panel focused at program start activeMng = leftMng; // create the function keys widget _fnKeys = new KFnKeys(this, krApp); _fnKeys->hide(); _fnKeys->setWhatsThis(i18n("Function keys allow performing fast " "operations on files.")); // and insert the whole thing into the main layout... at last mainLayout->addWidget(vert_splitter, 0, 0); //<> mainLayout->addWidget(_cmdLine, 1, 0); mainLayout->addWidget(_fnKeys, 2, 0); mainLayout->activate(); // get the last saved sizes of the splitter QList lst = cfg.readEntry("Splitter Sizes", QList()); if (lst.count() != 2) { lst.clear(); lst.push_back(100); lst.push_back(100); } else if (lst[0] < 1 && lst[1] < 1) { lst[ 0 ] = 100; lst[ 1 ] = 100; } horiz_splitter->setSizes(lst); verticalSplitterSizes = cfg.readEntry("Terminal Emulator Splitter Sizes", QList ()); if (verticalSplitterSizes.count() != 2 || (verticalSplitterSizes[0] < 1 && verticalSplitterSizes[1] < 1)) { verticalSplitterSizes.clear(); verticalSplitterSizes << 100 << 100; } leftPanel()->start(leftTabs.isEmpty() ? QUrl::fromLocalFile(QDir::homePath()) : leftTabs.at(0)); rightPanel()->start(rightTabs.isEmpty() ? QUrl::fromLocalFile(QDir::homePath()) : rightTabs.at(0)); activePanel()->gui->slotFocusOnMe(); // left starts out active for (int i = 1; i < leftTabs.count(); i++) leftMng->slotNewTab(leftTabs.at(i), false); for (int j = 1; j < rightTabs.count(); j++) rightMng->slotNewTab(rightTabs.at(j), false); // this is needed so that all tab labels get updated leftMng->layoutTabs(); rightMng->layoutTabs(); if(restoreSettings) { if(leftTabs.isEmpty()) leftMng->loadSettings(KConfigGroup(&cfg, "Left Tab Bar")); if(rightTabs.isEmpty()) rightMng->loadSettings(KConfigGroup(&cfg, "Right Tab Bar")); if (cfg.readEntry("Left Side Is Active", false)) leftPanel()->slotFocusOnMe(); else rightPanel()->slotFocusOnMe(); } } void KrusaderView::updateGUI(const KConfigGroup &cfg) { if (!cfg.readEntry("Show Cmd Line", _ShowCmdline)) { cmdLine()->hide(); KrActions::actToggleCmdline->setChecked(false); } else { cmdLine()->show(); KrActions::actToggleCmdline->setChecked(true); } // update the Fn bar to the shortcuts selected by the user fnKeys()->updateShortcuts(); if (!cfg.readEntry("Show FN Keys", _ShowFNkeys)) { fnKeys()->hide(); KrActions::actToggleFnkeys->setChecked(false); } else { fnKeys()->show(); KrActions::actToggleFnkeys->setChecked(true); } // set vertical mode if (cfg.readEntry("Vertical Mode", false)) { toggleVerticalMode(); } if (cfg.readEntry("Show Terminal Emulator", _ShowTerminalEmulator)) { setTerminalEmulator(true); // create konsole_part }; } void KrusaderView::setPanelSize(bool leftPanel, int percent) { QList panelSizes = horiz_splitter->sizes(); int totalSize = panelSizes[0] + panelSizes[1]; if (leftPanel) { panelSizes[0] = totalSize * percent / 100; panelSizes[1] = totalSize * (100 - percent) / 100; } else { // == RIGHT_PANEL panelSizes[0] = totalSize * (100 - percent) / 100; panelSizes[1] = totalSize * percent / 100; } horiz_splitter->setSizes(panelSizes); } PanelManager *KrusaderView::createManager(bool left) { PanelManager *panelManager = new PanelManager(horiz_splitter, krApp, left); connect(panelManager, &PanelManager::draggingTab, this, &KrusaderView::draggingTab); connect(panelManager, &PanelManager::draggingTabFinished, this, &KrusaderView::draggingTabFinished); connect(panelManager, &PanelManager::pathChanged, this, &KrusaderView::slotPathChanged); connect(panelManager, &PanelManager::setActiveManager, this, &KrusaderView::slotSetActiveManager); return panelManager; } void KrusaderView::updateCurrentActivePath() { const QString path = activePanel()->gui->lastLocalPath(); _cmdLine->setCurrent(path); KConfigGroup cfg = krConfig->group("General"); if (_terminalDock->isInitialised() && cfg.readEntry("Send CDs", _SendCDs)) { _terminalDock->sendCd(path); } } KrPanel *KrusaderView::activePanel() const { // active manager might not be set yet return activeMng ? activeMng->currentPanel() : nullptr; } ListPanel *KrusaderView::leftPanel() const { return leftMng->currentPanel()->gui; } ListPanel *KrusaderView::rightPanel() const { return rightMng->currentPanel()->gui; } // updates the command line whenever current panel or its path changes void KrusaderView::slotPathChanged(ListPanel *listPanel) { if (listPanel == activePanel()) { updateCurrentActivePath(); } } int KrusaderView::getFocusCandidates(QVector &widgets) { activePanel()->gui->getFocusCandidates(widgets); if(_terminalDock->isTerminalVisible()) widgets << _terminalDock; if(_cmdLine->isVisible()) widgets << _cmdLine; for(int i = 0; i < widgets.count(); i++) { if(widgets[i] == focusWidget() || widgets[i]->focusWidget() == focusWidget()) return i; } return -1; } void KrusaderView::focusUp() { qDebug() << "focus UP"; QVector widgets; int currentFocus = getFocusCandidates(widgets); if(currentFocus < 0) return; currentFocus--; if(currentFocus >= 0 && currentFocus < widgets.count()) widgets[currentFocus]->setFocus(); } void KrusaderView::focusDown() { qDebug() << "focus DOWN"; QVector widgets; int currentFocus = getFocusCandidates(widgets); if(currentFocus < 0) return; currentFocus++; if(currentFocus < widgets.count()) widgets[currentFocus]->setFocus(); } void KrusaderView::cmdLineFocus() // command line receive's keyboard focus { _cmdLine->setFocus(); } void KrusaderView::cmdLineUnFocus() // return focus to the active panel { activePanel()->gui->slotFocusOnMe(); } // Tab - switch focus void KrusaderView::panelSwitch() { activePanel()->otherPanel()->gui->slotFocusOnMe(); } void KrusaderView::slotSetActiveManager(PanelManager *manager) { activeMng = manager; updateCurrentActivePath(); } void KrusaderView::swapSides() { QList lst = horiz_splitter->sizes(); horiz_splitter->addWidget(leftMng); int old = lst[ 0 ]; lst[ 0 ] = lst [ 1 ]; lst[ 1 ] = old; horiz_splitter->setSizes(lst); PanelManager *tmpMng = leftMng; leftMng = rightMng; rightMng = tmpMng; leftMng->setLeft(true); rightMng->setLeft(false); leftPanel()->updateGeometry(); rightPanel()->updateGeometry(); } void KrusaderView::setTerminalEmulator(bool show, bool fullscreen) { qDebug() << "show=" << show << " fullscreen=" << fullscreen; static bool fnKeysShown = true; // first time init. should be overridden static bool cmdLineShown = true; static bool statusBarShown = true; static bool mainToolBarShown = true; static bool jobToolBarShown = true; static bool actionToolBarShown = true; static bool menuBarShown = true; static bool terminalEmulatorShown = true; if (show) { if (fullscreen) { // save what is shown fnKeysShown = !_fnKeys->isHidden(); cmdLineShown = !_cmdLine->isHidden(); statusBarShown = !krApp->statusBar()->isHidden(); mainToolBarShown = !krApp->toolBar()->isHidden(); jobToolBarShown = !krApp->toolBar("jobToolBar")->isHidden(); actionToolBarShown = !krApp->toolBar("actionToolBar")->isHidden(); menuBarShown = !krApp->menuBar()->isHidden(); terminalEmulatorShown = _terminalDock->isTerminalVisible(); } if(!_terminalDock->isTerminalVisible()) { // show terminal const bool isInitialized = _terminalDock->initialise(); if (!isInitialized) { _terminalDock->hide(); KrActions::actToggleTerminal->setChecked(false); return; } _terminalDock->show(); _terminalDock->setFocus(); updateCurrentActivePath(); KrActions::actToggleTerminal->setChecked(true); } else if (fullscreen) { // save current terminal size before going to fullscreen verticalSplitterSizes = vert_splitter->sizes(); } if (fullscreen) { // hide everything else leftMng->hide(); rightMng->hide(); _fnKeys->hide(); _cmdLine->hide(); krApp->statusBar()->hide(); krApp->toolBar()->hide(); krApp->toolBar("jobToolBar")->hide(); krApp->toolBar("actionToolBar")->hide(); krApp->menuBar()->hide(); // fix showing nothing if terminal is open but splitter widget size is zero vert_splitter->setSizes(QList() << 0 << vert_splitter->height()); } else { vert_splitter->setSizes(verticalSplitterSizes); } } else { // hide const bool isFullscreen = isTerminalEmulatorFullscreen(); if (!(fullscreen && terminalEmulatorShown)) { // hide terminal emulator activePanel()->gui->slotFocusOnMe(); if (_terminalDock->isTerminalVisible() && !isFullscreen) { verticalSplitterSizes = vert_splitter->sizes(); } _terminalDock->hide(); KrActions::actToggleTerminal->setChecked(false); } else { // not fullscreen anymore but terminal is still visible vert_splitter->setSizes(verticalSplitterSizes); } if (isFullscreen) { // restore: unhide everything that was hidden before leftMng->show(); rightMng->show(); if (fnKeysShown) _fnKeys->show(); if (cmdLineShown) _cmdLine->show(); if (statusBarShown) krApp->statusBar()->show(); if (mainToolBarShown) krApp->toolBar()->show(); if (jobToolBarShown) krApp->toolBar("jobToolBar")->show(); if (actionToolBarShown) krApp->toolBar("actionToolBar")->show(); if (menuBarShown) krApp->menuBar()->show(); } } } void KrusaderView::focusTerminalEmulator() { if (_terminalDock->isTerminalVisible()) _terminalDock->setFocus(); } void KrusaderView::toggleFullScreenTerminalEmulator() { setTerminalEmulator(!isTerminalEmulatorFullscreen(), true); } bool KrusaderView::isTerminalEmulatorFullscreen() { return leftMng->isHidden() && rightMng->isHidden(); } void KrusaderView::profiles(QString profileName) { ProfileManager profileManager("Panel", this); profileManager.hide(); connect(&profileManager, SIGNAL(saveToProfile(QString)), this, SLOT(savePanelProfiles(QString))); connect(&profileManager, SIGNAL(loadFromProfile(QString)), this, SLOT(loadPanelProfiles(QString))); if (profileName.isEmpty()) profileManager.profilePopup(); else profileManager.loadProfile(profileName); } void KrusaderView::loadPanelProfiles(QString group) { KConfigGroup ldg(krConfig, group); leftMng->loadSettings(KConfigGroup(&ldg, "Left Tabs")); rightMng->loadSettings(KConfigGroup(&ldg, "Right Tabs")); if (ldg.readEntry("Left Side Is Active", true)) leftPanel()->slotFocusOnMe(); else rightPanel()->slotFocusOnMe(); } void KrusaderView::savePanelProfiles(QString group) { KConfigGroup svr(krConfig, group); svr.writeEntry("Vertical Mode", isVertical()); svr.writeEntry("Left Side Is Active", activePanel()->gui->isLeft()); leftMng->saveSettings(KConfigGroup(&svr, "Left Tabs"), false); rightMng->saveSettings(KConfigGroup(&svr, "Right Tabs"), false); } void KrusaderView::toggleVerticalMode() { if (horiz_splitter->orientation() == Qt::Vertical) { horiz_splitter->setOrientation(Qt::Horizontal); KrActions::actVerticalMode->setText(i18n("Vertical Mode")); - KrActions::actVerticalMode->setIcon(QIcon::fromTheme("view-split-top-bottom")); + KrActions::actVerticalMode->setIcon(Icon("view-split-top-bottom")); } else { horiz_splitter->setOrientation(Qt::Vertical); KrActions::actVerticalMode->setText(i18n("Horizontal Mode")); - KrActions::actVerticalMode->setIcon(QIcon::fromTheme("view-split-left-right")); + KrActions::actVerticalMode->setIcon(Icon("view-split-left-right")); } } void KrusaderView::saveSettings(KConfigGroup &cfg) { QList lst = horiz_splitter->sizes(); cfg.writeEntry("Splitter Sizes", lst); QList vertSplitterSizes = _terminalDock->isVisible() && !isTerminalEmulatorFullscreen() // fix sizes() not returning correct values on fullscreen+shutdown && vert_splitter->sizes().first() != 0 ? vert_splitter->sizes() : verticalSplitterSizes; cfg.writeEntry("Terminal Emulator Splitter Sizes", vertSplitterSizes); cfg.writeEntry("Vertical Mode", isVertical()); cfg.writeEntry("Left Side Is Active", activePanel()->gui->isLeft()); leftMng->saveSettings(KConfigGroup(&cfg, "Left Tab Bar"), true); rightMng->saveSettings(KConfigGroup(&cfg, "Right Tab Bar"), true); } bool KrusaderView::cursorIsOnOtherSide(PanelManager *of, const QPoint &globalPos) { int border = -1; int pos = -1; if (horiz_splitter->orientation() == Qt::Horizontal) { pos = globalPos.x(); if(of == leftMng) border = leftMng->mapToGlobal(QPoint(leftMng->width(), 0)).x(); else border = rightMng->mapToGlobal(QPoint(0, 0)).x(); } else { pos = globalPos.y(); if(of == leftMng) border = leftMng->mapToGlobal(QPoint(0, leftMng->height())).y(); else border = rightMng->mapToGlobal(QPoint(0, 0)).y(); } return (of == leftMng) ? pos > border : pos < border; } void KrusaderView::draggingTab(PanelManager *from, QMouseEvent *e) { QString icon; if (horiz_splitter->orientation() == Qt::Horizontal) icon = (from == leftMng) ? "arrow-right" : "arrow-left"; else icon = (from == leftMng) ? "arrow-down" : "arrow-up"; - QCursor cursor(QIcon::fromTheme(icon).pixmap(22)); + QCursor cursor(Icon(icon).pixmap(22)); if (cursorIsOnOtherSide(from, e->globalPos())) { if(!qApp->overrideCursor()) qApp->setOverrideCursor(cursor); } else qApp->restoreOverrideCursor(); } void KrusaderView::draggingTabFinished(PanelManager *from, QMouseEvent *e) { qApp->restoreOverrideCursor(); if (cursorIsOnOtherSide(from, e->globalPos())) from->moveTabToOtherSide(); } diff --git a/krusader/main.cpp b/krusader/main.cpp index 46f223d9..0c857df1 100644 --- a/krusader/main.cpp +++ b/krusader/main.cpp @@ -1,345 +1,317 @@ /***************************************************************************** * Copyright (C) 2000 Shie Erlich * * 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 #include // QtCore #include #include #include #include #include #include #include // QtGui #include // QtDBus #include #include // QtWidgets #include #include #include #include #include #include #include #include "../Archive/krarchandler.h" #include "defaults.h" #include "krservices.h" #include "krslots.h" #include "krusader.h" +#include "icon.h" #include "krusaderversion.h" #include "krusaderview.h" #include "panelmanager.h" static const char *description = I18N_NOOP("Krusader\nTwin-Panel File Manager by KDE"); static void sigterm_handler(int i) { fprintf(stderr, "Signal: %d\n", i); QAbstractEventDispatcher *instance = QAbstractEventDispatcher::instance(); if (instance) instance->wakeUp(); QApplication::exit(- 15); } void openTabsRemote(QStringList tabs, bool left, QString appName) { // make sure left or right are not relative paths for (int i = 0; i != tabs.count(); i++) { tabs[ i ] = tabs[ i ].trimmed(); if (!tabs[ i ].startsWith('/') && tabs[ i ].indexOf(":/") < 0) tabs[ i ] = QDir::currentPath() + '/' + tabs[ i ]; } QDBusInterface remoteApp("org.krusader", "/Instances/" + appName + (left ? "/left_manager" : "/right_manager"), "org.krusader.PanelManager", QDBusConnection::sessionBus()); QDBusReply reply; if (remoteApp.isValid()) reply = remoteApp.call("newTabs", tabs); if (!reply.isValid()) fprintf(stderr, "DBus Error: %s, %s\n", reply.error().name().toLocal8Bit().constData(), reply.error().message().toLocal8Bit().constData()); } //! An object that manages archives in several parts of the source code. KRarcHandler arcHandler; int main(int argc, char *argv[]) { -// ============ begin icon-stuff =========== -// If the user has no icon specified over the commandline we set up our own. -// this is according to the users privileges. The icons are in Krusader::privIcon() - -/* bool hasIcon = false; - int i = 0; - char * myArgv[argc+2];*/ - -// if no --miniicon is given, --icon is used. So we don't need to check for --miniicon separately -/* for (i = 0; i < argc; ++i) { - if (strstr(argv[ i ], "-icon") != 0) // important: just one dash because both can appear! - hasIcon = true; - } - - static const char* const icon_text = "--icon"; - const char* icon_name = Krusader::privIcon(); - char addedParams[strlen(icon_text)+strlen(icon_name)+2]; - - if (! hasIcon) { - for (i = 0; i < argc; ++i) - myArgv[ i ] = argv[ i ]; - - strcpy(addedParams, icon_text); - strcpy(addedParams + strlen(icon_text) + 1, icon_name); - - myArgv[ argc ] = addedParams; - myArgv[ ++argc ] = addedParams + strlen(icon_text) + 1; - myArgv[ ++argc ] = 0; - - argv = myArgv; - }*/ -// ============ end icon-stuff =========== - // set global log message format qSetMessagePattern(KrServices::GLOBAL_MESSAGE_PATTERN); // prevent qt5-webengine crashing QApplication::setAttribute(Qt::AA_ShareOpenGLContexts); // create the application and set application domain so that calls to i18n get strings from right place. QApplication app(argc, argv); KLocalizedString::setApplicationDomain("krusader"); + // init icon theme + qDebug() << "System icon theme:" << QIcon::themeName(); + // [WORKAROUND] setThemeName sets user theme in QIconLoader and allows to avoid Qt issues with invalid icon caching later + // IMPORTANT: this must be done before the first QIcon::fromTheme / QIcon::hasThemeIcon call + QIcon::setThemeName(QIcon::themeName()); + // ABOUT data information #ifdef RELEASE_NAME QString versionName = QString("%1 \"%2\"").arg(VERSION).arg(RELEASE_NAME); #else QString versionName = VERSION; #endif KAboutData aboutData(QStringLiteral("krusader"), (geteuid() ? i18n("Krusader") : i18n("Krusader - ROOT PRIVILEGES")), versionName, i18n(description), KAboutLicense::GPL_V2, i18n("© 2000-2003 Shie Erlich, Rafi Yanai\n© 2004-2018 Krusader Krew"), i18n("Feedback:\nhttps://forum.kde.org/viewforum.php?f=225\n\nIRC\nserver: " "irc.freenode.net, channel: #krusader"), QStringLiteral("https://krusader.org")); aboutData.setOrganizationDomain(QByteArray("kde.org")); aboutData.setDesktopFileName(QStringLiteral("org.kde.krusader")); aboutData.addAuthor(i18n("Davide Gianforte"), i18n("Developer"), QStringLiteral("davide@gengisdave.org"), 0); aboutData.addAuthor(i18n("Toni Asensi Esteve"), i18n("Developer"), QStringLiteral("toni.asensi@kdemail.net"), 0); aboutData.addAuthor(i18n("Alexander Bikadorov"), i18n("Developer"), QStringLiteral("alex.bikadorov@kdemail.net"), 0); aboutData.addAuthor(i18n("Martin Kostolný"), i18n("Developer"), QStringLiteral("clearmartin@gmail.com"), 0); aboutData.addAuthor(i18n("Nikita Melnichenko"), i18n("Developer"), QStringLiteral("nikita+kde@melnichenko.name"), 0); aboutData.addAuthor(i18n("Yuri Chornoivan"), i18n("Documentation"), QStringLiteral("yurchor@ukr.net"), 0); aboutData.addAuthor(i18n("Rafi Yanai"), i18n("Author (retired)"), QStringLiteral("yanai@users.sourceforge.net")); aboutData.addAuthor(i18n("Shie Erlich"), i18n("Author (retired)"), QStringLiteral("erlich@users.sourceforge.net")); aboutData.addAuthor(i18n("Csaba Karai"), i18n("Developer (retired)"), QStringLiteral("ckarai@users.sourceforge.net"), 0); aboutData.addAuthor(i18n("Heiner Eichmann"), i18n("Developer (retired)"), QStringLiteral("h.eichmann@gmx.de"), 0); aboutData.addAuthor(i18n("Jonas Bähr"), i18n("Developer (retired)"), QStringLiteral("jonas.baehr@web.de"), 0); aboutData.addAuthor(i18n("Václav Jůza"), i18n("Developer (retired)"), QStringLiteral("vaclavjuza@gmail.com"), 0); aboutData.addAuthor(i18n("Jan Lepper"), i18n("Developer (retired)"), QStringLiteral("jan_lepper@gmx.de"), 0); aboutData.addAuthor(i18n("Andrey Matveyakin"), i18n("Developer (retired)"), QStringLiteral("a.matveyakin@gmail.com"), 0); aboutData.addAuthor(i18n("Simon Persson"), i18n("Developer (retired)"), QStringLiteral("simon.persson@mykolab.com"), 0); aboutData.addAuthor(i18n("Dirk Eschler"), i18n("Webmaster (retired)"), QStringLiteral("deschler@users.sourceforge.net"), 0); aboutData.addAuthor(i18n("Frank Schoolmeesters"), i18n("Documentation and marketing coordinator (retired)"), QStringLiteral("frank_schoolmeesters@yahoo.com"), 0); aboutData.addAuthor(i18n("Richard Holt"), i18n("Documentation & Proofing (retired)"), QStringLiteral("richard.holt@gmail.com"), 0); aboutData.addAuthor(i18n("Matej Urbancic"), i18n("Marketing & Product Research (retired)"), QStringLiteral("matej.urban@gmail.com"), 0); aboutData.addCredit(i18n("kde.org"), i18n("Everyone involved in KDE"), 0, 0); aboutData.addCredit(i18n("l10n.kde.org"), i18n("KDE Translation Teams"), 0, 0); aboutData.addCredit(i18n("Jiří Paleček"), i18n("QA, bug-hunting, patches and general help"), QStringLiteral("jpalecek@web.de"), 0); aboutData.addCredit(i18n("Jiří Klement"), i18n("Important help in KDE 4 porting"), 0, 0); aboutData.addCredit(i18n("Andrew Neupokoev"), i18n("Killer Logo and Icons for Krusader (contest winner)"), QStringLiteral("doom-blue@yandex.ru"), 0); aboutData.addCredit(i18n("The UsefulArts Organization"), i18n("Icon for Krusader"), QStringLiteral("mail@usefularts.org"), 0); aboutData.addCredit(i18n("Gábor Lehel"), i18n("Viewer module for 3rd Hand"), QStringLiteral("illissius@gmail.com"), 0); aboutData.addCredit(i18n("Mark Eatough"), i18n("Handbook Proof-Reader"), QStringLiteral("markeatough@yahoo.com"), 0); aboutData.addCredit(i18n("Jan Halasa"), i18n("The old Bookmark Module"), QStringLiteral("xhalasa@fi.muni.cz"), 0); aboutData.addCredit(i18n("Hans Löffler"), i18n("Dir history button"), 0, 0); aboutData.addCredit(i18n("Szombathelyi György"), i18n("ISO KIO slave"), 0, 0); aboutData.addCredit(i18n("Jan Willem van de Meent (Adios)"), i18n("Icons for Krusader"), QStringLiteral("janwillem@lorentz.leidenuniv.nl"), 0); aboutData.addCredit(i18n("Mikolaj Machowski"), i18n("Usability and QA"), QStringLiteral(""), 0); aboutData.addCredit(i18n("Cristi Dumitrescu"), i18n("QA, bug-hunting, patches and general help"), QStringLiteral("cristid@chip.ro"), 0); aboutData.addCredit(i18n("Aurelien Gateau"), i18n("patch for KViewer"), QStringLiteral("aurelien.gateau@free.fr"), 0); aboutData.addCredit(i18n("Milan Brabec"), i18n("the first patch ever!"), QStringLiteral("mbrabec@volny.cz"), 0); aboutData.addCredit(i18n("Asim Husanovic"), i18n("Bosnian translation"), QStringLiteral("asim@megatel.ba"), 0); aboutData.addCredit(i18n("Doutor Zero"), i18n("Brazilian Portuguese translation"), QStringLiteral("doutor.zero@gmail.com"), 0); aboutData.addCredit(i18n("Milen Ivanov"), i18n("Bulgarian translation"), QStringLiteral("milen.ivanov@abv.bg"), 0); aboutData.addCredit(i18n("Quim Perez"), i18n("Catalan translation"), QStringLiteral("noguer@osona.com"), 0); aboutData.addCredit(i18n("Jinghua Luo"), i18n("Chinese Simplified translation"), QStringLiteral("luojinghua@msn.com"), 0); aboutData.addCredit(i18n("Mitek"), i18n("Old Czech translation"), QStringLiteral("mitek@email.cz"), 0); aboutData.addCredit(i18n("Martin Sixta"), i18n("Old Czech translation"), QStringLiteral("lukumo84@seznam.cz"), 0); aboutData.addCredit(i18n("Vaclav Jůza"), i18n("Czech translation"), QStringLiteral("VaclavJuza@gmail.com"), 0); aboutData.addCredit(i18n("Anders Bruun Olsen"), i18n("Old Danish translation"), QStringLiteral("anders@bruun-olsen.net"), 0); aboutData.addCredit(i18n("Peter H. Sorensen"), i18n("Danish translation"), QStringLiteral("peters@skydebanen.net"), 0); aboutData.addCredit(i18n("Frank Schoolmeesters"), i18n("Dutch translation"), QStringLiteral("frank_schoolmeesters@yahoo.com"), 0); aboutData.addCredit(i18n("Rene-Pierre Lehmann"), i18n("Old French translation"), QStringLiteral("ripi@lepi.org"), 0); aboutData.addCredit(i18n("David Guillerm"), i18n("French translation"), QStringLiteral("dguillerm@gmail.com"), 0); aboutData.addCredit(i18n("Christoph Thielecke"), i18n("Old German translation"), QStringLiteral("crissi99@gmx.de"), 0); aboutData.addCredit(i18n("Dirk Eschler"), i18n("German translation"), QStringLiteral("deschler@users.sourceforge.net"), 0); aboutData.addCredit(i18n("Spiros Georgaras"), i18n("Greek translation"), QStringLiteral("sngeorgaras@gmail.com"), 0); aboutData.addCredit(i18n("Kukk Zoltan"), i18n("Old Hungarian translation"), QStringLiteral("kukkzoli@freemail.hu"), 0); aboutData.addCredit(i18n("Arpad Biro"), i18n("Hungarian translation"), QStringLiteral("biro_arpad@yahoo.com"), 0); aboutData.addCredit(i18n("Giuseppe Bordoni"), i18n("Italian translation"), QStringLiteral("geppo@geppozone.com"), 0); aboutData.addCredit(i18n("Hideki Kimura"), i18n("Japanese translation"), QStringLiteral("hangyo1973@gmail.com"), 0); aboutData.addCredit(i18n("UTUMI Hirosi"), i18n("Old Japanese translation"), QStringLiteral("utuhiro@mx12.freecom.ne.jp"), 0); aboutData.addCredit(i18n("Dovydas Sankauskas"), i18n("Lithuanian translation"), QStringLiteral("laisve@gmail.com"), 0); aboutData.addCredit(i18n("Bruno Queiros"), i18n("Portuguese translation"), QStringLiteral("brunoqueiros@portugalmail.com"), 0); aboutData.addCredit(i18n("Lukasz Janyst"), i18n("Old Polish translation"), QStringLiteral("ljan@wp.pl"), 0); aboutData.addCredit(i18n("Pawel Salawa"), i18n("Polish translation"), QStringLiteral("boogie@myslenice.one.pl"), 0); aboutData.addCredit(i18n("Tomek Grzejszczyk"), i18n("Polish translation"), QStringLiteral("tgrzej@onet.eu"), 0); aboutData.addCredit(i18n("Dmitry A. Bugay"), i18n("Russian translation"), QStringLiteral("sam@vhnet.ru"), 0); aboutData.addCredit(i18n("Dmitry Chernyak"), i18n("Old Russian translation"), QStringLiteral("chernyak@mail.ru"), 0); aboutData.addCredit(i18n("Sasa Tomic"), i18n("Serbian translation"), QStringLiteral("stomic@gmx.net"), 0); aboutData.addCredit(i18n("Zdenko Podobný and Ondrej Pačay (Yogi)"), i18n("Slovak translation"), QStringLiteral("zdenop@gmail.com"), 0); aboutData.addCredit(i18n("Matej Urbancic"), i18n("Slovenian translation"), QStringLiteral("matej.urban@gmail.com"), 0); aboutData.addCredit(i18n("Rafael Munoz"), i18n("Old Spanish translation"), QStringLiteral("muror@hotpop.com"), 0); aboutData.addCredit(i18n("Alejandro Araiza Alvarado"), i18n("Spanish translation"), QStringLiteral("mebrelith@gmail.com"), 0); aboutData.addCredit(i18n("Erik Johanssen"), i18n("Old Swedish translation"), QStringLiteral("erre@telia.com"), 0); aboutData.addCredit(i18n("Anders Linden"), i18n("Old Swedish translation"), QStringLiteral("connyosis@gmx.net"), 0); aboutData.addCredit(i18n("Peter Landgren"), i18n("Swedish translation"), QStringLiteral("peter.talken@telia.com"), 0); aboutData.addCredit(i18n("Bekir Sonat"), i18n("Turkish translation"), QStringLiteral("bekirsonat@kde.org.tr"), 0); aboutData.addCredit(i18n("Ivan Petrouchtchak"), i18n("Ukrainian translation"), QStringLiteral("connyosis@gmx.net"), 0); aboutData.addCredit(i18n("Seongnam Jee"), i18n("Korean translation"), QStringLiteral("snjee@intellicam.com"), 0); // This will call QCoreApplication::setApplicationName, etc for us by using info in the KAboutData instance. // The only thing not called for us is setWindowIcon(), which is why we do it ourselves here. KAboutData::setApplicationData(aboutData); - app.setWindowIcon(QIcon::fromTheme(Krusader::privIcon())); + app.setWindowIcon(Icon(Krusader::appIconName())); // Command line arguments ... QCommandLineParser parser; aboutData.setupCommandLine(&parser); parser.addOption(QCommandLineOption(QStringList() << QLatin1String("left"), i18n("Start left panel at "), QLatin1String("path"))); parser.addOption(QCommandLineOption(QStringList() << QLatin1String("right"), i18n("Start right panel at "), QLatin1String("path"))); parser.addOption(QCommandLineOption(QStringList() << QLatin1String("profile"), i18n("Load this profile on startup"), QLatin1String("panel-profile"))); parser.addOption(QCommandLineOption(QStringList() << "d" << QLatin1String("debug"), i18n("Enable debug output"))); parser.addPositionalArgument(QLatin1String("url"), i18n("URL to open")); // check for command line arguments parser.process(app); aboutData.processCommandLine(&parser); // set global message handler KrServices::setGlobalKrMessageHandler(parser.isSet("debug")); KConfigGroup cfg(KSharedConfig::openConfig(), QStringLiteral("Look&Feel")); bool singleInstanceMode = cfg.readEntry("Single Instance Mode", _SingleInstanceMode); QString url; if(!parser.positionalArguments().isEmpty()) { url = parser.positionalArguments().first(); } QString appName = "krusader"; if (!singleInstanceMode) appName += QString("%1").arg(getpid()); if (!QDBusConnection::sessionBus().isConnected()) { fprintf(stderr, "Cannot connect to the D-BUS session bus.\n" "To start it, run:\n" "\teval `dbus-launch --auto-syntax`\n"); } if (singleInstanceMode) { QDBusInterface remoteApp("org.krusader", "/Instances/" + appName, "org.krusader.Instance", QDBusConnection::sessionBus()); QDBusReply reply; if (remoteApp.isValid()) reply = remoteApp.call("isRunning"); if (!reply.isValid() && reply.error().type() != QDBusError::ServiceUnknown && reply.error().type() != QDBusError::UnknownObject) fprintf(stderr, "DBus Error: %s, %s\n", reply.error().name().toLocal8Bit().constData(), reply.error().message().toLocal8Bit().constData()); if (reply.isValid() && (bool)reply) { KStartupInfo::appStarted(); if (parser.isSet("left")) openTabsRemote(parser.value("left").split(','), true, appName); if (parser.isSet("right")) openTabsRemote(parser.value("right").split(','), false, appName); if(!url.isEmpty()) { reply = remoteApp.call("openUrl", url); if (!reply.isValid()) fprintf(stderr, "DBus Error: %s, %s\n", reply.error().name().toLocal8Bit().constData(), reply.error().message().toLocal8Bit().constData()); } return 0; } } // splash screen - if the user wants one QSplashScreen *splash = 0; { // don't remove bracket KConfigGroup cfg(KSharedConfig::openConfig(), QStringLiteral("Look&Feel")); if (cfg.readEntry("Show splashscreen", _ShowSplashScreen)) { QString splashFilename = QStandardPaths::locate(QStandardPaths::DataLocation, QStringLiteral("splash.png")); QPixmap pixmap(splashFilename); if (!pixmap.isNull()) { splash = new QSplashScreen(pixmap); splash->show(); } } } // don't remove bracket Krusader::AppName = appName; Krusader *krusader = new Krusader(parser); if(!url.isEmpty()) krusader->openUrl(url); QDBusConnection dbus = QDBusConnection::sessionBus(); if (!dbus.interface()->isServiceRegistered("org.krusader") && !dbus.registerService("org.krusader")) { fprintf(stderr, "DBus Error: %s, %s\n", dbus.lastError().name().toLocal8Bit().constData(), dbus.lastError().message().toLocal8Bit().constData()); } if (!dbus.registerObject("/Instances/" + appName, krusader, QDBusConnection::ExportScriptableSlots)) { fprintf(stderr, "DBus Error: %s, %s\n", dbus.lastError().name().toLocal8Bit().constData(), dbus.lastError().message().toLocal8Bit().constData()); } if (!dbus.registerObject("/Instances/" + appName + "/left_manager", LEFT_MNG, QDBusConnection::ExportScriptableSlots)) { fprintf(stderr, "DBus Error: %s, %s\n", dbus.lastError().name().toLocal8Bit().constData(), dbus.lastError().message().toLocal8Bit().constData()); } if (!dbus.registerObject("/Instances/" + appName + "/right_manager", RIGHT_MNG, QDBusConnection::ExportScriptableSlots)) { fprintf(stderr, "DBus Error: %s, %s\n", dbus.lastError().name().toLocal8Bit().constData(), dbus.lastError().message().toLocal8Bit().constData()); } - qDebug() << "Qt icon theme: " << QIcon::themeName(); - // catching SIGTERM, SIGHUP, SIGQUIT signal(SIGTERM, sigterm_handler); signal(SIGPIPE, sigterm_handler); signal(SIGHUP, sigterm_handler); QObject::connect(&app, &QGuiApplication::applicationStateChanged, SLOTS, &KRslots::applicationStateChanged); // hide splashscreen if (splash) { splash->finish(krusader); delete splash; } // let's go. return app.exec(); } diff --git a/krusader/panelmanager.cpp b/krusader/panelmanager.cpp index 9961c9ef..9a7bb43d 100644 --- a/krusader/panelmanager.cpp +++ b/krusader/panelmanager.cpp @@ -1,462 +1,462 @@ /***************************************************************************** * Copyright (C) 2002 Shie Erlich * * Copyright (C) 2002 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 "panelmanager.h" #include "defaults.h" +#include "icon.h" #include "tabactions.h" #include "krusaderview.h" #include "krmainwindow.h" #include "Panel/listpanel.h" #include "Panel/panelfunc.h" #include "Panel/PanelView/krviewfactory.h" #include // QtGui #include // QtWidgets #include #include #include #include #include -#include PanelManager::PanelManager(QWidget *parent, KrMainWindow* mainWindow, bool left) : QWidget(parent), _otherManager(0), _actions(mainWindow->tabActions()), _layout(0), _left(left), _currentPanel(0) { _layout = new QGridLayout(this); _layout->setContentsMargins(0, 0, 0, 0); _layout->setSpacing(0); _stack = new QStackedWidget(this); // new tab button _newTab = new QToolButton(this); _newTab->setAutoRaise(true); _newTab->setText(i18n("Open a new tab in home")); _newTab->setToolTip(i18n("Open a new tab in home")); - _newTab->setIcon(SmallIcon("tab-new")); + _newTab->setIcon(Icon("tab-new")); _newTab->adjustSize(); connect(_newTab, SIGNAL(clicked()), this, SLOT(slotNewTab())); // tab-bar _tabbar = new PanelTabBar(this, _actions); connect(_tabbar, SIGNAL(currentChanged(int)), this, SLOT(slotCurrentTabChanged(int))); connect(_tabbar, SIGNAL(tabCloseRequested(int)), this, SLOT(slotCloseTab(int))); connect(_tabbar, SIGNAL(closeCurrentTab()), this, SLOT(slotCloseTab())); connect(_tabbar, SIGNAL(newTab(QUrl)), this, SLOT(slotNewTab(QUrl))); connect(_tabbar, SIGNAL(draggingTab(QMouseEvent*)), this, SLOT(slotDraggingTab(QMouseEvent*))); connect(_tabbar, SIGNAL(draggingTabFinished(QMouseEvent*)), this, SLOT(slotDraggingTabFinished(QMouseEvent*))); QHBoxLayout *tabbarLayout = new QHBoxLayout; tabbarLayout->setSpacing(0); tabbarLayout->setContentsMargins(0, 0, 0, 0); tabbarLayout->addWidget(_tabbar); tabbarLayout->addWidget(_newTab); _layout->addWidget(_stack, 0, 0); _layout->addLayout(tabbarLayout, 1, 0); updateTabbarPos(); setLayout(_layout); addPanel(true); tabsCountChanged(); } void PanelManager::tabsCountChanged() { const KConfigGroup cfg(krConfig, "Look&Feel"); const bool showTabbar = _tabbar->count() > 1 || cfg.readEntry("Show Tab Bar On Single Tab", true); const bool showButtons = showTabbar && cfg.readEntry("Show Tab Buttons", true); _tabbar->setVisible(showTabbar); _newTab->setVisible(showButtons); // disable close button if only 1 tab is left _tabbar->setTabsClosable(showButtons && _tabbar->count() > 1); _actions->refreshActions(); } void PanelManager::activate() { assert(sender() == (currentPanel()->gui)); emit setActiveManager(this); _actions->refreshActions(); } void PanelManager::slotCurrentTabChanged(int index) { ListPanel *panel = _tabbar->getPanel(index); if (!panel || panel == _currentPanel) return; ListPanel *previousPanel = _currentPanel; _currentPanel = panel; _stack->setCurrentWidget(_currentPanel); if (previousPanel) { previousPanel->slotFocusOnMe(false); // FIXME - necessary ? } _currentPanel->slotFocusOnMe(this == ACTIVE_MNG); emit pathChanged(panel); if (otherManager()) { otherManager()->currentPanel()->otherPanelChanged(); } // go back to pinned url if tab is pinned and switched back to active if (panel->isPinned()) { panel->func->openUrl(panel->pinnedUrl()); } } ListPanel* PanelManager::createPanel(KConfigGroup cfg) { ListPanel * p = new ListPanel(_stack, this, cfg); connectPanel(p); return p; } void PanelManager::connectPanel(ListPanel *p) { connect(p, &ListPanel::activate, this, &PanelManager::activate); connect(p, &ListPanel::pathChanged, this, [=]() { pathChanged(p); }); connect(p, &ListPanel::pathChanged, this, [=]() { _tabbar->updateTab(p); }); } void PanelManager::disconnectPanel(ListPanel *p) { disconnect(p, &ListPanel::activate, this, nullptr); disconnect(p, &ListPanel::pathChanged, this, nullptr); } ListPanel* PanelManager::addPanel(bool setCurrent, KConfigGroup cfg, KrPanel *nextTo) { // create the panel and add it into the widgetstack ListPanel * p = createPanel(cfg); _stack->addWidget(p); // now, create the corresponding tab int index = _tabbar->addPanel(p, setCurrent, nextTo); tabsCountChanged(); if (setCurrent) slotCurrentTabChanged(index); return p; } void PanelManager::saveSettings(KConfigGroup config, bool saveHistory) { config.writeEntry("ActiveTab", activeTab()); KConfigGroup grpTabs(&config, "Tabs"); foreach(const QString &grpTab, grpTabs.groupList()) grpTabs.deleteGroup(grpTab); for(int i = 0; i < _tabbar->count(); i++) { ListPanel *panel = _tabbar->getPanel(i); KConfigGroup grpTab(&grpTabs, "Tab" + QString::number(i)); panel->saveSettings(grpTab, saveHistory); } } void PanelManager::loadSettings(KConfigGroup config) { KConfigGroup grpTabs(&config, "Tabs"); int numTabsOld = _tabbar->count(); int numTabsNew = grpTabs.groupList().count(); for(int i = 0; i < numTabsNew; i++) { KConfigGroup grpTab(&grpTabs, "Tab" + QString::number(i)); // TODO workaround for bug 371453. Remove this when bug is fixed if (grpTab.keyList().isEmpty()) continue; ListPanel *panel = i < numTabsOld ? _tabbar->getPanel(i) : addPanel(false, grpTab); panel->restoreSettings(grpTab); _tabbar->updateTab(panel); } for(int i = numTabsOld - 1; i >= numTabsNew && i > 0; i--) slotCloseTab(i); setActiveTab(config.readEntry("ActiveTab", 0)); // this is needed so that all tab labels get updated layoutTabs(); } void PanelManager::layoutTabs() { // delayed url refreshes may be pending - // delay the layout too so it happens after them QTimer::singleShot(0, _tabbar, SLOT(layoutTabs())); } KrPanel *PanelManager::currentPanel() const { return _currentPanel; } void PanelManager::moveTabToOtherSide() { if (tabCount() < 2) return; ListPanel *p; _tabbar->removeCurrentPanel(p); _stack->removeWidget(p); disconnectPanel(p); p->reparent(_otherManager->_stack, _otherManager); _otherManager->connectPanel(p); _otherManager->_stack->addWidget(p); _otherManager->_tabbar->addPanel(p, true); _otherManager->tabsCountChanged(); tabsCountChanged(); p->slotFocusOnMe(); } void PanelManager::slotNewTab(const QUrl &url, bool setCurrent, KrPanel *nextTo) { ListPanel *p = addPanel(setCurrent, KConfigGroup(), nextTo); if(nextTo && nextTo->gui) { // We duplicate tab settings by writing original settings to a temporary // group and making the new tab read settings from it. Duplicating // settings directly would add too much complexity. QString grpName = "PanelManager_" + QString::number(qApp->applicationPid()); krConfig->deleteGroup(grpName); // make sure the group is empty KConfigGroup cfg(krConfig, grpName); nextTo->gui->saveSettings(cfg, true); // reset undesired duplicated settings cfg.writeEntry("Properties", 0); p->restoreSettings(cfg); krConfig->deleteGroup(grpName); } p->start(url); } void PanelManager::slotNewTab() { slotNewTab(QUrl::fromLocalFile(QDir::home().absolutePath())); _currentPanel->slotFocusOnMe(); } void PanelManager::slotCloseTab() { slotCloseTab(_tabbar->currentIndex()); } void PanelManager::slotCloseTab(int index) { if (_tabbar->count() <= 1) /* if this is the last tab don't close it */ return; ListPanel *oldp; _tabbar->removePanel(index, oldp); //this automatically changes the current panel _stack->removeWidget(oldp); deletePanel(oldp); tabsCountChanged(); } void PanelManager::updateTabbarPos() { KConfigGroup group(krConfig, "Look&Feel"); if(group.readEntry("Tab Bar Position", "bottom") == "top") { _layout->addWidget(_stack, 2, 0); _tabbar->setShape(QTabBar::RoundedNorth); } else { _layout->addWidget(_stack, 0, 0); _tabbar->setShape(QTabBar::RoundedSouth); } } int PanelManager::activeTab() { return _tabbar->currentIndex(); } void PanelManager::setActiveTab(int index) { _tabbar->setCurrentIndex(index); } void PanelManager::slotRecreatePanels() { updateTabbarPos(); for (int i = 0; i != _tabbar->count(); i++) { QString grpName = "PanelManager_" + QString::number(qApp->applicationPid()); krConfig->deleteGroup(grpName); // make sure the group is empty KConfigGroup cfg(krConfig, grpName); ListPanel *oldPanel = _tabbar->getPanel(i); oldPanel->saveSettings(cfg, true); disconnect(oldPanel); ListPanel *newPanel = createPanel(cfg); _stack->insertWidget(i, newPanel); _tabbar->changePanel(i, newPanel); if (_currentPanel == oldPanel) { _currentPanel = newPanel; _stack->setCurrentWidget(_currentPanel); } _stack->removeWidget(oldPanel); deletePanel(oldPanel); newPanel->restoreSettings(cfg); _tabbar->updateTab(newPanel); krConfig->deleteGroup(grpName); } tabsCountChanged(); _currentPanel->slotFocusOnMe(this == ACTIVE_MNG); emit pathChanged(_currentPanel); } void PanelManager::slotNextTab() { int currTab = _tabbar->currentIndex(); int nextInd = (currTab == _tabbar->count() - 1 ? 0 : currTab + 1); _tabbar->setCurrentIndex(nextInd); } void PanelManager::slotPreviousTab() { int currTab = _tabbar->currentIndex(); int nextInd = (currTab == 0 ? _tabbar->count() - 1 : currTab - 1); _tabbar->setCurrentIndex(nextInd); } void PanelManager::reloadConfig() { for (int i = 0; i < _tabbar->count(); i++) { ListPanel *panel = _tabbar->getPanel(i); if (panel) { panel->func->refresh(); } } } void PanelManager::deletePanel(ListPanel * p) { disconnect(p); delete p; } void PanelManager::slotCloseInactiveTabs() { int i = 0; while (i < _tabbar->count()) { if (i == activeTab()) i++; else slotCloseTab(i); } } void PanelManager::slotCloseDuplicatedTabs() { int i = 0; while (i < _tabbar->count() - 1) { ListPanel * panel1 = _tabbar->getPanel(i); if (panel1 != 0) { for (int j = i + 1; j < _tabbar->count(); j++) { ListPanel * panel2 = _tabbar->getPanel(j); if (panel2 != 0 && panel1->virtualPath().matches(panel2->virtualPath(), QUrl::StripTrailingSlash)) { if (j == activeTab()) { slotCloseTab(i); i--; break; } else { slotCloseTab(j); j--; } } } } i++; } } int PanelManager::findTab(QUrl url) { url.setPath(QDir::cleanPath(url.path())); for(int i = 0; i < _tabbar->count(); i++) { if(_tabbar->getPanel(i)) { QUrl panelUrl = _tabbar->getPanel(i)->virtualPath(); panelUrl.setPath(QDir::cleanPath(panelUrl.path())); if(panelUrl.matches(url, QUrl::StripTrailingSlash)) return i; } } return -1; } void PanelManager::slotLockTab() { ListPanel *panel = _currentPanel; panel->gui->setTabState(panel->gui->isLocked() ? ListPanel::TabState::DEFAULT : ListPanel::TabState::LOCKED); _actions->refreshActions(); _tabbar->updateTab(panel); } void PanelManager::slotPinTab() { ListPanel *panel = _currentPanel; panel->gui->setTabState(panel->gui->isPinned() ? ListPanel::TabState::DEFAULT : ListPanel::TabState::PINNED); if (panel->gui->isPinned()) { QUrl virtualPath = panel->virtualPath(); panel->setPinnedUrl(virtualPath); } _actions->refreshActions(); _tabbar->updateTab(panel); } void PanelManager::newTabs(const QStringList& urls) { for(int i = 0; i < urls.count(); i++) slotNewTab(QUrl::fromUserInput(urls[i], QString(), QUrl::AssumeLocalFile)); } diff --git a/krusader/paneltabbar.cpp b/krusader/paneltabbar.cpp index a4eccf3c..25eee47d 100644 --- a/krusader/paneltabbar.cpp +++ b/krusader/paneltabbar.cpp @@ -1,338 +1,339 @@ /***************************************************************************** * Copyright (C) 2002 Shie Erlich * * Copyright (C) 2002 Rafi Yanai * * Copyright (C) 2004-2018 Krusader Krew [https://krusader.org] * * * * Based on original code from Sebastian Trueg * * * * 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 "paneltabbar.h" #include "defaults.h" #include "tabactions.h" #include "../krglobal.h" +#include "../icon.h" #include "Panel/listpanel.h" #include "Panel/panelfunc.h" // QtCore #include // QtGui #include #include #include // QtWidgets #include #include #include #include -#include #include + static const int sDragEnterDelay = 500; // msec PanelTabBar::PanelTabBar(QWidget *parent, TabActions *actions): QTabBar(parent), _maxTabLength(0), _tabClicked(false), _draggingTab(false), _dragTabIndex(-1) { _panelActionMenu = new KActionMenu(i18n("Panel"), this); setAcceptDrops(true); insertAction(actions->actNewTab); insertAction(actions->actLockTab); insertAction(actions->actPinTab); insertAction(actions->actDupTab); insertAction(actions->actMoveTabToOtherSide); insertAction(actions->actCloseTab); insertAction(actions->actCloseInactiveTabs); insertAction(actions->actCloseDuplicatedTabs); setMovable(true); // enable drag'n'drop _dragTimer = new QTimer(this); _dragTimer->setSingleShot(true); _dragTimer->setInterval(sDragEnterDelay); connect(_dragTimer, &QTimer::timeout, this, [=]() { if (_dragTabIndex != -1 && _dragTabIndex != currentIndex()) { setCurrentIndex(_dragTabIndex); } _dragTabIndex = -1; }); setShape(QTabBar::TriangularSouth); } void PanelTabBar::insertAction(QAction* action) { _panelActionMenu->addAction(action); } int PanelTabBar::addPanel(ListPanel *panel, bool setCurrent, KrPanel *nextTo) { int insertIndex = -1; if (nextTo) { for (int i = 0; i < count(); i++) { if (getPanel(i) == nextTo) { insertIndex = i + 1; break; } } } QUrl virtualPath = panel->virtualPath(); panel->setPinnedUrl(virtualPath); const QString text = squeeze(virtualPath); const int index = insertIndex != -1 ? insertTab(insertIndex, text) : addTab(text); setTabData(index, QVariant((long long) panel)); setIcon(index, panel); // make sure all tabs lengths are correct layoutTabs(); if (setCurrent) setCurrentIndex(index); return index; } ListPanel* PanelTabBar::getPanel(int tabIdx) { QVariant v = tabData(tabIdx); if (v.isNull()) return 0; return (ListPanel*)v.toLongLong(); } void PanelTabBar::changePanel(int tabIdx, ListPanel *panel) { setTabData(tabIdx, QVariant((long long) panel)); } ListPanel* PanelTabBar::removePanel(int index, ListPanel* &panelToDelete) { panelToDelete = getPanel(index); // old panel to kill later disconnect(panelToDelete, 0, this, 0); removeTab(index); layoutTabs(); return getPanel(currentIndex()); } ListPanel* PanelTabBar::removeCurrentPanel(ListPanel* &panelToDelete) { return removePanel(currentIndex(), panelToDelete); } void PanelTabBar::updateTab(ListPanel *panel) { // find which is the correct tab for (int i = 0; i < count(); i++) { if ((ListPanel*)tabData(i).toLongLong() == panel) { setPanelTextToTab(i, panel); setIcon(i, panel); break; } } } void PanelTabBar::duplicateTab() { int id = currentIndex(); emit newTab(((ListPanel*)tabData(id).toLongLong())->virtualPath()); } void PanelTabBar::setIcon(int index, ListPanel *panel) { - QIcon tabIcon; + Icon tabIcon; if (panel->isLocked()) { - tabIcon = krLoader->loadIcon("lock", KIconLoader::Toolbar, 16); + tabIcon = Icon("lock"); } else if (panel->isPinned()) { - tabIcon = krLoader->loadIcon("pin", KIconLoader::Toolbar, 16); + tabIcon = Icon("pin"); } setTabIcon(index, tabIcon); } QString PanelTabBar::squeeze(const QUrl &url, int tabIndex) { const QString longText = url.isEmpty() ? i18n("[invalid]") : url.isLocalFile() ? url.path() : url.toDisplayString(); if (tabIndex >= 0) setTabToolTip(tabIndex, longText); const KConfigGroup group(krConfig, "Look&Feel"); const bool showLongNames = group.readEntry("Fullpath Tab Names", _FullPathTabNames); QString text; if (!showLongNames) { const QString scheme = url.scheme().isEmpty() || url.isLocalFile() ? "" : (url.scheme() + ":"); const QString host = url.host().isEmpty() ? "" : (url.host() + ":"); const QString name = url.isLocalFile() && url.fileName().isEmpty() ? "/" : url.fileName(); text = scheme + host + name; } else { text = longText; } if (text.isEmpty()) text = i18nc("invalid URL path", "?"); // set the real max length QFontMetrics fm(fontMetrics()); _maxTabLength = (static_cast(parent())->width() - (6 * fm.width("W"))) / fm.width("W"); // each tab gets a fair share of the max tab length const int effectiveTabLength = _maxTabLength / (count() == 0 ? 1 : count()); const int labelWidth = fm.width("W") * effectiveTabLength; const int textWidth = fm.width(text); if (textWidth <= labelWidth) return text; // squeeze text - start with the dots only QString squeezedText = "..."; int squeezedWidth = fm.width(squeezedText); int letters = text.length() * (labelWidth - squeezedWidth) / textWidth / 2; if (labelWidth < squeezedWidth) letters = 1; squeezedText = text.left(letters) + "..." + text.right(letters); squeezedWidth = fm.width(squeezedText); if (squeezedWidth < labelWidth) { // we estimated too short // add letters while text < label do { letters++; squeezedText = text.left(letters) + "..." + text.right(letters); squeezedWidth = fm.width(squeezedText); } while (squeezedWidth < labelWidth); letters--; squeezedText = text.left(letters) + "..." + text.right(letters); } else if (squeezedWidth > labelWidth) { // we estimated too long // remove letters while text > label do { letters--; squeezedText = text.left(letters) + "..." + text.right(letters); squeezedWidth = fm.width(squeezedText); } while (letters && squeezedWidth > labelWidth); } return squeezedText; } void PanelTabBar::resizeEvent(QResizeEvent *e) { QTabBar::resizeEvent(e); layoutTabs(); } void PanelTabBar::mouseMoveEvent(QMouseEvent* e) { QTabBar::mouseMoveEvent(e); if(_tabClicked) { _draggingTab = true; emit draggingTab(e); } } void PanelTabBar::mousePressEvent(QMouseEvent* e) { int clickedTab = tabAt(e->pos()); if (-1 == clickedTab) { // clicked on nothing ... QTabBar::mousePressEvent(e); return; } _tabClicked = true; setCurrentIndex(clickedTab); ListPanel *p = getPanel(clickedTab); if (p) p->slotFocusOnMe(); if (e->button() == Qt::RightButton) { // show the popup menu _panelActionMenu->menu()->popup(e->globalPos()); } else { if (e->button() == Qt::MidButton)// close the current tab emit closeCurrentTab(); } QTabBar::mousePressEvent(e); } void PanelTabBar::mouseReleaseEvent(QMouseEvent* e) { QTabBar::mouseReleaseEvent(e); if(_draggingTab) emit draggingTabFinished(e); _draggingTab = false; _tabClicked = false; } void PanelTabBar::dragEnterEvent(QDragEnterEvent *e) { e->accept(); handleDragEvent(tabAt(e->pos())); QTabBar::dragEnterEvent(e); } void PanelTabBar::dragLeaveEvent(QDragLeaveEvent *) { handleDragEvent(-1); } void PanelTabBar::dragMoveEvent(QDragMoveEvent *e) { e->ignore(); handleDragEvent(tabAt(e->pos())); QTabBar::dragMoveEvent(e); } void PanelTabBar::handleDragEvent(int tabIndex) { if (_dragTabIndex == tabIndex) return; _dragTabIndex = tabIndex; if (_dragTabIndex == -1) { _dragTimer->stop(); } else { _dragTimer->start(); } } void PanelTabBar::layoutTabs() { for (int i = 0; i < count(); i++) { setPanelTextToTab(i, (ListPanel*) tabData(i).toLongLong()); } } void PanelTabBar::setPanelTextToTab(int tabIndex, ListPanel *panel) { // update tab text from pinnedUrl in case the tab is pinned if (panel->isPinned()) { setTabText(tabIndex, squeeze(panel->pinnedUrl(), tabIndex)); } else { setTabText(tabIndex, squeeze(panel->virtualPath(), tabIndex)); } } diff --git a/krusader/resources.qrc b/krusader/resources.qrc index 5036de94..8ee5f23b 100644 --- a/krusader/resources.qrc +++ b/krusader/resources.qrc @@ -1,5 +1,6 @@ - - - layout.xml - + + + layout.xml + icons/icon-missing.svgz + diff --git a/krusader/useraction_examples.xml b/krusader/useraction_examples.xml index 1a8c3224..7f823ea0 100644 --- a/krusader/useraction_examples.xml +++ b/krusader/useraction_examples.xml @@ -1,90 +1,90 @@ Equal panel-size Sets the ratio between the two panels to 50/50 view-split-left-right Samples %aPanelSize("50")% Alt+Ctrl+Equal Edit as root Edit a file as root - kate + document-edit Samples Edit a file with root permissions EDITOR='kate -b' SUDO_ASKPASS=/usr/bin/ssh-askpass sudoedit -A %aCurrent% Ctrl+E Mount Mount a new filesystem - hdd_mount + media-mount Samples mount -t %_Ask("Filesystem Type?")% %_Ask("Device ?")% %_Ask("Mount Point ?")% Alt+Ctrl+M Enqueue in Amarok Append selected item(s) to Amarok playlist amarok Multimedia amarok --append %aList("Selected")% Meta+A Copy current item to clipboard edit-paste Samples %_Clipboard("%aCurrent%")% Alt+Ctrl+C Sort by Name Sort by Name - view_text + sort-name User Interface Sorts the active panel by Name %aColSort("Name")% Ctrl+1 Sort by Extension Sort by Extension - view_text + sort-name User Interface Sorts the active panel by Extension %aColSort("Ext")% Ctrl+2 Sort by Size Sort by Size - view_text + sort-name User Interface Sorts the active panel by Size %aColSort("Size")% Ctrl+3 Sort by Modified Sort by Modified - view_text + sort-name User Interface Sorts the active panel by Modified %aColSort("Modified")% Ctrl+4 Backup current Backup current file in current folder document-save-as System Backs current file up in current folder and asks the user for a new filename. By default ".old" is appended to the original filename. %_Copy("%aCurrent("", "No")%", "%_Ask("New filename", "%aCurrent%.old")%")% Meta+F5