• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdegames API Reference
  • KDE Home
  • Contact Us
 

kgoldrunner

  • sources
  • kde-4.14
  • kdegames
  • kgoldrunner
  • src
kgreditor.cpp
Go to the documentation of this file.
1 #include "kgrdebug.h"
2 
3 /****************************************************************************
4  * Copyright 2009 Ian Wadham <iandw.au@gmail.com> *
5  * *
6  * This program is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU General Public License as *
8  * published by the Free Software Foundation; either version 2 of *
9  * the License, or (at your option) any later version. *
10  * *
11  * This program is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14  * GNU General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU General Public License *
17  * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18  ****************************************************************************/
19 
20 #include "kgreditor.h"
21 #include "kgrscene.h"
22 #include "kgrview.h"
23 #include "kgrselector.h"
24 #include "kgrdialog.h"
25 #include "kgrgameio.h"
26 
27 #include <ctype.h>
28 #include <QTimer>
29 
30 #include <KDebug>
31 
32 KGrEditor::KGrEditor (KGrView * theView,
33  const QString & theSystemDir,
34  const QString & theUserDir,
35  QList<KGrGameData *> & pGameList)
36  :
37  QObject (theView), // Destroy Editor if view closes.
38  view (theView),
39  scene (view->gameScene()),
40  io (new KGrGameIO (view)),
41  systemDataDir (theSystemDir),
42  userDataDir (theUserDir),
43  gameList (pGameList),
44  editObj (BRICK), // Default edit-object.
45  shouldSave (false),
46  mouseDisabled (true)
47 {
48  levelData.width = FIELDWIDTH; // Default values for a brand new game.
49  levelData.height = FIELDHEIGHT;
50 
51  // Connect and start the timer.
52  timer = new QTimer (this);
53  connect (timer, SIGNAL (timeout()), this, SLOT (tick()));
54  timer->start (TickTime); // TickTime def in kgrglobals.h.
55 
56  // Connect edit-mode slots to signals from "view".
57  connect (view, SIGNAL (mouseClick(int)), SLOT (doEdit(int)));
58  connect (view, SIGNAL (mouseLetGo(int)), SLOT (endEdit(int)));
59  connect (this, SIGNAL (getMousePos(int&,int&)),
60  scene, SLOT (getMousePos(int&,int&)));
61 }
62 
63 KGrEditor::~KGrEditor()
64 {
65 }
66 
67 void KGrEditor::setEditObj (char newEditObj)
68 {
69  editObj = newEditObj;
70 }
71 
72 bool KGrEditor::createLevel (int pGameIndex)
73 {
74  if (! saveOK ()) { // Check unsaved work.
75  return false;
76  }
77 
78  if (! ownerOK (USER)) {
79  KGrMessage::information (view, i18n ("Create Level"),
80  i18n ("You cannot create and save a level "
81  "until you have created a game to hold "
82  "it. Try menu item \"Create Game\"."));
83  return false;
84  }
85 
86  int i, j;
87  gameIndex = pGameIndex;
88  editLevel = 0;
89 
90  // Ignore player input from the mouse while the screen is set up.
91  mouseDisabled = true;
92 
93  levelData.level = 0;
94  levelData.name = "";
95  levelData.hint = "";
96  initEdit();
97 
98  // Clear the playfield.
99  levelData.layout.resize (levelData.width * levelData.height);
100  for (i = 1; i <= levelData.width; i++) {
101  for (j = 1; j <= levelData.height; j++) {
102  insertEditObj (i, j, FREE);
103  }
104  }
105 
106  // Add a hero.
107  insertEditObj (1, 1, HERO);
108 
109  savedLevelData.layout = levelData.layout; // Copy for "saveOK()".
110  savedLevelData.name = levelData.name;
111  savedLevelData.hint = levelData.hint;
112 
113  view->update(); // Show the level name.
114 
115  // Re-enable player input.
116  mouseDisabled = false;
117  return true;
118 }
119 
120 bool KGrEditor::updateLevel (int pGameIndex, int level)
121 {
122 
123  if (! saveOK ()) { // Check unsaved work.
124  return false;
125  }
126 
127  if (! ownerOK (USER)) {
128  KGrMessage::information (view, i18n ("Edit Level"),
129  i18n ("You cannot edit and save a level until you "
130  "have created a game and a level. Try menu item \"Create Game\"."));
131  return false;
132  }
133 
134  gameIndex = pGameIndex;
135 
136  // Ignore player input from the mouse while the screen is set up.
137  mouseDisabled = true;
138 
139  if (level < 0)
140  level = 0;
141  int selectedLevel = selectLevel (SL_UPDATE, level, gameIndex);
142  kDebug() << "Selected" << gameList.at(gameIndex)->name
143  << "level" << selectedLevel;
144  if (selectedLevel == 0) {
145  mouseDisabled = false;
146  return false;
147  }
148 
149  if (gameList.at(gameIndex)->owner == SYSTEM) {
150  KGrMessage::information (view, i18n ("Edit Level"),
151  i18n ("It is OK to edit a system level, but you MUST save "
152  "the level in one of your own games. You are not just "
153  "taking a peek at the hidden ladders "
154  "and fall-through bricks, are you? :-)"));
155  }
156 
157  loadEditLevel (selectedLevel);
158  mouseDisabled = false;
159  return true;
160 }
161 
162 void KGrEditor::loadEditLevel (int lev)
163 {
164  KGrLevelData d;
165 
166  kDebug() << "gameIndex" << gameIndex;
167  // If system game or ENDE screen, choose system dir, else choose user dir.
168  const QString dir = ((gameList.at(gameIndex)->owner == SYSTEM) ||
169  (lev == 0)) ? systemDataDir : userDataDir;
170  // Read the level data.
171  if (! io->readLevelData (dir, gameList.at(gameIndex)->prefix, lev, d)) {
172  return; // If I/O failed, no load.
173  }
174 
175  editLevel = lev;
176  initEdit();
177 
178  int i, j;
179  char obj;
180 
181  // Load the level.
182  for (i = 1; i <= levelData.width; i++) {
183  for (j = 1; j <= levelData.height; j++) {
184  obj = d.layout [(j-1) * d.width + (i-1)];
185  insertEditObj (i, j, obj);
186  }
187  }
188  savedLevelData.layout = d.layout; // Copy for "saveOK()".
189 
190  // Retain the original language of the name and hint when editing,
191  // but convert non-ASCII, UTF-8 substrings to Unicode (eg. ü to ü).
192  levelName = (d.name.size() > 0) ?
193  QString::fromUtf8 ((const char *) d.name) : "";
194  levelHint = (d.hint.size() > 0) ?
195  QString::fromUtf8 ((const char *) d.hint) : "";
196 
197  scene->setTitle (getTitle()); // Show the level name.
198 }
199 
200 void KGrEditor::editNameAndHint()
201 {
202  // Run a dialog box to create/edit the level name and hint.
203  KGrNHDialog * nh = new KGrNHDialog (levelName, levelHint, view);
204 
205  if (nh->exec() == QDialog::Accepted) {
206  levelName = nh->getName();
207  levelHint = nh->getHint();
208  shouldSave = true;
209  }
210 
211  delete nh;
212 }
213 
214 bool KGrEditor::saveLevelFile()
215 {
216  bool isNew;
217  int action;
218 
219  int i, j;
220  QString filePath;
221 
222  // Save the current game index.
223  int N = gameIndex;
224 
225  if (editLevel == 0) {
226  // New level: choose a number.
227  action = SL_CREATE;
228  }
229  else {
230  // Existing level: confirm the number or choose a new number.
231  action = SL_SAVE;
232  }
233 
234  // Pop up dialog box, which could change the game or level or both.
235  int selectedLevel = selectLevel (action, editLevel, gameIndex);
236  if (selectedLevel == 0) {
237  return false;
238  }
239 
240  // Get the new game (if changed).
241  int n = gameIndex;
242 
243  // Set the name of the output file.
244  filePath = getLevelFilePath (gameList.at(n), selectedLevel);
245  QFile levelFile (filePath);
246 
247  if ((action == SL_SAVE) && (n == N) && (selectedLevel == editLevel)) {
248  // This is a normal edit: the old file is to be re-written.
249  isNew = false;
250  }
251  else {
252  isNew = true;
253  // Check if the file is to be inserted in or appended to the game.
254  if (levelFile.exists()) {
255  switch (KGrMessage::warning (view, i18n ("Save Level"),
256  i18n ("Do you want to insert a level and "
257  "move existing levels up by one?"),
258  i18n ("&Insert Level"), i18n ("&Cancel"))) {
259 
260  case 0: if (! reNumberLevels (n, selectedLevel,
261  gameList.at (n)->nLevels, +1)) {
262  return false;
263  }
264  break;
265  case 1: return false;
266  break;
267  }
268  }
269  }
270 
271  // Open the output file.
272  if (! levelFile.open (QIODevice::WriteOnly)) {
273  KGrMessage::information (view, i18n ("Save Level"),
274  i18n ("Cannot open file '%1' for output.", filePath));
275  return false;
276  }
277 
278  // Save the level - row by row.
279  for (j = 1; j <= levelData.height; j++) {
280  for (i = 1; i <= levelData.width; i++) {
281  levelFile.putChar (editableCell (i, j));
282  }
283  }
284  savedLevelData.layout = levelData.layout; // Copy for "saveOK()".
285  levelFile.putChar ('\n');
286 
287  // Save the level name, changing non-ASCII chars to UTF-8 (eg. ü to ü).
288  QByteArray levelNameC = levelName.toUtf8();
289  int len1 = levelNameC.length();
290  if (len1 > 0) {
291  for (i = 0; i < len1; i++)
292  levelFile.putChar (levelNameC[i]);
293  levelFile.putChar ('\n'); // Add a newline.
294  }
295 
296  // Save the level hint, changing non-ASCII chars to UTF-8 (eg. ü to ü).
297  QByteArray levelHintC = levelHint.toUtf8();
298  int len2 = levelHintC.length();
299  char ch = '\0';
300 
301  if (len2 > 0) {
302  if (len1 <= 0)
303  levelFile.putChar ('\n'); // Leave blank line for name.
304  for (i = 0; i < len2; i++) {
305  ch = levelHintC[i];
306  levelFile.putChar (ch); // Copy the character.
307  }
308  if (ch != '\n')
309  levelFile.putChar ('\n'); // Add a newline character.
310  }
311 
312  levelFile.close();
313  shouldSave = false;
314 
315  if (isNew) {
316  gameList.at (n)->nLevels++;
317  saveGameData (USER);
318  }
319 
320  editLevel = selectedLevel;
321  scene->setLevel (editLevel); // Choose a background picture.
322  scene->setTitle (getTitle()); // Display new title.
323  return true;
324 }
325 
326 bool KGrEditor::moveLevelFile (int pGameIndex, int level)
327 {
328  if (level <= 0) {
329  KGrMessage::information (view, i18n ("Move Level"),
330  i18n ("You must first load a level to be moved. Use "
331  "the \"%1\" or \"%2\" menu.",
332  i18n ("Game"), i18n ("Editor")));
333  return false;
334  }
335  gameIndex = pGameIndex;
336 
337  int action = SL_MOVE;
338 
339  int fromC = gameIndex;
340  int fromL = level;
341  int toC = fromC;
342  int toL = fromL;
343 
344  if (! ownerOK (USER)) {
345  KGrMessage::information (view, i18n ("Move Level"),
346  i18n ("You cannot move a level until you "
347  "have created a game and at least two levels. Try "
348  "menu item \"Create Game\"."));
349  return false;
350  }
351 
352  if (gameList.at (fromC)->owner != USER) {
353  KGrMessage::information (view, i18n ("Move Level"),
354  i18n ("Sorry, you cannot move a system level."));
355  return false;
356  }
357 
358  // Pop up dialog box to get the game and level number to move to.
359  while ((toC == fromC) && (toL == fromL)) {
360  toL = selectLevel (action, toL, gameIndex);
361  if (toL == 0) {
362  return false;
363  }
364 
365  toC = gameIndex;
366 
367  if ((toC == fromC) && (toL == fromL)) {
368  KGrMessage::information (view, i18n ("Move Level"),
369  i18n ("You must change the level or the game or both."));
370  }
371  }
372 
373  QString filePath1;
374  QString filePath2;
375 
376  // Save the "fromN" file under a temporary name.
377  filePath1 = getLevelFilePath (gameList.at (fromC), fromL);
378  filePath2 = filePath1;
379  filePath2 = filePath2.append (".tmp");
380  if (! KGrGameIO::safeRename (view, filePath1, filePath2)) {
381  return false;
382  }
383 
384  if (toC == fromC) { // Same game.
385  if (toL < fromL) { // Decrease level.
386  // Move "toL" to "fromL - 1" up by 1.
387  if (! reNumberLevels (toC, toL, fromL-1, +1)) {
388  return false;
389  }
390  }
391  else { // Increase level.
392  // Move "fromL + 1" to "toL" down by 1.
393  if (! reNumberLevels (toC, fromL+1, toL, -1)) {
394  return false;
395  }
396  }
397  }
398  else { // Different game.
399  // In "fromC", move "fromL + 1" to "nLevels" down and update "nLevels".
400  if (! reNumberLevels (fromC, fromL + 1,
401  gameList.at (fromC)->nLevels, -1)) {
402  return false;
403  }
404  gameList.at (fromC)->nLevels--;
405 
406  // In "toC", move "toL + 1" to "nLevels" up and update "nLevels".
407  if (! reNumberLevels (toC, toL, gameList.at (toC)->nLevels, +1)) {
408  return false;
409  }
410  gameList.at (toC)->nLevels++;
411 
412  saveGameData (USER);
413  }
414 
415  // Rename the saved "fromL" file to become "toL".
416  filePath1 = getLevelFilePath (gameList.at (toC), toL);
417  KGrGameIO::safeRename (view, filePath2, filePath1);
418 
419  editLevel = toL;
420  scene->setLevel (editLevel); // Choose a background picture.
421  scene->setTitle (getTitle()); // Re-write title.
422  return true;
423 }
424 
425 bool KGrEditor::deleteLevelFile (int pGameIndex, int level)
426 {
427  int action = SL_DELETE;
428  gameIndex = pGameIndex;
429 
430  if (! ownerOK (USER)) {
431  KGrMessage::information (view, i18n ("Delete Level"),
432  i18n ("You cannot delete a level until you "
433  "have created a game and a level. Try "
434  "menu item \"Create Game\"."));
435  return false;
436  }
437 
438  // Pop up dialog box to get the game and level number.
439  int selectedLevel = selectLevel (action, level, gameIndex);
440  if (selectedLevel == 0) {
441  return false;
442  }
443 
444  QString filePath;
445 
446  // Set the name of the file to be deleted.
447  int n = gameIndex;
448  filePath = getLevelFilePath (gameList.at (n), selectedLevel);
449  QFile levelFile (filePath);
450 
451  // Delete the file for the selected game and level.
452  if (levelFile.exists()) {
453  if (selectedLevel < gameList.at (n)->nLevels) {
454  switch (KGrMessage::warning (view, i18n ("Delete Level"),
455  i18n ("Do you want to delete a level and "
456  "move higher levels down by one?"),
457  i18n ("&Delete Level"), i18n ("&Cancel"))) {
458  case 0: break;
459  case 1: return false; break;
460  }
461  levelFile.remove();
462  if (! reNumberLevels (n, selectedLevel + 1,
463  gameList.at(n)->nLevels, -1)) {
464  return false;
465  }
466  }
467  else {
468  levelFile.remove();
469  }
470  }
471  else {
472  KGrMessage::information (view, i18n ("Delete Level"),
473  i18n ("Cannot find file '%1' to be deleted.", filePath));
474  return false;
475  }
476 
477  gameList.at (n)->nLevels--;
478  saveGameData (USER);
479  if (selectedLevel <= gameList.at (n)->nLevels) {
480  editLevel = selectedLevel;
481  }
482  else {
483  editLevel = gameList.at (n)->nLevels;
484  }
485 
486  // Repaint the screen with the level that now has the selected number.
487  if (level > 0) {
488  loadEditLevel (editLevel); // Load level in edit mode.
489  }
490  else {
491  createLevel (gameIndex); // No levels left in game.
492  }
493  return true;
494 }
495 
496 bool KGrEditor::editGame (int pGameIndex)
497 {
498  int n = -1;
499  int action = (pGameIndex < 0) ? SL_CR_GAME : SL_UPD_GAME;
500  gameIndex = pGameIndex;
501 
502  // If editing, choose a game.
503  if (gameIndex >= 0) {
504  int selectedLevel = selectLevel (SL_UPD_GAME, editLevel, gameIndex);
505  if (selectedLevel == 0) {
506  return false;
507  }
508  editLevel = selectedLevel;
509  n = gameIndex;
510  }
511 
512  bool result = false;
513  KGrECDialog * ec = new KGrECDialog (action, n, gameList, view);
514 
515  while (ec->exec() == QDialog::Accepted) { // Loop until valid.
516 
517  // Validate the game details.
518  QString ecName = ec->getName();
519  int len = ecName.length();
520  if (len == 0) {
521  KGrMessage::information (view, i18n ("Save Game Info"),
522  i18n ("You must enter a name for the game."));
523  continue;
524  }
525 
526  QString ecPrefix = ec->getPrefix();
527  if ((action == SL_CR_GAME) || (gameList.at (n)->nLevels <= 0)) {
528  // The filename prefix could have been entered, so validate it.
529  len = ecPrefix.length();
530  if (len == 0) {
531  KGrMessage::information (view, i18n ("Save Game Info"),
532  i18n ("You must enter a filename prefix for the game."));
533  continue;
534  }
535  if (len > 5) {
536  KGrMessage::information (view, i18n ("Save Game Info"),
537  i18n ("The filename prefix should not "
538  "be more than 5 characters."));
539  continue;
540  }
541 
542  bool allAlpha = true;
543  for (int i = 0; i < len; i++) {
544  if (! isalpha (ecPrefix.at (i).toLatin1())) {
545  allAlpha = false;
546  break;
547  }
548  }
549  if (! allAlpha) {
550  KGrMessage::information (view, i18n ("Save Game Info"),
551  i18n ("The filename prefix should be "
552  "all alphabetic characters."));
553  continue;
554  }
555 
556  bool duplicatePrefix = false;
557  KGrGameData * c;
558  int imax = gameList.count();
559  for (int i = 0; i < imax; i++) {
560  c = gameList.at (i);
561  if ((c->prefix == ecPrefix) && (i != n)) {
562  duplicatePrefix = true;
563  break;
564  }
565  }
566 
567  if (duplicatePrefix) {
568  KGrMessage::information (view, i18n ("Save Game Info"),
569  i18n ("The filename prefix '%1' is already in use.",
570  ecPrefix));
571  continue;
572  }
573  }
574 
575  // Save the game details.
576  char rules = 'K';
577  if (ec->isTrad()) {
578  rules = 'T';
579  }
580 
581  KGrGameData * gameData = 0;
582  if (action == SL_CR_GAME) {
583  // Create empty game data and add it to the main list in KGrGame.
584  gameData = new KGrGameData();
585  gameList.append (gameData);
586  gameIndex = gameList.count() - 1;
587  editLevel = 1;
588 
589  // Set the initial values for a new game.
590  gameData->owner = USER;
591  gameData->nLevels = 0;
592  gameData->skill = 'N';
593  gameData->width = FIELDWIDTH;
594  gameData->height = FIELDHEIGHT;
595  }
596  else {
597  // Point to existing game data.
598  gameData = gameList.at (gameIndex);
599  }
600 
601  // Create or update the editable values.
602  gameData->rules = rules;
603  gameData->prefix = ecPrefix;
604  gameData->name = ecName;
605  gameData->about = ec->getAboutText().toUtf8();
606 
607  saveGameData (USER);
608  result = true; // Successful create/edit.
609  break; // All done now.
610  }
611 
612  delete ec;
613  return result;
614 }
615 
616 /******************************************************************************/
617 /************************ LEVEL SELECTION DIALOG ************************/
618 /******************************************************************************/
619 
620 int KGrEditor::selectLevel (int action, int requestedLevel, int & requestedGame)
621 {
622  int selectedLevel = 0; // 0 = no selection (Cancel) or invalid.
623  int selectedGame = requestedGame;
624 
625  // Create and run a modal dialog box to select a game and level.
626  KGrSLDialog * sl = new KGrSLDialog (action, requestedLevel, requestedGame,
627  gameList, systemDataDir, userDataDir,
628  view);
629  connect (sl, SIGNAL (editNameAndHint()), this, SLOT (editNameAndHint()));
630  bool selected = sl->selectLevel (selectedGame, selectedLevel);
631  delete sl;
632 
633  if (selected) {
634  requestedGame = selectedGame;
635  return (selectedLevel);
636  }
637  else {
638  return (0); // 0 = cancelled or invalid.
639  }
640 }
641 
642 /******************************************************************************/
643 /********************* SUPPORTING GAME EDITOR FUNCTIONS *********************/
644 /******************************************************************************/
645 
646 bool KGrEditor::saveOK ()
647 {
648  bool result = true;
649 
650  if ((shouldSave) || (levelData.layout != savedLevelData.layout)) {
651  // If shouldSave == true, level name or hint was edited.
652  switch (KGrMessage::warning (view, i18n ("Editor"),
653  i18n ("You have not saved your work. Do "
654  "you want to save it now?"),
655  i18n ("&Save"), i18n ("&Do Not Save"),
656  i18n ("&Go on editing")))
657  {
658  case 0:
659  result = saveLevelFile(); // Save, do next action: or more edits.
660  break;
661  case 1:
662  shouldSave = false; // Do not save, but do next action.
663  break;
664  case 2:
665  result = false; // Go back to editing.
666  break;
667  }
668  }
669 
670  return (result);
671 }
672 
673 void KGrEditor::initEdit()
674 {
675  paintEditObj = false;
676  paintAltObj = false;
677 
678  // Set the default object and button.
679  editObj = BRICK;
680 
681  oldI = 0;
682  oldJ = 0;
683  heroCount = 0;
684 
685  scene->setLevel (editLevel); // Choose a background picture.
686  scene->setTitle (getTitle()); // Show title of level.
687 
688  shouldSave = false; // Used to flag editing of name or hint.
689 }
690 
691 void KGrEditor::insertEditObj (int i, int j, char obj)
692 {
693  dbk2 << i << j << obj;
694  if ((i < 1) || (j < 1) || (i > levelData.width) || (j > levelData.height)) {
695  return; // Do nothing: mouse pointer is out of playfield.
696  }
697 
698  if (editableCell (i, j) == HERO) {
699  // The hero is in this cell: remove him.
700  setEditableCell (i, j, FREE);
701  heroCount = 0;
702  }
703 
704  if (obj == HERO) {
705  if (heroCount > 0) {
706  // Can only have one hero: remove him from his previous position.
707  for (int m = 1; m <= levelData.width; m++) {
708  for (int n = 1; n <= levelData.height; n++) {
709  if (editableCell (m, n) == HERO) {
710  setEditableCell (m, n, FREE);
711  }
712  }
713  }
714  }
715  heroCount = 1;
716  }
717 
718  setEditableCell (i, j, obj);
719 }
720 
721 char KGrEditor::editableCell (int i, int j)
722 {
723  return (levelData.layout [(i - 1) + (j - 1) * levelData.width]);
724 }
725 
726 void KGrEditor::setEditableCell (int i, int j, char type)
727 {
728  levelData.layout [(i - 1) + (j - 1) * levelData.width] = type;
729  scene->paintCell (i, j, type);
730 }
731 
732 void KGrEditor::showEditLevel()
733 {
734  // Disconnect play-mode slots from signals from "view".
735  disconnect (view, SIGNAL (mouseClick(int)), 0, 0);
736  disconnect (view, SIGNAL (mouseLetGo(int)), 0, 0);
737 
738  // Connect edit-mode slots to signals from "view".
739  connect (view, SIGNAL (mouseClick(int)), SLOT (doEdit(int)));
740  connect (view, SIGNAL (mouseLetGo(int)), SLOT (endEdit(int)));
741 }
742 
743 bool KGrEditor::reNumberLevels (int cIndex, int first, int last, int inc)
744 {
745  int i, n, step;
746  QString file1, file2;
747 
748  if (inc > 0) {
749  i = last;
750  n = first - 1;
751  step = -1;
752  }
753  else {
754  i = first;
755  n = last + 1;
756  step = +1;
757  }
758 
759  while (i != n) {
760  file1 = getLevelFilePath (gameList.at (cIndex), i);
761  file2 = getLevelFilePath (gameList.at (cIndex), i - step);
762  if (! KGrGameIO::safeRename (view, file1, file2)) {
763  return (false);
764  }
765  i = i + step;
766  }
767 
768  return (true);
769 }
770 
771 bool KGrEditor::ownerOK (Owner o)
772 {
773  // Check that this owner has at least one set of game data.
774  bool OK = false;
775 
776  foreach (KGrGameData * d, gameList) {
777  if (d->owner == o) {
778  OK = true;
779  break;
780  }
781  }
782 
783  return (OK);
784 }
785 
786 bool KGrEditor::saveGameData (Owner o)
787 {
788  QString filePath;
789 
790  if (o != USER) {
791  KGrMessage::information (view, i18n ("Save Game Info"),
792  i18n ("You can only modify user games."));
793  return (false);
794  }
795 
796  filePath = userDataDir + "games.dat";
797 
798  QFile c (filePath);
799 
800  // Open the output file.
801  if (! c.open (QIODevice::WriteOnly)) {
802  KGrMessage::information (view, i18n ("Save Game Info"),
803  i18n ("Cannot open file '%1' for output.", filePath));
804  return (false);
805  }
806 
807  // Save the game-data objects.
808  QString line;
809  QByteArray lineC;
810  int i, len;
811  char ch;
812 
813  foreach (KGrGameData * gData, gameList) {
814  if (gData->owner == o) {
815  line = QString ("%1 %2 %3 %4\n")
816  .arg (gData->nLevels, 3, 10, QChar('0')) // int 00n
817  .arg (gData->rules) // char
818  .arg (gData->prefix) // QString
819  .arg (gData->name); // QString
820  lineC = line.toUtf8();
821  len = lineC.length();
822  for (i = 0; i < len; i++) {
823  c.putChar (lineC.at (i));
824  }
825 
826  len = gData->about.length();
827  if (len > 0) {
828  QByteArray aboutC = gData->about;
829  len = aboutC.length(); // Might be longer now.
830  for (i = 0; i < len; i++) {
831  ch = aboutC[i];
832  if (ch != '\n') {
833  c.putChar (ch); // Copy the character.
834  }
835  else {
836  c.putChar ('\\'); // Change newline to \ and n.
837  c.putChar ('n');
838  }
839  }
840  c.putChar ('\n'); // Add a real newline.
841  }
842  }
843  }
844 
845  c.close();
846  return (true);
847 }
848 
849 QString KGrEditor::getTitle()
850 {
851  if (editLevel <= 0) {
852  // Generate a special title for a new level.
853  return (i18n ("New Level"));
854  }
855 
856  // Set title string to "Game-name - NNN" or "Game-name - NNN - Level-name".
857  KGrGameData * gameData = gameList.at(gameIndex);
858  QString levelNumber = QString::number(editLevel).rightJustified(3,'0');
859 
860  QString levelTitle = (levelName.length() <= 0)
861  ?
862  i18nc ("Game name - level number.",
863  "%1 - %2",
864  gameData->name, levelNumber)
865  :
866  i18nc ("Game name - level number - level name.",
867  "%1 - %2 - %3",
868  gameData->name, levelNumber, levelName);
869  return (levelTitle);
870 }
871 
872 QString KGrEditor::getLevelFilePath (KGrGameData * gameData, int lev)
873 {
874  QString filePath = userDataDir + "levels/" + gameData->prefix +
875  QString::number(lev).rightJustified(3,'0') + ".grl";
876  return (filePath);
877 }
878 
879 /******************************************************************************/
880 /********************* EDIT ACTION SLOTS **********************************/
881 /******************************************************************************/
882 
883 void KGrEditor::doEdit (int button)
884 {
885  if (mouseDisabled) {
886  return;
887  }
888 
889  // Mouse button down: start making changes.
890  int i, j;
891  emit getMousePos (i, j);
892  kDebug() << "Button" << button << "at" << i << j;
893 
894  switch (button) {
895  case Qt::LeftButton:
896  paintEditObj = true;
897  insertEditObj (i, j, editObj);
898  oldI = i;
899  oldJ = j;
900  break;
901  case Qt::RightButton:
902  paintAltObj = true;
903  insertEditObj (i, j, FREE);
904  oldI = i;
905  oldJ = j;
906  break;
907  default:
908  break;
909  }
910 }
911 
912 void KGrEditor::tick()
913 {
914  if (mouseDisabled) {
915  return;
916  }
917 
918  // Check if a mouse-button is down: left = paint, right = erase.
919  if (paintEditObj || paintAltObj) {
920 
921  int i, j;
922  emit getMousePos (i, j);
923 
924  // Check if the mouse has moved.
925  if ((i != oldI) || (j != oldJ)) {
926  // If so, paint or erase a cell.
927  insertEditObj (i, j, (paintEditObj) ? editObj : FREE);
928  oldI = i;
929  oldJ = j;
930  }
931  }
932 }
933 
934 void KGrEditor::endEdit (int button)
935 {
936  if (mouseDisabled) {
937  return;
938  }
939 
940  // Mouse button released: finish making changes.
941  int i, j;
942  emit getMousePos (i, j);
943 
944  switch (button) {
945  case Qt::LeftButton:
946  paintEditObj = false;
947  if ((i != oldI) || (j != oldJ)) {
948  insertEditObj (i, j, editObj);
949  }
950  break;
951  case Qt::RightButton:
952  paintAltObj = false;
953  if ((i != oldI) || (j != oldJ)) {
954  insertEditObj (i, j, FREE);
955  }
956  break;
957  default:
958  break;
959  }
960 }
961 
962 #include "kgreditor.moc"
SL_SAVE
Definition: kgrglobals.h:60
KGrLevelData::hint
QByteArray hint
Level hint (optional).
Definition: kgrglobals.h:111
KGrEditor::editNameAndHint
void editNameAndHint()
Run a dialog in which the name and hint of a level can be edited.
Definition: kgreditor.cpp:200
kgrdebug.h
KGrLevelData::height
int height
Height of grid, in cells.
Definition: kgrglobals.h:108
QString::append
QString & append(QChar ch)
KGrGameData::height
int height
Height of grid, in cells.
Definition: kgrglobals.h:97
kgreditor.h
KGrGameIO
The KGrGameIO class handles I/O for text-files containing KGoldrunner games and levels.
Definition: kgrgameio.h:58
KGrGameData::prefix
QString prefix
Game's filename prefix.
Definition: kgrglobals.h:94
KGrGameData::owner
Owner owner
Owner of the game: "System" or "User".
Definition: kgrglobals.h:91
KGrGameData
KGrGameData structure: contains attributes of a KGoldrunner game.
Definition: kgrglobals.h:88
QByteArray
QByteArray::at
char at(int i) const
KGrMessage::warning
static int warning(QWidget *parent, const QString &caption, const QString &text, const QString &label0, const QString &label1, const QString &label2="")
Definition: kgrdialog.cpp:314
KGrEditor::deleteLevelFile
bool deleteLevelFile(int pGameIndex, int pLevel)
Delete a level from a game.
Definition: kgreditor.cpp:425
KGrECDialog::getPrefix
const QString getPrefix()
Definition: kgrdialog.h:75
QChar
TickTime
const int TickTime
Definition: kgrglobals.h:217
SL_UPD_GAME
Definition: kgrglobals.h:61
HERO
const char HERO
Definition: kgrglobals.h:31
KGrEditor::setEditObj
void setEditObj(char newEditObj)
Set the next object for the editor to paint, e.g.
Definition: kgreditor.cpp:67
QList::at
const T & at(int i) const
KGrGameData::width
int width
Width of grid, in cells.
Definition: kgrglobals.h:96
KGrEditor::getMousePos
void getMousePos(int &i, int &j)
Get the next grid-position at which to paint an object in the layout.
KGrECDialog
Definition: kgrdialog.h:65
KGrEditor::editGame
bool editGame(int pGameIndex)
Create a new game (a collection point for levels) or load the details of an existing game...
Definition: kgreditor.cpp:496
KGrEditor::KGrEditor
KGrEditor(KGrView *theView, const QString &theSystemDir, const QString &theUserDir, QList< KGrGameData * > &pGameList)
The constructor of KGrEditor.
Definition: kgreditor.cpp:32
QByteArray::length
int length() const
FIELDHEIGHT
const int FIELDHEIGHT
Definition: kgrglobals.h:49
KGrLevelData::layout
QByteArray layout
Codes for the level layout (mandatory).
Definition: kgrglobals.h:109
KGrScene::setTitle
void setTitle(const QString &newTitle)
Set the text for the title of the current level.
Definition: kgrscene.cpp:227
SYSTEM
Definition: kgrglobals.h:26
QObject::disconnect
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
QFile
QWidget::update
void update()
KGrGameData::rules
char rules
Game's rules: KGoldrunner or Traditional.
Definition: kgrglobals.h:93
KGrNHDialog
Definition: kgrdialog.h:45
QByteArray::resize
void resize(int size)
kgrdialog.h
KGrGameIO::readLevelData
bool readLevelData(const QString &dir, const QString &prefix, const int levelNo, KGrLevelData &d)
Find and read data for a level of a game.
Definition: kgrgameio.cpp:151
QString::number
QString number(int n, int base)
QList::count
int count(const T &value) const
KGrGameData::about
QByteArray about
Optional info about game (untranslated).
Definition: kgrglobals.h:99
QList::append
void append(const T &value)
SL_CR_GAME
Definition: kgrglobals.h:61
QString::fromUtf8
QString fromUtf8(const char *str, int size)
KGrEditor::moveLevelFile
bool moveLevelFile(int pGameIndex, int pLevel)
Move a level to another game or level number.
Definition: kgreditor.cpp:326
QTimer
QString::rightJustified
QString rightJustified(int width, QChar fill, bool truncate) const
QObject
KGrEditor::~KGrEditor
~KGrEditor()
Definition: kgreditor.cpp:63
FIELDWIDTH
const int FIELDWIDTH
Definition: kgrglobals.h:48
KGrMessage::information
static void information(QWidget *parent, const QString &caption, const QString &text, const QString &dontShowAgain=QString())
Definition: kgrdialog.cpp:306
KGrLevelData
KGrLevelData structure: contains attributes of a KGoldrunner level.
Definition: kgrglobals.h:103
KGrGameData::nLevels
int nLevels
Number of levels in the game.
Definition: kgrglobals.h:92
KGrECDialog::isTrad
bool isTrad()
Definition: kgrdialog.h:76
QString
QList< KGrGameData * >
KGrLevelData::level
int level
Level number.
Definition: kgrglobals.h:106
KGrECDialog::getAboutText
const QString getAboutText()
Definition: kgrdialog.h:77
QChar::toLatin1
char toLatin1() const
BRICK
const char BRICK
Definition: kgrglobals.h:33
kgrscene.h
dbk2
#define dbk2
Definition: kgrdebug.h:25
KGrNHDialog::getHint
const QString getHint()
Definition: kgrdialog.h:54
kgrview.h
KGrSLDialog
Definition: kgrselector.h:50
KGrEditor::createLevel
bool createLevel(int pGameIndex)
Set up a blank level-layout, ready for editing.
Definition: kgreditor.cpp:72
KGrEditor::saveLevelFile
bool saveLevelFile()
Save an edited level in a text file (*.grl) in the user's area.
Definition: kgreditor.cpp:214
QString::at
const QChar at(int position) const
KGrNHDialog::getName
const QString getName()
Definition: kgrdialog.h:53
kgrselector.h
KGrView
Definition: kgrview.h:27
KGrLevelData::width
int width
Width of grid, in cells.
Definition: kgrglobals.h:107
QString::length
int length() const
KGrSLDialog::selectLevel
bool selectLevel(int &selectedGame, int &selectedLevel)
Definition: kgrselector.cpp:72
USER
Definition: kgrglobals.h:26
KGrEditor::updateLevel
bool updateLevel(int pGameIndex, int pLevel)
Load and display an existing level, ready for editing.
Definition: kgreditor.cpp:120
QTimer::start
void start(int msec)
OK
Definition: kgrgameio.h:29
KGrScene::setLevel
void setLevel(unsigned int level)
Set the current level number.
Definition: kgrscene.cpp:346
KGrEditor::saveOK
bool saveOK()
Check if there are any unsaved edits and, if so, ask the user what to do.
Definition: kgreditor.cpp:646
KGrECDialog::getName
const QString getName()
Definition: kgrdialog.h:74
KGrGameData::name
QString name
Name of game (translated, if System game).
Definition: kgrglobals.h:98
SL_MOVE
Definition: kgrglobals.h:61
QByteArray::size
int size() const
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
kgrgameio.h
SL_DELETE
Definition: kgrglobals.h:61
KGrGameData::skill
char skill
Game's skill: Tutorial, Normal or Champion.
Definition: kgrglobals.h:95
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QTest::mouseClick
void mouseClick(QWidget *widget, Qt::MouseButton button, QFlags< Qt::KeyboardModifier > modifier, QPoint pos, int delay)
KGrGameIO::safeRename
static bool safeRename(QWidget *theView, const QString &oldName, const QString &newName)
Definition: kgrgameio.cpp:356
SL_UPDATE
Definition: kgrglobals.h:60
FREE
const char FREE
Definition: kgrglobals.h:28
SL_CREATE
Definition: kgrglobals.h:60
KGrScene::paintCell
void paintCell(const int i, const int j, const char type)
Requests the view to display a particular type of tile at a particular cell, or make it empty and sho...
Definition: kgrscene.cpp:430
Owner
Owner
Definition: kgrglobals.h:26
QString::toUtf8
QByteArray toUtf8() const
KGrLevelData::name
QByteArray name
Level name (optional).
Definition: kgrglobals.h:110
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:18:24 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kgoldrunner

Skip menu "kgoldrunner"
  • Main Page
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdegames API Reference

Skip menu "kdegames API Reference"
  • granatier
  • kapman
  • kblackbox
  • kgoldrunner
  • kigo
  • kmahjongg
  • KShisen
  • ksquares
  • libkdegames
  •   highscore
  •   libkdegamesprivate
  •     kgame
  • libkmahjongg
  • palapeli
  •   libpala

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal