Merged custom actions feature
FossilOrigin-Name: 7cd82ba8f02f659d13a370043f256212f55669db
This commit is contained in:
commit
a69645064c
33
manifest
33
manifest
@ -1,5 +1,5 @@
|
||||
C Add\ssupport\sfor\sFreeBSD
|
||||
D 2015-07-08T20:10:53.376
|
||||
C Merged\scustom\sactions\sfeature
|
||||
D 2015-07-10T18:24:26.540
|
||||
F .travis.yml 77966888a81c4ceee1fcc79bce842c9667ad8a35
|
||||
F debian/changelog eb4304dfcb6bb66850ec740838090eb50ce1249b
|
||||
F debian/compat b6abd567fa79cbe0196d093a067271361dc6ca8b
|
||||
@ -219,27 +219,27 @@ F src/FileActionDialog.h 15db1650b3a13d70bc338371e4c033c66e3b79ce
|
||||
F src/FileTableView.cpp 5ddf8c391c9a3ac449ec61fb1db837b577afeec2
|
||||
F src/FileTableView.h 03e56d87c2d46411b9762b87f4d301619aaf18df
|
||||
F src/Fossil.cpp 0149ce9af91392bb51b87c700e7edd4f8a4aefe7
|
||||
F src/Fossil.h e706992b331385660d57df6a27e5418342c14e19
|
||||
F src/Fossil.h 02599a958e6c27ac5f15d52a813abd40b8f5b2f4
|
||||
F src/FslSettingsDialog.cpp 2531d3709f0eab66651671e3edead2ca720d07d5
|
||||
F src/FslSettingsDialog.h dfe2a61884a55a74cbb9206b6f6b482b979725e7
|
||||
F src/LoggedProcess.cpp 2a1e5c94bc1e57c8984563e66c210e43a14dc60c
|
||||
F src/LoggedProcess.h 85df7c635c807a5a0e8c4763f17a0752aaff7261
|
||||
F src/MainWindow.cpp 191dff3e4759644be48ce40048d6f93d3a5e03f2
|
||||
F src/MainWindow.h 31870bca434835471159ab350583c21028e77e47
|
||||
F src/MainWindow.cpp 764eb76c1c420ea4677639baae925e5e8fc203d6
|
||||
F src/MainWindow.h 765c362ad4937da808276ec321adf4a351ab5b28
|
||||
F src/RemoteDialog.cpp 8540cc5e2e41c4127ed8a028d84691604fa6ecac
|
||||
F src/RemoteDialog.h 5e0438c2bd7c79b1bb44bfbd58c2181b544a9e5d
|
||||
F src/RevisionDialog.cpp e58c4f8a704f00addebb15d521b76620fdafda79
|
||||
F src/RevisionDialog.h b718c3009342eaabad39c8a11a253a4e4fef7a73
|
||||
F src/SearchBox.cpp d4209c575baa9933e1ce5ed376e785b289a145ba
|
||||
F src/SearchBox.h 0c78d3a68136dab3e0e71b83ae36f22bd2688ab2
|
||||
F src/Settings.cpp 7a674604caa9d9f5ffb6b73d95745bde09525389
|
||||
F src/Settings.h 883ac5c0f38a6ac93b400b7b96447b017ee50c06
|
||||
F src/SettingsDialog.cpp 25be4c351dd21ea9132321944f42dc0bc22fb128
|
||||
F src/SettingsDialog.h b324dfd77ca3ad24fd83588aaf79a7e4c291e716
|
||||
F src/Utils.cpp d53b1b92352e586a7c12a19ec6b109a9f095b7f1
|
||||
F src/Utils.h 011e4be3f94cd26be537299cd44ab9c135db44a5
|
||||
F src/Settings.cpp 258d3f466f6a125ce2b8519d6d57a312cbc44a3f
|
||||
F src/Settings.h 0a10b0b83fe804bdc7dac58eed06b5b6ee422055
|
||||
F src/SettingsDialog.cpp cab739fb0569bd26550e57f97136c7515fe757fe
|
||||
F src/SettingsDialog.h 5eb3ae2cbb00ab5544e1889860f5376f69fe47cd
|
||||
F src/Utils.cpp 876942a44202611d3c778c67f6d0a344e241a000
|
||||
F src/Utils.h 4613424aaeb6910689b5821a2dd44ca0b6dd301f
|
||||
F src/Workspace.cpp 7004c2c30f79d2e64691aa9b2c55ee72a84d978b
|
||||
F src/Workspace.h 7ae2e63196433ae34864d182e49e3a2f0726fb78
|
||||
F src/Workspace.h 0ab9b941a537134a7c43cfccee5299b8ccda143a
|
||||
F src/main.cpp d8c65ea5e54102e4989fef9fd8cfd4f13ef8a8f0
|
||||
F tools/git-push.sh 62cc58434cae5b7bcd6bd9d4cce8b08739f31cd7 x
|
||||
F tools/pack.sh d7f38a498c4e9327fecd6a6e5ac27be270d43008 x
|
||||
@ -251,8 +251,9 @@ F ui/FslSettingsDialog.ui eb3d4cb764cab90b01e82922237d8c42d6ce1749
|
||||
F ui/MainWindow.ui 10181826a25056ed5aba2b23a7d110159be7c043
|
||||
F ui/RemoteDialog.ui 95a4750d972ed8c49bb10b95db91ff16cfe2dd0b
|
||||
F ui/RevisionDialog.ui 27c3b98c665fec014a50cbf3352c0627f75e68cd
|
||||
F ui/SettingsDialog.ui 4c480cd595a32664d01c85bf74845c4282fc0068
|
||||
P e7792ddc67a212767eafe7c59f346d58e71c8d51 0987410cc3fd8d64510e762b1845880a416c27b3
|
||||
R adcbe091d9c9da5e307a37458d63ec2e
|
||||
F ui/SettingsDialog.ui 47b9a31e28ad523f14a1c4cd361270b6babbdf7d
|
||||
P d869092a71de1d2294d475f394a17f35740420aa 4270974c3f9f7fb166a74a9d76c9db8a24428fe5
|
||||
R 59482a1a26cd7b9ebf570bd4be545d73
|
||||
T +closed 4270974c3f9f7fb166a74a9d76c9db8a24428fe5
|
||||
U kostas
|
||||
Z bf0228f8244ded20fee8d07eb1281cca
|
||||
Z e952ccb1c86d4465716c40a0723206c8
|
||||
|
@ -1 +1 @@
|
||||
d869092a71de1d2294d475f394a17f35740420aa
|
||||
7cd82ba8f02f659d13a370043f256212f55669db
|
@ -10,8 +10,6 @@ class QStringList;
|
||||
|
||||
typedef QMap<QString, QString> stashmap_t;
|
||||
|
||||
#define PATH_SEPARATOR "/"
|
||||
|
||||
enum RunFlags
|
||||
{
|
||||
RUNFLAGS_NONE = 0<<0,
|
||||
|
@ -99,6 +99,12 @@ MainWindow::MainWindow(Settings &_settings, QWidget *parent, QString *workspaceP
|
||||
QAction *separator = new QAction(this);
|
||||
separator->setSeparator(true);
|
||||
|
||||
fileActionSeparator = new QAction(this);
|
||||
fileActionSeparator->setSeparator(true);
|
||||
|
||||
workspaceActionSeparator = new QAction(this);
|
||||
workspaceActionSeparator->setSeparator(true);
|
||||
|
||||
// fileTableView
|
||||
ui->fileTableView->setModel(&getWorkspace().getFileModel());
|
||||
|
||||
@ -111,6 +117,7 @@ MainWindow::MainWindow(Settings &_settings, QWidget *parent, QString *workspaceP
|
||||
ui->fileTableView->addAction(ui->actionRevert);
|
||||
ui->fileTableView->addAction(ui->actionRename);
|
||||
ui->fileTableView->addAction(ui->actionDelete);
|
||||
|
||||
connect( ui->fileTableView,
|
||||
SIGNAL( dragOutEvent() ),
|
||||
SLOT( onFileViewDragOut() ),
|
||||
@ -199,7 +206,7 @@ MainWindow::MainWindow(Settings &_settings, QWidget *parent, QString *workspaceP
|
||||
}
|
||||
}
|
||||
Q_ASSERT(recent_sep);
|
||||
for (int i = 0; i < MAX_RECENT; ++i)
|
||||
for(int i = 0; i < MAX_RECENT; ++i)
|
||||
{
|
||||
recentWorkspaceActs[i] = new QAction(this);
|
||||
recentWorkspaceActs[i]->setVisible(false);
|
||||
@ -207,6 +214,16 @@ MainWindow::MainWindow(Settings &_settings, QWidget *parent, QString *workspaceP
|
||||
ui->menuFile->insertAction(recent_sep, recentWorkspaceActs[i]);
|
||||
}
|
||||
|
||||
// Custom Actions
|
||||
for(int i = 0; i < settings.GetCustomActions().size(); ++i)
|
||||
{
|
||||
customActions[i] = new QAction(this);
|
||||
customActions[i]->setVisible(false);
|
||||
connect(customActions[i], SIGNAL(triggered()), this, SLOT(on_actionCustomAction_triggered()));
|
||||
customActions[i]->setData(i);
|
||||
customActions[i]->setShortcut(QKeySequence(QString("Ctrl+%0").arg(i+1)));
|
||||
}
|
||||
|
||||
// TabWidget
|
||||
ui->tabWidget->setCurrentIndex(TAB_LOG);
|
||||
|
||||
@ -604,7 +621,7 @@ void MainWindow::enableActions(bool on)
|
||||
ui->actionDeleteTag,
|
||||
ui->actionCreateBranch,
|
||||
ui->actionMergeBranch,
|
||||
ui->actionFossilSettings
|
||||
ui->actionFossilSettings,
|
||||
};
|
||||
|
||||
for(size_t i=0; i<COUNTOF(actions); ++i)
|
||||
@ -1055,6 +1072,39 @@ void MainWindow::applySettings()
|
||||
// Set the workspace after loading the settings, since it may trigger a remote info storage
|
||||
if(!active_workspace.isEmpty())
|
||||
setCurrentWorkspace(active_workspace);
|
||||
|
||||
|
||||
// Custom Actions
|
||||
for(int i=0; i<MAX_CUSTOM_ACTIONS; ++i)
|
||||
settings.GetCustomActions()[i].Clear();
|
||||
|
||||
int num_actions = store->beginReadArray("CustomActions");
|
||||
int last_action = 0;
|
||||
for(int i=0; i<num_actions; ++i)
|
||||
{
|
||||
store->setArrayIndex(i);
|
||||
CustomAction &action = settings.GetCustomActions()[last_action];
|
||||
|
||||
QString descr;
|
||||
if(store->contains("Description"))
|
||||
descr = store->value("Description").toString();
|
||||
|
||||
if(descr.isEmpty())
|
||||
continue;
|
||||
action.Description = descr;
|
||||
|
||||
if(store->contains("Command"))
|
||||
action.Command = store->value("Command").toString();
|
||||
if(store->contains("Context"))
|
||||
action.Context = static_cast<CustomActionContext>(store->value("Context").toInt());
|
||||
if(store->contains("MultipleSelection"))
|
||||
action.MultipleSelection = store->value("MultipleSelection").toBool();
|
||||
|
||||
++last_action;
|
||||
}
|
||||
store->endArray();
|
||||
|
||||
updateCustomActions();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -1093,6 +1143,25 @@ void MainWindow::updateSettings()
|
||||
store->setValue("ViewUnchanged", ui->actionViewUnchanged->isChecked());
|
||||
store->setValue("ViewIgnored", ui->actionViewIgnored->isChecked());
|
||||
store->setValue("ViewAsList", ui->actionViewAsList->isChecked());
|
||||
|
||||
// Custom Actions
|
||||
Settings::custom_actions_t &actions = settings.GetCustomActions();
|
||||
store->beginWriteArray("CustomActions", actions.size());
|
||||
int active_actions = 0;
|
||||
for(int i=0; i<actions.size(); ++i)
|
||||
{
|
||||
CustomAction &action = actions[i];
|
||||
if(!action.IsValid())
|
||||
continue;
|
||||
store->setArrayIndex(active_actions);
|
||||
|
||||
store->setValue("Description", action.Description);
|
||||
store->setValue("Command", action.Command);
|
||||
store->setValue("Context", static_cast<int>(action.Context));
|
||||
store->setValue("MultipleSelection", action.MultipleSelection);
|
||||
++active_actions;
|
||||
}
|
||||
store->endArray();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -1144,7 +1213,7 @@ void MainWindow::getSelectionPaths(stringset_t &paths)
|
||||
Q_ASSERT(data.isValid());
|
||||
|
||||
WorkspaceItem tv = data.value<WorkspaceItem>();
|
||||
if(tv.Type != WorkspaceItem::TYPE_FOLDER)
|
||||
if(tv.Type != WorkspaceItem::TYPE_FOLDER && tv.Type != WorkspaceItem::TYPE_WORKSPACE)
|
||||
continue;
|
||||
|
||||
paths.insert(tv.Value);
|
||||
@ -1364,6 +1433,8 @@ void MainWindow::on_fileTableView_doubleClicked(const QModelIndex &/*index*/)
|
||||
on_actionOpenFile_triggered();
|
||||
else if(action==FILE_DLBCLICK_ACTION_OPENCONTAINING)
|
||||
on_actionOpenContaining_triggered();
|
||||
else if(action==FILE_DLBCLICK_ACTION_CUSTOM)
|
||||
invokeCustomAction(0);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -1654,6 +1725,8 @@ void MainWindow::on_actionSettings_triggered()
|
||||
// Run the dialog
|
||||
if(!SettingsDialog::run(this, settings))
|
||||
return;
|
||||
|
||||
updateCustomActions();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -2440,7 +2513,7 @@ void MainWindow::on_actionCreateBranch_triggered()
|
||||
updateRevision(branch_name);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void MainWindow::MergeRevision(const QString &defaultRevision)
|
||||
void MainWindow::mergeRevision(const QString &defaultRevision)
|
||||
{
|
||||
QStringList res;
|
||||
QString revision = defaultRevision;
|
||||
@ -2474,7 +2547,7 @@ void MainWindow::on_actionMergeBranch_triggered()
|
||||
|
||||
if(!selectedBranches.isEmpty())
|
||||
revision = selectedBranches.first();
|
||||
MergeRevision(revision);
|
||||
mergeRevision(revision);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -2661,3 +2734,103 @@ void MainWindow::on_actionDeleteRemote_triggered()
|
||||
updateWorkspaceView();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void MainWindow::updateCustomActions()
|
||||
{
|
||||
Settings::custom_actions_t custom_actions = settings.GetCustomActions();
|
||||
Q_ASSERT(MAX_CUSTOM_ACTIONS == custom_actions.size());
|
||||
|
||||
// Remove All Actions
|
||||
for(int i = 0; i < custom_actions.size(); ++i)
|
||||
{
|
||||
QAction *action = customActions[i];
|
||||
ui->fileTableView->removeAction(action);
|
||||
menuWorkspace->removeAction(action);
|
||||
}
|
||||
ui->fileTableView->removeAction(fileActionSeparator);
|
||||
menuWorkspace->removeAction(workspaceActionSeparator);
|
||||
|
||||
// Add them to the top
|
||||
ui->fileTableView->addAction(fileActionSeparator);
|
||||
menuWorkspace->addAction(workspaceActionSeparator);
|
||||
|
||||
bool has_file_actions = false;
|
||||
bool has_folder_actions = false;
|
||||
|
||||
for(int i = 0; i < custom_actions.size(); ++i)
|
||||
{
|
||||
CustomAction &cust_act = custom_actions[i];
|
||||
QAction *action = customActions[i];
|
||||
action->setVisible(cust_act.IsValid());
|
||||
action->setText(cust_act.Description);
|
||||
|
||||
if(cust_act.IsActive(ACTION_CONTEXT_FILES))
|
||||
{
|
||||
ui->fileTableView->addAction(action);
|
||||
has_file_actions = true;
|
||||
}
|
||||
|
||||
if(cust_act.IsActive(ACTION_CONTEXT_FOLDERS))
|
||||
{
|
||||
menuWorkspace->addAction(action);
|
||||
has_folder_actions = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!has_file_actions)
|
||||
ui->fileTableView->removeAction(fileActionSeparator);
|
||||
|
||||
if(!has_folder_actions)
|
||||
menuWorkspace->removeAction(workspaceActionSeparator);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void MainWindow::invokeCustomAction(int actionId)
|
||||
{
|
||||
Q_ASSERT(actionId < settings.GetCustomActions().size());
|
||||
CustomAction &cust_action = settings.GetCustomActions()[actionId];
|
||||
Q_ASSERT(cust_action.IsValid());
|
||||
|
||||
Q_ASSERT(!cust_action.Command.isEmpty());
|
||||
|
||||
QStringList file_selection;
|
||||
if(cust_action.IsActive(ACTION_CONTEXT_FILES))
|
||||
getSelectionFilenames(file_selection, WorkspaceFile::TYPE_ALL);
|
||||
|
||||
stringset_t path_selection;
|
||||
if(cust_action.IsActive(ACTION_CONTEXT_FOLDERS))
|
||||
getSelectionPaths(path_selection);
|
||||
|
||||
// Trim excess items for single selection
|
||||
if(!cust_action.MultipleSelection)
|
||||
{
|
||||
if(!file_selection.empty())
|
||||
{
|
||||
QString item = *file_selection.begin();
|
||||
file_selection.clear();
|
||||
file_selection.push_back(item);
|
||||
path_selection.clear();
|
||||
}
|
||||
else if(!path_selection.empty())
|
||||
{
|
||||
QString item = *path_selection.begin();
|
||||
path_selection.clear();
|
||||
path_selection.insert(item);
|
||||
}
|
||||
}
|
||||
|
||||
const QString &wkdir = fossil().getCurrentWorkspace();
|
||||
|
||||
SpawnExternalProcess(this, cust_action.Command, file_selection, path_selection, wkdir, uiCallback);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void MainWindow::on_actionCustomAction_triggered()
|
||||
{
|
||||
QAction *action = qobject_cast<QAction *>(sender());
|
||||
if(!action)
|
||||
return;
|
||||
|
||||
int action_id = action->data().toInt();
|
||||
invokeCustomAction(action_id);
|
||||
}
|
||||
|
@ -52,7 +52,9 @@ private:
|
||||
void updateWorkspaceView();
|
||||
void updateFileView();
|
||||
void selectRootDir();
|
||||
void MergeRevision(const QString& defaultRevision);
|
||||
void mergeRevision(const QString& defaultRevision);
|
||||
void updateCustomActions();
|
||||
void invokeCustomAction(int actionId);
|
||||
|
||||
void fossilBrowse(const QString &fossilUrl);
|
||||
void dragEnterEvent(class QDragEnterEvent *event);
|
||||
@ -132,6 +134,7 @@ private slots:
|
||||
void on_actionSetDefaultRemote_triggered();
|
||||
void on_actionAddRemote_triggered();
|
||||
void on_actionDeleteRemote_triggered();
|
||||
void on_actionCustomAction_triggered();
|
||||
|
||||
private:
|
||||
class MainWinUICallback : public UICallback
|
||||
@ -169,6 +172,9 @@ private:
|
||||
QFileIconProvider iconProvider;
|
||||
icon_map_t iconCache;
|
||||
class QAction *recentWorkspaceActs[MAX_RECENT];
|
||||
class QAction *customActions[MAX_CUSTOM_ACTIONS];
|
||||
class QAction *fileActionSeparator;
|
||||
class QAction *workspaceActionSeparator;
|
||||
class QProgressBar *progressBar;
|
||||
class QLabel *lblRevision;
|
||||
class QLabel *lblTags;
|
||||
|
@ -37,6 +37,14 @@ Settings::Settings(bool portableMode) : store(0)
|
||||
if(!HasValue(FUEL_SETTING_WEB_BROWSER))
|
||||
SetValue(FUEL_SETTING_WEB_BROWSER, 0);
|
||||
|
||||
|
||||
for(int i=0; i<MAX_CUSTOM_ACTIONS; ++i)
|
||||
{
|
||||
CustomAction action;
|
||||
action.Id = QObject::tr("Custom Action %0").arg(i+1);
|
||||
customActions.append(action);
|
||||
}
|
||||
|
||||
ApplyEnvironment();
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <QMap>
|
||||
#include <QVariant>
|
||||
#include <QTranslator>
|
||||
#include <QVector>
|
||||
|
||||
#define FUEL_SETTING_FOSSIL_PATH "FossilPath"
|
||||
#define FUEL_SETTING_COMMIT_MSG "CommitMsgHistory"
|
||||
@ -24,9 +25,56 @@ enum FileDblClickAction
|
||||
FILE_DLBCLICK_ACTION_DIFF,
|
||||
FILE_DLBCLICK_ACTION_OPEN,
|
||||
FILE_DLBCLICK_ACTION_OPENCONTAINING,
|
||||
FILE_DLBCLICK_ACTION_CUSTOM, // Custom Action 1
|
||||
FILE_DLBCLICK_ACTION_MAX
|
||||
};
|
||||
|
||||
|
||||
enum CustomActionContext
|
||||
{
|
||||
ACTION_CONTEXT_FILES = 1 << 0,
|
||||
ACTION_CONTEXT_FOLDERS = 1 << 1,
|
||||
ACTION_CONTEXT_FILES_AND_FOLDERS = ACTION_CONTEXT_FILES|ACTION_CONTEXT_FOLDERS
|
||||
};
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
MAX_CUSTOM_ACTIONS = 9
|
||||
};
|
||||
|
||||
struct CustomAction
|
||||
{
|
||||
QString Id;
|
||||
QString Description;
|
||||
QString Command;
|
||||
CustomActionContext Context;
|
||||
bool MultipleSelection;
|
||||
|
||||
CustomAction()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return !(Description.isEmpty() || Command.isEmpty());
|
||||
}
|
||||
|
||||
bool IsActive(CustomActionContext context) const
|
||||
{
|
||||
return (Context & context) != 0;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
Description.clear();
|
||||
Command.clear();
|
||||
Context = ACTION_CONTEXT_FILES;
|
||||
MultipleSelection = true;
|
||||
}
|
||||
};
|
||||
|
||||
struct Settings
|
||||
{
|
||||
struct Setting
|
||||
@ -43,6 +91,7 @@ struct Settings
|
||||
SettingType Type;
|
||||
};
|
||||
typedef QMap<QString, Setting> mappings_t;
|
||||
typedef QVector<CustomAction> custom_actions_t;
|
||||
|
||||
|
||||
Settings(bool portableMode = false);
|
||||
@ -63,10 +112,14 @@ struct Settings
|
||||
|
||||
bool SupportsLang(const QString &langId) const;
|
||||
bool InstallLang(const QString &langId);
|
||||
|
||||
custom_actions_t &GetCustomActions() { return customActions; }
|
||||
private:
|
||||
mappings_t Mappings;
|
||||
class QSettings *store;
|
||||
QTranslator translator;
|
||||
mappings_t Mappings;
|
||||
class QSettings *store;
|
||||
QTranslator translator;
|
||||
|
||||
custom_actions_t customActions;
|
||||
};
|
||||
|
||||
|
||||
|
@ -17,6 +17,7 @@ SettingsDialog::SettingsDialog(QWidget *parent, Settings &_settings) :
|
||||
ui->cmbDoubleClickAction->addItem(tr("Diff File"));
|
||||
ui->cmbDoubleClickAction->addItem(tr("Open File"));
|
||||
ui->cmbDoubleClickAction->addItem(tr("Open Containing Folder"));
|
||||
ui->cmbDoubleClickAction->addItem(tr("Custom Action %0").arg(1));
|
||||
|
||||
ui->cmbFossilBrowser->addItem(tr("System"));
|
||||
ui->cmbFossilBrowser->addItem(tr("Internal"));
|
||||
@ -36,6 +37,22 @@ SettingsDialog::SettingsDialog(QWidget *parent, Settings &_settings) :
|
||||
ui->cmbActiveLanguage->findText(
|
||||
LangIdToName(lang)));
|
||||
|
||||
|
||||
lastActionIndex = 0;
|
||||
currentCustomActions = settings->GetCustomActions();
|
||||
|
||||
ui->cmbCustomActionContext->addItem(tr("Files"));
|
||||
ui->cmbCustomActionContext->addItem(tr("Folders"));
|
||||
ui->cmbCustomActionContext->setCurrentIndex(0);
|
||||
|
||||
GetCustomAction(0);
|
||||
|
||||
for(int i=0; i<currentCustomActions.size(); ++i)
|
||||
{
|
||||
CustomAction &a = currentCustomActions[i];
|
||||
ui->cmbCustomAction->addItem(a.Id);
|
||||
}
|
||||
ui->cmbCustomAction->setCurrentIndex(0);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -68,6 +85,17 @@ void SettingsDialog::on_buttonBox_accepted()
|
||||
if(curr_langid != new_langid)
|
||||
QMessageBox::information(this, tr("Restart required"), tr("The language change will take effect after restarting the application"), QMessageBox::Ok);
|
||||
|
||||
for(int i=0; i<currentCustomActions.size(); ++i)
|
||||
{
|
||||
CustomAction &a = currentCustomActions[i];
|
||||
a.Description = a.Description.trimmed();
|
||||
a.Command = QDir::fromNativeSeparators(a.Command.trimmed());
|
||||
}
|
||||
|
||||
PutCustomAction(ui->cmbCustomAction->currentIndex());
|
||||
|
||||
settings->GetCustomActions() = currentCustomActions;
|
||||
|
||||
settings->ApplyEnvironment();
|
||||
}
|
||||
|
||||
@ -121,3 +149,53 @@ QString SettingsDialog::LangNameToId(const QString &name)
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void SettingsDialog::on_btnSelectCustomFileActionCommand_clicked()
|
||||
{
|
||||
QString path = SelectExe(this, tr("Select command"));
|
||||
if(!path.isEmpty())
|
||||
ui->lineCustomActionCommand->setText(QDir::toNativeSeparators(path));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void SettingsDialog::GetCustomAction(int index)
|
||||
{
|
||||
Q_ASSERT(index>=0 && index < currentCustomActions.size());
|
||||
CustomAction &action = currentCustomActions[index];
|
||||
ui->lineCustomActionDescription->setText(action.Description);
|
||||
ui->lineCustomActionCommand->setText(action.Command);
|
||||
ui->cmbCustomActionContext->setCurrentIndex(action.Context-1);
|
||||
ui->chkCustomActionMultipleSelection->setChecked(action.MultipleSelection);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void SettingsDialog::PutCustomAction(int index)
|
||||
{
|
||||
Q_ASSERT(index>=0 && index < currentCustomActions.size());
|
||||
CustomAction &action = currentCustomActions[index];
|
||||
action.Description = ui->lineCustomActionDescription->text().trimmed();
|
||||
action.Command = QDir::fromNativeSeparators(ui->lineCustomActionCommand->text().trimmed());
|
||||
action.Context = static_cast<CustomActionContext>(ui->cmbCustomActionContext->currentIndex()+1);
|
||||
action.MultipleSelection = ui->chkCustomActionMultipleSelection->isChecked();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void SettingsDialog::on_cmbCustomAction_currentIndexChanged(int index)
|
||||
{
|
||||
if(index != lastActionIndex)
|
||||
PutCustomAction(lastActionIndex);
|
||||
|
||||
GetCustomAction(index);
|
||||
lastActionIndex = index;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void SettingsDialog::on_cmbCustomActionContext_currentIndexChanged(int index)
|
||||
{
|
||||
int action_index = ui->cmbCustomAction->currentIndex();
|
||||
if(action_index<0)
|
||||
return;
|
||||
Q_ASSERT(action_index>=0 && action_index < currentCustomActions.size());
|
||||
currentCustomActions[action_index].Context = static_cast<CustomActionContext>(index+1);
|
||||
}
|
||||
|
@ -23,11 +23,16 @@ private slots:
|
||||
void on_btnSelectFossil_clicked();
|
||||
void on_buttonBox_accepted();
|
||||
void on_btnClearMessageHistory_clicked();
|
||||
void on_btnSelectCustomFileActionCommand_clicked();
|
||||
void on_cmbCustomAction_currentIndexChanged(int index);
|
||||
void on_cmbCustomActionContext_currentIndexChanged(int index);
|
||||
|
||||
private:
|
||||
QString LangIdToName(const QString &id);
|
||||
QString LangNameToId(const QString &name);
|
||||
void CreateLangMap();
|
||||
void GetCustomAction(int index);
|
||||
void PutCustomAction(int index);
|
||||
|
||||
struct LangMap
|
||||
{
|
||||
@ -43,6 +48,8 @@ private:
|
||||
QList<LangMap> langMap;
|
||||
Ui::SettingsDialog *ui;
|
||||
Settings *settings;
|
||||
Settings::custom_actions_t currentCustomActions;
|
||||
int lastActionIndex;
|
||||
};
|
||||
|
||||
#endif // SETTINGSDIALOG_H
|
||||
|
109
src/Utils.cpp
109
src/Utils.cpp
@ -4,8 +4,9 @@
|
||||
#include <QFileDialog>
|
||||
#include <QEventLoop>
|
||||
#include <QUrl>
|
||||
#include "ext/qtkeychain/keychain.h"
|
||||
#include <QProcess>
|
||||
#include <QCryptographicHash>
|
||||
#include "ext/qtkeychain/keychain.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
QMessageBox::StandardButton DialogQuery(QWidget *parent, const QString &title, const QString &query, QMessageBox::StandardButtons buttons)
|
||||
@ -475,3 +476,109 @@ QString UrlToStringNoCredentials(const QUrl& url)
|
||||
return url.toString(QUrl::PrettyDecoded|QUrl::RemoveUserInfo);
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool SpawnExternalProcess(QObject *procesParent, const QString& command, const QStringList& file_selection, const stringset_t& path_selection, const QString &wkdir, UICallback &ui)
|
||||
{
|
||||
QStringList params;
|
||||
|
||||
// Process command string
|
||||
QString cmd = command;
|
||||
Q_ASSERT(!cmd.isEmpty());
|
||||
|
||||
// Split command from embedded params
|
||||
QString extra_params;
|
||||
|
||||
// Command ends after first space
|
||||
QChar cmd_char_end = ' ';
|
||||
int start = 0;
|
||||
|
||||
// ...unless it is a quoted command
|
||||
if(cmd[0]=='"')
|
||||
{
|
||||
cmd_char_end = '"';
|
||||
start = 1;
|
||||
}
|
||||
|
||||
int cmd_end = cmd.indexOf(cmd_char_end, start);
|
||||
if(cmd_end != -1)
|
||||
{
|
||||
extra_params = cmd.mid(cmd_end+1);
|
||||
cmd = cmd.left(cmd_end);
|
||||
}
|
||||
|
||||
cmd = cmd.trimmed();
|
||||
extra_params = extra_params.trimmed();
|
||||
|
||||
// Push all additional params, except those containing macros
|
||||
QString macro_file;
|
||||
QString macro_folder;
|
||||
|
||||
if(!extra_params.isEmpty())
|
||||
{
|
||||
QStringList extra_param_list = extra_params.split(' ');
|
||||
|
||||
foreach(const QString &p, extra_param_list)
|
||||
{
|
||||
if(p.indexOf("$FILE")!=-1)
|
||||
{
|
||||
macro_file = p;
|
||||
continue;
|
||||
}
|
||||
else if(p.indexOf("$FOLDER")!=-1)
|
||||
{
|
||||
macro_folder = p;
|
||||
continue;
|
||||
}
|
||||
else if(p.indexOf("$WORKSPACE")!=-1)
|
||||
{
|
||||
// Add in-place
|
||||
QString n = p;
|
||||
n.replace("$WORKSPACE", wkdir, Qt::CaseInsensitive);
|
||||
params.push_back(n);
|
||||
continue;
|
||||
}
|
||||
|
||||
params.push_back(p);
|
||||
}
|
||||
}
|
||||
|
||||
// Build file params
|
||||
foreach(const QString &f, file_selection)
|
||||
{
|
||||
QString path = QFileInfo(wkdir + PATH_SEPARATOR + f).absoluteFilePath();
|
||||
|
||||
// Apply macro
|
||||
if(!macro_file.isEmpty())
|
||||
{
|
||||
QString macro = macro_file;
|
||||
path = macro.replace("$FILE", path, Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
params.append(path);
|
||||
}
|
||||
|
||||
|
||||
// Build folder params
|
||||
foreach(const QString &f, path_selection)
|
||||
{
|
||||
QString path = QFileInfo(wkdir + PATH_SEPARATOR + f).absoluteFilePath();
|
||||
|
||||
// Apply macro
|
||||
if(!macro_folder.isEmpty())
|
||||
{
|
||||
QString macro = macro_folder;
|
||||
path = macro.replace("$FOLDER", path, Qt::CaseInsensitive);
|
||||
}
|
||||
params.append(path);
|
||||
}
|
||||
|
||||
// Skip action if nothing is available
|
||||
if(params.empty())
|
||||
return false;
|
||||
|
||||
ui.logText("<b>"+cmd + " "+params.join(" ")+"</b><br>", true);
|
||||
|
||||
QProcess proc(procesParent);
|
||||
return proc.startDetached(cmd, params);
|
||||
}
|
||||
|
53
src/Utils.h
53
src/Utils.h
@ -5,37 +5,16 @@
|
||||
#include <QMessageBox>
|
||||
#include <QMap>
|
||||
#include <QStandardItem>
|
||||
#include <QSet>
|
||||
|
||||
#define COUNTOF(array) (sizeof(array)/sizeof(array[0]))
|
||||
#define FOSSIL_CHECKOUT1 "_FOSSIL_"
|
||||
#define FOSSIL_CHECKOUT2 ".fslckout"
|
||||
#define FOSSIL_EXT "fossil"
|
||||
#define PATH_SEPARATOR "/"
|
||||
|
||||
typedef QSet<QString> stringset_t;
|
||||
|
||||
QMessageBox::StandardButton DialogQuery(QWidget *parent, const QString &title, const QString &query, QMessageBox::StandardButtons buttons = QMessageBox::Yes|QMessageBox::No);
|
||||
QString QuotePath(const QString &path);
|
||||
QStringList QuotePaths(const QStringList &paths);
|
||||
QString SelectExe(QWidget *parent, const QString &description);
|
||||
|
||||
|
||||
typedef QMap<QString, QModelIndex> name_modelindex_map_t;
|
||||
void GetStandardItemTextRecursive(QString &name, const QStandardItem &item, const QChar &separator='/');
|
||||
void BuildNameToModelIndex(name_modelindex_map_t &map, const QStandardItem &item);
|
||||
void BuildNameToModelIndex(name_modelindex_map_t &map, const QStandardItemModel &model);
|
||||
bool KeychainSet(QObject* parent, const QUrl& url);
|
||||
bool KeychainGet(QObject* parent, QUrl& url);
|
||||
bool KeychainDelete(QObject* parent, const QUrl& url);
|
||||
QString HashString(const QString &str);
|
||||
QString UrlToStringDisplay(const QUrl &url);
|
||||
QString UrlToStringNoCredentials(const QUrl& url);
|
||||
|
||||
|
||||
typedef QMap<QString, QString> QStringMap;
|
||||
void ParseProperties(QStringMap &properties, const QStringList &lines, QChar separator=' ');
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
bool ShowExplorerMenu(HWND hwnd, const QString &path, const QPoint &qpoint);
|
||||
#endif
|
||||
|
||||
class UICallback
|
||||
{
|
||||
@ -65,4 +44,30 @@ private:
|
||||
UICallback *uiCallback;
|
||||
};
|
||||
|
||||
|
||||
QMessageBox::StandardButton DialogQuery(QWidget *parent, const QString &title, const QString &query, QMessageBox::StandardButtons buttons = QMessageBox::Yes|QMessageBox::No);
|
||||
QString QuotePath(const QString &path);
|
||||
QStringList QuotePaths(const QStringList &paths);
|
||||
QString SelectExe(QWidget *parent, const QString &description);
|
||||
|
||||
|
||||
typedef QMap<QString, QModelIndex> name_modelindex_map_t;
|
||||
void GetStandardItemTextRecursive(QString &name, const QStandardItem &item, const QChar &separator='/');
|
||||
void BuildNameToModelIndex(name_modelindex_map_t &map, const QStandardItem &item);
|
||||
void BuildNameToModelIndex(name_modelindex_map_t &map, const QStandardItemModel &model);
|
||||
bool KeychainSet(QObject* parent, const QUrl& url);
|
||||
bool KeychainGet(QObject* parent, QUrl& url);
|
||||
bool KeychainDelete(QObject* parent, const QUrl& url);
|
||||
QString HashString(const QString &str);
|
||||
QString UrlToStringDisplay(const QUrl &url);
|
||||
QString UrlToStringNoCredentials(const QUrl& url);
|
||||
bool SpawnExternalProcess(QObject *procesParent, const QString &command, const QStringList &file_selection, const stringset_t &path_selection, const QString& wkdir, UICallback& ui);
|
||||
|
||||
typedef QMap<QString, QString> QStringMap;
|
||||
void ParseProperties(QStringMap &properties, const QStringList &lines, QChar separator=' ');
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
bool ShowExplorerMenu(HWND hwnd, const QString &path, const QPoint &qpoint);
|
||||
#endif
|
||||
|
||||
#endif // UTILS_H
|
||||
|
@ -97,9 +97,6 @@ private:
|
||||
QString Path;
|
||||
};
|
||||
|
||||
|
||||
typedef QSet<QString> stringset_t;
|
||||
|
||||
class Remote
|
||||
{
|
||||
public:
|
||||
|
@ -9,8 +9,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>457</width>
|
||||
<height>204</height>
|
||||
<width>449</width>
|
||||
<height>428</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -27,18 +27,6 @@
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="minimumSize">
|
||||
@ -180,6 +168,118 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Custom Actions</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Action</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="cmbCustomAction"/>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="lineCustomActionDescription">
|
||||
<property name="toolTip">
|
||||
<string>Name of custom action</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Description</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Command</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_10">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineCustomActionCommand">
|
||||
<property name="toolTip">
|
||||
<string>Custom action command line</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnSelectCustomFileActionCommand">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Context</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="cmbCustomActionContext"/>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QCheckBox" name="chkCustomActionMultipleSelection">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Multiple Selection</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
Loading…
x
Reference in New Issue
Block a user