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 }