diff --git a/cockatrice/src/client/menus/deck_editor/deck_editor_menu.cpp b/cockatrice/src/client/menus/deck_editor/deck_editor_menu.cpp index 935cd7580..be4d50d58 100644 --- a/cockatrice/src/client/menus/deck_editor/deck_editor_menu.cpp +++ b/cockatrice/src/client/menus/deck_editor/deck_editor_menu.cpp @@ -30,6 +30,12 @@ DeckEditorMenu::DeckEditorMenu(QWidget *parent, AbstractTabDeckEditor *_deckEdit aLoadDeckFromClipboard = new QAction(QString(), this); connect(aLoadDeckFromClipboard, SIGNAL(triggered()), deckEditor, SLOT(actLoadDeckFromClipboard())); + aEditDeckInClipboard = new QAction(QString(), this); + connect(aEditDeckInClipboard, SIGNAL(triggered()), deckEditor, SLOT(actEditDeckInClipboard())); + + aEditDeckInClipboardRaw = new QAction(QString(), this); + connect(aEditDeckInClipboardRaw, SIGNAL(triggered()), deckEditor, SLOT(actEditDeckInClipboardRaw())); + aSaveDeckToClipboard = new QAction(QString(), this); connect(aSaveDeckToClipboard, SIGNAL(triggered()), deckEditor, SLOT(actSaveDeckToClipboard())); @@ -64,6 +70,10 @@ DeckEditorMenu::DeckEditorMenu(QWidget *parent, AbstractTabDeckEditor *_deckEdit aClose = new QAction(QString(), this); connect(aClose, &QAction::triggered, deckEditor, &AbstractTabDeckEditor::closeRequest); + editDeckInClipboardMenu = new QMenu(this); + editDeckInClipboardMenu->addAction(aEditDeckInClipboard); + editDeckInClipboardMenu->addAction(aEditDeckInClipboardRaw); + saveDeckToClipboardMenu = new QMenu(this); saveDeckToClipboardMenu->addAction(aSaveDeckToClipboard); saveDeckToClipboardMenu->addAction(aSaveDeckToClipboardNoSetNameAndNumber); @@ -77,6 +87,7 @@ DeckEditorMenu::DeckEditorMenu(QWidget *parent, AbstractTabDeckEditor *_deckEdit addAction(aSaveDeckAs); addSeparator(); addAction(aLoadDeckFromClipboard); + addMenu(editDeckInClipboardMenu); addMenu(saveDeckToClipboardMenu); addSeparator(); addAction(aPrintDeck); @@ -133,8 +144,13 @@ void DeckEditorMenu::retranslateUi() aClearRecents->setText(tr("Clear")); aSaveDeck->setText(tr("&Save deck")); aSaveDeckAs->setText(tr("Save deck &as...")); + aLoadDeckFromClipboard->setText(tr("Load deck from cl&ipboard...")); + editDeckInClipboardMenu->setTitle(tr("Edit deck in clipboard")); + aEditDeckInClipboard->setText(tr("Annotated")); + aEditDeckInClipboardRaw->setText(tr("Not Annotated")); + saveDeckToClipboardMenu->setTitle(tr("Save deck to clipboard")); aSaveDeckToClipboard->setText(tr("Annotated")); aSaveDeckToClipboardNoSetNameAndNumber->setText(tr("Annotated (No set name or number)")); @@ -160,6 +176,8 @@ void DeckEditorMenu::refreshShortcuts() aExportDeckDecklist->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aExportDeckDecklist")); aSaveDeckAs->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aSaveDeckAs")); aLoadDeckFromClipboard->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aLoadDeckFromClipboard")); + aEditDeckInClipboard->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aEditDeckInClipboard")); + aEditDeckInClipboardRaw->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aEditDeckInClipboardRaw")); aPrintDeck->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aPrintDeck")); aAnalyzeDeckDeckstats->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aAnalyzeDeck")); aClose->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aClose")); diff --git a/cockatrice/src/client/menus/deck_editor/deck_editor_menu.h b/cockatrice/src/client/menus/deck_editor/deck_editor_menu.h index c9411a013..5d0a3f9e6 100644 --- a/cockatrice/src/client/menus/deck_editor/deck_editor_menu.h +++ b/cockatrice/src/client/menus/deck_editor/deck_editor_menu.h @@ -15,10 +15,10 @@ public: AbstractTabDeckEditor *deckEditor; QAction *aNewDeck, *aLoadDeck, *aClearRecents, *aSaveDeck, *aSaveDeckAs, *aLoadDeckFromClipboard, - *aSaveDeckToClipboard, *aSaveDeckToClipboardNoSetNameAndNumber, *aSaveDeckToClipboardRaw, - *aSaveDeckToClipboardRawNoSetNameAndNumber, *aPrintDeck, *aExportDeckDecklist, *aAnalyzeDeckDeckstats, - *aAnalyzeDeckTappedout, *aClose; - QMenu *loadRecentDeckMenu, *analyzeDeckMenu, *saveDeckToClipboardMenu; + *aEditDeckInClipboard, *aEditDeckInClipboardRaw, *aSaveDeckToClipboard, *aSaveDeckToClipboardNoSetNameAndNumber, + *aSaveDeckToClipboardRaw, *aSaveDeckToClipboardRawNoSetNameAndNumber, *aPrintDeck, *aExportDeckDecklist, + *aAnalyzeDeckDeckstats, *aAnalyzeDeckTappedout, *aClose; + QMenu *loadRecentDeckMenu, *analyzeDeckMenu, *editDeckInClipboardMenu, *saveDeckToClipboardMenu; void setSaveStatus(bool newStatus); diff --git a/cockatrice/src/client/tabs/abstract_tab_deck_editor.cpp b/cockatrice/src/client/tabs/abstract_tab_deck_editor.cpp index 98f38bb23..4dcc57ea6 100644 --- a/cockatrice/src/client/tabs/abstract_tab_deck_editor.cpp +++ b/cockatrice/src/client/tabs/abstract_tab_deck_editor.cpp @@ -394,6 +394,28 @@ void AbstractTabDeckEditor::actLoadDeckFromClipboard() deckMenu->setSaveStatus(true); } +void AbstractTabDeckEditor::editDeckInClipboard(bool annotated) +{ + DlgEditDeckInClipboard dlg(*getDeckList(), annotated, this); + if (!dlg.exec()) + return; + + setDeck(dlg.getDeckList()); + setModified(true); + + deckMenu->setSaveStatus(true); +} + +void AbstractTabDeckEditor::actEditDeckInClipboard() +{ + editDeckInClipboard(true); +} + +void AbstractTabDeckEditor::actEditDeckInClipboardRaw() +{ + editDeckInClipboard(false); +} + void AbstractTabDeckEditor::actSaveDeckToClipboard() { getDeckList()->saveToClipboard(true, true); diff --git a/cockatrice/src/client/tabs/abstract_tab_deck_editor.h b/cockatrice/src/client/tabs/abstract_tab_deck_editor.h index ee8af472c..94fbe9bde 100644 --- a/cockatrice/src/client/tabs/abstract_tab_deck_editor.h +++ b/cockatrice/src/client/tabs/abstract_tab_deck_editor.h @@ -92,6 +92,8 @@ protected slots: bool actSaveDeck(); bool actSaveDeckAs(); virtual void actLoadDeckFromClipboard(); + void actEditDeckInClipboard(); + void actEditDeckInClipboardRaw(); void actSaveDeckToClipboard(); void actSaveDeckToClipboardNoSetNameAndNumber(); void actSaveDeckToClipboardRaw(); @@ -114,6 +116,9 @@ protected slots: virtual void dockVisibleTriggered() = 0; virtual void dockFloatingTriggered() = 0; +private: + void editDeckInClipboard(bool annotated); + protected: /** * @brief Enum for selecting deck open location diff --git a/cockatrice/src/dialogs/dlg_load_deck_from_clipboard.cpp b/cockatrice/src/dialogs/dlg_load_deck_from_clipboard.cpp index 47c1af242..6cecc10bf 100644 --- a/cockatrice/src/dialogs/dlg_load_deck_from_clipboard.cpp +++ b/cockatrice/src/dialogs/dlg_load_deck_from_clipboard.cpp @@ -2,6 +2,7 @@ #include "../deck/deck_loader.h" #include "../settings/cache_settings.h" +#include "dlg_settings.h" #include #include @@ -13,17 +14,20 @@ #include #include -DlgLoadDeckFromClipboard::DlgLoadDeckFromClipboard(QWidget *parent) : QDialog(parent), deckList(nullptr) +/** + * Creates the main layout and connects the signals that are common to all versions of this window + */ +AbstractDlgDeckTextEdit::AbstractDlgDeckTextEdit(QWidget *parent) : QDialog(parent) { contentsEdit = new QPlainTextEdit; refreshButton = new QPushButton(tr("&Refresh")); - connect(refreshButton, SIGNAL(clicked()), this, SLOT(actRefresh())); + connect(refreshButton, &QPushButton::clicked, this, &AbstractDlgDeckTextEdit::actRefresh); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); buttonBox->addButton(refreshButton, QDialogButtonBox::ActionRole); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(actOK())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(buttonBox, &QDialogButtonBox::accepted, this, &AbstractDlgDeckTextEdit::actOK); + connect(buttonBox, &QDialogButtonBox::rejected, this, &AbstractDlgDeckTextEdit::reject); loadSetNameAndNumberCheckBox = new QCheckBox(tr("Parse Set Name and Number (if available)")); loadSetNameAndNumberCheckBox->setChecked(true); @@ -38,54 +42,57 @@ DlgLoadDeckFromClipboard::DlgLoadDeckFromClipboard(QWidget *parent) : QDialog(pa setLayout(mainLayout); - setWindowTitle(tr("Load deck from clipboard")); resize(500, 500); - actRefresh(); - connect(&SettingsCache::instance().shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts())); + connect(&SettingsCache::instance().shortcuts(), &ShortcutsSettings::shortCutChanged, this, + &AbstractDlgDeckTextEdit::refreshShortcuts); refreshShortcuts(); } -void DlgLoadDeckFromClipboard::actRefresh() -{ - contentsEdit->setPlainText(QApplication::clipboard()->text()); -} - -void DlgLoadDeckFromClipboard::refreshShortcuts() +void AbstractDlgDeckTextEdit::refreshShortcuts() { refreshButton->setShortcut( SettingsCache::instance().shortcuts().getSingleShortcut("DlgLoadDeckFromClipboard/refreshButton")); } -void DlgLoadDeckFromClipboard::actOK() +/** + * Replaces the contents of the contentsEdit with the given text. + * @param text The text + */ +void AbstractDlgDeckTextEdit::setText(const QString &text) { - QString buffer = contentsEdit->toPlainText(); - QTextStream stream(&buffer); - - auto *deckLoader = new DeckLoader; - deckLoader->setParent(this); - - if (buffer.contains("")) { - if (deckLoader->loadFromString_Native(buffer)) { - deckList = deckLoader; - accept(); - } else { - QMessageBox::critical(this, tr("Error"), tr("Invalid deck list.")); - } - } else if (deckLoader->loadFromStream_Plain(stream)) { - deckList = deckLoader; - if (loadSetNameAndNumberCheckBox->isChecked()) { - deckList->resolveSetNameAndNumberToProviderID(); - } else { - deckList->clearSetNamesAndNumbers(); - } - accept(); - } else { - QMessageBox::critical(this, tr("Error"), tr("Invalid deck list.")); - } + contentsEdit->setPlainText(text); } -void DlgLoadDeckFromClipboard::keyPressEvent(QKeyEvent *event) +/** + * Tries to load the current contents of the contentsEdit into the DeckLoader + * + * @param deckLoader The DeckLoader to load the deck into + * @return Whether the loading was successful + */ +bool AbstractDlgDeckTextEdit::loadIntoDeck(DeckLoader *deckLoader) const +{ + QString buffer = contentsEdit->toPlainText(); + + if (buffer.contains("")) { + return deckLoader->loadFromString_Native(buffer); + } + + QTextStream stream(&buffer); + + if (deckLoader->loadFromStream_Plain(stream)) { + if (loadSetNameAndNumberCheckBox->isChecked()) { + deckLoader->resolveSetNameAndNumberToProviderID(); + } else { + deckLoader->clearSetNamesAndNumbers(); + } + return true; + } + + return false; +} + +void AbstractDlgDeckTextEdit::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Return && event->modifiers() & Qt::ControlModifier) { event->accept(); @@ -93,4 +100,79 @@ void DlgLoadDeckFromClipboard::keyPressEvent(QKeyEvent *event) return; } QDialog::keyPressEvent(event); +} + +/** + * Creates the dialog window for the "Load deck from clipboard" action + * + * @param parent The parent widget + */ +DlgLoadDeckFromClipboard::DlgLoadDeckFromClipboard(QWidget *parent) : AbstractDlgDeckTextEdit(parent), deckList(nullptr) +{ + setWindowTitle(tr("Load deck from clipboard")); + + DlgLoadDeckFromClipboard::actRefresh(); +} + +void DlgLoadDeckFromClipboard::actRefresh() +{ + setText(QApplication::clipboard()->text()); +} + +void DlgLoadDeckFromClipboard::actOK() +{ + deckList = new DeckLoader; + deckList->setParent(this); + + if (loadIntoDeck(deckList)) { + accept(); + } else { + QMessageBox::critical(this, tr("Error"), tr("Invalid deck list.")); + } +} + +/** + * Creates the dialog window for the "Edit deck in clipboard" action + * + * @param deckList The existing deck in the deck editor. Copies the instance + * @param _annotated Whether to add annotations to the text that is loaded from the deck + * @param parent The parent widget + */ +DlgEditDeckInClipboard::DlgEditDeckInClipboard(const DeckLoader &deckList, bool _annotated, QWidget *parent) + : AbstractDlgDeckTextEdit(parent), annotated(_annotated) +{ + setWindowTitle(tr("Edit deck in clipboard")); + + deckLoader = new DeckLoader(deckList); + deckLoader->setParent(this); + + DlgEditDeckInClipboard::actRefresh(); +} + +/** + * Loads the contents of the DeckList into a String. Always loads it with addSetNameAndNumber=true + * @param deckList The deck to load + * @param addComments Whether to add annotations + * @return A QString + */ +static QString deckListToString(const DeckLoader *deckList, bool addComments) +{ + QString buffer; + QTextStream stream(&buffer); + deckList->saveToStream_Plain(stream, addComments); + return buffer; +} + +void DlgEditDeckInClipboard::actRefresh() +{ + setText(deckListToString(deckLoader, annotated)); +} + +void DlgEditDeckInClipboard::actOK() +{ + if (loadIntoDeck(deckLoader)) { + accept(); + } else { + QMessageBox::critical(this, tr("Error"), tr("Invalid deck list.")); + } } \ No newline at end of file diff --git a/cockatrice/src/dialogs/dlg_load_deck_from_clipboard.h b/cockatrice/src/dialogs/dlg_load_deck_from_clipboard.h index 19d8cfff8..ce2ccf720 100644 --- a/cockatrice/src/dialogs/dlg_load_deck_from_clipboard.h +++ b/cockatrice/src/dialogs/dlg_load_deck_from_clipboard.h @@ -8,22 +8,22 @@ class DeckLoader; class QPlainTextEdit; class QPushButton; -class DlgLoadDeckFromClipboard : public QDialog +/** + * Base class for dialog windows for actions that involve loading decks from text input. + */ +class AbstractDlgDeckTextEdit : public QDialog { Q_OBJECT -private slots: - void actOK(); - void actRefresh(); - void refreshShortcuts(); - private: - DeckLoader *deckList; QPlainTextEdit *contentsEdit; QPushButton *refreshButton; QCheckBox *loadSetNameAndNumberCheckBox; +private slots: + void refreshShortcuts(); + public: - explicit DlgLoadDeckFromClipboard(QWidget *parent = nullptr); + explicit AbstractDlgDeckTextEdit(QWidget *parent = nullptr); /** * Gets the loaded deck. Only call this method after this dialog window has been successfully exec'd. @@ -32,13 +32,61 @@ public: * to use it, since otherwise it will get destroyed once this dlg is destroyed * @return The DeckLoader */ - DeckLoader *getDeckList() const + virtual DeckLoader *getDeckList() const = 0; + +protected: + void setText(const QString &text); + bool loadIntoDeck(DeckLoader *deckLoader) const; + void keyPressEvent(QKeyEvent *event) override; + +protected slots: + virtual void actOK() = 0; + virtual void actRefresh() = 0; +}; + +/** + * Dialog window for the "Load deck from clipboard" action + */ +class DlgLoadDeckFromClipboard : public AbstractDlgDeckTextEdit +{ + Q_OBJECT +protected slots: + void actOK() override; + void actRefresh() override; + +private: + DeckLoader *deckList; + +public: + explicit DlgLoadDeckFromClipboard(QWidget *parent = nullptr); + + DeckLoader *getDeckList() const override { return deckList; } +}; -protected: - void keyPressEvent(QKeyEvent *event) override; +/** + * Dialog window for the "Edit deck in clipboard" action + */ +class DlgEditDeckInClipboard : public AbstractDlgDeckTextEdit +{ + Q_OBJECT +protected slots: + void actOK() override; + void actRefresh() override; + +private: + DeckLoader *deckLoader; + bool annotated; + +public: + explicit DlgEditDeckInClipboard(const DeckLoader &deckList, bool _annotated, QWidget *parent = nullptr); + + DeckLoader *getDeckList() const override + { + return deckLoader; + } }; #endif diff --git a/cockatrice/src/settings/shortcuts_settings.h b/cockatrice/src/settings/shortcuts_settings.h index 28470260f..ce0127d57 100644 --- a/cockatrice/src/settings/shortcuts_settings.h +++ b/cockatrice/src/settings/shortcuts_settings.h @@ -206,6 +206,14 @@ private: ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Load Deck from Clipboard..."), parseSequenceString("Ctrl+Shift+V"), ShortcutGroup::Deck_Editor)}, + {"TabDeckEditor/aEditDeckInClipboard", + ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Edit Deck in Clipboard, Annotated"), + parseSequenceString(""), + ShortcutGroup::Deck_Editor)}, + {"TabDeckEditor/aEditDeckInClipboardRaw", + ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Edit Deck in Clipboard"), + parseSequenceString(""), + ShortcutGroup::Deck_Editor)}, {"TabDeckEditor/aNewDeck", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "New Deck"), parseSequenceString("Ctrl+N"), ShortcutGroup::Deck_Editor)},