diff --git a/manifest b/manifest index 5bad25c..27a79ea 100644 --- a/manifest +++ b/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 diff --git a/manifest.uuid b/manifest.uuid index 534251d..4c045de 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d869092a71de1d2294d475f394a17f35740420aa \ No newline at end of file +7cd82ba8f02f659d13a370043f256212f55669db \ No newline at end of file diff --git a/src/Fossil.h b/src/Fossil.h index c2c75ac..2dc1fc6 100644 --- a/src/Fossil.h +++ b/src/Fossil.h @@ -10,8 +10,6 @@ class QStringList; typedef QMap stashmap_t; -#define PATH_SEPARATOR "/" - enum RunFlags { RUNFLAGS_NONE = 0<<0, diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 337f0ab..1ed61ce 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -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; ibeginReadArray("CustomActions"); + int last_action = 0; + for(int i=0; isetArrayIndex(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(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; isetArrayIndex(active_actions); + + store->setValue("Description", action.Description); + store->setValue("Command", action.Command); + store->setValue("Context", static_cast(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(); - 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(sender()); + if(!action) + return; + + int action_id = action->data().toInt(); + invokeCustomAction(action_id); +} diff --git a/src/MainWindow.h b/src/MainWindow.h index cbdf458..d3b07cf 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -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; diff --git a/src/Settings.cpp b/src/Settings.cpp index 1a88187..0f9a652 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -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 #include #include +#include #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 mappings_t; + typedef QVector 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; }; diff --git a/src/SettingsDialog.cpp b/src/SettingsDialog.cpp index 59b86d7..4f93e74 100644 --- a/src/SettingsDialog.cpp +++ b/src/SettingsDialog.cpp @@ -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; icmbCustomAction->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; icmbCustomAction->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(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(index+1); +} diff --git a/src/SettingsDialog.h b/src/SettingsDialog.h index 418f2ea..3b0fdb7 100644 --- a/src/SettingsDialog.h +++ b/src/SettingsDialog.h @@ -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; Ui::SettingsDialog *ui; Settings *settings; + Settings::custom_actions_t currentCustomActions; + int lastActionIndex; }; #endif // SETTINGSDIALOG_H diff --git a/src/Utils.cpp b/src/Utils.cpp index ce32157..f9ae60a 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -4,8 +4,9 @@ #include #include #include -#include "ext/qtkeychain/keychain.h" +#include #include +#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(""+cmd + " "+params.join(" ")+"
", true); + + QProcess proc(procesParent); + return proc.startDetached(cmd, params); +} diff --git a/src/Utils.h b/src/Utils.h index 4eb4987..b37c401 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -5,37 +5,16 @@ #include #include #include +#include #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 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 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 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 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 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 diff --git a/src/Workspace.h b/src/Workspace.h index fb58735..b7cd50e 100644 --- a/src/Workspace.h +++ b/src/Workspace.h @@ -97,9 +97,6 @@ private: QString Path; }; - -typedef QSet stringset_t; - class Remote { public: diff --git a/ui/SettingsDialog.ui b/ui/SettingsDialog.ui index 0685355..93f1d15 100644 --- a/ui/SettingsDialog.ui +++ b/ui/SettingsDialog.ui @@ -9,8 +9,8 @@ 0 0 - 457 - 204 + 449 + 428 @@ -27,18 +27,6 @@ - - 0 - - - 0 - - - 0 - - - 0 - @@ -180,6 +168,118 @@ + + + + Custom Actions + + + + 0 + + + 0 + + + + + Action + + + + + + + + + + Name of custom action + + + + + + + + 100 + 0 + + + + Description + + + + + + + + 100 + 0 + + + + Command + + + + + + + + + Custom action command line + + + + + + + + 0 + 0 + + + + + 24 + 24 + + + + ... + + + + + + + + + Context + + + + + + + + + + + + + + + + + Multiple Selection + + + + + +