mainwindow.cpp 36.4 KB
Newer Older
1
/*
2
3
4
 * Copyright (C) 1995 Paul Olav Tvete <paul@troll.no>
 * Copyright (C) 1997 Mario Weilguni <mweilguni@sime.com>
 * Copyright (C) 2000-2009 Stephan Kulow <coolo@kde.org>
Parker Coates's avatar
Parker Coates committed
5
 * Copyright (C) 2009-2010 Parker Coates <coates@kde.org>
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 *
 * License of original code:
 * -------------------------------------------------------------------------
 *   Permission to use, copy, modify, and distribute this software and its
 *   documentation for any purpose and without fee is hereby granted,
 *   provided that the above copyright notice appear in all copies and that
 *   both that copyright notice and this permission notice appear in
 *   supporting documentation.
 *
 *   This file is provided AS IS with no warranties of any kind.  The author
 *   shall have no liability with respect to the infringement of copyrights,
 *   trade secrets or any patents by this file or any part thereof.  In no
 *   event will the author be liable for any lost revenue or profits or
 *   other special, indirect and consequential damages.
 * -------------------------------------------------------------------------
 *
 * License of modifications/additions made after 2009-01-01:
 * -------------------------------------------------------------------------
 *   This program is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU General Public License as
26
 *   published by the Free Software Foundation; either version 2 of
27
28
29
30
31
32
33
34
35
36
37
 *   the License, or (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * -------------------------------------------------------------------------
 */
Michael Koch's avatar
Michael Koch committed
38

Parker Coates's avatar
Parker Coates committed
39
#include "mainwindow.h"
40
41

#include "dealer.h"
42
#include "dealerinfo.h"
43
#include "gameselectionscene.h"
44
#include "kpat_debug.h"
45
#include "numbereddealdialog.h"
Parker Coates's avatar
Parker Coates committed
46
#include "renderer.h"
47
#include "settings.h"
48
#include "soundengine.h"
49
#include "statisticsdialog.h"
50
51
#include "view.h"

52
53
#include "KCardTheme"
#include "KCardThemeWidget"
54

Stefan Majewsky's avatar
Stefan Majewsky committed
55
#include <KgThemeSelector>
56
#include <KStandardGameAction>
57
#include <KStandardAction>
Matt Williams's avatar
Matt Williams committed
58

Laurent Montel's avatar
Port++    
Laurent Montel committed
59
#include <QAction>
60
#include <KActionCollection>
61
#include <KConfigDialog>
Laurent Montel's avatar
Laurent Montel committed
62
#include <QFileDialog>
Laurent Montel's avatar
Laurent Montel committed
63
#include <QIcon>
Laurent Montel's avatar
Laurent Montel committed
64
#include <KLocalizedString>
65
#include <KMessageBox>
Nicolas Fella's avatar
Nicolas Fella committed
66
#include <QRandomGenerator>
Laurent Montel's avatar
Laurent Montel committed
67
68
#include <QStatusBar>
#include <QMenuBar>
Laurent Montel's avatar
Laurent Montel committed
69
#include <QTemporaryFile>
70
#include <KToggleAction>
71
#include <KIOCore/KIO/StoredTransferJob>
Laurent Montel's avatar
Laurent Montel committed
72
73
#include <KXMLGUIFactory>

74
#include <QScreen>
75
76
77
#include <QList>
#include <QPointer>
#include <QTimer>
78
#include <QBuffer>
79
#include <QXmlStreamReader>
Laurent Montel's avatar
Laurent Montel committed
80
81
#include <QDesktopWidget>
#include <QKeySequence>
Laurent Montel's avatar
Laurent Montel committed
82
#include <KHelpClient>
Laurent Montel's avatar
Laurent Montel committed
83
#include <QStandardPaths>
84
#include <QApplication>
Laurent Montel's avatar
Laurent Montel committed
85
#include <KSharedConfig>
Inge Wallin's avatar
Inge Wallin committed
86
87


88
89
namespace
{
90
91
92
    const QUrl dialogUrl( QStringLiteral("kfiledialog:///kpat") );
    const QString saveFileMimeType( QStringLiteral("application/vnd.kde.kpatience.savedgame") );
    const QString legacySaveFileMimeType( QStringLiteral("application/vnd.kde.kpatience.savedstate") );
93
94
95
}


Parker Coates's avatar
Parker Coates committed
96
MainWindow::MainWindow()
Fabian Kosmale's avatar
Fabian Kosmale committed
97
98
99
100
101
102
103
  : KXmlGuiWindow( nullptr ),
    m_view( nullptr ),
    m_dealer( nullptr ),
    m_selector( nullptr ),
    m_cardDeck( nullptr ),
    m_soundEngine( nullptr ),
    m_dealDialog( nullptr )
104
{
105
    setObjectName( QStringLiteral( "MainWindow" ) );
106
    // KCrash::setEmergencySaveFunction(::saveGame);
107

108
109
110
    setupActions();

    foreach( const DealerInfo * di, DealerInfoList::self()->games() )
111
112
113
    {
        m_dealer_map.insert( di->baseId(), di );
        foreach( int id, di->subtypeIds() )
114
            m_dealer_map.insert( id, di );
115
    }
116
117
118
119
120
    m_dealer_it = m_dealer_map.constEnd();

    m_view = new PatienceView( this );
    setCentralWidget( m_view );

121
122
    const QRect screenSize = QApplication::desktop()->screenGeometry(this);
    QSize defaultSize = screenSize.size() * 0.7;
123
124
    setupGUI(defaultSize, Create | Save | ToolBar | StatusBar | Keys);

125
126
127
    m_solverStatusLabel = new QLabel(QString(), statusBar());
    m_solverStatusLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
    statusBar()->addWidget( m_solverStatusLabel, 1);
128

129
130
131
    m_moveCountStatusLabel = new QLabel(QString(), statusBar());
    m_moveCountStatusLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
    statusBar()->addWidget( m_moveCountStatusLabel, 0);
132
133

    m_showMenubarAction->setChecked(!menuBar()->isHidden());
134
135
136
137
}

MainWindow::~MainWindow()
{
Laurent Montel's avatar
Laurent Montel committed
138
    m_recentFilesAction->saveEntries(KSharedConfig::openConfig()->group( QString() ));
139

Laurent Montel's avatar
Laurent Montel committed
140
    Settings::self()->save();
141

142
143
    delete m_dealer;
    delete m_view;
144
    Renderer::deleteSelf();
145
146
147
148
149
}


void MainWindow::setupActions()
{
Laurent Montel's avatar
Port++    
Laurent Montel committed
150
    QAction *a;
151
152

    // Game Menu
153
    a = actionCollection()->addAction( QStringLiteral( "new_game" ));
154
    a->setText(i18nc("Start a new game of a different type","New &Game..."));
155
    a->setIcon( QIcon::fromTheme( QStringLiteral( "document-new" )) );
Laurent Montel's avatar
Laurent Montel committed
156
    actionCollection()->setDefaultShortcut(a, Qt::CTRL + Qt::SHIFT + Qt::Key_N);
Laurent Montel's avatar
Laurent Montel committed
157
    connect(a, &QAction::triggered, this, &MainWindow::slotShowGameSelectionScreen);
158

159
    a = actionCollection()->addAction( QStringLiteral( "new_deal" ));
160
    a->setText(i18nc("Start a new game of without changing the game type", "New &Deal"));
161
    a->setIcon( QIcon::fromTheme( QStringLiteral( "document-new" )) );
Laurent Montel's avatar
Laurent Montel committed
162
    actionCollection()->setDefaultShortcut(a, Qt::CTRL + Qt::Key_N);
Laurent Montel's avatar
Laurent Montel committed
163
    connect(a, &QAction::triggered, this, &MainWindow::newGame);
164

165
    a = actionCollection()->addAction( QStringLiteral( "new_numbered_deal" ));
166
    a->setText(i18nc("Start a game by giving its particular number", "New &Numbered Deal..."));
Laurent Montel's avatar
Laurent Montel committed
167
    actionCollection()->setDefaultShortcut(a, Qt::CTRL + Qt::Key_D);
Laurent Montel's avatar
Laurent Montel committed
168
    connect(a, &QAction::triggered, this, &MainWindow::newNumberedDeal);
169
170
171

    a = KStandardGameAction::restart(this, SLOT(restart()), actionCollection());
    a->setText(i18nc("Replay the current deal from the start", "Restart Deal"));
172

173
174
175
    // Note that this action is not shown in the menu or toolbar. It is
    // only provided for advanced users who can use it by shorcut or add it to
    // the toolbar if they wish.
176
    a = actionCollection()->addAction( QStringLiteral( "next_deal" ));
177
    a->setText(i18nc("Start the game with the number one greater than the current one", "Next Deal"));
178
    a->setIcon( QIcon::fromTheme( QStringLiteral( "go-next" )) );
Laurent Montel's avatar
Laurent Montel committed
179
    actionCollection()->setDefaultShortcut(a, Qt::CTRL + Qt::Key_Plus);
Laurent Montel's avatar
Laurent Montel committed
180
    connect(a, &QAction::triggered, this, &MainWindow::nextDeal);
181
182
183
184

    // Note that this action is not shown in the menu or toolbar. It is
    // only provided for advanced users who can use it by shorcut or add it to
    // the toolbar if they wish.
185
    a = actionCollection()->addAction( QStringLiteral( "previous_deal" ));
186
    a->setText(i18nc("Start the game with the number one less than the current one", "Previous Deal"));
187
    a->setIcon( QIcon::fromTheme( QStringLiteral( "go-previous" )) );
Laurent Montel's avatar
Laurent Montel committed
188
    actionCollection()->setDefaultShortcut(a, Qt::CTRL + Qt::Key_Minus);
Laurent Montel's avatar
Laurent Montel committed
189
    connect(a, &QAction::triggered, this, &MainWindow::previousDeal);
190

191
    KStandardGameAction::load( this, SLOT(loadGame()), actionCollection() );
192

Laurent Montel's avatar
Laurent Montel committed
193
    m_recentFilesAction = KStandardGameAction::loadRecent( this, SLOT(loadGame(QUrl)), actionCollection() );
Laurent Montel's avatar
Laurent Montel committed
194
    m_recentFilesAction->loadEntries(KSharedConfig::openConfig()->group( QString() ));
195

196
    m_saveAction = KStandardGameAction::saveAs(this, SLOT(saveGame()), actionCollection());
Laurent Montel's avatar
Laurent Montel committed
197
    actionCollection()->setDefaultShortcut(m_saveAction, Qt::CTRL + Qt::Key_S);
Luciano Montanaro's avatar
Luciano Montanaro committed
198

199
    a = actionCollection()->addAction( QStringLiteral( "game_stats" ));
200
    a->setText(i18n("Statistics"));
201
    a->setIcon( QIcon::fromTheme( QStringLiteral( "games-highscores" )) );
Laurent Montel's avatar
Laurent Montel committed
202
    connect(a, &QAction::triggered, this, &MainWindow::showStats);
203

204
205
206
207
    KStandardGameAction::quit(this, SLOT(close()), actionCollection());


    // Move Menu
208
    m_undoAction = KStandardGameAction::undo(this, SLOT(undoMove()), actionCollection());
209

210
    m_redoAction = KStandardGameAction::redo(this, SLOT(redoMove()), actionCollection());
211

212
    m_demoAction = KStandardGameAction::demo( this, SLOT(toggleDemo()), actionCollection() );
213

214
215
216
    // KStandardGameAction::hint is a regular action, but we want a toggle
    // action, so we must create a new action and copy all the standard
    // properties over one by one.
217
    m_hintAction = new KToggleAction( actionCollection() );
Fabian Kosmale's avatar
Fabian Kosmale committed
218
    a = KStandardGameAction::hint( nullptr, nullptr, nullptr );
219
220
    m_hintAction->setText( a->text() );
    m_hintAction->setIcon( a->icon() );
221
    actionCollection()->setDefaultShortcut( m_hintAction, a->shortcut() );
222
223
    m_hintAction->setToolTip( a->toolTip() );
    m_hintAction->setWhatsThis( a->whatsThis() );
224
225
    delete a;
    QString actionName( KStandardGameAction::name( KStandardGameAction::Hint ) );
226
    actionCollection()->addAction( actionName, m_hintAction );
Laurent Montel's avatar
Laurent Montel committed
227
    connect(m_hintAction, &QAction::triggered, this, &MainWindow::toggleHints);
228

229
    m_drawAction = actionCollection()->addAction( QStringLiteral( "move_draw" ));
230
    m_drawAction->setText( i18nc("Take one or more cards from the deck, flip them, and place them in play", "Dra&w") );
231
    m_drawAction->setIcon( QIcon::fromTheme( QStringLiteral( "kpat" )) );
Laurent Montel's avatar
Laurent Montel committed
232
    actionCollection()->setDefaultShortcut(m_drawAction, Qt::Key_Tab );
233

234
    m_dealAction = actionCollection()->addAction( QStringLiteral( "move_deal" ));
235
    m_dealAction->setText( i18nc("Deal a new row of cards from the deck", "Dea&l Row") );
236
    m_dealAction->setIcon( QIcon::fromTheme( QStringLiteral( "kpat" )) );
Laurent Montel's avatar
Laurent Montel committed
237
    actionCollection()->setDefaultShortcut(m_dealAction, Qt::Key_Return );
238

239
    m_redealAction = actionCollection()->addAction( QStringLiteral( "move_redeal" ));
240
    m_redealAction->setText( i18nc("Collect the cards in play, shuffle them and redeal them", "&Redeal") );
241
    m_redealAction->setIcon( QIcon::fromTheme( QStringLiteral( "roll" )) );
Laurent Montel's avatar
Laurent Montel committed
242
    actionCollection()->setDefaultShortcut(m_redealAction, Qt::Key_R );
243

244
245
    m_dropAction = new KToggleAction( actionCollection() );
    m_dropAction->setText( i18nc("Automatically move cards to the foundation piles", "Dro&p") );
246
    m_dropAction->setIcon( QIcon::fromTheme( QStringLiteral( "games-endturn" )) );
Laurent Montel's avatar
Laurent Montel committed
247
    actionCollection()->setDefaultShortcut(m_dropAction, Qt::Key_P );
248
    actionCollection()->addAction( QStringLiteral(  "move_drop" ), m_dropAction );
Laurent Montel's avatar
Laurent Montel committed
249
    connect(m_dropAction, &QAction::triggered, this, &MainWindow::toggleDrop);
250

251
252

    // Settings Menu
253
    a = actionCollection()->addAction( QStringLiteral( "select_deck" ));
Parker Coates's avatar
Parker Coates committed
254
    a->setText(i18n("Change Appearance..."));
Laurent Montel's avatar
Laurent Montel committed
255
    connect(a, &QAction::triggered, this, &MainWindow::configureAppearance);
Laurent Montel's avatar
Laurent Montel committed
256
    actionCollection()->setDefaultShortcut(a, Qt::Key_F10 );
257

258
    m_autoDropEnabledAction = new KToggleAction(i18n("&Enable Autodrop"), this);
259
    actionCollection()->addAction( QStringLiteral( "enable_autodrop" ), m_autoDropEnabledAction );
Laurent Montel's avatar
Laurent Montel committed
260
    connect(m_autoDropEnabledAction, &KToggleAction::triggered, this, &MainWindow::setAutoDropEnabled);
261
    m_autoDropEnabledAction->setChecked( Settings::autoDropEnabled() );
Stephan Kulow's avatar
Stephan Kulow committed
262

263
    m_solverEnabledAction = new KToggleAction(i18n("E&nable Solver"), this);
264
    actionCollection()->addAction( QStringLiteral( "enable_solver" ), m_solverEnabledAction );
Laurent Montel's avatar
Laurent Montel committed
265
    connect(m_solverEnabledAction, &KToggleAction::triggered, this, &MainWindow::enableSolver);
266
    m_solverEnabledAction->setChecked( Settings::solverEnabled() );
267

268
269
    m_playSoundsAction = new KToggleAction( QIcon::fromTheme( QStringLiteral( "preferences-desktop-sound") ), i18n("Play &Sounds" ), this );
    actionCollection()->addAction( QStringLiteral( "play_sounds" ), m_playSoundsAction );
Laurent Montel's avatar
Laurent Montel committed
270
    connect(m_playSoundsAction, &KToggleAction::triggered, this, &MainWindow::enableSounds);
271
272
    m_playSoundsAction->setChecked( Settings::playSounds() );

273
    m_rememberStateAction = new KToggleAction(i18n("&Remember State on Exit"), this);
274
    actionCollection()->addAction( QStringLiteral( "remember_state" ), m_rememberStateAction );
Laurent Montel's avatar
Laurent Montel committed
275
    connect(m_rememberStateAction, &KToggleAction::triggered, this, &MainWindow::enableRememberState);
276
    m_rememberStateAction->setChecked( Settings::rememberStateOnExit() );
Stephan Kulow's avatar
Stephan Kulow committed
277
278


279
    // Help Menu
280
281
    m_gameHelpAction = actionCollection()->addAction( QStringLiteral( "help_game" ));
    m_gameHelpAction->setIcon( QIcon::fromTheme( QStringLiteral( "help-browser" )) );
Laurent Montel's avatar
Laurent Montel committed
282
    connect(m_gameHelpAction, &QAction::triggered, this, &MainWindow::helpGame);
Laurent Montel's avatar
Laurent Montel committed
283
    actionCollection()->setDefaultShortcut(m_gameHelpAction, Qt::CTRL + Qt::SHIFT + Qt::Key_F1 );
284

285

286
    // Hidden actions
287
    if (!qEnvironmentVariableIsEmpty("KDE_DEBUG")) // developer shortcut
288
    {
289
        a = actionCollection()->addAction( QStringLiteral( "themePreview" ));
290
        a->setText(i18n("Generate a theme preview image"));
Laurent Montel's avatar
Laurent Montel committed
291
        connect(a, &QAction::triggered, this, &MainWindow::generateThemePreview);
Laurent Montel's avatar
Laurent Montel committed
292
        actionCollection()->setDefaultShortcut(a, Qt::Key_F7 );
293

294
        a = actionCollection()->addAction( QStringLiteral( "snapshot" ));
295
        a->setText(i18n("Take Game Preview Snapshots"));
Laurent Montel's avatar
Laurent Montel committed
296
        connect(a, &QAction::triggered, this, &MainWindow::slotSnapshot);
Laurent Montel's avatar
Laurent Montel committed
297
        actionCollection()->setDefaultShortcut(a, Qt::Key_F8);
298

299
        a = actionCollection()->addAction( QStringLiteral( "random_set" ));
300
        a->setText(i18n("Random Cards"));
Laurent Montel's avatar
Laurent Montel committed
301
        connect(a, &QAction::triggered, this, &MainWindow::slotPickRandom);
Laurent Montel's avatar
Laurent Montel committed
302
        actionCollection()->setDefaultShortcut(a, Qt::Key_F9);
303
    }
304
305

    // Keyboard navigation actions
306
    m_leftAction = actionCollection()->addAction( QStringLiteral( "focus_left" ));
307
    m_leftAction->setText(i18n("Move Focus to Previous Pile"));
Laurent Montel's avatar
Laurent Montel committed
308
    actionCollection()->setDefaultShortcut(m_leftAction, Qt::Key_Left );
309

310
    m_rightAction = actionCollection()->addAction( QStringLiteral( "focus_right" ));
311
    m_rightAction->setText(i18n("Move Focus to Next Pile"));
Laurent Montel's avatar
Laurent Montel committed
312
    actionCollection()->setDefaultShortcut(m_rightAction, Qt::Key_Right );
313

314
    m_upAction = actionCollection()->addAction( QStringLiteral( "focus_up" ));
315
    m_upAction->setText(i18n("Move Focus to Card Below"));
Laurent Montel's avatar
Laurent Montel committed
316
    actionCollection()->setDefaultShortcut(m_upAction, Qt::Key_Up );
317

318
    m_downAction = actionCollection()->addAction( QStringLiteral( "focus_down" ));
319
    m_downAction->setText(i18n("Move Focus to Card Above"));
Laurent Montel's avatar
Laurent Montel committed
320
    actionCollection()->setDefaultShortcut(m_downAction, Qt::Key_Down );
321

322
    m_cancelAction = actionCollection()->addAction( QStringLiteral( "focus_cancel" ));
323
    m_cancelAction->setText(i18n("Cancel Focus"));
Laurent Montel's avatar
Laurent Montel committed
324
    actionCollection()->setDefaultShortcut(m_cancelAction, Qt::Key_Escape );
325

326
    m_pickUpSetDownAction = actionCollection()->addAction( QStringLiteral( "focus_activate" ));
327
    m_pickUpSetDownAction->setText(i18n("Pick Up or Set Down Focus"));
Laurent Montel's avatar
Laurent Montel committed
328
    actionCollection()->setDefaultShortcut(m_pickUpSetDownAction, Qt::Key_Space );
329

330
331
332
    // showMenubar isn't a part of KStandardGameAction
    m_showMenubarAction = KStandardAction::showMenubar(this, SLOT(toggleMenubar()), actionCollection());
}
Stephan Kulow's avatar
Stephan Kulow committed
333

Parker Coates's avatar
Parker Coates committed
334
void MainWindow::undoMove() {
335
336
    if( m_dealer )
        m_dealer->undo();
Stephan Kulow's avatar
Stephan Kulow committed
337
}
338

Parker Coates's avatar
Parker Coates committed
339
void MainWindow::redoMove() {
340
341
    if( m_dealer )
        m_dealer->redo();
Stephan Kulow's avatar
Stephan Kulow committed
342
343
}

Parker Coates's avatar
Parker Coates committed
344
void MainWindow::helpGame()
345
{
346
    if (m_dealer && m_dealer_map.contains(m_dealer->gameId()))
347
    {
348
        const DealerInfo * di = m_dealer_map.value(m_dealer->gameId());
349
350
        QString anchor = QString::fromUtf8( di->untranslatedBaseName() );
        anchor = anchor.toLower();
351
        anchor = anchor.remove('\'').replace('&', QLatin1String("and")).replace(' ', '-');
352
        KHelpClient::invokeHelp(QLatin1String("rules-specific.html#") + anchor);
353
    }
354
355
}

356
357

void MainWindow::setAutoDropEnabled( bool enabled )
358
{
359
360
361
362
363
364
365
366
367
    Settings::setAutoDropEnabled( enabled );
    if ( m_dealer )
    {
        m_dealer->setAutoDropEnabled( enabled );
        if ( enabled )
            m_dealer->startDrop();
        else
            m_dealer->stopDrop();
    }
368
    updateGameActionList();
369
370
}

371

Parker Coates's avatar
Parker Coates committed
372
void MainWindow::enableSolver(bool enable)
Stephan Kulow's avatar
Stephan Kulow committed
373
{
374
    Settings::setSolverEnabled( enable );
375
    m_solverStatusLabel->setText( QString() );
376
    if (m_dealer)
377
    {
378
        m_dealer->setSolverEnabled(enable);
379
380
381
        if(enable)
            m_dealer->startSolver();
    }
Stephan Kulow's avatar
Stephan Kulow committed
382
383
}

384
385
386
387
388
389
390
391

void MainWindow::enableSounds( bool enable )
{
    Settings::setPlaySounds( enable );
    updateSoundEngine();
}


Parker Coates's avatar
Parker Coates committed
392
void MainWindow::enableRememberState(bool enable)
393
{
394
    Settings::setRememberStateOnExit( enable );
395
396
}

Parker Coates's avatar
Parker Coates committed
397
void MainWindow::newGame()
Inge Wallin's avatar
Inge Wallin committed
398
{
399
    if (m_dealer && m_dealer->allowedToStartNewGame())
400
        startRandom();
Stephan Kulow's avatar
Stephan Kulow committed
401
402
}

Parker Coates's avatar
Parker Coates committed
403
void MainWindow::restart()
404
{
405
406
407
    startNew(-1);
}

Parker Coates's avatar
Parker Coates committed
408
void MainWindow::startRandom()
409
{
410
411
412
    const auto seed = QRandomGenerator::global()->generate();
    const int signed_seed = (int)(seed & (~(((quint32)1) << 31)));
    startNew(signed_seed);
413
414
}

Parker Coates's avatar
Parker Coates committed
415
void MainWindow::startNew(int gameNumber)
Inge Wallin's avatar
Inge Wallin committed
416
{
417
    m_dealer->startNew(gameNumber);
418
    setGameCaption();
419
}
Michael Koch's avatar
Michael Koch committed
420

Parker Coates's avatar
Parker Coates committed
421
void MainWindow::slotPickRandom()
422
{
423
    QList<KCardTheme> themes = KCardTheme::findAll();
424
    KCardTheme theme = themes.at( QRandomGenerator::global()->bounded( themes.size() ) );
425
    Settings::setCardTheme( theme.dirName() );
426

427
    appearanceChanged();
428
429
}

Parker Coates's avatar
Parker Coates committed
430
void MainWindow::configureAppearance()
Luciano Montanaro's avatar
Luciano Montanaro committed
431
{
432
433
    const QString previewFormat = QStringLiteral("back;10_spade,jack_diamond,queen_club,king_heart;1_spade");
    const QSet<QString> features = QSet<QString>() << QStringLiteral("AngloAmerican") << QStringLiteral("Backs1");
434

435
    if ( !KConfigDialog::showDialog(QStringLiteral("KPatAppearanceDialog")) )
436
    {
437
        KConfigDialog * dialog = new KConfigDialog( this, QStringLiteral("KPatAppearanceDialog"), Settings::self() );
Parker Coates's avatar
Parker Coates committed
438
439
440

        dialog->addPage( new KCardThemeWidget( features, previewFormat ),
                         i18n("Card Deck"),
441
                         QStringLiteral("games-config-theme"),
Parker Coates's avatar
Parker Coates committed
442
443
444
                         i18n("Select a card deck")
                       );

Stefan Majewsky's avatar
Stefan Majewsky committed
445
446
        KgThemeProvider* provider = Renderer::self()->themeProvider();
        dialog->addPage( new KgThemeSelector(provider),
Parker Coates's avatar
Parker Coates committed
447
                         i18n("Game Theme"),
448
                         QStringLiteral("games-config-theme"),
Parker Coates's avatar
Parker Coates committed
449
450
451
                         i18n("Select a theme for non-card game elements")
                       );

Laurent Montel's avatar
Laurent Montel committed
452
453
        connect(provider, &KgThemeProvider::currentThemeChanged, this, &MainWindow::appearanceChanged);
        connect(dialog, &KConfigDialog::settingsChanged, this, &MainWindow::appearanceChanged);
454
455
456
        dialog->show();
    }
}
457

458
459
460

void MainWindow::appearanceChanged()
{
461
    if ( m_cardDeck && Settings::cardTheme() != m_cardDeck->theme().dirName() )
462
    {
463
464
        KCardTheme theme( Settings::cardTheme() );
        if ( theme.isValid() )
465
        {
466
            m_cardDeck->setTheme( KCardTheme( theme ) );
467
468
            if ( m_dealer )
                m_dealer->relayoutScene();
469
        }
Luciano Montanaro's avatar
Luciano Montanaro committed
470
471
472
    }
}

473

Parker Coates's avatar
Parker Coates committed
474
void MainWindow::setGameCaption()
475
{
476
    QString caption;
477
    if ( m_dealer )
478
    {
479
        const DealerInfo * di = m_dealer_map.value( m_dealer->gameId() );
480
        caption = QStringLiteral("%1 - %2").arg( di->baseName() ).arg(m_dealer->gameNumber());
481
    }
482
    setCaption( caption );
Stephan Kulow's avatar
Stephan Kulow committed
483
484
}

Parker Coates's avatar
Parker Coates committed
485
void MainWindow::slotGameSelected(int id)
486
{
487
488
    if ( m_dealer_map.contains(id) )
    {
489
        setGameType( id );
490
        QTimer::singleShot(0 , this, &MainWindow::startRandom );
491
    }
492
493
}

494
void MainWindow::setGameType(int id)
495
{
496
497
498
499
500
501
502
503
504
    // Only bother calling creating a new DealerScene if we don't already have
    // the right DealerScene open.
    if ( m_dealer && m_dealer_map.value( id ) == m_dealer_map.value( m_dealer->gameId() ) )
    {
        m_dealer->recordGameStatistics();
        m_dealer->mapOldId( id );
        return;
    }

505
    // If we're replacing an existing DealerScene, record the stats of the
506
    // game already in progress.
507
    if ( m_dealer )
508
    {
509
        m_dealer->recordGameStatistics();
510
        delete m_dealer;
Fabian Kosmale's avatar
Fabian Kosmale committed
511
512
        m_view->setScene(nullptr);
        m_dealer = nullptr;
513
    }
514

515
516
517
518
519
520
    if ( !m_cardDeck )
    {
        KCardTheme theme = KCardTheme( Settings::cardTheme() );
        if ( !theme.isValid() )
            theme = KCardTheme( Settings::defaultCardThemeValue() );

521
        m_cardDeck = new KCardDeck( theme, this );
522
523
    }

524
525
    const DealerInfo * di = m_dealer_map.value(id, DealerInfoList::self()->games().first());
    m_dealer = di->createGame();
526
527
    m_dealer->setDeck( m_cardDeck );
    m_dealer->initialize();
528
    m_dealer->mapOldId( id );
529
530
    m_dealer->setSolverEnabled( m_solverEnabledAction->isChecked() );
    m_dealer->setAutoDropEnabled( m_autoDropEnabledAction->isChecked() );
531

532
    m_view->setScene( m_dealer );
533

534
    m_gameHelpAction->setText(i18nc("Is disabled and changes to \"Help &with Current Game\" when"
535
                                  " there is no current game.",
Laurent Montel's avatar
Laurent Montel committed
536
                                  "Help &with %1", di->baseName().replace('&', QLatin1String("&&"))));
537

Laurent Montel's avatar
Laurent Montel committed
538
539
    connect(m_dealer, &DealerScene::solverStateChanged, this, &MainWindow::updateSolverDescription);
    connect(m_dealer, &DealerScene::updateMoves, this, &MainWindow::slotUpdateMoves);
540

541
542
543
544
    m_solverStatusLabel->setText(QString());
    m_solverStatusLabel->setVisible(true);
    m_moveCountStatusLabel->setText(QString());
    m_moveCountStatusLabel->setVisible(true);
545

546
    updateActions();
547
    updateSoundEngine();
Stephan Kulow's avatar
Stephan Kulow committed
548
}
549

Parker Coates's avatar
Parker Coates committed
550
void MainWindow::slotShowGameSelectionScreen()
551
{
552
    if (!m_dealer || m_dealer->allowedToStartNewGame())
553
    {
554
555
556
        if (m_dealer)
        {
            m_dealer->recordGameStatistics();
557
            delete m_dealer;
Fabian Kosmale's avatar
Fabian Kosmale committed
558
559
            m_view->setScene(nullptr);
            m_dealer = nullptr;
560
        }
561

562
        if (!m_selector)
563
        {
564
            m_selector = new GameSelectionScene(this);
Laurent Montel's avatar
Laurent Montel committed
565
            connect(m_selector, &GameSelectionScene::gameSelected, this, &MainWindow::slotGameSelected);
566
        }
567
        m_view->setScene(m_selector);
568

569
        m_gameHelpAction->setText(i18nc("Shown when there is no game open. Is always disabled.",
570
                                      "Help &with Current Game"));
571

572
        updateActions();
573

574
        setGameCaption();
575

576
577
        m_solverStatusLabel->setVisible(false);
        m_moveCountStatusLabel->setVisible(false);
578
    }
579
580
}

Parker Coates's avatar
Parker Coates committed
581
void MainWindow::updateActions()
582
{
583
584
    // Enable/disable application actions that aren't appropriate on game
    // selection screen.
585
586
587
588
    actionCollection()->action( QStringLiteral("new_game") )->setEnabled( m_dealer );
    actionCollection()->action( QStringLiteral("new_deal") )->setEnabled( m_dealer );
    actionCollection()->action( QStringLiteral("game_restart") )->setEnabled( m_dealer );
    actionCollection()->action( QStringLiteral("game_save_as") )->setEnabled( m_dealer );
589
    m_gameHelpAction->setEnabled( m_dealer );
590

591
592
    // Initially disable game actions. They'll be reenabled through signals
    // if/when appropriate.
593
594
595
596
597
598
599
600
    m_undoAction->setEnabled( false );
    m_redoAction->setEnabled( false );
    m_hintAction->setEnabled( false );
    m_demoAction->setEnabled( false );
    m_dropAction->setEnabled( false );
    m_drawAction->setEnabled( false );
    m_dealAction->setEnabled( false );
    m_redealAction->setEnabled( false );
601

Parker Coates's avatar
Parker Coates committed
602
    // If a dealer exists, connect the game actions to it.
603
604
    if ( m_dealer )
    {
Laurent Montel's avatar
Laurent Montel committed
605
606
        connect(m_dealer, &DealerScene::undoPossible, m_undoAction, &QAction::setEnabled);
        connect(m_dealer, &DealerScene::redoPossible, m_redoAction, &QAction::setEnabled);
607

Laurent Montel's avatar
Laurent Montel committed
608
609
        connect(m_dealer, &DealerScene::hintActive, m_hintAction, &QAction::setChecked);
        connect(m_dealer, &DealerScene::gameInProgress, m_hintAction, &QAction::setEnabled);
610

Laurent Montel's avatar
Laurent Montel committed
611
612
        connect(m_dealer, &DealerScene::demoActive, this, &MainWindow::toggleDemoAction);
        connect(m_dealer, &DealerScene::gameInProgress, m_demoAction, &QAction::setEnabled);
613

Laurent Montel's avatar
Laurent Montel committed
614
615
        connect(m_dealer, &DealerScene::dropActive, m_dropAction, &QAction::setChecked);
        connect(m_dealer, &DealerScene::gameInProgress, m_dropAction, &QAction::setEnabled);
616

Laurent Montel's avatar
Laurent Montel committed
617
        connect(m_dealer, &DealerScene::gameInProgress, m_saveAction, &QAction::setEnabled);
618

Laurent Montel's avatar
Laurent Montel committed
619
620
621
622
623
624
        connect(m_leftAction, &QAction::triggered, m_dealer, &DealerScene::keyboardFocusLeft);
        connect(m_rightAction, &QAction::triggered, m_dealer, &DealerScene::keyboardFocusRight);
        connect(m_upAction, &QAction::triggered, m_dealer, &DealerScene::keyboardFocusUp);
        connect(m_downAction, &QAction::triggered, m_dealer, &DealerScene::keyboardFocusDown);
        connect(m_cancelAction, &QAction::triggered, m_dealer, &DealerScene::keyboardFocusCancel);
        connect(m_pickUpSetDownAction, &QAction::triggered, m_dealer, &DealerScene::keyboardFocusSelect);
625

626
627
        if ( m_dealer->actions() & DealerScene::Draw )
        {
Laurent Montel's avatar
Laurent Montel committed
628
629
            connect(m_drawAction, &QAction::triggered, m_dealer, &DealerScene::drawDealRowOrRedeal);
            connect(m_dealer, &DealerScene::newCardsPossible, m_drawAction, &QAction::setEnabled);
630
631
632
        }
        else if ( m_dealer->actions() & DealerScene::Deal )
        {
Laurent Montel's avatar
Laurent Montel committed
633
634
            connect(m_dealAction, &QAction::triggered, m_dealer, &DealerScene::drawDealRowOrRedeal);
            connect(m_dealer, &DealerScene::newCardsPossible, m_dealAction, &QAction::setEnabled);
635
636
637
        }
        else if ( m_dealer->actions() & DealerScene::Redeal )
        {
Laurent Montel's avatar
Laurent Montel committed
638
639
            connect(m_redealAction, &QAction::triggered, m_dealer, &DealerScene::drawDealRowOrRedeal);
            connect(m_dealer, &DealerScene::newCardsPossible, m_redealAction, &QAction::setEnabled);
640
        }
641

642
643
        guiFactory()->unplugActionList( this, QStringLiteral("dealer_options") );
        guiFactory()->plugActionList( this, QStringLiteral("dealer_options"), m_dealer->configActions() );
644
    }
645

646
647
    updateGameActionList();
}
648

Parker Coates's avatar
Parker Coates committed
649
void MainWindow::updateGameActionList()
650
{
651
    guiFactory()->unplugActionList( this, QStringLiteral("game_actions") );
652

653
    m_dropAction->setEnabled( m_dealer && !m_dealer->autoDropEnabled() );
654

655
656
657
658
    if ( m_dealer )
    {
        QList<QAction*> actionList;
        if ( m_dealer->actions() & DealerScene::Hint )
659
            actionList.append( m_hintAction );
660
        if ( m_dealer->actions() & DealerScene::Demo )
661
            actionList.append( m_demoAction );
662
        if ( m_dealer->actions() & DealerScene::Draw )
663
            actionList.append( m_drawAction );
664
        if ( m_dealer->actions() & DealerScene::Deal )
665
            actionList.append( m_dealAction );
666
        if ( m_dealer->actions() & DealerScene::Redeal )
667
            actionList.append( m_redealAction );
668
        if ( !m_dealer->autoDropEnabled() )
669
            actionList.append( m_dropAction );
670
        guiFactory()->plugActionList( this, QStringLiteral("game_actions"), actionList );
671
    }
672
673
}

674

675
676
677
678
679
680
681
682
683
void MainWindow::updateSoundEngine()
{
    if ( m_dealer )
    {
        if ( Settings::playSounds() )
        {
            if ( !m_soundEngine )
                m_soundEngine = new SoundEngine( this );

Laurent Montel's avatar
Laurent Montel committed
684
685
            connect(m_dealer, &DealerScene::cardsPickedUp, m_soundEngine, &SoundEngine::cardsPickedUp);
            connect(m_dealer, &DealerScene::cardsPutDown, m_soundEngine, &SoundEngine::cardsPutDown);
686
        }
687
        else if ( m_soundEngine )
688
        {
Fabian Kosmale's avatar
Fabian Kosmale committed
689
            disconnect( m_dealer, nullptr, m_soundEngine, nullptr );
690
691
692
693
694
        }
    }
}


Parker Coates's avatar
Parker Coates committed
695
696
697
698
699
700
701
702
703
704
705
706
void MainWindow::toggleDrop()
{
    if ( m_dealer )
    {
        if ( !m_dealer->isDropActive() )
            m_dealer->startDrop();
        else
            m_dealer->stopDrop();
    }
}


707
void MainWindow::toggleHints()
708
709
710
{
    if ( m_dealer )
    {
Parker Coates's avatar
Parker Coates committed
711
        if ( !m_dealer->isHintActive() )
712
            m_dealer->startHint();
713
        else
714
            m_dealer->stop();
715
716
717
718
719
720
721
722
723
724
    }
}


void MainWindow::toggleDemo()
{
    if ( m_dealer )
    {
        if ( !m_dealer->isDemoActive() )
            m_dealer->startDemo();
725
        else
726
            m_dealer->stop();
727
728
729
730
    }
}


731
void MainWindow::toggleDemoAction(bool active)
732
{
733
    m_demoAction->setChecked( active );
Laurent Montel's avatar
Laurent Montel committed
734
    m_demoAction->setIcon( QIcon::fromTheme( QLatin1String( active ? "media-playback-pause" : "media-playback-start" ) ) );
735
736
}

737
738
739
740
741
742
743
744
745
746
void MainWindow::toggleMenubar()
{
    if(m_showMenubarAction->isChecked())
        menuBar()->show();
    else if(KMessageBox::warningContinueCancel(this,
            i18n("Are you sure you want to hide the menubar? The current shortcut to show it again is %1.",
                 m_showMenubarAction->shortcut().toString(QKeySequence::NativeText)),
            i18n("Hide Menubar"),
            KStandardGuiItem::cont(),
            KStandardGuiItem::cancel(),
747
            QStringLiteral("MenubarWarning")) == KMessageBox::Continue)
748
749
750
751
752
        menuBar()->hide();
    else
      m_showMenubarAction->setChecked(true);
}

Parker Coates's avatar
Parker Coates committed
753
void MainWindow::saveNewToolbarConfig()
754
755
{
    KXmlGuiWindow::saveNewToolbarConfig();
756
    updateGameActionList();
757
758
}

Parker Coates's avatar
Parker Coates committed
759
void MainWindow::closeEvent(QCloseEvent *e)
760
{
761
    QString stateDirName = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
762
763
764
765
766
767
768
    QString stateFileName = stateDirName + QLatin1Char('/') + saved_state_file ;
    QDir stateFileDir(stateDirName);
    if(!stateFileDir.exists())
    {
        //create the directory if it doesn't exist (bug#350160)
        stateFileDir.mkpath(QStringLiteral("."));
    }
769
770
771
772
    QFile stateFile( stateFileName );

    // Remove the existing state file, if any.
    stateFile.remove();
773

774
    if ( m_dealer )
775
    {