diff --git a/manifest b/manifest index 0b81bc0..581f3f5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Initial\swork\son\suser\sdefined\sfile\sactions\n -D 2015-06-02T17:28:10.948 +C Support\sfor\smultiple\scustom\sactions\n +D 2015-07-09T18:55:33.249 F .travis.yml 77966888a81c4ceee1fcc79bce842c9667ad8a35 F debian/changelog eb4304dfcb6bb66850ec740838090eb50ce1249b F debian/compat b6abd567fa79cbe0196d093a067271361dc6ca8b @@ -224,18 +224,18 @@ F src/FslSettingsDialog.cpp 2531d3709f0eab66651671e3edead2ca720d07d5 F src/FslSettingsDialog.h dfe2a61884a55a74cbb9206b6f6b482b979725e7 F src/LoggedProcess.cpp 2a1e5c94bc1e57c8984563e66c210e43a14dc60c F src/LoggedProcess.h 85df7c635c807a5a0e8c4763f17a0752aaff7261 -F src/MainWindow.cpp 8521536cfe2167d5b82bc5c7808dff8117d3da4f -F src/MainWindow.h d3216b30702df9a44b3a93e6c96fd05ceb0e3822 +F src/MainWindow.cpp 272e8424e81eb81b1c7a996ded26a217f9ec45e5 +F src/MainWindow.h b03f3d99985dd6d2bfe406239ca54e69f571db6a 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 8e8c85f2c2aecb6df3d456ce775a4a53704ebbed -F src/Settings.h 9eeeec1ac9cee4d8dc44a448995d0d599274c2ff -F src/SettingsDialog.cpp 611405e28ce746b2db6ff210c2784d5b8f2dbde8 -F src/SettingsDialog.h fea64d7f92ff326ea49f14559e36379892c0a7c4 +F src/Settings.cpp 258d3f466f6a125ce2b8519d6d57a312cbc44a3f +F src/Settings.h 02bee6bd1178dc456fc80b277edd0843e535649c +F src/SettingsDialog.cpp b0d0bfc45534b7bed148776d4c3865a68d59ec15 +F src/SettingsDialog.h 5eb3ae2cbb00ab5544e1889860f5376f69fe47cd F src/Utils.cpp d53b1b92352e586a7c12a19ec6b109a9f095b7f1 F src/Utils.h 011e4be3f94cd26be537299cd44ab9c135db44a5 F src/Workspace.cpp 7004c2c30f79d2e64691aa9b2c55ee72a84d978b @@ -248,14 +248,11 @@ F ui/CloneDialog.ui 4886e7d4f258ea8b852b5eefc860396e35145712 F ui/CommitDialog.ui 1e5dafa742e9ae07ec937bcda8cda3297ddc6199 F ui/FileActionDialog.ui 89bb4dc2d0b8adcd41adcb11ec65f2028a09a12d F ui/FslSettingsDialog.ui eb3d4cb764cab90b01e82922237d8c42d6ce1749 -F ui/MainWindow.ui 140d5b3e8c37d2e764afd3ee9e74bc754888d067 +F ui/MainWindow.ui 10181826a25056ed5aba2b23a7d110159be7c043 F ui/RemoteDialog.ui 95a4750d972ed8c49bb10b95db91ff16cfe2dd0b F ui/RevisionDialog.ui 27c3b98c665fec014a50cbf3352c0627f75e68cd -F ui/SettingsDialog.ui 2a84288694c666badb6f29e4badaa3f0bdd46287 -P 1954aea71218df9a36b6059fac19ab416ef470dc -R e725cdba0f62a2aad3ff979a23275b03 -T *branch * user-actions -T *sym-user-actions * -T -sym-trunk * +F ui/SettingsDialog.ui b5858067cdb16c3f132af4cf8332e4ad255c915c +P c1562dbda3ad33559227bb0d2fd177e35cae6681 +R 084d6ff50c0d7d634da28bd5e41e98ef U kostas -Z 732d3b0fa352093eb465015746a344aa +Z 5e0824e216c8fc6ae7795004bb7a7ace diff --git a/manifest.uuid b/manifest.uuid index 6ce7e81..0885c2c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c1562dbda3ad33559227bb0d2fd177e35cae6681 \ No newline at end of file +172938d454db50a53cd0e0435991a7fccea59ae7 \ No newline at end of file diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 238d5c8..1f73b13 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()); @@ -106,8 +112,6 @@ MainWindow::MainWindow(Settings &_settings, QWidget *parent, QString *workspaceP ui->fileTableView->addAction(ui->actionHistory); ui->fileTableView->addAction(ui->actionOpenFile); ui->fileTableView->addAction(ui->actionOpenContaining); - ui->actionCustomFileAction->setVisible(false); - ui->fileTableView->addAction(ui->actionCustomFileAction); ui->fileTableView->addAction(separator); ui->fileTableView->addAction(ui->actionAdd); ui->fileTableView->addAction(ui->actionRevert); @@ -202,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); @@ -210,6 +214,17 @@ MainWindow::MainWindow(Settings &_settings, QWidget *parent, QString *workspaceP ui->menuFile->insertAction(recent_sep, recentWorkspaceActs[i]); } + // Custom Actions + //ui->fileTableView->addAction(separator); + 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); @@ -608,7 +623,6 @@ void MainWindow::enableActions(bool on) ui->actionCreateBranch, ui->actionMergeBranch, ui->actionFossilSettings, - ui->actionCustomFileAction }; 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()); + + ++last_action; + } + store->endArray(); + applyUserActions(); } @@ -1099,6 +1142,24 @@ 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)); + ++active_actions; + } + store->endArray(); } //------------------------------------------------------------------------------ @@ -2672,42 +2733,128 @@ void MainWindow::on_actionDeleteRemote_triggered() //------------------------------------------------------------------------------ void MainWindow::applyUserActions() { - QString fileaction_name; - QString fileaction_cmd; + Settings::custom_actions_t custom_actions = settings.GetCustomActions(); + Q_ASSERT(MAX_CUSTOM_ACTIONS == custom_actions.size()); - if(settings.HasValue(FUEL_SETTING_FILEACTION_NAME) && settings.HasValue(FUEL_SETTING_FILEACTION_COMMAND)) + // Remove All Actions + for(int i = 0; i < custom_actions.size(); ++i) { - fileaction_name = settings.GetValue(FUEL_SETTING_FILEACTION_NAME).toString(); - fileaction_cmd = settings.GetValue(FUEL_SETTING_FILEACTION_COMMAND).toString(); + 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(!fileaction_name.isEmpty() && !fileaction_cmd.isEmpty()) - { - ui->actionCustomFileAction->setVisible(true); - ui->actionCustomFileAction->setText(fileaction_name); - } - else - ui->actionCustomFileAction->setVisible(false); + if(!has_file_actions) + ui->fileTableView->removeAction(fileActionSeparator); + + if(!has_folder_actions) + menuWorkspace->removeAction(workspaceActionSeparator); } //------------------------------------------------------------------------------ -void MainWindow::on_actionCustomFileAction_triggered() +void MainWindow::on_actionCustomAction_triggered() { - if(!settings.HasValue(FUEL_SETTING_FILEACTION_NAME) || !settings.HasValue(FUEL_SETTING_FILEACTION_COMMAND)) + QAction *action = qobject_cast(sender()); + if(!action) return; - QStringList selection; - getSelectionFilenames(selection, WorkspaceFile::TYPE_ALL); - - QProcess proc(this); + int action_id = action->data().toInt(); + Q_ASSERT(action_id < settings.GetCustomActions().size()); + CustomAction &cust_action = settings.GetCustomActions()[action_id]; + Q_ASSERT(cust_action.IsValid()); QStringList params; - foreach(const QString &f, selection) + + // Process command string + QString cmd = cust_action.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]=='"') { - QString path = QFileInfo(fossil().getCurrentWorkspace() + "/" + f).absoluteFilePath(); - params.append(path); + cmd_char_end = '"'; + start = 1; } - const QString &cmd = settings.GetValue(FUEL_SETTING_FILEACTION_COMMAND).toString(); + 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(); + QStringList extra_param_list = extra_params.split(' '); + foreach(const QString &p, extra_param_list) + params.push_back(p); + + // Extract selection + if(cust_action.IsActive(ACTION_CONTEXT_FILES)) + { + QStringList file_selection; + getSelectionFilenames(file_selection, WorkspaceFile::TYPE_ALL); + foreach(const QString &f, file_selection) + { + QString path = QFileInfo(fossil().getCurrentWorkspace() + "/" + f).absoluteFilePath(); + params.append(path); + } + } + + if(cust_action.IsActive(ACTION_CONTEXT_FOLDERS)) + { + stringset_t path_selection; + getSelectionPaths(path_selection); + foreach(const QString &f, path_selection) + { + QString path = QFileInfo(fossil().getCurrentWorkspace() + "/" + f).absoluteFilePath(); + params.append(path); + } + } + + // Skip action if nothing is available + if(params.empty()) + return; + + + log(""+cmd + " "+params.join(" ")+"
", true); + + QProcess proc(this); proc.startDetached(cmd, params); -} +} \ No newline at end of file diff --git a/src/MainWindow.h b/src/MainWindow.h index bde410d..49f7de5 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -134,7 +134,7 @@ private slots: void on_actionSetDefaultRemote_triggered(); void on_actionAddRemote_triggered(); void on_actionDeleteRemote_triggered(); - void on_actionCustomFileAction_triggered(); + void on_actionCustomAction_triggered(); private: class MainWinUICallback : public UICallback @@ -172,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 5c35c26..0f9a652 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -37,10 +37,13 @@ Settings::Settings(bool portableMode) : store(0) if(!HasValue(FUEL_SETTING_WEB_BROWSER)) SetValue(FUEL_SETTING_WEB_BROWSER, 0); - if(!HasValue(FUEL_SETTING_FILEACTION_NAME)) - SetValue(FUEL_SETTING_FILEACTION_NAME, ""); - if(!HasValue(FUEL_SETTING_FILEACTION_COMMAND)) - SetValue(FUEL_SETTING_FILEACTION_COMMAND, ""); + + for(int i=0; i #include #include +#include #define FUEL_SETTING_FOSSIL_PATH "FossilPath" #define FUEL_SETTING_COMMIT_MSG "CommitMsgHistory" #define FUEL_SETTING_FILE_DBLCLICK "FileDblClickAction" #define FUEL_SETTING_LANGUAGE "Language" #define FUEL_SETTING_WEB_BROWSER "WebBrowser" -#define FUEL_SETTING_FILEACTION_NAME "FileActionName" -#define FUEL_SETTING_FILEACTION_COMMAND "FileActionCommand" #define FOSSIL_SETTING_GDIFF_CMD "gdiff-command" #define FOSSIL_SETTING_GMERGE_CMD "gmerge-command" @@ -29,6 +28,50 @@ enum FileDblClickAction 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 = 5 +}; + +struct CustomAction +{ + QString Id; + QString Description; + QString Command; + CustomActionContext Context; + + 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; + } +}; + struct Settings { struct Setting @@ -45,6 +88,7 @@ struct Settings SettingType Type; }; typedef QMap mappings_t; + typedef QVector custom_actions_t; Settings(bool portableMode = false); @@ -65,10 +109,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 c2e92f2..f513e2c 100644 --- a/src/SettingsDialog.cpp +++ b/src/SettingsDialog.cpp @@ -26,9 +26,6 @@ SettingsDialog::SettingsDialog(QWidget *parent, Settings &_settings) : ui->cmbDoubleClickAction->setCurrentIndex(settings->GetValue(FUEL_SETTING_FILE_DBLCLICK).toInt()); ui->cmbFossilBrowser->setCurrentIndex(settings->GetValue(FUEL_SETTING_WEB_BROWSER).toInt()); - ui->lineCustomFileActionName->setText(settings->GetValue(FUEL_SETTING_FILEACTION_NAME).toString()); - ui->lineCustomFileActionCommand->setText(settings->GetValue(FUEL_SETTING_FILEACTION_COMMAND).toString()); - // Initialize language combo foreach(const LangMap &m, langMap) ui->cmbActiveLanguage->addItem(m.name); @@ -39,6 +36,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); } //----------------------------------------------------------------------------- @@ -71,11 +84,16 @@ 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; iHasValue(FUEL_SETTING_FILEACTION_NAME)); - settings->SetValue(FUEL_SETTING_FILEACTION_NAME, ui->lineCustomFileActionName->text().trimmed()); - Q_ASSERT(settings->HasValue(FUEL_SETTING_FILEACTION_COMMAND)); - settings->SetValue(FUEL_SETTING_FILEACTION_COMMAND, QDir::fromNativeSeparators(ui->lineCustomFileActionCommand->text().trimmed())); + PutCustomAction(ui->cmbCustomAction->currentIndex()); + + settings->GetCustomActions() = currentCustomActions; settings->ApplyEnvironment(); } @@ -134,7 +152,47 @@ QString SettingsDialog::LangNameToId(const QString &name) //----------------------------------------------------------------------------- void SettingsDialog::on_btnSelectCustomFileActionCommand_clicked() { - QString path = SelectExe(this, tr("Select executable")); + QString path = SelectExe(this, tr("Select command")); if(!path.isEmpty()) - ui->lineCustomFileActionCommand->setText(QDir::toNativeSeparators(path)); + 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); +} + +//----------------------------------------------------------------------------- +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); +} + +//----------------------------------------------------------------------------- +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 5eef6a6..3b0fdb7 100644 --- a/src/SettingsDialog.h +++ b/src/SettingsDialog.h @@ -24,11 +24,15 @@ private slots: 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 { @@ -44,6 +48,8 @@ private: QList langMap; Ui::SettingsDialog *ui; Settings *settings; + Settings::custom_actions_t currentCustomActions; + int lastActionIndex; }; #endif // SETTINGSDIALOG_H diff --git a/ui/MainWindow.ui b/ui/MainWindow.ui index a4043e0..9607069 100644 --- a/ui/MainWindow.ui +++ b/ui/MainWindow.ui @@ -1047,14 +1047,6 @@ Delete Remote - - - Custom File Action - - - Custom File Action - - diff --git a/ui/SettingsDialog.ui b/ui/SettingsDialog.ui index ae0116d..35c5367 100644 --- a/ui/SettingsDialog.ui +++ b/ui/SettingsDialog.ui @@ -9,8 +9,8 @@ 0 0 - 457 - 278 + 449 + 408 @@ -27,18 +27,6 @@ - - 0 - - - 0 - - - 0 - - - 0 - @@ -180,69 +168,104 @@ - - - - - 100 - 0 - - - - Custom File Action Name + + + + Custom Actions + + + 0 + + + 0 + + + + + Action + + + + + + + + + + Name of custom action + + + + + + + + 100 + 0 + + + + Description + + + + + + + Context + + + + + + + + + + + 100 + 0 + + + + Command + + + + + + + + + Custom action command line + + + + + + + + 0 + 0 + + + + + 24 + 24 + + + + ... + + + + + + - - - - Name of custom action - - - - - - - - 100 - 0 - - - - Custom File Action Command - - - - - - - - - Custom action command line - - - - - - - - 0 - 0 - - - - - 24 - 24 - - - - ... - - - - -