[04]コカトリスインターフェース構成



Cockatrice Interface Composition



目次

前書き



ソースコード分析

[1] MainWindowを呼び出す



[2] MainWindowクラス構成

公衆:

明示的なMainWindow(QWidget * parent = nullptr)



void setConnectTo(QString url)

保護:

void closeEvent(QCloseEvent * event)オーバーライド

void changeEvent(QEvent * event)オーバーライド

QString extractInvalidUsernameMessage(QString&in)

民間:

void setClientStatusTitle()

void retranslateUi()

void createActions()

void createMenus()

void createTrayIcon()

void createTrayActions()

int getNextCustomSetPrefix(QDir dataDir)

インラインQStringgetCardUpdaterBinaryName()

パブリックスロット:

void actCheckCardUpdates()

void actCheckServerUpdates()

プライベートスロット:

void updateTabMenu(const QList&newMenuList)

void statusChanged(ClientStatus _status)

void processConnectionClosedEvent(const Event_ConnectionClosed&event)

void processServerShutdownEvent(const Event_ServerShutdown&event)

void serverTimeout()

void loginError(Response :: ResponseCode r、QString reasonStr、quint32 endTime、QList MissingFeatures)

void registerError(Response :: ResponseCode r、QString reasonStr、quint32 endTime)

void activateError()

void socketError(const QString&errorStr)

void protocolVersionMismatch(int localVersion、int remoteVersion)

void userInfoReceived(const ServerInfo_User&userInfo)

void registerAccepted()

void registerAcceptedNeedsActivate()

void activateAccepted()

void localGameEnded()

void pixmapCacheSizeChanged(int newSizeInMBs)

void notifyUserAboutUpdate()

void actConnect()

void actDisconnect()

void actSinglePlayer()

void actWatchReplay()

void actDeckEditor()

void actFullScreen(boolchecked)

void actRegister()

void actSettings()

void actExit()

void actForgotPasswordRequest()

void actAbout()

void actTips()

void actUpdate()

void actViewLog()

void forgotPasswordSuccess()

void forgotPasswordError()

void promptForgotPasswordReset()

void iconActivated(QSystemTrayIcon :: ActivationReason理由)

void promptForgotPasswordChallenge()

void showWindowIfHidden()

void cardUpdateError(QProcess :: ProcessError err)

void cardUpdateFinished(int exitCode、QProcess :: ExitStatus exitStatus)

void refreshShortcuts()

void cardDatabaseLoadingFailed()

void cardDatabaseNewSetsFound(int numUnknownSets、QStringList unknownSetsNames)

void cardDatabaseAllNewSetsEnabled()

void actOpenCustomFolder()

void actOpenCustomsetsFolder()

void actAddCustomSet()

void actManageSets()

void actEditTokens()

void startupConfigCheck()

void alertForcedOracleRun(const QString&version、bool isUpdate)

民間:

static const QString appName

static const QStringList fileNameFilters

QList tabMenus

QMenu * cockatriceMenu

QMenu * dbMenu

QMenu * helpMenu

QMenu * trailIconMenu

QAction * aConnect

QAction * aDisconnect

QAction * aSinglePlayer

QAction * aWatchReplay

QAction * aDeckEditor

QAction * aFullScreen

QAction * aSettings

QAction * aExit

QAction * aAbout

QAction * aTips

QAction * aCheckCardUpdates

QAction * aRegister

QAction * aUpdate

QAction * aViewLog

QAction * closeAction

QAction * aManageSets

QAction * aEditTokens

QAction * aOpenCustomFolder

QAction * aOpenCustomsetsFolder

QAction * aAddCustomSet

TabSupervisor * tabSupervisor

WndSets * wndSets

RemoteClient * client

QThread * clientThread

LocalServer * localServer

bool bHasActivated

QMessageBox serverShutdownMessageBox

QProcess * cardUpdateProcess

DlgViewLog * logviewDialog

DlgConnect * dlgConnect

GameReplay *リプレイ

DlgTipOfTheDay *ヒント

QUrl connectTo


[1] MainWindowを呼び出す

main()でMainWindowを呼び出してメインインターフェイスを生成し、メインウィンドウとステータスバーのアイコンを設定します。

int main(int argc, char *argv[]) { 。。。 MainWindow ui---->Create MainWindow instance if (parser.isSet('connect')) { ui.setConnectTo(parser.value('connect'))---->Finally, QUrl is used to save the server address to be connected } qDebug('main(): MainWindow constructor finished') ui.setWindowIcon(QPixmap('theme:cockatrice'))---->Set the icon displayed in the main window & status bar of the program 。。。 ui.show()---->Show window qDebug('main(): ui.show() finished') 。。。 }

[2] MainWindowクラス構成

MainWindowクラスはQMainWindowを継承し、主にQMainWindowに基づいて多くのスロット関数を追加します。

class MainWindow : public QMainWindow { Q_OBJECT public slots: void actCheckCardUpdates()---->Start a thread to load the external database 'oracle.exe' to update the card status void actCheckServerUpdates()---->Update the official server list file from the Git mirror address. private slots: void updateTabMenu(const QList &newMenuList)---->Update the menu bar with the content of newMenuList void statusChanged(ClientStatus _status)---->Switch the program running status void processConnectionClosedEvent(const Event_ConnectionClosed &event)---->Process connection close event void processServerShutdownEvent(const Event_ServerShutdown &event)---->Process server disconnection event void serverTimeout()---->Server timeout void loginError(Response::ResponseCode r, QString reasonStr, quint32 endTime, QList missingFeatures)---->Login error void registerError(Response::ResponseCode r, QString reasonStr, quint32 endTime)---->Registration error void activateError()----> void socketError(const QString &errorStr)----> void protocolVersionMismatch(int localVersion, int remoteVersion)---->protocol version does not match void userInfoReceived(const ServerInfo_User &userInfo)---->User Information Receive void registerAccepted()---->Registration allowed void registerAcceptedNeedsActivate()---->Activation is required after registration is allowed void activateAccepted()---->Activation allowed void localGameEnded()---->The local game ends void pixmapCacheSizeChanged(int newSizeInMBs)---->Image cache size changed void notifyUserAboutUpdate()----> void actConnect()----> void actDisconnect()----> void actSinglePlayer()----> void actWatchReplay()----> void actDeckEditor()----> void actFullScreen(bool checked)----> void actRegister()----> void actSettings()----> void actExit()----> void actForgotPasswordRequest()----> void actAbout()----> void actTips()----> void actUpdate()----> void actViewLog()----> void forgotPasswordSuccess()----> void forgotPasswordError()----> void promptForgotPasswordReset()----> void iconActivated(QSystemTrayIcon::ActivationReason reason)----> void promptForgotPasswordChallenge()----> void showWindowIfHidden()----> void cardUpdateError(QProcess::ProcessError err)----> void cardUpdateFinished(int exitCode, QProcess::ExitStatus exitStatus)----> void refreshShortcuts()----> void cardDatabaseLoadingFailed()----> void cardDatabaseNewSetsFound(int numUnknownSets, QStringList unknownSetsNames)----> void cardDatabaseAllNewSetsEnabled()----> void actOpenCustomFolder()----> void actOpenCustomsetsFolder()----> void actAddCustomSet()----> void actManageSets()----> void actEditTokens()----> void startupConfigCheck()----> void alertForcedOracleRun(const QString &version, bool isUpdate)----> private: static const QString appName static const QStringList fileNameFilters void setClientStatusTitle()----> void retranslateUi()----> void createActions()----> void createMenus()----> void createTrayIcon()----> void createTrayActions()----> int getNextCustomSetPrefix(QDir dataDir)----> // TODO: add a preference item to choose updater name for other games inline QString getCardUpdaterBinaryName()----> { return 'oracle' } QList tabMenus QMenu *cockatriceMenu, *dbMenu, *helpMenu, *trayIconMenu QAction *aConnect, *aDisconnect, *aSinglePlayer, *aWatchReplay, *aDeckEditor, *aFullScreen, *aSettings, *aExit, *aAbout, *aTips, *aCheckCardUpdates, *aRegister, *aUpdate, *aViewLog, *closeAction QAction *aManageSets, *aEditTokens, *aOpenCustomFolder, *aOpenCustomsetsFolder, *aAddCustomSet TabSupervisor *tabSupervisor WndSets *wndSets RemoteClient *client QThread *clientThread LocalServer *localServer bool bHasActivated QMessageBox serverShutdownMessageBox QProcess *cardUpdateProcess DlgViewLog *logviewDialog DlgConnect *dlgConnect GameReplay *replay DlgTipOfTheDay *tip QUrl connectTo public: explicit MainWindow(QWidget *parent = nullptr)----> void setConnectTo(QString url)----> { connectTo = QUrl(QString('cockatrice://%1').arg(url)) } ~MainWindow() override----> protected: void closeEvent(QCloseEvent *event) override----> void changeEvent(QEvent *event) override----> QString extractInvalidUsernameMessage(QString &in)----> }

公衆:

明示的なMainWindow(QWidget * parent = nullptr)

コンストラクター、明示的はこ​​れが表示コンストラクターであることを意味します(パラメーターは暗黙的に変換されません)、parent = nullptrはこれが最上位関数であり、すべてのウィンドウの父であり、それを強制終了すると、すべての子ウィンドウ/コントロールが逆になります構造によると破壊します。

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), localServer(nullptr), bHasActivated(false), cardUpdateProcess(nullptr), logviewDialog(nullptr) { connect(settingsCache, SIGNAL(pixmapCacheSizeChanged(int)), this, SLOT(pixmapCacheSizeChanged(int))) pixmapCacheSizeChanged(settingsCache->getPixmapCacheSize()) client = new RemoteClient connect(client, SIGNAL(connectionClosedEventReceived(const Event_ConnectionClosed &)), this, SLOT(processConnectionClosedEvent(const Event_ConnectionClosed &))) connect(client, SIGNAL(serverShutdownEventReceived(const Event_ServerShutdown &)), this, SLOT(processServerShutdownEvent(const Event_ServerShutdown &))) connect(client, SIGNAL(loginError(Response::ResponseCode, QString, quint32, QList)), this, SLOT(loginError(Response::ResponseCode, QString, quint32, QList))) connect(client, SIGNAL(socketError(const QString &)), this, SLOT(socketError(const QString &))) connect(client, SIGNAL(serverTimeout()), this, SLOT(serverTimeout())) connect(client, SIGNAL(statusChanged(ClientStatus)), this, SLOT(statusChanged(ClientStatus))) connect(client, SIGNAL(protocolVersionMismatch(int, int)), this, SLOT(protocolVersionMismatch(int, int))) connect(client, SIGNAL(userInfoChanged(const ServerInfo_User &)), this, SLOT(userInfoReceived(const ServerInfo_User &)), Qt::BlockingQueuedConnection) connect(client, SIGNAL(notifyUserAboutUpdate()), this, SLOT(notifyUserAboutUpdate())) connect(client, SIGNAL(registerAccepted()), this, SLOT(registerAccepted())) connect(client, SIGNAL(registerAcceptedNeedsActivate()), this, SLOT(registerAcceptedNeedsActivate())) connect(client, SIGNAL(registerError(Response::ResponseCode, QString, quint32)), this, SLOT(registerError(Response::ResponseCode, QString, quint32))) connect(client, SIGNAL(activateAccepted()), this, SLOT(activateAccepted())) connect(client, SIGNAL(activateError()), this, SLOT(activateError())) connect(client, SIGNAL(sigForgotPasswordSuccess()), this, SLOT(forgotPasswordSuccess())) connect(client, SIGNAL(sigForgotPasswordError()), this, SLOT(forgotPasswordError())) connect(client, SIGNAL(sigPromptForForgotPasswordReset()), this, SLOT(promptForgotPasswordReset())) connect(client, SIGNAL(sigPromptForForgotPasswordChallenge()), this, SLOT(promptForgotPasswordChallenge())) clientThread = new QThread(this) client->moveToThread(clientThread) clientThread->start() createActions() createMenus() tabSupervisor = new TabSupervisor(client) connect(tabSupervisor, SIGNAL(setMenu(QList)), this, SLOT(updateTabMenu(QList))) connect(tabSupervisor, SIGNAL(localGameEnded()), this, SLOT(localGameEnded())) connect(tabSupervisor, SIGNAL(showWindowIfHidden()), this, SLOT(showWindowIfHidden())) tabSupervisor->addDeckEditorTab(nullptr) setCentralWidget(tabSupervisor) retranslateUi() if (!restoreGeometry(settingsCache->getMainWindowGeometry())) { setWindowState(Qt::WindowMaximized) } aFullScreen->setChecked(static_cast(windowState() & Qt::WindowFullScreen)) if (QSystemTrayIcon::isSystemTrayAvailable()) { createTrayActions() createTrayIcon() } connect(&settingsCache->shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts())) refreshShortcuts() connect(db, SIGNAL(cardDatabaseLoadingFailed()), this, SLOT(cardDatabaseLoadingFailed())) connect(db, SIGNAL(cardDatabaseNewSetsFound(int, QStringList)), this, SLOT(cardDatabaseNewSetsFound(int, QStringList))) connect(db, SIGNAL(cardDatabaseAllNewSetsEnabled()), this, SLOT(cardDatabaseAllNewSetsEnabled())) tip = new DlgTipOfTheDay() // run startup check async QTimer::singleShot(0, this, &MainWindow::startupConfigCheck) }

void setConnectTo(QString url)

connectTo変数に値を割り当て、サーバーアドレスを指定します。

void setConnectTo(QString url) { connectTo = QUrl(QString('cockatrice://%1').arg(url)) }

〜MainWindow()オーバーライド

デストラクタ、いい隣人になるために〜

MainWindow::~MainWindow() { if (tip != nullptr) { delete tip tip = nullptr } if (trayIcon) { trayIcon->hide() trayIcon->deleteLater() } client->deleteLater() clientThread->wait() }

保護:

void closeEvent(QCloseEvent * event)オーバーライド

QMainWindowのcloseEventを書き直して、QTネイティブcloseEvent()イベントが2回続けてトリガーされるという問題を解決します。

void MainWindow::closeEvent(QCloseEvent *event) { // workaround Qt bug where closeEvent gets called twice static bool bClosingDown = false if (bClosingDown) return bClosingDown = true if (!tabSupervisor->closeRequest()) { event->ignore() bClosingDown = false return } tip->close() event->accept() settingsCache->setMainWindowGeometry(saveGeometry()) tabSupervisor->deleteLater() }

void changeEvent(QEvent * event)オーバーライド

QMainWindowのchangeEventをオーバーライドし、QMainWindowのchangeEventを呼び出す前に、QEvent :: LanguageChangeイベントとQEvent :: ActivationChangeイベントを追加で処理します。

void MainWindow::changeEvent(QEvent *event) { if (event->type() == QEvent::LanguageChange) retranslateUi() else if (event->type() == QEvent::ActivationChange) { if (isActiveWindow() && !bHasActivated) { bHasActivated = true if (!connectTo.isEmpty()) { qDebug() << 'Command line connect to ' servers().getAutoConnect()) { qDebug()

QString extractInvalidUsernameMessage(QString&in)

この関数は、ユーザー名が無効な場合にのみ呼び出す必要があります。ユーザー名が無効である理由を検出し、関連するプロンプトメッセージを出力します。

QString MainWindow::extractInvalidUsernameMessage(QString &in) { QString out = tr('Invalid username.') + '
' QStringList rules = in.split(QChar('|')) if (rules.size() == 7 || rules.size() == 9) { out += tr('Your username must respect these rules:') + '
    ' out += '
  • ' + tr('is %1 - %2 characters long').arg(rules.at(0)).arg(rules.at(1)) + '
  • ' out += '
  • ' + tr('can %1 contain lowercase characters').arg((rules.at(2).toInt() > 0) ? '' : tr('NOT')) + '
  • ' out += '
  • ' + tr('can %1 contain uppercase characters').arg((rules.at(3).toInt() > 0) ? '' : tr('NOT')) + '
  • ' out += '
  • ' + tr('can %1 contain numeric characters').arg((rules.at(4).toInt() > 0) ? '' : tr('NOT')) + '
  • ' if (rules.at(6).size() > 0) out += '
  • ' + tr('can contain the following punctuation: %1').arg(rules.at(6).toHtmlEscaped()) + '
  • ' out += '
  • ' + tr('first character can %1 be a punctuation mark').arg((rules.at(5).toInt() > 0) ? '' : tr('NOT')) + '
  • ' if (rules.size() == 9) { if (rules.at(7).size() > 0) out += '
  • ' + tr('can not contain any of the following words: %1').arg(rules.at(7).toHtmlEscaped()) + '
  • ' if (rules.at(8).size() > 0) out += '
  • ' + tr('can not match any of the following expressions: %1').arg(rules.at(8).toHtmlEscaped()) + '
  • ' } out += '
' } else { out += tr('You may only use A-Z, a-z, 0-9, _, ., and - in your username.') } return out }

民間:

void setClientStatusTitle()

client-> getStatus()を使用して現在のプログラムの実行ステータスを取得し、プログラムのタイトルバーに対応する説明を表示します。プログラム名は通常動作時に表示されます。

void MainWindow::setClientStatusTitle() { switch (client->getStatus()) { case StatusConnecting: setWindowTitle(appName + ' - ' + tr('Connecting to %1...').arg(client->peerName())) break case StatusRegistering: setWindowTitle(appName + ' - ' + tr('Registering to %1 as %2...').arg(client->peerName()).arg(client->getUserName())) break case StatusDisconnected: setWindowTitle(appName + ' - ' + tr('Disconnected')) break case StatusLoggingIn: setWindowTitle(appName + ' - ' + tr('Connected, logging in at %1').arg(client->peerName())) break case StatusLoggedIn: setWindowTitle(client->getUserName() + '@' + client->peerName()) break case StatusRequestingForgotPassword: setWindowTitle( appName + ' - ' + tr('Requesting forgotten password to %1 as %2...').arg(client->peerName()).arg(client->getUserName())) break case StatusSubmitForgotPasswordChallenge: setWindowTitle( appName + ' - ' + tr('Requesting forgotten password to %1 as %2...').arg(client->peerName()).arg(client->getUserName())) break case StatusSubmitForgotPasswordReset: setWindowTitle( appName + ' - ' + tr('Requesting forgotten password to %1 as %2...').arg(client->peerName()).arg(client->getUserName())) break default: setWindowTitle(appName) } }

void retranslateUi()

setClientStatusTitle()を呼び出して、プログラムの実行ステータスをタイトルバーに更新し(主に表示されるテキスト言語を更新します)、すべてのメニュー(メニューバー)/アクティブ(メニュー項目)/タブ(タブ)の表示テキスト言語を更新します。

void MainWindow::retranslateUi() { setClientStatusTitle() aConnect->setText(tr('&Connect...')) aDisconnect->setText(tr('&Disconnect')) aSinglePlayer->setText(tr('Start &local game...')) aWatchReplay->setText(tr('&Watch replay...')) aDeckEditor->setText(tr('&Deck editor')) aFullScreen->setText(tr('&Full screen')) aRegister->setText(tr('&Register to server...')) aSettings->setText(tr('&Settings...')) aSettings->setIcon(QPixmap('theme:icons/settings')) aExit->setText(tr('&Exit')) #if defined(__APPLE__) /* For OSX */ cockatriceMenu->setTitle(tr('A&ctions')) #else cockatriceMenu->setTitle(tr('&Cockatrice')) #endif dbMenu->setTitle(tr('C&ard Database')) aOpenCustomFolder->setText(tr('Open custom image folder')) aOpenCustomsetsFolder->setText(tr('Open custom sets folder')) aAddCustomSet->setText(tr('Add custom sets/cards')) aManageSets->setText(tr('&Manage sets...')) aEditTokens->setText(tr('Edit custom &tokens...')) aAbout->setText(tr('&About Cockatrice')) aTips->setText(tr('&Tip of the Day')) aUpdate->setText(tr('Check for Client Updates')) aViewLog->setText(tr('View &debug log')) helpMenu->setTitle(tr('&Help')) aCheckCardUpdates->setText(tr('Check for card updates...')) tabSupervisor->retranslateUi() }

void createActions()

すべてのメニュー項目を作成します。

void MainWindow::createActions() { aConnect = new QAction(this) connect(aConnect, SIGNAL(triggered()), this, SLOT(actConnect())) aDisconnect = new QAction(this) aDisconnect->setEnabled(false) connect(aDisconnect, SIGNAL(triggered()), this, SLOT(actDisconnect())) aSinglePlayer = new QAction(this) connect(aSinglePlayer, SIGNAL(triggered()), this, SLOT(actSinglePlayer())) aWatchReplay = new QAction(this) connect(aWatchReplay, SIGNAL(triggered()), this, SLOT(actWatchReplay())) aDeckEditor = new QAction(this) connect(aDeckEditor, SIGNAL(triggered()), this, SLOT(actDeckEditor())) aFullScreen = new QAction(this) aFullScreen->setCheckable(true) connect(aFullScreen, SIGNAL(toggled(bool)), this, SLOT(actFullScreen(bool))) aRegister = new QAction(this) connect(aRegister, SIGNAL(triggered()), this, SLOT(actRegister())) aSettings = new QAction(this) connect(aSettings, SIGNAL(triggered()), this, SLOT(actSettings())) aExit = new QAction(this) connect(aExit, SIGNAL(triggered()), this, SLOT(actExit())) aAbout = new QAction(this) connect(aAbout, SIGNAL(triggered()), this, SLOT(actAbout())) aTips = new QAction(this) connect(aTips, SIGNAL(triggered()), this, SLOT(actTips())) aUpdate = new QAction(this) connect(aUpdate, SIGNAL(triggered()), this, SLOT(actUpdate())) aViewLog = new QAction(this) connect(aViewLog, SIGNAL(triggered()), this, SLOT(actViewLog())) aCheckCardUpdates = new QAction(this) connect(aCheckCardUpdates, SIGNAL(triggered()), this, SLOT(actCheckCardUpdates())) aOpenCustomsetsFolder = new QAction(QString(), this) connect(aOpenCustomsetsFolder, SIGNAL(triggered()), this, SLOT(actOpenCustomsetsFolder())) aOpenCustomFolder = new QAction(QString(), this) connect(aOpenCustomFolder, SIGNAL(triggered()), this, SLOT(actOpenCustomFolder())) aAddCustomSet = new QAction(QString(), this) connect(aAddCustomSet, SIGNAL(triggered()), this, SLOT(actAddCustomSet())) aManageSets = new QAction(QString(), this) connect(aManageSets, SIGNAL(triggered()), this, SLOT(actManageSets())) aEditTokens = new QAction(QString(), this) connect(aEditTokens, SIGNAL(triggered()), this, SLOT(actEditTokens())) #if defined(__APPLE__) /* For OSX */ aSettings->setMenuRole(QAction::PreferencesRole) aExit->setMenuRole(QAction::QuitRole) aAbout->setMenuRole(QAction::AboutRole) Q_UNUSED(QT_TRANSLATE_NOOP('QMenuBar', 'Services')) Q_UNUSED(QT_TRANSLATE_NOOP('QMenuBar', 'Hide %1')) Q_UNUSED(QT_TRANSLATE_NOOP('QMenuBar', 'Hide Others')) Q_UNUSED(QT_TRANSLATE_NOOP('QMenuBar', 'Show All')) Q_UNUSED(QT_TRANSLATE_NOOP('QMenuBar', 'Preferences...')) Q_UNUSED(QT_TRANSLATE_NOOP('QMenuBar', 'Quit %1')) Q_UNUSED(QT_TRANSLATE_NOOP('QMenuBar', 'About %1')) #endif // translate Qt's dialogs 'default button text' list taken from QPlatformTheme::defaultStandardButtonText() Q_UNUSED(QT_TRANSLATE_NOOP('QPlatformTheme', 'OK')) Q_UNUSED(QT_TRANSLATE_NOOP('QPlatformTheme', 'Save')) Q_UNUSED(QT_TRANSLATE_NOOP('QPlatformTheme', 'Save All')) Q_UNUSED(QT_TRANSLATE_NOOP('QPlatformTheme', 'Open')) Q_UNUSED(QT_TRANSLATE_NOOP('QPlatformTheme', '&Yes')) Q_UNUSED(QT_TRANSLATE_NOOP('QPlatformTheme', 'Yes to &All')) Q_UNUSED(QT_TRANSLATE_NOOP('QPlatformTheme', '&No')) Q_UNUSED(QT_TRANSLATE_NOOP('QPlatformTheme', 'N&o to All')) Q_UNUSED(QT_TRANSLATE_NOOP('QPlatformTheme', 'Abort')) Q_UNUSED(QT_TRANSLATE_NOOP('QPlatformTheme', 'Retry')) Q_UNUSED(QT_TRANSLATE_NOOP('QPlatformTheme', 'Ignore')) Q_UNUSED(QT_TRANSLATE_NOOP('QPlatformTheme', 'Close')) Q_UNUSED(QT_TRANSLATE_NOOP('QPlatformTheme', 'Cancel')) Q_UNUSED(QT_TRANSLATE_NOOP('QPlatformTheme', 'Discard')) Q_UNUSED(QT_TRANSLATE_NOOP('QPlatformTheme', 'Help')) Q_UNUSED(QT_TRANSLATE_NOOP('QPlatformTheme', 'Apply')) Q_UNUSED(QT_TRANSLATE_NOOP('QPlatformTheme', 'Reset')) Q_UNUSED(QT_TRANSLATE_NOOP('QPlatformTheme', 'Restore Defaults')) }

void createMenus()

すべてのメニューバーを作成し、対応するメニューバーに特定のメニュー項目を追加します。

void MainWindow::createMenus() cockatriceMenu = menuBar()->addMenu(QString()) cockatriceMenu->addAction(aConnect) cockatriceMenu->addAction(aDisconnect) cockatriceMenu->addAction(aRegister) cockatriceMenu->addSeparator() cockatriceMenu->addAction(aSinglePlayer) cockatriceMenu->addAction(aWatchReplay) cockatriceMenu->addSeparator() cockatriceMenu->addAction(aDeckEditor) cockatriceMenu->addSeparator() cockatriceMenu->addAction(aFullScreen) cockatriceMenu->addSeparator() cockatriceMenu->addAction(aSettings) cockatriceMenu->addAction(aCheckCardUpdates) cockatriceMenu->addSeparator() cockatriceMenu->addAction(aExit) dbMenu = menuBar()->addMenu(QString()) dbMenu->addAction(aManageSets) dbMenu->addAction(aEditTokens) dbMenu->addSeparator() #if defined(Q_OS_WIN)

void createTrayIcon()

システムトレイアイコン(右下隅のステータスバー)を作成します。

void MainWindow::createTrayIcon() { trayIconMenu = new QMenu(this) trayIconMenu->addAction(closeAction) trayIcon = new QSystemTrayIcon(this) trayIcon->setContextMenu(trayIconMenu) trayIcon->setIcon(QPixmap('theme:cockatrice')) trayIcon->show() connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason))) }

void createTrayActions()

システムトレイアイコンのメニュー項目を作成し、現在はプログラムを終了するだけです。

void MainWindow::createTrayActions() { closeAction = new QAction(tr('&Exit'), this) connect(closeAction, SIGNAL(triggered()), this, SLOT(close())) }

int getNextCustomSetPrefix(QDir dataDir)

データベースディレクトリ内のすべてのファイルを読み取り、リストを作成し、トラバースして最大の番号名を検出し、番号+1を新しいファイル名として出力します。

トラバーサルの実装では、非常に古典的なC ++スタイルのトラバーサーを使用します。

int MainWindow::getNextCustomSetPrefix(QDir dataDir) { QStringList files = dataDir.entryList() int maxIndex = 0 QStringList::const_iterator filesIterator for (filesIterator = files.constBegin() filesIterator != files.constEnd() ++filesIterator) { int fileIndex = (*filesIterator).split('.').at(0).toInt() if (fileIndex > maxIndex) maxIndex = fileIndex } return maxIndex + 1 }

インラインQStringgetCardUpdaterBinaryName()

呼び出された外部データベースプログラムの名前を返します。現在、oracleが使用されています。

inlineは、これがインライン関数であることを示します。インライン関数は通常、ヘッダーファイルで定義することをお勧めします。インライン関数は、直接再帰的(自身を呼び出す)または複雑な制御ステートメント(while / switchなど)を含むことはできず、特定の効果はコンパイラーに関連しています。

inline QString getCardUpdaterBinaryName() { return 'oracle' }

パブリックスロット:

void actCheckCardUpdates()

スレッドを開始して外部データベースプログラム「oracle.exe」をロードし、カードのステータスを更新します。データベースプログラム名はgetCardUpdaterBinaryName()を介して取得されます。

/* CARD UPDATER */ void MainWindow::actCheckCardUpdates() { if (cardUpdateProcess) { QMessageBox::information(this, tr('Information'), tr('A card database update is already running.')) return } cardUpdateProcess = new QProcess(this) connect(cardUpdateProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(cardUpdateError(QProcess::ProcessError))) connect(cardUpdateProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(cardUpdateFinished(int, QProcess::ExitStatus))) // full 'run the update' command leave empty if not present QString updaterCmd QString binaryName QDir dir = QDir(QApplication::applicationDirPath()) #if defined(Q_OS_MAC) binaryName = getCardUpdaterBinaryName() // exit from the application bundle dir.cdUp() dir.cdUp() dir.cdUp() dir.cd(binaryName + '.app') dir.cd('Contents') dir.cd('MacOS') #elif defined(Q_OS_WIN) binaryName = getCardUpdaterBinaryName() + '.exe' #else binaryName = getCardUpdaterBinaryName() #endif if (dir.exists(binaryName)) updaterCmd = dir.absoluteFilePath(binaryName) if (updaterCmd.isEmpty()) { QMessageBox::warning(this, tr('Error'), tr('Unable to run the card database updater: ') + dir.absoluteFilePath(binaryName)) return } cardUpdateProcess->start(''' + updaterCmd + ''') }

void actCheckServerUpdates()

Cockatriceの公式サーバーアドレスリストを「https://cockatrice.github.io/public-servers.json」からダウンロードします。独自のサーバーを構築する場合は、このURLを変更するか、独自のサーバーアドレスを公式リストに追加する必要があります。

void MainWindow::actCheckServerUpdates() { auto hps = new HandlePublicServers(this) hps->downloadPublicServers() connect(hps, &HandlePublicServers::sigPublicServersDownloadedSuccessfully, [=]() { hps->deleteLater() }) }

プライベートスロット:

void updateTabMenu(const QList&newMenuList)

newMenuListのコンテンツでメニューバーを更新します。

void MainWindow::updateTabMenu(const QList &newMenuList) { for (auto &tabMenu : tabMenus) menuBar()->removeAction(tabMenu->menuAction()) tabMenus = newMenuList for (auto &tabMenu : tabMenus) menuBar()->insertMenu(helpMenu->menuAction(), tabMenu) }

void statusChanged(ClientStatus _status)

void MainWindow::statusChanged(ClientStatus _status) { setClientStatusTitle() switch (_status) { case StatusDisconnected: tabSupervisor->stop() aSinglePlayer->setEnabled(true) aConnect->setEnabled(true) aRegister->setEnabled(true) aDisconnect->setEnabled(false) break case StatusLoggingIn: aSinglePlayer->setEnabled(false) aConnect->setEnabled(false) aRegister->setEnabled(false) aDisconnect->setEnabled(true) break case StatusConnecting: case StatusRegistering: case StatusLoggedIn: default: break } }

void processConnectionClosedEvent(const Event_ConnectionClosed&event)

void MainWindow::processConnectionClosedEvent(const Event_ConnectionClosed &event) { client->disconnectFromServer() QString reasonStr switch (event.reason()) { case Event_ConnectionClosed::USER_LIMIT_REACHED: reasonStr = tr('The server has reached its maximum user capacity, please check back later.') break case Event_ConnectionClosed::TOO_MANY_CONNECTIONS: reasonStr = tr('There are too many concurrent connections from your address.') break case Event_ConnectionClosed::BANNED: { reasonStr = tr('Banned by moderator') if (event.has_end_time()) reasonStr.append(' ' + tr('Expected end time: %1').arg(QDateTime::fromTime_t(event.end_time()).toString())) else reasonStr.append(' ' + tr('This ban lasts indefinitely.')) if (event.has_reason_str()) reasonStr.append(' ' + QString::fromStdString(event.reason_str())) break } case Event_ConnectionClosed::SERVER_SHUTDOWN: reasonStr = tr('Scheduled server shutdown.') break case Event_ConnectionClosed::USERNAMEINVALID: reasonStr = tr('Invalid username.') break case Event_ConnectionClosed::LOGGEDINELSEWERE: reasonStr = tr('You have been logged out due to logging in at another location.') break default: reasonStr = QString::fromStdString(event.reason_str()) } QMessageBox::critical(this, tr('Connection closed'), tr('The server has terminated your connection. Reason: %1').arg(reasonStr)) }

void processServerShutdownEvent(const Event_ServerShutdown&event)

void MainWindow::processServerShutdownEvent(const Event_ServerShutdown &event) { serverShutdownMessageBox.setInformativeText(tr('The server is going to be restarted in %n minute(s). All running ' 'games will be lost. Reason for shutdown: %1', '', event.minutes()) .arg(QString::fromStdString(event.reason()))) serverShutdownMessageBox.setIconPixmap(QPixmap('theme:cockatrice').scaled(64, 64)) serverShutdownMessageBox.setText(tr('Scheduled server shutdown')) serverShutdownMessageBox.setWindowModality(Qt::ApplicationModal) serverShutdownMessageBox.setVisible(true) }

void serverTimeout()

void MainWindow::serverTimeout() { QMessageBox::critical(this, tr('Error'), tr('Server timeout')) actConnect() }

void loginError(Response :: ResponseCode r、QString reasonStr、quint32 endTime、QList MissingFeatures)

void MainWindow::loginError(Response::ResponseCode r, QString reasonStr, quint32 endTime, QList missingFeatures) { switch (r) { case Response::RespClientUpdateRequired: { QString formattedMissingFeatures formattedMissingFeatures = 'Missing Features: ' for (int i = 0 i Check for Client Updates'.')) msgBox.setDetailedText(formattedMissingFeatures) msgBox.exec() break } case Response::RespWrongPassword: QMessageBox::critical( this, tr('Error'), tr('Incorrect username or password. Please check your authentication information and try again.')) break case Response::RespWouldOverwriteOldSession: QMessageBox::critical(this, tr('Error'), tr('There is already an active session using this user name. Please close that ' 'session first and re-login.')) break case Response::RespUserIsBanned: { QString bannedStr if (endTime) bannedStr = tr('You are banned until %1.').arg(QDateTime::fromTime_t(endTime).toString()) else bannedStr = tr('You are banned indefinitely.') if (!reasonStr.isEmpty()) bannedStr.append(' ' + reasonStr) QMessageBox::critical(this, tr('Error'), bannedStr) break } case Response::RespUsernameInvalid: { QMessageBox::critical(this, tr('Error'), extractInvalidUsernameMessage(reasonStr)) break } case Response::RespRegistrationRequired: if (QMessageBox::question(this, tr('Error'), tr('This server requires user registration. Do you want to register now?'), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { actRegister() } break case Response::RespClientIdRequired: QMessageBox::critical( this, tr('Error'), tr('This server requires client IDs. Your client is either failing to generate an ID or you are ' 'running a modified client. Please close and reopen your client to try again.')) break case Response::RespContextError: QMessageBox::critical(this, tr('Error'), tr('An internal error has occurred, please close and reopen Cockatrice before trying ' 'again. If the error persists, ensure you are running the latest version of the ' 'software and if needed contact the software developers.')) break case Response::RespAccountNotActivated: { bool ok = false QString token = QInputDialog::getText(this, tr('Account activation'), tr('Your account has not been activated yet. You need to provide ' 'the activation token received in the activation email.'), QLineEdit::Normal, QString(), &ok) if (ok && !token.isEmpty()) { client->activateToServer(token) return } client->disconnectFromServer() break } case Response::RespServerFull: { QMessageBox::critical(this, tr('Server Full'), tr('The server has reached its maximum user capacity, please check back later.')) break } default: QMessageBox::critical(this, tr('Error'), tr('Unknown login error: %1').arg(static_cast(r)) + tr(' This usually means that your client version is out of date, and the server ' 'sent a reply your client doesn't understand.')) break } actConnect() }

void registerError(Response :: ResponseCode r、QString reasonStr、quint32 endTime)

void MainWindow::registerError(Response::ResponseCode r, QString reasonStr, quint32 endTime) { switch (r) { case Response::RespRegistrationDisabled: QMessageBox::critical(this, tr('Registration denied'), tr('Registration is currently disabled on this server')) break case Response::RespUserAlreadyExists: QMessageBox::critical(this, tr('Registration denied'), tr('There is already an existing account with the same user name.')) break case Response::RespEmailRequiredToRegister: QMessageBox::critical(this, tr('Registration denied'), tr('It's mandatory to specify a valid email address when registering.')) break case Response::RespEmailBlackListed: QMessageBox::critical( this, tr('Registration denied'), tr('The email address provider used during registration has been blacklisted for use on this server.')) break case Response::RespTooManyRequests: QMessageBox::critical( this, tr('Registration denied'), tr('It appears you are attempting to register a new account on this server yet you already have an ' 'account registered with the email provided. This server restricts the number of accounts a user ' 'can register per address. Please contact the server operator for further assistance or to obtain ' 'your credential information.')) break case Response::RespPasswordTooShort: QMessageBox::critical(this, tr('Registration denied'), tr('Password too short.')) break case Response::RespUserIsBanned: { QString bannedStr if (endTime) bannedStr = tr('You are banned until %1.').arg(QDateTime::fromTime_t(endTime).toString()) else bannedStr = tr('You are banned indefinitely.') if (!reasonStr.isEmpty()) bannedStr.append(' ' + reasonStr) QMessageBox::critical(this, tr('Error'), bannedStr) break } case Response::RespUsernameInvalid: { QMessageBox::critical(this, tr('Error'), extractInvalidUsernameMessage(reasonStr)) break } case Response::RespRegistrationFailed: QMessageBox::critical(this, tr('Error'), tr('Registration failed for a technical problem on the server.')) break default: QMessageBox::critical(this, tr('Error'), tr('Unknown registration error: %1').arg(static_cast(r)) + tr(' This usually means that your client version is out of date, and the server ' 'sent a reply your client doesn't understand.')) } actRegister() }

void activateError()

void MainWindow::activateError() { QMessageBox::critical(this, tr('Error'), tr('Account activation failed')) client->disconnectFromServer() actConnect() }

void socketError(const QString&errorStr)

void MainWindow::socketError(const QString &errorStr) { QMessageBox::critical(this, tr('Error'), tr('Socket error: %1').arg(errorStr)) actConnect() }

void protocolVersionMismatch(int localVersion、int remoteVersion)

void MainWindow::protocolVersionMismatch(int localVersion, int remoteVersion) { if (localVersion > remoteVersion) QMessageBox::critical(this, tr('Error'), tr('You are trying to connect to an obsolete server. Please downgrade your Cockatrice ' 'version or connect to a suitable server. Local version is %1, remote version is %2.') .arg(localVersion) .arg(remoteVersion)) else QMessageBox::critical(this, tr('Error'), tr('Your Cockatrice client is obsolete. Please update your Cockatrice version. Local ' 'version is %1, remote version is %2.') .arg(localVersion) .arg(remoteVersion)) }

void userInfoReceived(const ServerInfo_User&userInfo)

void MainWindow::userInfoReceived(const ServerInfo_User &info) { tabSupervisor->start(info) }

void registerAccepted()

void MainWindow::registerAccepted() { QMessageBox::information(this, tr('Success'), tr('Registration accepted. Will now login.')) }

void registerAcceptedNeedsActivate()

void MainWindow::registerAcceptedNeedsActivate() { // nothing }

void activateAccepted()

void MainWindow::activateAccepted() { QMessageBox::information(this, tr('Success'), tr('Account activation accepted. Will now login.')) }

void localGameEnded()

void MainWindow::localGameEnded() { delete localServer localServer = nullptr aConnect->setEnabled(true) aRegister->setEnabled(true) aSinglePlayer->setEnabled(true) }

void pixmapCacheSizeChanged(int newSizeInMBs)

void MainWindow::pixmapCacheSizeChanged(int newSizeInMBs) { // qDebug() << 'Setting pixmap cache size to ' << value << ' MBs' // translate MBs to KBs QPixmapCache::setCacheLimit(newSizeInMBs * 1024) }

void notifyUserAboutUpdate()

void MainWindow::notifyUserAboutUpdate() { QMessageBox::information( this, tr('Information'), tr('This server supports additional features that your client doesn't have. This is most likely not a ' 'problem, but this message might mean there is a new version of Cockatrice available or this server is ' 'running a custom or pre-release version. To update your client, go to Help -> Check for Updates.')) }

void actConnect()

void MainWindow::actConnect() { dlgConnect = new DlgConnect(this) connect(dlgConnect, SIGNAL(sigStartForgotPasswordRequest()), this, SLOT(actForgotPasswordRequest())) if (dlgConnect->exec()) { client->connectToServer(dlgConnect->getHost(), static_cast(dlgConnect->getPort()), dlgConnect->getPlayerName(), dlgConnect->getPassword()) } }

void actDisconnect()

void MainWindow::actDisconnect() { client->disconnectFromServer() }

void actSinglePlayer()

void MainWindow::actSinglePlayer() { bool ok int numberPlayers = QInputDialog::getInt(this, tr('Number of players'), tr('Please enter the number of players.'), 1, 1, 8, 1, &ok) if (!ok) return aConnect->setEnabled(false) aRegister->setEnabled(false) aSinglePlayer->setEnabled(false) localServer = new LocalServer(this) LocalServerInterface *mainLsi = localServer->newConnection() LocalClient *mainClient = new LocalClient(mainLsi, tr('Player %1').arg(1), settingsCache->getClientID(), this) QList localClients localClients.append(mainClient) for (int i = 0 i newConnection() LocalClient *slaveClient = new LocalClient(slaveLsi, tr('Player %1').arg(i + 2), settingsCache->getClientID(), this) localClients.append(slaveClient) } tabSupervisor->startLocal(localClients) Command_CreateGame createCommand createCommand.set_max_players(static_cast(numberPlayers)) mainClient->sendCommand(LocalClient::prepareRoomCommand(createCommand, 0)) }

void actWatchReplay()

void MainWindow::actWatchReplay() { QFileDialog dlg(this, tr('Load replay')) dlg.setDirectory(settingsCache->getReplaysPath()) dlg.setNameFilters(QStringList() openReplay(replay) }

void actDeckEditor()

void MainWindow::actDeckEditor() { tabSupervisor->addDeckEditorTab(nullptr) }

void actFullScreen(boolchecked)

void MainWindow::actFullScreen(bool checked) Qt::WindowFullScreen) else setWindowState(windowState() & ~Qt::WindowFullScreen)

void actRegister()

void MainWindow::actRegister() { DlgRegister dlg(this) if (dlg.exec()) { client->registerToServer(dlg.getHost(), static_cast(dlg.getPort()), dlg.getPlayerName(), dlg.getPassword(), dlg.getEmail(), dlg.getGender(), dlg.getCountry(), dlg.getRealName()) } }

void actSettings()

void MainWindow::actSettings() { DlgSettings dlg(this) dlg.exec() }

void actExit()

void MainWindow::actExit() { close() }

void actForgotPasswordRequest()

void MainWindow::actForgotPasswordRequest() { DlgForgotPasswordRequest dlg(this) if (dlg.exec()) client->requestForgotPasswordToServer(dlg.getHost(), static_cast(dlg.getPort()), dlg.getPlayerName()) }

void actAbout()

void MainWindow::actAbout() { QMessageBox mb( QMessageBox::NoIcon, tr('About Cockatrice'), QString(' Cockatrice (' + QString::fromStdString(BUILD_ARCHITECTURE) + ')
' + tr('Version') + QString(' %1').arg(VERSION_STRING) + '

' + tr('Cockatrice Webpage') + '
' + '
' + tr('Project Manager:') + '
Zach Halpern

' + ' ' + tr('Past Project Managers:') + '
Gavin Bisesi
Max-Wilhelm Bruker
Marcus Schütz

' + ' ' + tr('Developers:') + '
' + ' ' + tr('Our Developers') + '
' + ' ' + tr('Help Develop!') + '

' + ' ' + tr('Translators:') + '
' + ' ' + tr('Our Translators') + '
' + ' ' + tr('Help Translate!') + '

' + ' ' + tr('Support:') + '
' + ' ' + tr('Report an Issue') + '
' + ' ' + tr('Troubleshooting') + '
' + ' ' + tr('F.A.Q.') + '
'), QMessageBox::Ok, this) mb.setIconPixmap(QPixmap('theme:cockatrice').scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)) mb.setTextInteractionFlags(Qt::TextBrowserInteraction) mb.exec() }

void actTips()

void MainWindow::actTips() { if (tip != nullptr) { delete tip tip = nullptr } tip = new DlgTipOfTheDay(this) if (tip->successfulInit) { tip->show() } }

void actUpdate()

void MainWindow::actUpdate() { DlgUpdate dlg(this) dlg.exec() }

void actViewLog()

void MainWindow::actViewLog() { if (logviewDialog == nullptr) { logviewDialog = new DlgViewLog(this) } logviewDialog->show() logviewDialog->raise() logviewDialog->activateWindow() }

void forgotPasswordSuccess()

void MainWindow::forgotPasswordSuccess() { QMessageBox::information( this, tr('Forgot Password'), tr('Your password has been reset successfully, you can now log in using the new credentials.')) settingsCache->servers().setFPHostName('') settingsCache->servers().setFPPort('') settingsCache->servers().setFPPlayerName('') }

void forgotPasswordError()

void MainWindow::forgotPasswordError() { QMessageBox::warning( this, tr('Forgot Password'), tr('Failed to reset user account password, please contact the server operator to reset your password.')) settingsCache->servers().setFPHostName('') settingsCache->servers().setFPPort('') settingsCache->servers().setFPPlayerName('') }

void promptForgotPasswordReset()

void MainWindow::promptForgotPasswordReset() { QMessageBox::information(this, tr('Forgot Password'), tr('Activation request received, please check your email for an activation token.')) DlgForgotPasswordReset dlg(this) if (dlg.exec()) { client->submitForgotPasswordResetToServer(dlg.getHost(), static_cast(dlg.getPort()), dlg.getPlayerName(), dlg.getToken(), dlg.getPassword()) } }

void iconActivated(QSystemTrayIcon :: ActivationReason理由)

void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason) { if (reason == QSystemTrayIcon::DoubleClick) { if (windowState() != Qt::WindowMinimized && windowState() != Qt::WindowMinimized + Qt::WindowMaximized) showMinimized() else { showNormal() QApplication::setActiveWindow(this) } } }

void promptForgotPasswordChallenge()

void MainWindow::promptForgotPasswordChallenge() { DlgForgotPasswordChallenge dlg(this) if (dlg.exec()) client->submitForgotPasswordChallengeToServer(dlg.getHost(), static_cast(dlg.getPort()), dlg.getPlayerName(), dlg.getEmail()) }

void showWindowIfHidden()

void MainWindow::showWindowIfHidden() { // keep the previous window state setWindowState(windowState() & ~Qt::WindowMinimized) show() }

void cardUpdateError(QProcess :: ProcessError err)

void MainWindow::cardUpdateError(QProcess::ProcessError err) { QString error switch (err) { case QProcess::FailedToStart: error = tr('failed to start.') break case QProcess::Crashed: error = tr('crashed.') break case QProcess::Timedout: error = tr('timed out.') break case QProcess::WriteError: error = tr('write error.') break case QProcess::ReadError: error = tr('read error.') break case QProcess::UnknownError: default: error = tr('unknown error.') break } cardUpdateProcess->deleteLater() cardUpdateProcess = nullptr QMessageBox::warning(this, tr('Error'), tr('The card database updater exited with an error: %1').arg(error)) }

void cardUpdateFinished(int exitCode、QProcess :: ExitStatus exitStatus)

void MainWindow::cardUpdateFinished(int, QProcess::ExitStatus) { cardUpdateProcess->deleteLater() cardUpdateProcess = nullptr QtConcurrent::run(db, &CardDatabase::loadCardDatabases) }

void refreshShortcuts()

void MainWindow::refreshShortcuts() { aConnect->setShortcuts(settingsCache->shortcuts().getShortcut('MainWindow/aConnect')) aDisconnect->setShortcuts(settingsCache->shortcuts().getShortcut('MainWindow/aDisconnect')) aSinglePlayer->setShortcuts(settingsCache->shortcuts().getShortcut('MainWindow/aSinglePlayer')) aWatchReplay->setShortcuts(settingsCache->shortcuts().getShortcut('MainWindow/aWatchReplay')) aDeckEditor->setShortcuts(settingsCache->shortcuts().getShortcut('MainWindow/aDeckEditor')) aFullScreen->setShortcuts(settingsCache->shortcuts().getShortcut('MainWindow/aFullScreen')) aRegister->setShortcuts(settingsCache->shortcuts().getShortcut('MainWindow/aRegister')) aSettings->setShortcuts(settingsCache->shortcuts().getShortcut('MainWindow/aSettings')) aExit->setShortcuts(settingsCache->shortcuts().getShortcut('MainWindow/aExit')) aCheckCardUpdates->setShortcuts(settingsCache->shortcuts().getShortcut('MainWindow/aCheckCardUpdates')) aOpenCustomFolder->setShortcuts(settingsCache->shortcuts().getShortcut('MainWindow/aOpenCustomFolder')) aManageSets->setShortcuts(settingsCache->shortcuts().getShortcut('MainWindow/aManageSets')) aEditTokens->setShortcuts(settingsCache->shortcuts().getShortcut('MainWindow/aEditTokens')) }

void cardDatabaseLoadingFailed()

void MainWindow::cardDatabaseLoadingFailed() { QMessageBox msgBox msgBox.setWindowTitle(tr('Card database')) msgBox.setIcon(QMessageBox::Question) msgBox.setText(tr('Cockatrice is unable to load the card database. ' 'Do you want to update your card database now? ' 'If unsure or first time user, choose 'Yes'')) QPushButton *yesButton = msgBox.addButton(tr('Yes'), QMessageBox::YesRole) msgBox.addButton(tr('No'), QMessageBox::NoRole) QPushButton *settingsButton = msgBox.addButton(tr('Open settings'), QMessageBox::ActionRole) msgBox.setDefaultButton(yesButton) msgBox.exec() if (msgBox.clickedButton() == yesButton) { actCheckCardUpdates() } else if (msgBox.clickedButton() == settingsButton) { actSettings() } }

void cardDatabaseNewSetsFound(int numUnknownSets、QStringList unknownSetsNames)

void MainWindow::cardDatabaseNewSetsFound(int numUnknownSets, QStringList unknownSetsNames) { QMessageBox msgBox msgBox.setWindowTitle(tr('New sets found')) msgBox.setIcon(QMessageBox::Question) msgBox.setText(tr('%n new set(s) found in the card database ' 'Set code(s): %1 ' 'Do you want to enable it/them?', '', numUnknownSets) .arg(unknownSetsNames.join(', '))) QPushButton *yesButton = msgBox.addButton(tr('Yes'), QMessageBox::YesRole) QPushButton *noButton = msgBox.addButton(tr('No'), QMessageBox::NoRole) QPushButton *settingsButton = msgBox.addButton(tr('View sets'), QMessageBox::ActionRole) msgBox.setDefaultButton(yesButton) msgBox.exec() if (msgBox.clickedButton() == yesButton) { db->enableAllUnknownSets() QtConcurrent::run(db, &CardDatabase::loadCardDatabases) } else if (msgBox.clickedButton() == noButton) { db->markAllSetsAsKnown() } else if (msgBox.clickedButton() == settingsButton) { db->markAllSetsAsKnown() actManageSets() } }

void cardDatabaseAllNewSetsEnabled()

void MainWindow::cardDatabaseAllNewSetsEnabled() { QMessageBox::information( this, tr('Welcome'), tr('Hi! It seems like you're running this version of Cockatrice for the first time. All the sets in the card ' 'database have been enabled. Read more about changing the set order or disabling specific sets and ' 'consequent effects in the 'Manage Sets' dialog.')) actManageSets() }

void actOpenCustomFolder()

void MainWindow::actOpenCustomFolder() { QString dir = settingsCache->getCustomPicsPath() #if defined(Q_OS_MAC) QStringList scriptArgs scriptArgs << QLatin1String('-e') scriptArgs << QString::fromLatin1(R'(tell application 'Finder' to open POSIX file '%1')').arg(dir) scriptArgs << QLatin1String('-e') scriptArgs << QLatin1String('tell application 'Finder' to activate') QProcess::execute('/usr/bin/osascript', scriptArgs) #elif defined(Q_OS_WIN) QStringList args args << QDir::toNativeSeparators(dir) QProcess::startDetached('explorer', args) #endif }

void actOpenCustomsetsFolder()

void MainWindow::actOpenCustomsetsFolder() { QString dir = settingsCache->getCustomCardDatabasePath() #if defined(Q_OS_MAC) QStringList scriptArgs scriptArgs << QLatin1String('-e') scriptArgs << QString::fromLatin1(R'(tell application 'Finder' to open POSIX file '%1')').arg(dir) scriptArgs << QLatin1String('-e') scriptArgs << QLatin1String('tell application 'Finder' to activate') QProcess::execute('/usr/bin/osascript', scriptArgs) #elif defined(Q_OS_WIN) QStringList args args << QDir::toNativeSeparators(dir) QProcess::startDetached('explorer', args) #endif }

void actAddCustomSet()

void MainWindow::actAddCustomSet() { QFileDialog dialog(this, tr('Load sets/cards'), QDir::homePath()) dialog.setNameFilters(MainWindow::fileNameFilters) if (!dialog.exec()) { return } QString fullFilePath = dialog.selectedFiles().at(0) if (!QFile::exists(fullFilePath)) { QMessageBox::warning(this, tr('Load sets/cards'), tr('Selected file cannot be found.')) return } if (QFileInfo(fullFilePath).suffix() != 'xml') // fileName = *.xml { QMessageBox::warning(this, tr('Load sets/cards'), tr('You can only import XML databases at this time.')) return } QDir dir = settingsCache->getCustomCardDatabasePath() int nextPrefix = getNextCustomSetPrefix(dir) bool res QString fileName = QFileInfo(fullFilePath).fileName() if (fileName.compare('spoiler.xml', Qt::CaseInsensitive) == 0) { /* * If the file being added is 'spoiler.xml' * then we'll want to overwrite the old version * and replace it with the new one */ if (QFile::exists(dir.absolutePath() + '/spoiler.xml')) { QFile::remove(dir.absolutePath() + '/spoiler.xml') } res = QFile::copy(fullFilePath, dir.absolutePath() + '/spoiler.xml') } else { res = QFile::copy(fullFilePath, dir.absolutePath() + '/' + (nextPrefix > 9 ? '' : '0') + QString::number(nextPrefix) + '.' + fileName) } if (res) { QMessageBox::information( this, tr('Load sets/cards'), tr('The new sets/cards have been added successfully. Cockatrice will now reload the card database.')) QtConcurrent::run(db, &CardDatabase::loadCardDatabases) } else { QMessageBox::warning(this, tr('Load sets/cards'), tr('Sets/cards failed to import.')) } }

void actManageSets()

void MainWindow::actManageSets() { wndSets = new WndSets(this) wndSets->show() }

void actEditTokens()

void MainWindow::actEditTokens() { DlgEditTokens dlg(this) dlg.exec() db->saveCustomTokensToFile() }

void startupConfigCheck()

void MainWindow::startupConfigCheck() { if (settingsCache->getClientVersion() == CLIENT_INFO_NOT_SET) { // no config found, 99% new clean install qDebug() getClientVersion() != VERSION_STRING) { // config found, from another (presumably older) version qDebug() << 'Startup: old client version' setClientVersion(VERSION_STRING) } else { // previous config from this version found qDebug() getShowTipsOnStartup() && tip->newTipsAvailable) { tip->raise() tip->show() } } }

void alertForcedOracleRun(const QString&version、bool isUpdate)

void MainWindow::alertForcedOracleRun(const QString &version, bool isUpdate) { if (isUpdate) { QMessageBox::information(this, tr('New Version'), tr('Congratulations on updating to Cockatrice %1! ' 'Oracle will now launch to update your card database.') .arg(version)) } else { QMessageBox::information(this, tr('Cockatrice installed'), tr('Congratulations on installing Cockatrice %1! ' 'Oracle will now launch to install the initial card database.') .arg(version)) } actCheckCardUpdates() actCheckServerUpdates() }

民間:

static const QString appName

static const QStringList fileNameFilters

QList tabMenus

QMenu * cockatriceMenu

QMenu * dbMenu

QMenu * helpMenu

QMenu * trailIconMenu

QAction * aConnect

QAction * aDisconnect

QAction * aSinglePlayer

QAction * aWatchReplay

QAction * aDeckEditor

QAction * aFullScreen

QAction * aSettings

QAction * aExit

QAction * aAbout

QAction * aTips

QAction * aCheckCardUpdates

QAction * aRegister

QAction * aUpdate

QAction * aViewLog

QAction * closeAction

QAction * aManageSets

QAction * aEditTokens

QAction * aOpenCustomFolder

QAction * aOpenCustomsetsFolder

QAction * aAddCustomSet

TabSupervisor * tabSupervisor

WndSets * wndSets

RemoteClient * client

QThread * clientThread

LocalServer * localServer

bool bHasActivated

QMessageBox serverShutdownMessageBox

QProcess * cardUpdateProcess

DlgViewLog * logviewDialog

DlgConnect * dlgConnect

GameReplay *リプレイ

DlgTipOfTheDay *ヒント

QUrl connectTo