diff --git a/krusader/Synchronizer/synchronizergui.cpp b/krusader/Synchronizer/synchronizergui.cpp
index 137a286f..e918523a 100644
--- a/krusader/Synchronizer/synchronizergui.cpp
+++ b/krusader/Synchronizer/synchronizergui.cpp
@@ -1,1633 +1,1634 @@
/***************************************************************************
synchronizergui.cpp - description
-------------------
copyright : (C) 2003 + by Csaba Karai
e-mail : krusader@users.sourceforge.net
web site : http://krusader.sourceforge.net
---------------------------------------------------------------------------
Description
***************************************************************************
A
db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b.
88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D
88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY'
88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b
88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88.
YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD
S o u r c e F i l e
***************************************************************************
* *
* This program 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. *
* *
***************************************************************************/
#include "synchronizergui.h"
#include "../krglobal.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->setUrls(urls);
drag->setMimeData(mimeData);
drag->start();
}
};
SynchronizerGUI::SynchronizerGUI(QWidget* parent, QUrl leftURL, QUrl rightURL, QStringList selList) :
QDialog(parent)
{
- initGUI(parent, QString(), leftURL, rightURL, selList);
+ initGUI(QString(), leftURL, rightURL, selList);
}
SynchronizerGUI::SynchronizerGUI(QWidget* parent, QString profile) :
QDialog(parent)
{
- initGUI(parent, profile, QUrl(), QUrl(), QStringList());
+ initGUI(profile, QUrl(), QUrl(), QStringList());
}
-void SynchronizerGUI::initGUI(QWidget* /* parent */, QString profileName, QUrl leftURL, QUrl rightURL, QStringList selList)
+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);
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);
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->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->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->setEnabled(false);
buttons->addWidget(btnStopComparing);
btnFeedToListBox = new QPushButton(this);
btnFeedToListBox->setText(i18n("Feed to listbox"));
btnFeedToListBox->setIcon(QIcon::fromTheme("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->setEnabled(false);
buttons->addWidget(btnSynchronize);
QPushButton *btnCloseSync = new QPushButton(this);
btnCloseSync->setText(i18n("Close"));
btnCloseSync->setIcon(QIcon::fromTheme("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))
- showMaximized();
- else
- show();
+ 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"));
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)))
button->setText(text);
button->setIcon(QIcon::fromTheme(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->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/Synchronizer/synchronizergui.h b/krusader/Synchronizer/synchronizergui.h
index 8279beb7..4a9c731f 100644
--- a/krusader/Synchronizer/synchronizergui.h
+++ b/krusader/Synchronizer/synchronizergui.h
@@ -1,262 +1,262 @@
/***************************************************************************
synchronizergui.h - description
-------------------
copyright : (C) 2003 + by Csaba Karai
e-mail : krusader@users.sourceforge.net
web site : http://krusader.sourceforge.net
---------------------------------------------------------------------------
Description
***************************************************************************
A
db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b.
88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D
88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY'
88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b
88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88.
YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD
H e a d e r F i l e
***************************************************************************
* *
* This program 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. *
* *
***************************************************************************/
#ifndef SYNCHRONIZERGUI_H
#define SYNCHRONIZERGUI_H
// QtCore
#include
// QtGui
#include
#include
#include
// QtWidgets
#include
#include
#include
#include
#include
#include "synchronizer.h"
#include "../GUI/profilemanager.h"
#include "../GUI/krtreewidget.h"
#include "../Filter/filtertabs.h"
#include "../Filter/generalfilter.h"
class QSpinBox;
-class SynchronizerGUI : QDialog
+class SynchronizerGUI : public QDialog
{
Q_OBJECT
public:
class SyncViewItem : public QTreeWidgetItem
{
private:
SynchronizerFileItem *syncItemRef;
SyncViewItem *lastItemRef;
public:
SyncViewItem(SynchronizerFileItem *item, QColor txt, QColor base, QTreeWidget * parent, QTreeWidgetItem *after, QString label1,
QString label2 = QString(), QString label3 = QString(), QString label4 = QString(),
QString label5 = QString(), QString label6 = QString(),
QString label7 = QString(), QString label8 = QString()) :
QTreeWidgetItem(parent, after), syncItemRef(item), lastItemRef(0) {
setText(0, label1);
setText(1, label2);
setText(2, label3);
setText(3, label4);
setText(4, label5);
setText(5, label6);
setText(6, label7);
setText(7, label8);
setTextAlignment(1, Qt::AlignRight);
setTextAlignment(3, Qt::AlignHCenter);
setTextAlignment(5, Qt::AlignRight);
item->setUserData((void *)this);
setColors(txt, base);
}
SyncViewItem(SynchronizerFileItem *item, QColor txt, QColor base, QTreeWidgetItem * parent, QTreeWidgetItem *after, QString label1,
QString label2 = QString(), QString label3 = QString(), QString label4 = QString(),
QString label5 = QString(), QString label6 = QString(),
QString label7 = QString(), QString label8 = QString()) :
QTreeWidgetItem(parent, after), syncItemRef(item), lastItemRef(0) {
setText(0, label1);
setText(1, label2);
setText(2, label3);
setText(3, label4);
setText(4, label5);
setText(5, label6);
setText(6, label7);
setText(7, label8);
setTextAlignment(1, Qt::AlignRight);
setTextAlignment(3, Qt::AlignHCenter);
setTextAlignment(5, Qt::AlignRight);
item->setUserData((void *)this);
setColors(txt, base);
}
~SyncViewItem() {
syncItemRef->setUserData(0);
}
inline SynchronizerFileItem * synchronizerItemRef() {
return syncItemRef;
}
inline SyncViewItem * lastItem() {
return lastItemRef;
}
inline void setLastItem(SyncViewItem*s) {
lastItemRef = s;
}
void setColors(QColor fore, QColor back) {
QBrush textColor(fore);
QBrush baseColor(back);
for (int i = 0; i != columnCount(); i++) {
if (back.isValid())
setBackground(i, baseColor);
if (fore.isValid())
setForeground(i, textColor);
}
}
};
public:
// if rightDirectory is null, leftDirectory is actually the profile name to load
SynchronizerGUI(QWidget* parent, QUrl leftDirectory, QUrl rightDirectory = QUrl(), QStringList selList = QStringList());
SynchronizerGUI(QWidget* parent, QString profile);
~SynchronizerGUI();
inline bool wasSynchronization() {
return wasSync;
}
public slots:
void rightMouseClicked(QTreeWidgetItem *, const QPoint &);
void doubleClicked(QTreeWidgetItem *);
void compare();
void synchronize();
void stop();
void feedToListBox();
void closeDialog();
void refresh();
void swapSides();
void loadFromProfile(QString);
void saveToProfile(QString);
protected slots:
void reject();
void addFile(SynchronizerFileItem *);
void markChanged(SynchronizerFileItem *, bool);
void setScrolling(bool);
void statusInfo(QString);
void subdirsChecked(bool);
void setPanelLabels();
void setCompletion();
void checkExcludeURLValidity(QString &text, QString &error);
void connectFilters(const QString &);
private:
- void initGUI(QWidget* parent, QString profile, QUrl leftURL, QUrl rightURL, QStringList selList);
+ void initGUI(QString profile, QUrl leftURL, QUrl rightURL, QStringList selList);
QString convertTime(time_t time) const;
void setMarkFlags();
void disableMarkButtons();
void enableMarkButtons();
void copyToClipboard(bool isLeft);
int convertToSeconds(int time, int unit);
void convertFromSeconds(int &time, int &unit, int second);
static QPushButton *createButton(QWidget *parent, const QString &iconName, bool checked,
const QKeySequence &shortCut, const QString &description,
const QString &text = QString(), bool textAndIcon = false);
protected:
virtual void keyPressEvent(QKeyEvent *) Q_DECL_OVERRIDE;
virtual void resizeEvent(QResizeEvent *e) Q_DECL_OVERRIDE;
virtual bool eventFilter(QObject *, QEvent *) Q_DECL_OVERRIDE;
void executeOperation(SynchronizerFileItem *item, int op);
ProfileManager *profileManager;
FilterTabs *filterTabs;
GeneralFilter *generalFilter;
QTabWidget *synchronizerTabs;
KHistoryComboBox *leftLocation;
KHistoryComboBox *rightLocation;
KHistoryComboBox *fileFilter;
KrTreeWidget *syncList;
Synchronizer synchronizer;
QCheckBox *cbSubdirs;
QCheckBox *cbSymlinks;
QCheckBox *cbByContent;
QCheckBox *cbIgnoreDate;
QCheckBox *cbAsymmetric;
QCheckBox *cbIgnoreCase;
QPushButton *btnSwapSides;
QPushButton *btnCompareDirs;
QPushButton *btnStopComparing;
QPushButton *btnSynchronize;
QPushButton *btnFeedToListBox;
QPushButton *btnScrollResults;
QPushButton *btnLeftToRight;
QPushButton *btnEquals;
QPushButton *btnDifferents;
QPushButton *btnRightToLeft;
QPushButton *btnDeletable;
QPushButton *btnDuplicates;
QPushButton *btnSingles;
QLabel *statusLabel;
QLabel *leftDirLabel;
QLabel *rightDirLabel;
QStringList selectedFiles;
QSpinBox *parallelThreadsSpinBox;
QSpinBox *equalitySpinBox;
QComboBox *equalityUnitCombo;
QSpinBox *timeShiftSpinBox;
QComboBox *timeShiftUnitCombo;
QCheckBox *ignoreHiddenFilesCB;
private:
static QString dirLabel(); // returns translated ''
bool isComparing;
bool wasClosed;
bool wasSync;
bool firstResize;
bool hasSelectedFiles;
SyncViewItem *lastItem;
int sizeX;
int sizeY;
QColor foreGrounds[ TT_MAX ];
QColor backGrounds[ TT_MAX ];
};
#endif /* __SYNCHRONIZERGUI_H__ */
diff --git a/krusader/UserAction/expander.cpp b/krusader/UserAction/expander.cpp
index 608b4be5..40e34b67 100644
--- a/krusader/UserAction/expander.cpp
+++ b/krusader/UserAction/expander.cpp
@@ -1,1215 +1,1216 @@
/*****************************************************************************
* Copyright (C) 2004 Jonas Bähr *
* Copyright (C) 2004 Shie Erlich *
* *
* This program 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. *
* *
* This package 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 this package; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
*****************************************************************************/
#include "expander.h"
#include "../krusader.h"
#include "../krusaderview.h"
#include "../panelmanager.h"
#include "../Panel/listpanel.h"
#include "../Panel/panelfunc.h"
#include "../Panel/PanelView/krview.h"
#include "../Search/krsearchdialog.h"
#include "../GUI/profilemanager.h"
#include "../FileSystem/filesystemprovider.h"
#include "../KViewer/krviewer.h"
#include "../krservices.h"
#ifdef SYNCHRONIZER_ENABLED
#include "../Synchronizer/synchronizergui.h"
#endif
#ifdef __KJSEMBED__
#include "../KrJS/krjs.h"
#endif
// QtCore
#include
#include
#include
#include
#include
// QtGui
#include
// QtWidgets
#include
#include
#include
#include
#include
#include
using namespace std;
#define NEED_PANEL if (panel==0) { panelMissingError(_expression,exp); return QString(); }
inline void exp_placeholder::setError(Expander& exp, const Error& e)
{
exp.setError(e);
}
inline QStringList exp_placeholder::splitEach(const TagString& s)
{
return Expander::splitEach(s);
}
inline exp_placeholder::exp_placeholder()
{
}
void exp_placeholder::panelMissingError(const QString &s, Expander& exp)
{
exp.setError(Error(Error::exp_S_FATAL, Error::exp_C_ARGUMENT, i18n("Needed panel specification missing in expander %1", s)));
}
QStringList exp_placeholder::fileList(const KrPanel* const panel, const QString& type, const QString& mask, const bool omitPath, const bool useUrl, Expander& exp, const QString& error)
{
QStringList items;
if (type.isEmpty() || type == "all")
panel->view->getItemsByMask(mask, &items);
else if (type == "files")
panel->view->getItemsByMask(mask, &items, false, true);
else if (type == "dirs")
panel->view->getItemsByMask(mask, &items, true, false);
else if (type == "selected")
panel->view->getSelectedItems(&items);
else {
setError(exp, Error(Error::exp_S_FATAL, Error::exp_C_ARGUMENT, i18n("Expander: Bad argument to %1: %2 is not valid item specifier", error, type)));
return QStringList();
}
if (!omitPath) { // add the current path
// translate to urls using filesystem
QList list = panel->func->files()->getUrls(items);
items.clear();
// parse everything to a single qstring
foreach(const QUrl &url, list) {
items.push_back(useUrl ? url.url() : url.path());
}
}
return items;
}
namespace
{
class exp_simpleplaceholder : public exp_placeholder
{
public:
EXP_FUNC;
virtual TagString expFunc(const KrPanel*, const QStringList&, const bool&, Expander&) const = 0;
};
#define PLACEHOLDER_CLASS(name) \
class name : public exp_placeholder { \
public: \
name(); \
virtual TagString expFunc ( const KrPanel*, const TagStringList&, const bool&, Expander& ) const; \
};
#define SIMPLE_PLACEHOLDER_CLASS(name) \
class name : public exp_simpleplaceholder { \
public: \
using exp_simpleplaceholder::expFunc; \
name(); \
virtual TagString expFunc ( const KrPanel*, const QStringList&, const bool&, Expander& ) const; \
};
/**
* expands %_Path% ('_' is replaced by 'a', 'o', 'r' or 'l' to indicate the active, other, right or left panel) with the path of the specified panel
*/
SIMPLE_PLACEHOLDER_CLASS(exp_Path)
/**
* expands %_Count% ('_' is replaced by 'a', 'o', 'r' or 'l' to indicate the active, other, right or left panel) with the number of items, which type is specified by the first Parameter
*/
SIMPLE_PLACEHOLDER_CLASS(exp_Count)
/**
* expands %_Filter% ('_' is replaced by 'a', 'o', 'r' or 'l' to indicate the active, other, right or left panel) with the correspondend filter (ie: "*.cpp")
*/
SIMPLE_PLACEHOLDER_CLASS(exp_Filter)
/**
* expands %_Current% ('_' is replaced by 'a', 'o', 'r' or 'l' to indicate the active, other, right or left panel) with the current item ( != the selected onec)
*/
SIMPLE_PLACEHOLDER_CLASS(exp_Current);
/**
* expands %_List% ('_' is replaced by 'a', 'o', 'r' or 'l' to indicate the active, other, right or left panel) with a list of items, which type is specified by the first Parameter
*/
SIMPLE_PLACEHOLDER_CLASS(exp_List);
/**
* expands %_ListFile% ('_' is replaced by 'a', 'o', 'r' or 'l' to indicate
* the active, other, right or left panel) with the name of a temporary file,
* containing a list of items, which type is specified by the first Parameter
*/
SIMPLE_PLACEHOLDER_CLASS(exp_ListFile);
/**
* expands %_Ask% ('_' is necessary because there is no panel needed)
* with the return of an input-dialog
*/
SIMPLE_PLACEHOLDER_CLASS(exp_Ask);
/**
* This copies it's first Parameter to the clipboard
*/
PLACEHOLDER_CLASS(exp_Clipboard);
/**
* This selects all items by the mask given with the first Parameter
*/
SIMPLE_PLACEHOLDER_CLASS(exp_Select);
/**
* This changes the panel'spath to the value given with the first Parameter.
*/
SIMPLE_PLACEHOLDER_CLASS(exp_Goto);
/**
* This is equal to 'cp '.
*/
PLACEHOLDER_CLASS(exp_Copy);
/**
* This is equal to 'mv '.
*/
PLACEHOLDER_CLASS(exp_Move);
#ifdef SYNCHRONIZER_ENABLED
/**
* This opens the synchronizer with a given profile
*/
SIMPLE_PLACEHOLDER_CLASS(exp_Sync);
#endif
/**
* This opens the searchmodule with a given profile
*/
SIMPLE_PLACEHOLDER_CLASS(exp_NewSearch);
/**
* This loads the panel-profile with a given name
*/
SIMPLE_PLACEHOLDER_CLASS(exp_Profile);
/**
* This is setting marks in the string where he is later split up for each {all, selected, files, dirs}
*/
SIMPLE_PLACEHOLDER_CLASS(exp_Each);
/**
* This sets the sorting on a specific colunm
*/
SIMPLE_PLACEHOLDER_CLASS(exp_ColSort);
/**
* This sets relation between the left and right panel
*/
SIMPLE_PLACEHOLDER_CLASS(exp_PanelSize);
#ifdef __KJSEMBED__
/**
* This sets relation between the left and right panel
*/
SIMPLE_PLACEHOLDER_CLASS(exp_Script);
#endif
/**
* This loads a file in the internal viewer
*/
SIMPLE_PLACEHOLDER_CLASS(exp_View);
////////////////////////////////////////////////////////////
//////////////////////// utils ////////////////////////
////////////////////////////////////////////////////////////
/**
* escapes everything that confuses bash in filenames
* @param s String to manipulate
* @return escaped string
*/
QString bashquote(QString s)
{
/*
// we _can_not_ use this function because it _encloses_ the sting in single-quots!
// In this case quotes strings could not be concaternated anymore
return KrServices::quote(s);
*/
static const QString evilstuff = "\\\"'`()[]{}!?;$&<>| \t\r\n"; // stuff that should get escaped
for (int i = 0; i < evilstuff.length(); ++i)
s.replace(evilstuff[ i ], ('\\' + evilstuff[ i ]));
return s;
}
QString separateAndQuote(QStringList list, const QString& separator, const bool quote)
{
if (quote)
transform(list.begin(), list.end(), list.begin(), bashquote);
// QLineEdit::text() always escapes special characters, revert this for newline and tab
QString decodedSeparator = separator;
decodedSeparator.replace("\\n", "\n").replace("\\t", "\t");
return list.join(decodedSeparator);
}
/////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////// expander classes ////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
exp_Path::exp_Path()
{
_expression = "Path";
_description = i18n("Panel's Path...");
_needPanel = true;
addParameter(exp_parameter(i18n("Automatically escape spaces"), "__yes", false));
}
TagString exp_Path::expFunc(const KrPanel* panel, const QStringList& parameter, const bool& useUrl, Expander& exp) const
{
NEED_PANEL
QString result;
if (useUrl)
result = panel->func->files()->currentDirectory().url() + '/';
else
result = panel->func->files()->currentDirectory().path() + '/';
if (parameter.count() > 0 && parameter[0].toLower() == "no") // don't escape spaces
return TagString(result);
else
return TagString(bashquote(result));
}
exp_Count::exp_Count()
{
_expression = "Count";
_description = i18n("Number of...");
_needPanel = true;
addParameter(exp_parameter(i18n("Count:"), "__choose:All;Files;Dirs;Selected", false));
}
TagString exp_Count::expFunc(const KrPanel* panel, const QStringList& parameter, const bool&, Expander& exp) const
{
NEED_PANEL
int n = -1;
if (parameter.count() == 0 || parameter[ 0 ].isEmpty() || parameter[ 0 ].toLower() == "all")
n = panel->view->numDirs() + panel->view->numFiles();
else if (parameter[ 0 ].toLower() == "files")
n = panel->view->numFiles();
else if (parameter[ 0 ].toLower() == "dirs")
n = panel->view->numDirs();
else if (parameter[ 0 ].toLower() == "selected")
n = panel->view->numSelected();
else {
setError(exp, Error(Error::exp_S_FATAL, Error::exp_C_ARGUMENT, i18n("Expander: Bad argument to Count: %1 is not valid item specifier", parameter[0])));
return QString();
}
return TagString(QString("%1").arg(n));
}
exp_Filter::exp_Filter()
{
_expression = "Filter";
_description = i18n("Filter Mask (*.h, *.cpp, etc.)");
_needPanel = true;
}
TagString exp_Filter::expFunc(const KrPanel* panel, const QStringList&, const bool&, Expander& exp) const
{
NEED_PANEL
return panel->view->filterMask().nameFilter();
}
exp_Current::exp_Current()
{
_expression = "Current";
_description = i18n("Current File (!= Selected File)...");
_needPanel = true;
addParameter(exp_parameter(i18n("Omit the current path (optional)"), "__no", false));
addParameter(exp_parameter(i18n("Automatically escape spaces"), "__yes", false));
}
TagString exp_Current::expFunc(const KrPanel* panel, const QStringList& parameter, const bool& useUrl, Expander& exp) const
{
NEED_PANEL
QString item = panel->view->getCurrentItem();
QString result;
if (parameter.count() > 0 && parameter[0].toLower() == "yes") // omit the current path
result = item;
else {
QUrl url = panel->func->files()->getUrl(item);
if (useUrl)
result = url.url();
else
result = url.path();
}
if (parameter.count() > 1 && parameter[1].toLower() == "no") // don't escape spaces
return result;
else
return bashquote(result);
}
exp_List::exp_List()
{
_expression = "List";
_description = i18n("Item List of...");
_needPanel = true;
addParameter(exp_parameter(i18n("Which items:"), "__choose:All;Files;Dirs;Selected", false));
addParameter(exp_parameter(i18n("Separator between the items (optional):"), " ", false));
addParameter(exp_parameter(i18n("Omit the current path (optional)"), "__no", false));
addParameter(exp_parameter(i18n("Mask (optional, all but 'Selected'):"), "__select", false));
addParameter(exp_parameter(i18n("Automatically escape spaces"), "__yes", false));
}
TagString exp_List::expFunc(const KrPanel* panel, const QStringList& parameter, const bool& useUrl, Expander& exp) const
{
NEED_PANEL
// get selected items from view
QStringList items;
QString mask;
if (parameter.count() <= 3 || parameter[3].isEmpty())
mask = '*';
else
mask = parameter[3];
return separateAndQuote(
fileList(panel,
parameter.isEmpty() ? QString() : parameter[0].toLower(),
mask, parameter.count() > 2 ? parameter[2].toLower() == "yes" : false,
useUrl, exp, "List"),
parameter.count() > 1 ? parameter[1] : " ",
parameter.count() > 4 ? parameter[4].toLower() == "yes" : true);
}
exp_ListFile::exp_ListFile()
{
_expression = "ListFile";
_description = i18n("Filename of an Item List...");
_needPanel = true;
addParameter(exp_parameter(i18n("Which items:"), "__choose:All;Files;Dirs;Selected", false));
addParameter(exp_parameter(i18n("Separator between the items (optional)"), "\n", false));
addParameter(exp_parameter(i18n("Omit the current path (optional)"), "__no", false));
addParameter(exp_parameter(i18n("Mask (optional, all but 'Selected'):"), "__select", false));
addParameter(exp_parameter(i18n("Automatically escape spaces"), "__no", false));
}
TagString exp_ListFile::expFunc(const KrPanel* panel, const QStringList& parameter, const bool& useUrl, Expander& exp) const
{
NEED_PANEL
// get selected items from view
QStringList items;
QString mask;
if (parameter.count() <= 3 || parameter[3].isEmpty())
mask = '*';
else
mask = parameter[3];
QTemporaryFile tmpFile(QDir::tempPath() + QLatin1String("/krusader_XXXXXX.itemlist"));
tmpFile.setAutoRemove(false);
if (!tmpFile.open()) {
setError(exp, Error(Error::exp_S_FATAL, Error::exp_C_WORLD, i18n("Expander: temporary file could not be opened (%1)", tmpFile.errorString())));
return QString();
}
QTextStream stream(&tmpFile);
stream << separateAndQuote(
fileList(panel,
parameter.isEmpty() ? QString() : parameter[0].toLower(),
mask, parameter.count() > 2 ? parameter[2].toLower() == "yes" : false,
useUrl, exp, "ListFile"),
parameter.count() > 1 ? parameter[1] : "\n",
parameter.count() > 4 ? parameter[4].toLower() == "yes" : true)
<< "\n";
tmpFile.close();
return tmpFile.fileName();
}
exp_Select::exp_Select()
{
_expression = "Select";
_description = i18n("Manipulate the Selection...");
_needPanel = true;
addParameter(exp_parameter(i18n("Selection mask:"), "__select", true));
addParameter(exp_parameter(i18n("Manipulate in which way:"), "__choose:Set;Add;Remove", false));
}
TagString exp_Select::expFunc(const KrPanel* panel, const QStringList& parameter, const bool& , Expander& exp) const
{
NEED_PANEL
KRQuery mask;
if (parameter.count() <= 0 || parameter[0].isEmpty())
mask = KRQuery("*");
else
mask = KRQuery(parameter[0]);
if (parameter.count() > 1 && parameter[1].toLower() == "list-add")
panel->view->select(mask);
else if (parameter.count() > 1 && parameter[1].toLower() == "list-remove")
panel->view->unselect(mask);
else { // parameter[1].toLower() == "set" or isEmpty() or whatever
panel->view->unselect(KRQuery("*"));
panel->view->select(mask);
}
return QString(); // this doesn't return anything, that's normal!
}
exp_Goto::exp_Goto()
{
_expression = "Goto";
_description = i18n("Jump to a Location...");
_needPanel = true;
addParameter(exp_parameter(i18n("Choose a path:"), "__goto", true));
addParameter(exp_parameter(i18n("Open location in a new tab"), "__no", false));
}
TagString exp_Goto::expFunc(const KrPanel* panel, const QStringList& parameter, const bool&, Expander& exp) const
{
NEED_PANEL
bool newTab = false;
if (parameter.count() > 1 && parameter[1].toLower() == "yes")
newTab = true;
if (parameter.count() == 0) {
setError(exp, Error(Error::exp_S_FATAL, Error::exp_C_ARGUMENT, i18n("Expander: at least 1 parameter is required for Goto.")));
return QString();
}
QUrl url = QUrl::fromUserInput(parameter[0], QString(), QUrl::AssumeLocalFile);
if (newTab) {
if (panel == LEFT_PANEL)
MAIN_VIEW->leftManager()->slotNewTab(url);
else
MAIN_VIEW->rightManager()->slotNewTab(url);
} else {
panel->func->openUrl(url, "");
panel->gui->slotFocusOnMe();
}
return QString(); // this doesn't return anything, that's normal!
}
/*
exp_Search::exp_Search() {
_expression = "Search";
_description = i18n("Search for files");
_needPanel = true;
addParameter( new exp_parameter( i18n("please choose the setting"), "__searchprofile", true ) );
addParameter( new exp_parameter( i18n("open the search in a new tab"), "__yes", false ) ); //TODO: add this also to panel-dependent as soon as filesystem support the display of search-results
}
*/
exp_Ask::exp_Ask()
{
_expression = "Ask";
_description = i18n("Ask Parameter from User...");
_needPanel = false;
addParameter(exp_parameter(i18n("Question:"), "Where do you want do go today?", true));
addParameter(exp_parameter(i18n("Preset (optional):"), "", false));
addParameter(exp_parameter(i18n("Caption (optional):"), "", false));
}
TagString exp_Ask::expFunc(const KrPanel*, const QStringList& parameter, const bool&, Expander& exp) const
{
QString caption, preset, result;
if (parameter.count() == 0) {
setError(exp, Error(Error::exp_S_FATAL, Error::exp_C_ARGUMENT, i18n("Expander: at least 1 parameter is required for Ask.")));
return QString();
}
if (parameter.count() <= 2 || parameter[2].isEmpty())
caption = i18n("User Action");
else
caption = parameter[2];
if (parameter.count() <= 1 || parameter[1].isEmpty())
preset.clear();
else
preset = parameter[1];
bool ok;
result = QInputDialog::getText(krMainWindow, caption, parameter[0], QLineEdit::Normal, preset, &ok);
if (ok)
return result;
else {
setError(exp, Error(Error::exp_S_ERROR, Error::exp_C_USER, "User cancelled"));
return QString();
}
}
exp_Clipboard::exp_Clipboard()
{
_expression = "Clipboard";
_description = i18n("Copy to Clipboard...");
_needPanel = false;
addParameter(exp_parameter(i18n("What to copy:"), "__placeholder", true));
addParameter(exp_parameter(i18n("Append to current clipboard content with this separator (optional):"), "", false));
}
TagString exp_Clipboard::expFunc(const KrPanel*, const TagStringList& parameter, const bool&, Expander& exp) const
{
// qDebug() << "Expander::exp_Clipboard, parameter[0]: '" << parameter[0] << "', Clipboard: " << QApplication::clipboard()->text() << endl;
if (parameter.count() == 0) {
setError(exp, Error(Error::exp_S_FATAL, Error::exp_C_ARGUMENT, i18n("Expander: at least 1 parameter is required for Clipboard.")));
return QString();
}
QStringList lst = splitEach(parameter[0]);
if (parameter.count() > 1 && !parameter[1].isSimple()) {
setError(exp, Error(Error::exp_S_FATAL, Error::exp_C_SYNTAX, i18n("Expander: %Each% may not be in the second argument of %Clipboard%")));
return QString();
}
if (parameter.count() <= 1 || parameter[1].string().isEmpty() || QApplication::clipboard()->text().isEmpty())
QApplication::clipboard()->setText(lst.join("\n"));
else
QApplication::clipboard()->setText(QApplication::clipboard()->text() + parameter[1].string() + lst.join("\n"));
return QString(); // this doesn't return anything, that's normal!
}
exp_Copy::exp_Copy()
{
_expression = "Copy";
_description = i18n("Copy a File/Folder...");
_needPanel = false;
addParameter(exp_parameter(i18n("What to copy:"), "__placeholder", true));
addParameter(exp_parameter(i18n("Where to copy:"), "__placeholder", true));
}
TagString exp_Copy::expFunc(const KrPanel*, const TagStringList& parameter, const bool&, Expander& exp) const
{
if (parameter.count() < 2) {
setError(exp, Error(Error::exp_S_FATAL, Error::exp_C_ARGUMENT, i18n("Expander: at least 2 parameter is required for Copy.")));
return QString();
}
// basically the parameter can already be used as URL, but since QUrl has problems with ftp-proxy-urls (like ftp://username@proxyusername@url...) this is neccesary:
QStringList lst = splitEach(parameter[0]);
if (!parameter[1].isSimple()) {
setError(exp, Error(Error::exp_S_FATAL, Error::exp_C_SYNTAX, i18n("Expander: %Each% may not be in the second argument of %Copy%")));
return QString();
}
QList src;
for (QStringList::const_iterator it = lst.constBegin(), end = lst.constEnd();it != end;++it)
src.push_back(QUrl::fromUserInput(*it, QString(), QUrl::AssumeLocalFile));
// or transform(...) ?
QUrl dest = QUrl::fromUserInput(parameter[1].string(), QString(), QUrl::AssumeLocalFile);
if (!dest.isValid() || find_if(src.constBegin(), src.constEnd(), not1(mem_fun_ref(&QUrl::isValid))) != src.constEnd()) {
setError(exp, Error(Error::exp_S_FATAL, Error::exp_C_ARGUMENT, i18n("Expander: invalid URLs in %_Copy(\"src\", \"dest\")%")));
return QString();
}
FileSystemProvider::instance().startCopyFiles(src, dest);
return QString(); // this doesn't return everything, that's normal!
}
exp_Move::exp_Move()
{
_expression = "Move";
_description = i18n("Move/Rename a File/Folder...");
_needPanel = false;
addParameter(exp_parameter(i18n("What to move/rename:"), "__placeholder", true));
addParameter(exp_parameter(i18n("New target/name:"), "__placeholder", true));
}
TagString exp_Move::expFunc(const KrPanel*, const TagStringList& parameter, const bool& , Expander& exp) const
{
if (parameter.count() < 2) {
setError(exp, Error(Error::exp_S_FATAL, Error::exp_C_ARGUMENT, i18n("Expander: at least 2 parameter is required for Move.")));
return QString();
}
// basically the parameter can already be used as URL, but since QUrl has problems with ftp-proxy-urls (like ftp://username@proxyusername@url...) this is neccesary:
QStringList lst = splitEach(parameter[0]);
if (!parameter[1].isSimple()) {
setError(exp, Error(Error::exp_S_FATAL, Error::exp_C_SYNTAX, i18n("%Each% may not be in the second argument of %Move%")));
return QString();
}
QList src;
for (QStringList::const_iterator it = lst.constBegin(), end = lst.constEnd();it != end;++it)
src.push_back(QUrl::fromUserInput(*it, QString(), QUrl::AssumeLocalFile));
// or transform(...) ?
QUrl dest = QUrl::fromUserInput(parameter[1].string(), QString(), QUrl::AssumeLocalFile);
if (!dest.isValid() || find_if(src.constBegin(), src.constEnd(), not1(mem_fun_ref(&QUrl::isValid))) != src.constEnd()) {
setError(exp, Error(Error::exp_S_FATAL, Error::exp_C_ARGUMENT, i18n("Expander: invalid URLs in %_Move(\"src\", \"dest\")%")));
return QString();
}
FileSystemProvider::instance().startCopyFiles(src, dest, KIO::CopyJob::Move);
return QString(); // this doesn't return anything, that's normal!
}
#ifdef SYNCHRONIZER_ENABLED
exp_Sync::exp_Sync()
{
_expression = "Sync";
_description = i18n("Load a Synchronizer Profile...");
_needPanel = false;
addParameter(exp_parameter(i18n("Choose a profile:"), "__syncprofile", true));
}
TagString exp_Sync::expFunc(const KrPanel*, const QStringList& parameter, const bool&, Expander& exp) const
{
if (parameter.count() == 0 || parameter[0].isEmpty()) {
setError(exp, Error(Error::exp_S_FATAL, Error::exp_C_ARGUMENT, i18n("Expander: no profile specified for %_Sync(profile)%")));
return QString();
}
- new SynchronizerGUI(0, parameter[0]);
+ SynchronizerGUI *synchronizerDialog = new SynchronizerGUI(MAIN_VIEW, parameter[0]);
+ synchronizerDialog->show(); // destroyed on close
return QString(); // this doesn't return everything, that's normal!
}
#endif
exp_NewSearch::exp_NewSearch()
{
_expression = "NewSearch";
_description = i18n("Load a Searchmodule Profile...");
_needPanel = false;
addParameter(exp_parameter(i18n("Choose a profile:"), "__searchprofile", true));
}
TagString exp_NewSearch::expFunc(const KrPanel*, const QStringList& parameter, const bool&, Expander& exp) const
{
if (parameter.count() == 0 || parameter[0].isEmpty()) {
setError(exp, Error(Error::exp_S_FATAL, Error::exp_C_ARGUMENT, i18n("Expander: no profile specified for %_NewSearch(profile)%")));
return QString();
}
new KrSearchDialog(parameter[0], krApp);
return QString(); // this doesn't return everything, that's normal!
}
exp_Profile::exp_Profile()
{
_expression = "Profile";
_description = i18n("Load a Panel Profile...");
_needPanel = false;
addParameter(exp_parameter(i18n("Choose a profile:"), "__panelprofile", true));
}
TagString exp_Profile::expFunc(const KrPanel*, const QStringList& parameter, const bool&, Expander& exp) const
{
if (parameter.count() == 0 || parameter[0].isEmpty()) {
setError(exp, Error(Error::exp_S_FATAL, Error::exp_C_ARGUMENT, i18n("Expander: no profile specified for %_Profile(profile)%; abort...")));
return QString();
}
MAIN_VIEW->profiles(parameter[0]);
return QString(); // this doesn't return everything, that's normal!
}
exp_Each::exp_Each()
{
_expression = "Each";
_description = i18n("Separate Program Call for Each...");
_needPanel = true;
addParameter(exp_parameter(i18n("Which items:"), "__choose:All;Files;Dirs;Selected", false));
addParameter(exp_parameter(i18n("Omit the current path (optional)"), "__no", false));
addParameter(exp_parameter(i18n("Mask (optional, all but 'Selected'):"), "__select", false));
addParameter(exp_parameter(i18n("Automatically escape spaces"), "__yes", false));
}
TagString exp_Each::expFunc(const KrPanel* panel, const QStringList& parameter, const bool& useUrl, Expander& exp) const
{
NEED_PANEL
QString mask;
if (parameter.count() <= 2 || parameter[2].isEmpty())
mask = '*';
else
mask = parameter[2];
TagString ret;
QStringList l = fileList(panel,
parameter.empty() ? QString() : parameter[0].toLower(),
mask, parameter.count() > 1 && parameter[1].toLower() == "yes",
useUrl, exp, "Each");
if (!(parameter.count() <= 3 || parameter[3].toLower() != "yes"))
transform(l.begin(), l.end(), l.begin(), bashquote);
ret.insertTag(0, l);
return ret;
}
exp_ColSort::exp_ColSort()
{
_expression = "ColSort";
_description = i18n("Set Sorting for This Panel...");
_needPanel = true;
addParameter(exp_parameter(i18n("Choose a column:"), "__choose:Name;Ext;Type;Size;Modified;Perms;rwx;Owner;Group", true));
addParameter(exp_parameter(i18n("Choose a sort sequence:"), "__choose:Toggle;Asc;Desc", false));
}
TagString exp_ColSort::expFunc(const KrPanel* panel, const QStringList& parameter, const bool&, Expander& exp) const
{
NEED_PANEL
if (parameter.count() == 0 || parameter[0].isEmpty()) {
setError(exp, Error(Error::exp_S_FATAL, Error::exp_C_ARGUMENT, i18n("Expander: no column specified for %_ColSort(column)%")));
return QString();
}
KrViewProperties::ColumnType oldColumn = panel->view->properties()->sortColumn;
KrViewProperties::ColumnType column = oldColumn;
if (parameter[0].toLower() == "name") {
column = KrViewProperties::Name;
} else if (parameter[0].toLower() == "ext") {
column = KrViewProperties::Ext;
} else if (parameter[0].toLower() == "type") {
column = KrViewProperties::Type;
} else if (parameter[0].toLower() == "size") {
column = KrViewProperties::Size;
} else if (parameter[0].toLower() == "modified") {
column = KrViewProperties::Modified;
} else if (parameter[0].toLower() == "changed") {
column = KrViewProperties::Changed;
} else if (parameter[0].toLower() == "accessed") {
column = KrViewProperties::Accessed;
} else if (parameter[0].toLower() == "perms") {
column = KrViewProperties::Permissions;
} else if (parameter[0].toLower() == "rwx") {
column = KrViewProperties::KrPermissions;
} else if (parameter[0].toLower() == "owner") {
column = KrViewProperties::Owner;
} else if (parameter[0].toLower() == "group") {
column = KrViewProperties::Group;
} else {
setError(exp, Error(Error::exp_S_WARNING, Error::exp_C_ARGUMENT,
i18n("Expander: unknown column specified for %_ColSort(%1)%",
parameter[0])));
return QString();
}
bool descending = panel->view->properties()->sortOptions & KrViewProperties::Descending;
if (parameter.count() <= 1 || (parameter[1].toLower() != "asc" && parameter[1].toLower() != "desc")) { // no sortdir parameter
if(column == oldColumn) // reverse direction if column is unchanged
descending = !descending;
else // otherwise set to ascending
descending = false;
} else { // sortdir specified
if (parameter[1].toLower() == "asc")
descending = false;
else // == desc
descending = true;
}
panel->view->setSortMode(column, descending);
return QString(); // this doesn't return anything, that's normal!
}
exp_PanelSize::exp_PanelSize()
{
_expression = "PanelSize";
_description = i18n("Set Relation Between the Panels...");
_needPanel = true;
addParameter(exp_parameter(i18n("Set the new size in percent:"), "__int:0;100;5;50", true));
}
TagString exp_PanelSize::expFunc(const KrPanel* panel, const QStringList& parameter, const bool&, Expander& exp) const
{
NEED_PANEL
int newSize;
if (parameter.count() == 0 || parameter[0].isEmpty())
newSize = 50; //default is 50%
else
newSize = parameter[0].toInt();
if (newSize < 0 || newSize > 100) {
setError(exp, Error(Error::exp_S_FATAL, Error::exp_C_ARGUMENT, i18n("Expander: Value %1 out of range for %_PanelSize(percent)%. The first parameter has to be >0 and <100", newSize)));
return QString();
}
MAIN_VIEW->setPanelSize(panel->isLeft(), newSize);
return QString(); // this doesn't return everything, that's normal!
}
#ifdef __KJSEMBED__
exp_Script::exp_Script()
{
_expression = "Script";
_description = i18n("Execute a JavaScript Extension...");
_needPanel = false;
addParameter(exp_parameter(i18n("Location of the script"), "", true));
addParameter(exp_parameter(i18n("Set some variables for the execution (optional).\ni.e. \"return=return_var;foo=bar\", consult the handbook for more information"), "", false));
}
TagString exp_Script::expFunc(const KrPanel*, const QStringList& parameter, const bool&, Expander& exp) const
{
if (parameter.count() == 0 || parameter[0].isEmpty()) {
setError(exp, Error(Error::exp_S_FATAL, Error::exp_C_ARGUMENT, i18n("Expander: no script specified for %_Script(script)%")));
return QString();
}
QString filename = parameter[0];
if (filename.find('/') && QUrl::isRelativeUrl(filename)) {
// this return the local version of the file if this exists. else the global one is returnd
filename = locate("data", "krusader/js/" + filename);
}
if (! krJS)
krJS = new KrJS();
KJS::ExecState *exec = krJS->globalExec();
QString jsReturn;
if (parameter[1].toLower() == "yes") // to stay compatible with the old-style parameter
jsReturn = "cmd";
else {
QStringList jsVariables = parameter[1].split(';');
QString jsVariable, jsValue;
for (QStringList::Iterator it = jsVariables.begin(); it != jsVariables.end(); ++it) {
jsVariable = (*it).section('=', 0, 0).trimmed();
jsValue = (*it).section('=', 1);
if (jsVariable == "return")
jsReturn = jsValue.trimmed();
else
krJS->putValue(jsVariable, KJSEmbed::convertToValue(exec, jsValue));
}
}
krJS->runFile(filename);
if (! jsReturn.isEmpty())
return krJS->getValue(jsReturn).toString(krJS->globalExec()).qstring();
else
return QString();
}
#endif
exp_View::exp_View()
{
_expression = "View";
_description = i18n("View File with Krusader's Internal Viewer...");
_needPanel = false;
addParameter(exp_parameter(i18n("Which file to view (normally '%aCurrent%'):"), "__placeholder", true));
addParameter(exp_parameter(i18n("Choose a view mode:"), "__choose:generic;text;hex", false));
//addParameter( exp_parameter( i18n("Choose a window-mode"), "__choose:tab;window;panel", false ) );
//TODO: window-mode 'panel' should open the file in the third-hand viewer
addParameter(exp_parameter(i18n("Choose a window mode:"), "__choose:tab;window", false));
}
TagString exp_View::expFunc(const KrPanel*, const QStringList& parameter, const bool&, Expander& exp) const
{
if (parameter.count() == 0 || parameter[0].isEmpty()) {
setError(exp, Error(Error::exp_S_FATAL, Error::exp_C_ARGUMENT, i18n("Expander: no file to view in %_View(filename)%")));
return QString();
}
QString viewMode, windowMode;
if (parameter.count() <= 1 || parameter[1].isEmpty())
viewMode = "generic";
else
viewMode = parameter[1];
if (parameter.count() <= 2 || parameter[2].isEmpty())
windowMode = "tab";
else
windowMode = parameter[2];
KrViewer::Mode mode = KrViewer::Generic;
if (viewMode == "text") mode = KrViewer::Text;
else if (viewMode == "hex") mode = KrViewer::Hex;
QUrl url = QUrl::fromUserInput(parameter[0], QString(), QUrl::AssumeLocalFile);
KrViewer::view(url, mode, (windowMode == "window"));
//TODO: Call the viewer with viewMode and windowMode. Filename is in parameter[0].
// It would be nice if parameter[0] could also be a space-separated filename-list (provided if the first parameter is %aList(selected)%)
return QString(); // this doesn't return everything, that's normal!
}
/////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// end of expander classes ////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
TagString exp_simpleplaceholder::expFunc(const KrPanel* p, const TagStringList& parameter, const bool& useUrl, Expander& exp) const
{
QStringList lst;
for (TagStringList::const_iterator it = parameter.begin(), end = parameter.end();it != end;++it)
if ((*it).isSimple())
lst.push_back((*it).string());
else {
setError(exp, Error(Error::exp_S_FATAL, Error::exp_C_SYNTAX, i18n("%Each% is not allowed in parameter to %1", description())));
return QString();
}
return expFunc(p, lst, useUrl, exp);
}
}
KrPanel* Expander::getPanel(const char panelIndicator, const exp_placeholder* pl, Expander& exp)
{
switch (panelIndicator) {
case 'a':
return ACTIVE_PANEL;
case 'o':
return OTHER_PANEL;
case 'l':
return LEFT_PANEL;
case 'r':
return RIGHT_PANEL;
case '_':
return 0;
default:
exp.setError(Error(Error::exp_S_FATAL, Error::exp_C_SYNTAX, i18n("Expander: Bad panel specifier %1 in placeholder %2", panelIndicator, pl->description())));
return 0;
}
}
void Expander::expand(const QString& stringToExpand, bool useUrl)
{
TagString result = expandCurrent(stringToExpand, useUrl);
if (error())
return;
if (!result.isSimple())
resultList = splitEach(result);
else
resultList.append(result.string());
// krOut << resultList[0] << endl;
}
TagString Expander::expandCurrent(const QString& stringToExpand, bool useUrl)
{
TagString result;
QString exp;
TagString tmpResult;
int begin, end, i;
// int brackets = 0;
// bool inQuotes = false;
int idx = 0;
while (idx < stringToExpand.length()) {
if ((begin = stringToExpand.indexOf('%', idx)) == -1) break;
if ((end = findEnd(stringToExpand, begin)) == -1) {
// xgettext:no-c-format
setError(Error(Error::exp_S_FATAL, Error::exp_C_SYNTAX, i18n("Error: unterminated % in Expander")));
return QString();
}
result += stringToExpand.mid(idx, begin - idx); // copy until the start of %exp%
// get the expression, and expand it using the correct expander function
exp = stringToExpand.mid(begin + 1, end - begin - 1);
// qDebug() << "------------- exp: '" << exp << "'" << endl;
if (exp.isEmpty())
result += QString(QChar('%'));
else {
TagStringList parameter = separateParameter(&exp, useUrl);
if (error())
return QString();
char panelIndicator = exp.toLower()[0].toLatin1();
exp.replace(0, 1, "");
for (i = 0; i < placeholderCount(); ++i)
if (exp == placeholder(i)->expression()) {
// qDebug() << "---------------------------------------" << endl;
tmpResult = placeholder(i)->expFunc(getPanel(panelIndicator, placeholder(i), *this), parameter, useUrl, *this);
if (error()) {
return QString();
} else
result += tmpResult;
// qDebug() << "---------------------------------------" << endl;
break;
}
if (i == placeholderCount()) { // didn't find an expander
setError(Error(Error::exp_S_FATAL, Error::exp_C_SYNTAX, i18n("Error: unrecognized %%%1%2%% in Expander", panelIndicator, exp)));
return QString();
}
} //else
idx = end + 1;
}
// copy the rest of the string
result += stringToExpand.mid(idx);
// qDebug() << "============== result '" << result << "'" << endl;
return result;
}
QStringList Expander::splitEach(TagString stringToSplit)
{
if (stringToSplit.isSimple()) {
// krOut << stringToSplit.string() << endl;
QStringList l;
l << stringToSplit.string();
return l;
}
pair pl = *stringToSplit.tagsBegin();
stringToSplit.eraseTag(stringToSplit.tagsBegin());
QStringList ret;
for (QStringList::const_iterator it = pl.second.constBegin(), end = pl.second.constEnd();it != end;++it) {
TagString s = stringToSplit;
s.insert(pl.first, *it);
ret += splitEach(s);
}
return ret;
// qDebug() << "stringToSplit: " << stringToSplit << endl;
}
TagStringList Expander::separateParameter(QString* const exp, bool useUrl)
{
TagStringList parameter;
QStringList parameter1;
QString result;
int begin, end;
if ((begin = exp->indexOf('(')) != -1) {
if ((end = exp->lastIndexOf(')')) == -1) {
setError(Error(Error::exp_S_FATAL, Error::exp_C_SYNTAX, i18n("Error: missing ')' in Expander")));
return TagStringList();
}
result = exp->mid(begin + 1, end - begin - 1);
*exp = exp->left(begin);
bool inQuotes = false;
int idx = 0;
begin = 0;
while (idx < result.length()) {
if (result[ idx ].toLatin1() == '\\') {
if (result[ idx+1 ].toLatin1() == '"')
result.replace(idx, 1, "");
}
if (result[ idx ].toLatin1() == '"')
inQuotes = !inQuotes;
if (result[ idx ].toLatin1() == ',' && !inQuotes) {
parameter1.append(result.mid(begin, idx - begin));
begin = idx + 1;
// krOut << " ---- parameter: " << parameter.join(";") << endl;
}
idx++;
}
parameter1.append(result.mid(begin, idx - begin)); //don't forget the last one
for (QStringList::Iterator it = parameter1.begin(); it != parameter1.end(); ++it) {
*it = (*it).trimmed();
if ((*it).left(1) == "\"")
*it = (*it).mid(1, (*it).length() - 2);
parameter.push_back(expandCurrent(*it, useUrl));
if (error())
return TagStringList();
}
}
// krOut << "------- exp: " << *exp << " ---- parameter: " << parameter.join(";") << endl;
return parameter;
}
int Expander::findEnd(const QString& str, int start)
{
int end = str.indexOf('%', start + 1);
if (end == -1)
return end;
int bracket = str.indexOf('(', start + 1);
if (end < bracket || bracket == -1)
return end;
int idx = bracket + 1;
bool inQuotes = false;
int depth = 1;
while (idx < str.length()) {
switch (str[ idx ].toLatin1()) {
case '\\':
idx ++;
break;
case '"':
inQuotes = !inQuotes;
break;
case '(':
if (!inQuotes)
depth++;
break;
case ')':
if (!inQuotes)
--depth;
break;
case '%':
if (depth == 0)
return idx;
} //switch
idx++;
} //while
// failsafe
return -1;
}
QList& Expander::_placeholder()
{
static QList ret;
if(!ret.count()) {
ret << new exp_View;
ret << new exp_PanelSize;
ret << new exp_ColSort;
ret << new exp_Each;
ret << new exp_Profile;
ret << new exp_NewSearch;
#ifdef SYNCHRONIZER_ENABLED
ret << new exp_Sync;
#endif
ret << new exp_Move;
ret << new exp_Copy;
ret << new exp_Goto;
ret << new exp_Select;
ret << new exp_Clipboard;
ret << new exp_Ask;
ret << new exp_ListFile;
ret << new exp_List;
ret << new exp_Current;
ret << new exp_Filter;
ret << new exp_Count;
ret << new exp_Path;
#ifdef __KJSEMBED__
ret << new exp_Script;
#endif
}
return ret;
}
diff --git a/krusader/krslots.cpp b/krusader/krslots.cpp
index d432b8d5..a7d1fb08 100644
--- a/krusader/krslots.cpp
+++ b/krusader/krslots.cpp
@@ -1,753 +1,755 @@
/***************************************************************************
krslots.cpp
-------------------
copyright : (C) 2001 by Shie Erlich & Rafi Yanai
email : krusader@users.sourceforge.net
web site : http://krusader.sourceforge.net
---------------------------------------------------------------------------
Description
***************************************************************************
A
db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b.
88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D
88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY'
88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b
88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88.
YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD
S o u r c e F i l e
***************************************************************************
* *
* This program 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. *
* *
***************************************************************************/
#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 "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/panelpopup.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)
{
- new SynchronizerGUI(0, LEFT_PANEL->virtualPath(), RIGHT_PANEL->virtualPath(), 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 du(ACTIVE_PANEL->virtualPath(), MAIN_VIEW);
}
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"));
act->setData(QVariant(OPEN_ID));
act = trashMenu.addAction(krLoader->loadIcon("trash-empty", KIconLoader::Panel), 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();
}