File indexing completed on 2022-08-04 15:10:13
0001 /* 0002 * ksokoban - a Sokoban game by KDE 0003 * Copyright (C) 1998 Anders Widell <awl@hem.passagen.se> 0004 * 0005 * This program is free software; you can redistribute it and/or modify 0006 * it under the terms of the GNU General Public License as published by 0007 * the Free Software Foundation; either version 2 of the License, or 0008 * (at your option) any later version. 0009 * 0010 * This program is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 * GNU General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU General Public License 0016 * along with this program; if not, write to the Free Software 0017 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 0018 */ 0019 0020 #include <stdio.h> 0021 #include <assert.h> 0022 0023 #include <QApplication> 0024 #include <KSharedConfig> 0025 #include <KConfigGroup> 0026 #include <QMenu> 0027 #include <QMenuBar> 0028 #include <QAction> 0029 #include <QKeyEvent> 0030 #include <QSignalMapper> 0031 0032 #include <QString> 0033 #include <KUrlMimeData> 0034 #include <QFrame> 0035 #include <QTemporaryFile> 0036 #include <KMessageBox> 0037 #include <KIO/Job> 0038 #include <KIO/TransferJob> 0039 #include <QDragEnterEvent> 0040 #include <KStandardShortcut> 0041 #include <KLocalizedString> 0042 #include <QFileDialog> 0043 0044 #include "MainWindow.h" 0045 #include "PlayField.h" 0046 #include "LevelCollection.h" 0047 0048 0049 void 0050 MainWindow::createCollectionMenu(QMenu* collection_) { 0051 level_act = new QAction*[internalCollections_.collections()]; 0052 for (int i=0; i<internalCollections_.collections(); i++) { 0053 QAction *qact = new QAction(internalCollections_[i]->name(), this); 0054 level_act[i] = qact; 0055 qact->setCheckable(true); 0056 connect(qact, &QAction::triggered, this, [this,i ]() {changeCollection(i);}); 0057 collection_->addAction(qact); 0058 } 0059 checkedCollection_ = 0; 0060 0061 KSharedConfigPtr cfg=KSharedConfig::openConfig(); 0062 KConfigGroup settingsGroup(cfg, "settings"); 0063 int id = settingsGroup.readEntry("collection", "10").toInt(); 0064 0065 currentCollection_ = 0; 0066 for (int i=0; i<internalCollections_.collections(); i++) { 0067 if (internalCollections_[i]->id() == id) currentCollection_ = i; 0068 } 0069 0070 changeCollection(currentCollection_); 0071 } 0072 0073 0074 MainWindow::MainWindow() : KMainWindow(nullptr), externalCollection_(nullptr) { 0075 int i; 0076 QAction *qact; 0077 0078 //setEraseColor(QColor(0,0,0)); 0079 0080 KSharedConfigPtr cfg=KSharedConfig::openConfig(); 0081 KConfigGroup geometryGroup(cfg, "Geometry"); 0082 int width = geometryGroup.readEntry("width", "750").toInt(); 0083 int height = geometryGroup.readEntry("height", "562").toInt(); 0084 resize(width, height); 0085 0086 playField_ = new PlayField(this); 0087 setCentralWidget(playField_); 0088 //playField_->show(); 0089 0090 menu_ = menuBar();// new KMenuBar(this); 0091 0092 game_ = menu_->addMenu(i18n("&Game")); 0093 0094 qact = new QAction(i18n("&Load Levels..."), this); 0095 connect(qact, &QAction::triggered, this, &MainWindow::loadLevels); 0096 game_->addAction(qact); 0097 0098 qact = new QAction(i18n("&Next Level"), this); 0099 qact->setShortcut(Qt::Key_N); 0100 connect(qact, &QAction::triggered, playField_, &PlayField::nextLevel); 0101 game_->addAction(qact); 0102 0103 qact = new QAction(i18n("&Previous Level"), this); 0104 qact->setShortcut(Qt::Key_P); 0105 connect(qact, &QAction::triggered, playField_, &PlayField::previousLevel); 0106 game_->addAction(qact); 0107 0108 qact = new QAction(i18n("Re&start Level"), this); 0109 qact->setShortcut(Qt::Key_Escape); 0110 connect(qact, &QAction::triggered, playField_, &PlayField::restartLevel); 0111 game_->addAction(qact); 0112 0113 createCollectionMenu(game_->addMenu(i18n("&Level Collection"))); 0114 0115 qact = new QAction(i18n("&Undo"), this); 0116 qact->setShortcut((KStandardShortcut::undo())[0]); 0117 connect(qact, &QAction::triggered, playField_, &PlayField::undo); 0118 game_->addAction(qact); 0119 0120 qact = new QAction(i18n("&Redo"), this); 0121 qact->setShortcut((KStandardShortcut::redo())[0]); 0122 connect(qact, &QAction::triggered, playField_, &PlayField::redo); 0123 game_->addAction(qact); 0124 0125 game_->addSeparator(); 0126 0127 qact = new QAction(i18n("&Quit"), this); 0128 qact->setShortcut((KStandardShortcut::quit())[0]); 0129 connect(qact, SIGNAL(triggered()), qApp, SLOT(closeAllWindows())); 0130 game_->addAction(qact); 0131 0132 animation_ = menu_->addMenu(i18n("&Animation")); 0133 qa_slow = new QAction(i18n("&Slow"), this); 0134 qa_slow->setCheckable(true); 0135 qa_medium = new QAction(i18n("&Medium"), this); 0136 qa_medium->setCheckable(true); 0137 qa_fast = new QAction(i18n("&Fast"), this); 0138 qa_fast->setCheckable(true); 0139 qa_off = new QAction(i18n("&Off"), this); 0140 qa_off->setCheckable(true); 0141 animation_->addAction(qa_slow); 0142 animation_->addAction(qa_medium); 0143 animation_->addAction(qa_fast); 0144 animation_->addAction(qa_off); 0145 connect(qa_slow, &QAction::triggered, this, [this]() {updateAnim(3);}); 0146 connect(qa_medium, &QAction::triggered, this, [this]() {updateAnim(2);}); 0147 connect(qa_fast, &QAction::triggered, this, [this]() {updateAnim(1);}); 0148 connect(qa_off, &QAction::triggered, this, [this]() {updateAnim(0);}); 0149 0150 checkedAnim_ = playField_->animDelay(); 0151 updateAnimMenu(checkedAnim_); 0152 0153 0154 0155 bookmarkMenu_ = menu_->addMenu(i18n("&Bookmarks")); 0156 setBM_ = bookmarkMenu_->addMenu(i18n("&Set Bookmark")); 0157 setBM_act[0] = setBM_->addAction(i18n("(unused)")); 0158 setBM_act[0]->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_1)); 0159 connect(setBM_act[0], &QAction::triggered, this, [this]() {setBookmark(1);}); 0160 setBM_act[1] = setBM_->addAction(i18n("(unused)")); 0161 setBM_act[1]->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_2)); 0162 connect(setBM_act[1], &QAction::triggered, this, [this]() {setBookmark(2);}); 0163 setBM_act[2] = setBM_->addAction(i18n("(unused)")); 0164 setBM_act[2]->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_3)); 0165 connect(setBM_act[2], &QAction::triggered, this, [this]() {setBookmark(3);}); 0166 setBM_act[3] = setBM_->addAction(i18n("(unused)")); 0167 setBM_act[3]->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_4)); 0168 connect(setBM_act[3], &QAction::triggered, this, [this]() {setBookmark(4);}); 0169 setBM_act[4] = setBM_->addAction(i18n("(unused)")); 0170 setBM_act[4]->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_5)); 0171 connect(setBM_act[4], &QAction::triggered, this, [this]() {setBookmark(5);}); 0172 setBM_act[5] = setBM_->addAction(i18n("(unused)")); 0173 setBM_act[5]->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_6)); 0174 connect(setBM_act[5], &QAction::triggered, this, [this]() {setBookmark(6);}); 0175 setBM_act[6] = setBM_->addAction(i18n("(unused)")); 0176 setBM_act[6]->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_7)); 0177 connect(setBM_act[6], &QAction::triggered, this, [this]() {setBookmark(7);}); 0178 setBM_act[7] = setBM_->addAction(i18n("(unused)")); 0179 setBM_act[7]->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_8)); 0180 connect(setBM_act[7], &QAction::triggered, this, [this]() {setBookmark(8);}); 0181 setBM_act[8] = setBM_->addAction(i18n("(unused)")); 0182 setBM_act[8]->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_9)); 0183 connect(setBM_act[8], &QAction::triggered, this, [this]() {setBookmark(9);}); 0184 setBM_act[9] = setBM_->addAction(i18n("(unused)")); 0185 setBM_act[9]->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_0)); 0186 connect(setBM_act[9], &QAction::triggered, this, [this]() {setBookmark(10);}); 0187 0188 goToBM_ = bookmarkMenu_->addMenu(i18n("&Go to Bookmark")); 0189 goToBM_act[0] = goToBM_->addAction(i18n("(unused)")); 0190 goToBM_act[0]->setShortcut(QKeySequence(Qt::Key_1)); 0191 connect(goToBM_act[0], &QAction::triggered, this, [this]() {goToBookmark(1);}); 0192 0193 goToBM_act[1] = goToBM_->addAction(i18n("(unused)")); 0194 goToBM_act[1]->setShortcut(QKeySequence(Qt::Key_2)); 0195 connect(goToBM_act[1], &QAction::triggered, this, [this]() {goToBookmark(2);}); 0196 goToBM_act[2] = goToBM_->addAction(i18n("(unused)")); 0197 goToBM_act[2]->setShortcut(QKeySequence(Qt::Key_3)); 0198 connect(goToBM_act[2], &QAction::triggered, this, [this]() {goToBookmark(3);}); 0199 goToBM_act[3] = goToBM_->addAction(i18n("(unused)")); 0200 goToBM_act[3]->setShortcut(QKeySequence(Qt::Key_4)); 0201 connect(goToBM_act[3], &QAction::triggered, this, [this]() {goToBookmark(4);}); 0202 goToBM_act[4] = goToBM_->addAction(i18n("(unused)")); 0203 goToBM_act[4]->setShortcut(QKeySequence(Qt::Key_5)); 0204 connect(goToBM_act[4], &QAction::triggered, this, [this]() {goToBookmark(5);}); 0205 goToBM_act[5] = goToBM_->addAction(i18n("(unused)")); 0206 goToBM_act[5]->setShortcut(QKeySequence(Qt::Key_6)); 0207 connect(goToBM_act[5], &QAction::triggered, this, [this]() {goToBookmark(6);}); 0208 goToBM_act[6] = goToBM_->addAction(i18n("(unused)")); 0209 goToBM_act[6]->setShortcut(QKeySequence(Qt::Key_7)); 0210 connect(goToBM_act[6], &QAction::triggered, this, [this]() {goToBookmark(7);}); 0211 goToBM_act[7] = goToBM_->addAction(i18n("(unused)")); 0212 goToBM_act[7]->setShortcut(QKeySequence(Qt::Key_8)); 0213 connect(goToBM_act[7], &QAction::triggered, this, [this]() {goToBookmark(8);}); 0214 goToBM_act[8] = goToBM_->addAction(i18n("(unused)")); 0215 goToBM_act[8]->setShortcut(QKeySequence(Qt::Key_9)); 0216 connect(goToBM_act[8], &QAction::triggered, this, [this]() {goToBookmark(9);}); 0217 goToBM_act[9] = goToBM_->addAction(i18n("(unused)")); 0218 goToBM_act[9]->setShortcut(QKeySequence(Qt::Key_0)); 0219 connect(goToBM_act[9], &QAction::triggered, this, [this]() {goToBookmark(10);}); 0220 0221 for (i=1; i<=10; i++) { 0222 bookmarks_[i-1] = new Bookmark(i); 0223 updateBookmark(i); 0224 } 0225 0226 help_ = new KHelpMenu(this, QString(), false); 0227 menu_->addSeparator(); 0228 menu_->addMenu( help_->menu() ); 0229 0230 menu_->show(); 0231 playField_->show(); 0232 0233 setAcceptDrops(true); 0234 } 0235 0236 MainWindow::~MainWindow() 0237 { 0238 KSharedConfigPtr cfg=KSharedConfig::openConfig(); 0239 KConfigGroup geometryGroup(cfg, "Geometry"); 0240 geometryGroup.writeEntry("width", QStringLiteral("%1").arg(width())); 0241 geometryGroup.writeEntry("height", QStringLiteral("%1").arg(height())); 0242 0243 KConfigGroup settingsGroup(cfg, "settings"); 0244 settingsGroup.writeEntry("collection", QStringLiteral("%1").arg(internalCollections_[checkedCollection_]->id())); 0245 0246 for (int i=1; i<=10; i++) { 0247 delete bookmarks_[i-1]; 0248 } 0249 0250 0251 delete externalCollection_; 0252 delete[] level_act; 0253 0254 // The following line segfaults when linked against qt 1.44 0255 //delete help_; 0256 //delete goToBM_; 0257 //delete setBM_; 0258 //delete bookmarkMenu_; 0259 //delete animation_; 0260 //delete collection_; 0261 //delete game_; 0262 //delete menu_; 0263 0264 //delete playField_; 0265 } 0266 0267 0268 void 0269 MainWindow::updateAnim(int val) { 0270 updateAnimMenu(val); 0271 playField_->changeAnim(val); 0272 } 0273 0274 void 0275 MainWindow::focusInEvent(QFocusEvent *) { 0276 playField_->setFocus(); 0277 } 0278 0279 void 0280 MainWindow::updateAnimMenu(int id) { 0281 switch(checkedAnim_) { 0282 case 0: 0283 qa_off->setChecked(false); 0284 break; 0285 case 1: 0286 qa_fast->setChecked(false); 0287 break; 0288 case 2: 0289 qa_medium->setChecked(false); 0290 break; 0291 case 3: 0292 qa_slow->setChecked(false); 0293 break; 0294 } 0295 switch(id) { 0296 case 0: 0297 qa_off->setChecked(true); 0298 break; 0299 case 1: 0300 qa_fast->setChecked(true); 0301 break; 0302 case 2: 0303 qa_medium->setChecked(true); 0304 break; 0305 case 3: 0306 qa_slow->setChecked(true); 0307 break; 0308 } 0309 checkedAnim_ = id; 0310 } 0311 0312 void 0313 MainWindow::updateBookmark(int num) { 0314 int col = internalCollections_.toInternalId(bookmarks_[num-1]->collection()); 0315 int lev = bookmarks_[num-1]->level(); 0316 int mov = bookmarks_[num-1]->moves(); 0317 0318 if (col < 0 || lev < 0) return; 0319 0320 QString name; 0321 if (col >= 0 && col < internalCollections_.collections()) 0322 name = internalCollections_[col]->name(); 0323 else 0324 name = i18n("(invalid)"); 0325 QString l; 0326 l.setNum(lev+1); 0327 name += " #" + l; 0328 l.setNum(mov); 0329 name += " (" + l + QLatin1Char(')'); 0330 0331 setBM_act[num-1]->setText(name); 0332 goToBM_act[num-1]->setText(name); 0333 } 0334 0335 void 0336 MainWindow::setBookmark(int id) { 0337 assert(id >= 1 && id <= 10); 0338 playField_->setBookmark(bookmarks_[id-1]); 0339 updateBookmark(id); 0340 } 0341 0342 void 0343 MainWindow::goToBookmark(int id) { 0344 assert(id >= 1 && id <= 10); 0345 0346 Bookmark *bm = bookmarks_[id-1]; 0347 int collection = internalCollections_.toInternalId(bm->collection()); 0348 int level = bm->level(); 0349 0350 if (collection < 0 || collection >= internalCollections_.collections()) return; 0351 LevelCollection* colPtr = internalCollections_[collection]; 0352 if (colPtr == nullptr) return; 0353 if (level < 0 || level >= colPtr->noOfLevels()) return; 0354 if (level > colPtr->completedLevels()) return; 0355 0356 playField_->setUpdatesEnabled(false); 0357 changeCollection(collection); 0358 playField_->setUpdatesEnabled(true); 0359 playField_->goToBookmark(bookmarks_[id-1]); 0360 } 0361 0362 void 0363 MainWindow::changeCollection(int id) 0364 { 0365 level_act[checkedCollection_]->setChecked(false); 0366 checkedCollection_ = id; 0367 level_act[checkedCollection_]->setChecked(true); 0368 0369 delete externalCollection_; 0370 externalCollection_ = nullptr; 0371 playField_->changeCollection(internalCollections_[id]); 0372 } 0373 0374 void 0375 MainWindow::loadLevels() { 0376 KSharedConfigPtr cfg=KSharedConfig::openConfig(); 0377 KConfigGroup settingsGroup(cfg, "settings"); 0378 QString lastFile = settingsGroup.readPathEntry("lastLevelFile",QLatin1String("")); 0379 0380 QUrl result = QFileDialog::getOpenFileUrl(this, i18nc("@title:window", "Load Levels from a File"), lastFile, QStringLiteral("*")); 0381 if (result.isEmpty()) return; 0382 0383 openURL(result); 0384 } 0385 0386 void 0387 MainWindow::openURL(const QUrl &_url) { 0388 KSharedConfigPtr cfg=KSharedConfig::openConfig(); 0389 0390 // int namepos = _url.path().findRev('/') + 1; // NOTE: findRev can return -1 0391 // QString levelName = _url.path().mid(namepos); 0392 QString levelName = _url.fileName(); 0393 0394 QString levelFile; 0395 QTemporaryFile f; 0396 if (_url.isLocalFile()) { 0397 levelFile = _url.path(); 0398 } else { 0399 // levelFile = locateLocal("appdata", "levels/" + levelName); 0400 KIO::TransferJob * job = KIO::get(_url); 0401 job->exec(); 0402 if (job->error()) { 0403 return; 0404 } 0405 f.open(); 0406 QByteArray data; 0407 Q_EMIT job->data(job, data); 0408 f.write(data); 0409 levelFile = f.fileName(); 0410 } 0411 0412 LevelCollection *tmpCollection = new LevelCollection(levelFile, levelName); 0413 0414 if (tmpCollection->noOfLevels() < 1) { 0415 KMessageBox::error(this, i18n("No levels found in file")); 0416 delete tmpCollection; 0417 return; 0418 } 0419 if (_url.isLocalFile()) { 0420 KConfigGroup settingsGroup(cfg,"settings"); 0421 settingsGroup.writePathEntry("lastLevelFile", _url.path()); 0422 } 0423 0424 delete externalCollection_; 0425 externalCollection_ = tmpCollection; 0426 0427 level_act[checkedCollection_]->setChecked(false); 0428 playField_->changeCollection(externalCollection_); 0429 0430 0431 } 0432 /* 0433 void 0434 MainWindow::dragEnterEvent(QDragEnterEvent* event) { 0435 event->accept(KURLDrag::canDecode(event)); 0436 } 0437 */ 0438 0439 void 0440 MainWindow::dropEvent(QDropEvent* event) { 0441 QList<QUrl> urls = KUrlMimeData::urlsFromMimeData(event->mimeData()); 0442 if (!urls.isEmpty()) { 0443 // kdDebug() << "MainWindow:Handling QUriDrag..." << endl; 0444 if (urls.count() > 0) { 0445 const QUrl &url = urls.first(); 0446 openURL(url); 0447 } 0448 } 0449 }