diff options
| author | isanae <14251494+isanae@users.noreply.github.com> | 2019-07-02 11:05:31 -0400 |
|---|---|---|
| committer | isanae <14251494+isanae@users.noreply.github.com> | 2019-07-02 11:05:31 -0400 |
| commit | c6e80f1a5eed4a57663e7fc55c2727258eaad552 (patch) | |
| tree | 2c4633f4dc3b912a696d36a52329059fe982321b | |
| parent | 16b6e772a7ae1561ba87c6d76d001b19635761cd (diff) | |
focus tabs when they need a confirmation to close
dialog did not handle closeEvent() at all, it only checked the close button
bunch of comments
| -rw-r--r-- | src/modinfodialog.cpp | 34 | ||||
| -rw-r--r-- | src/modinfodialog.h | 6 | ||||
| -rw-r--r-- | src/modinfodialogtab.cpp | 5 | ||||
| -rw-r--r-- | src/modinfodialogtab.h | 87 | ||||
| -rw-r--r-- | src/modinfodialogtextfiles.cpp | 2 |
5 files changed, 126 insertions, 8 deletions
diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index b3055b5a..4af479c4 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -154,7 +154,7 @@ ModInfoDialog::ModInfoDialog( connect( tabInfo.tab.get(), &ModInfoDialogTab::originModified, [this, i](int originID) { - onOriginModified(static_cast<std::size_t>(i), originID); + onOriginModified(originID); }); connect( @@ -167,6 +167,15 @@ ModInfoDialog::ModInfoDialog( connect( tabInfo.tab.get(), &ModInfoDialogTab::hasDataChanged, [&]{ setTabsColors(); }); + + connect( + tabInfo.tab.get(), &ModInfoDialogTab::wantsFocus, + [&, i=static_cast<std::size_t>(i)] + { + if (i < m_tabs.size()) { + switchToTab(ETabs(m_tabs[i].tab->tabID())); + } + }); } connect(ui->tabWidget, &QTabWidget::currentChanged, [&]{ onTabChanged(); }); @@ -546,6 +555,7 @@ void ModInfoDialog::reAddTabs(const std::vector<bool>& visibility, ETabs sel) } + // removing all tabs ui->tabWidget->clear(); // reset real positions @@ -566,7 +576,7 @@ void ModInfoDialog::reAddTabs(const std::vector<bool>& visibility, ETabs sel) } } -void ModInfoDialog::onOriginModified(std::size_t tabIndex, int originID) +void ModInfoDialog::onOriginModified(int originID) { emit originModified(originID); updateTabs(true); @@ -581,15 +591,31 @@ void ModInfoDialog::onDeleteShortcut() } } +void ModInfoDialog::closeEvent(QCloseEvent* e) +{ + if (tryClose()) { + e->accept(); + } else { + e->ignore(); + } +} + void ModInfoDialog::on_closeButton_clicked() { + if (tryClose()) { + close(); + } +} + +bool ModInfoDialog::tryClose() +{ for (auto& tabInfo : m_tabs) { if (!tabInfo.tab->canClose()) { - return; + return false; } } - close(); + return true; } void ModInfoDialog::onTabChanged() diff --git a/src/modinfodialog.h b/src/modinfodialog.h index 030b3f93..899a3eab 100644 --- a/src/modinfodialog.h +++ b/src/modinfodialog.h @@ -117,6 +117,9 @@ public: signals:
void originModified(int originID);
+protected:
+ void closeEvent(QCloseEvent* e);
+
private slots:
void on_closeButton_clicked();
void on_nextButton_clicked();
@@ -158,8 +161,9 @@ private: void switchToTab(ETabs id);
void reAddTabs(const std::vector<bool>& visibility, ETabs sel);
std::vector<QString> getOrderedTabNames() const;
+ bool tryClose();
- void onOriginModified(std::size_t tabIndex, int originID);
+ void onOriginModified(int originID);
void onTabChanged();
void onTabMoved();
diff --git a/src/modinfodialogtab.cpp b/src/modinfodialogtab.cpp index f5eeeed1..0468b405 100644 --- a/src/modinfodialogtab.cpp +++ b/src/modinfodialogtab.cpp @@ -137,6 +137,11 @@ void ModInfoDialogTab::setHasData(bool b) } } +void ModInfoDialogTab::setFocus() +{ + emit wantsFocus(); +} + NotesTab::NotesTab( OrganizerCore& oc, PluginContainer& plugin, diff --git a/src/modinfodialogtab.h b/src/modinfodialogtab.h index ce29c868..3f98314a 100644 --- a/src/modinfodialogtab.h +++ b/src/modinfodialogtab.h @@ -10,6 +10,36 @@ namespace Ui { class ModInfoDialog; } class Settings; class OrganizerCore; +// base class for all tabs in the mod info dialog +// +// when the dialog is opened or when next/previous is clicked, the sequence is: +// setMod(), clear(), feedFile() an update() +// +// when the dialog is closed, canClose() is called on all tabs +// +// when a tab is selected for the first time for the current mod, +// firstActivation() is called; this is used by NexusTab to refresh stuff +// +// when the dialog is first shown, restoreState() is called on all tabs and +// saveState() is called when the dialog is closed +// +// there isn't a good framework for keyboard shortcuts because only the delete +// key is used for now, which calls deletedRequested() on all tabs until one +// returns true +// +// each tab override canHandleSeparators() and canHandleUnmanaged() to return +// true if they can handle separators or unmanaged mods; if these return false +// (which they do by default), the tabs will be removed from the widget entirely +// +// when tabs modify the origin and call emitOriginModified() (such as the +// conflicts tabs), all tabs that return true in usesOriginFiles() will go +// through the full update sequence as above +// +// tabs can call emitModOpen() to request showing a different mod +// +// hasDataChanged() should be called when a tab goes from having data to being +// empty or vice versa; this will update the tab text color +// class ModInfoDialogTab : public QObject { Q_OBJECT; @@ -21,13 +51,63 @@ public: ModInfoDialogTab& operator=(ModInfoDialogTab&&) = default; virtual ~ModInfoDialogTab() = default; + // called by ModInfoDialog every time this tab is selected; this will call + // firstActivation() the first time it's called, until resetFirstActivation() + // is called + // void activated(); + + // called by ModInfoDialog when the selected mod has changed, to make sure + // activated() will call firstActivation() next time + // void resetFirstActivation(); + + // called when the selected mod changed, `mod` can never be empty, but + // `origin` can (if the mod is not active, for example) + // + // derived classes can override this to connect to events on the mod for + // examples (see NexusTab), but must call the base class implementation + // + virtual void setMod(ModInfo::Ptr mod, MOShared::FilesOrigin* origin); + + // this tab should clear its user interface; clear() will always be called + // before feedFile() and update() + // virtual void clear() = 0; - virtual void update(); + + // the dialog will go through each file in the mod and call feedFile() + // with it on all tabs; if a tab handles the file, it should return true to + // prevent other tabs from displaying it + // + // this prevents individual tabs from having to go through the filesystem + // independently, which would kill performance, but it cannot be the only way + // to update tabs because some of them don't actually use files (like + // NotesTab) or they use the internal structures such as `FilesOrigin` (like + // ConflictsTab) + // + // once all the files have been fed to tabs, update() will be called; tabs + // that need to do additional work after being fed files, or tabs that are + // unable to use feedFile() at all can use update() to do work + // virtual bool feedFile(const QString& rootPath, const QString& filename); + + // called after all the files on the filesystem have been sent through + // feedFile() + // + // this can be used to do a final processing of the files handled by + // feedFile() (ImagesTab will set up the scrollbars, for example) or something + // completely different (CategoriesTab will fill up the lists) + // + virtual void update(); + + // called when a tab is visible for the first time for the current mod, can + // be used to do expensive work that's not worth doing until the tab is + // actually selected by the user + // virtual void firstActivation(); + + // virtual bool canClose(); virtual void saveState(Settings& s); virtual void restoreState(const Settings& s); @@ -38,8 +118,6 @@ public: virtual bool canHandleUnmanaged() const; virtual bool usesOriginFiles() const; - virtual void setMod(ModInfo::Ptr mod, MOShared::FilesOrigin* origin); - ModInfo::Ptr mod() const; MOShared::FilesOrigin* origin() const; @@ -50,6 +128,7 @@ signals: void originModified(int originID); void modOpen(QString name); void hasDataChanged(); + void wantsFocus(); protected: Ui::ModInfoDialog* ui; @@ -67,6 +146,8 @@ protected: void emitModOpen(QString name); void setHasData(bool b); + void setFocus(); + // this needs to be a template because saveState() and restoreState() are // not in QWidget, but they're in various widgets // diff --git a/src/modinfodialogtextfiles.cpp b/src/modinfodialogtextfiles.cpp index 52891bf5..bc44ee3e 100644 --- a/src/modinfodialogtextfiles.cpp +++ b/src/modinfodialogtextfiles.cpp @@ -133,6 +133,8 @@ bool GenericFilesTab::canClose() return true; } + setFocus(); + const int res = QMessageBox::question( parentWidget(), QObject::tr("Save changes?"), |
