source: projects/punch-card/punch-card-editor/src/app/editorwindow.cc @ 47

Last change on this file since 47 was 47, checked in by sven, 10 years ago

Continued implementation:

  • removed bugs
  • improved features

Programming continues, but quite slow since I've got few time... unfortunately

File size: 14.9 KB
Line 
1#include "editorwindow.h"
2#include "qpunchcard/card.h"
3#include "qpunchcard/widget.h"
4#include "qpunchcard/deckmodel.h"
5
6#include <QApplication>
7#include <QLabel>
8#include <QtDebug>
9#include <QListView>
10#include <QDockWidget>
11#include <QHBoxLayout>
12#include <QPushButton>
13#include <QMessageBox>
14#include <QFileDialog>
15#include <QFileInfo>
16
17using namespace QPunchCard;
18
19EditorWindow::EditorWindow() {
20        // sehr praktisch:
21        setAttribute(Qt::WA_DeleteOnClose, true);
22
23        // etwas kartenmaterial besorgen
24        Card* foo = new Card;
25        foo->column[0] = 12;
26        foo->column[9] = 78;
27        foo->column[12][0] = true;
28        foo->column[12][9] = true;
29
30        deck = new Deck;
31        deck->push_back(foo);
32
33        for(int x = 0; x < 10; x++) {
34                Card* c = new Card;
35                c->column[x] = x;
36                deck->push_back(c);
37        }
38
39        //deck = new Deck();
40
41        createGraphicalEditor();
42        createActions();
43        createMenus();
44        createToolBars();
45        createStatusBar();
46        createDockWindows();
47
48        // Titel einrichten und so
49        connect(this, SIGNAL(fileOpened(bool)), this, SLOT(window_update_on_file_state(bool)));
50        // und jetzt:
51
52        notifyFileOpened();
53}
54
55void EditorWindow::createGraphicalEditor() {
56        graphical_editor = new CardEditor(this);
57        setCentralWidget(graphical_editor);
58        // signale und so:
59        connect(this, SIGNAL(cardSelected(DeckIndex)), graphical_editor, SLOT(setCard(DeckIndex)));
60        connect(this, SIGNAL(fileOpened(bool)), graphical_editor, SLOT(fileOpened(bool)));
61        connect(this, SIGNAL(contentsChanged(DeckIndex, DeckIndex)), graphical_editor, SLOT(contentsChanged(DeckIndex, DeckIndex)));
62
63}
64
65void EditorWindow::window_update_on_file_state(bool opened) {
66        // * Window Title setzen
67        // * contentsChanged-Signal broadcasten
68        if(opened) {
69                // titel setzen
70                setWindowFilePath(QFileInfo(file).filePath());
71                setWindowTitle(tr("%1[*] - %2").arg(
72                        file.fileName().isEmpty() ? tr("New Card Deck") : file.fileName()
73                        ).arg(tr("Punch Card Editor")));
74                // Modified-Stern ([*]) verbinden
75                connect(deck, SIGNAL(modified(bool)), this, SLOT(setWindowModified(bool)));
76
77                // Broadcasting von "Edited" verbinden
78                connect(deck, SIGNAL(contentsChanged(DeckIndex, DeckIndex)), this, SIGNAL(contentsChanged(DeckIndex,DeckIndex)));
79        } else {
80                setWindowTitle(tr("Punch Card Editor"));
81                // passiert folgendes nicht sowieso automatisch?
82                disconnect(this, SLOT(setWindowModified(bool)));
83                // urhm, den broadcaster... nicht die slots freisetzen, waere bloed.
84        }
85}
86
87bool EditorWindow::maybeSave() {
88        if(!deck->isModified())
89                return true;
90        if(deck->empty()) // oder sowas in der Art -- eine leere Lochkarte oder so
91                return true;
92        switch(QMessageBox::warning(this, tr("Punch Card Editor"),
93                tr("The document has been modified.\nDo you want to save your changes?"),
94                QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel)) {
95
96                case QMessageBox::Save:
97                        return saveFile();
98                case QMessageBox::Cancel:
99                        return false; // aborted the whole thing
100                default:
101                        return true; // discard the file
102        }
103}
104
105void EditorWindow::newWindow() {
106        // einfacher gehts nicht:
107        new EditorWindow();
108}
109
110void EditorWindow::closeDeck() {
111        qDebug() << "Deleting deck.";
112        delete deck;
113        emit fileOpened(deck); // also false
114}
115
116void EditorWindow::loadDeck(const QString& filename) {
117        // load a new deck from a file. There can still be an old deck open,
118        // this method will close it when everything went good
119        QFile file(filename);
120        FileFormat* format = autoDetectFileFormat(file);
121        Deck* new_deck = new Deck(format);
122        // Leser anschmeissen
123        if( format->read(file) ) {
124                statusBar()->showMessage(QString(tr("Deck read in successfully")), 4000);
125        } else
126                qDebug() << "Errors while reading in the Deck.";
127        // Alte Datei rausschmeissen
128        closeDeck();
129        // Neue setzen
130        deck = new_deck;
131        this->file.setFileName( file.fileName() );
132        notifyFileOpened();
133}
134
135void EditorWindow::notifyFileOpened() {
136        if(deck) {
137                emit fileOpened(deck);
138                if(deck->count() > 0)
139                        emit setCard( deck->createIndex(0) );
140                else {
141                        // naja, das Deck ist *leer*. gibt also nix.
142                }
143        } else
144                qDebug("notifyFileOpened is supposed to be called when a file was *opened*");
145}
146
147void EditorWindow::newFile() {
148        if(maybeSave()) {
149                // alte Datei schliessen.
150                // d.h. defakto: Deck loeschen, neues erstellen.
151                // und dann alle darueber informieren. Sehr kompliziert.
152                closeDeck();
153                deck = new Deck();
154                notifyFileOpened();
155        }
156}
157
158void EditorWindow::openFile() {
159        if(maybeSave()) {
160                // Oeffnen-Dialog anzeigen.
161                QString filename = QFileDialog::getOpenFileName(this,
162                        tr("Open Card Deck File..."),
163                        QFileInfo(file).absolutePath(),
164                        tr("Jones Emulated Card Decks (*);;Card Editor XML-Files (*.xml *.cml)"));
165                if(!filename.isEmpty()) {
166                        loadDeck(filename);
167                }
168        }
169}
170
171bool EditorWindow::saveFile() {
172        if(!file.exists() || !deck->canSave())
173                return saveFileAs();
174        else
175                return deck->save(file);
176}
177
178bool EditorWindow::saveFileAs() {
179        // GUI anzeigen zum Speichern
180        QString filename = QFileDialog::getSaveFileName(this,
181                tr("Save Card Deck File..."),
182                QFileInfo(file).absolutePath(),
183                tr("Jones Emulator Card Decks (*);;Card Editor XML-Files (*.xml *.cml)"));
184        if(filename.isEmpty())
185                return false;
186        // Eigentlich jetzt: Nachschauen, welches Dateiformat zum Benutzen und so.
187        // stattdessen jetzt mal billig:
188        file.setFileName(filename);
189        if(deck->canSave()) {
190                // Nutze das bekannte Dateiformat
191                return deck->save(file);
192        } else {
193                // Nutze einfach mal
194                deck->setFormat( new JonesFileFormat );
195                return deck->save(file);
196        }
197}
198
199void EditorWindow::exportText() {
200        // Strategie: In die text_editors-Liste schauen, wenn nur ein Editor
201        // drin ist, ist der zu nutzende Codec klar definiert. Sonst fragen,
202        // welchen Codec benutzen.
203        // Dann abspeichern oder so... hier waere natuerlich auch interessant,
204        // auf bestehende Dateinamen zurueckgreifen zu koennen...
205}
206
207void EditorWindow::exportPicture() {
208        // das haupteditorwidget bzw. nach Auswahl alle/bestimmte Karten als PNG/SVG/...
209        // rendern.
210}
211
212void EditorWindow::closeFile() {
213        if(maybeSave()) {
214                // Deck schliessen und fertig.
215                closeDeck();
216        }
217}
218
219void EditorWindow::quit() {
220        if(maybeSave()) {
221                // Deck schliesst automatisch ;-)
222                qApp->quit();
223        }
224}
225
226void EditorWindow::closeEvent(QCloseEvent* event) {
227        if(maybeSave()) {
228                event->accept();
229        } else
230                event->ignore();
231}
232
233void EditorWindow::help() {
234
235}
236
237void EditorWindow::about() {
238        QMessageBox::about(this, tr("About the Punch Card Editor"),
239                tr("<big><b>Punch Card Editor</b></big><br>Development version"
240                   "<br>This application is GPLv3 licensed"
241                   "<br>Copyright Sven Koeppel"));
242}
243
244void EditorWindow::newTextEditor() {
245        TextEditorDock* editor = new TextEditorDock(this);
246        addDockWidget(Qt::BottomDockWidgetArea, editor);
247        view_menu->addAction(editor->toggleViewAction());
248        text_editors.push_back(editor);
249
250        // Signale anschalten:
251        connect(editor, SIGNAL(cardSelected(DeckIndex)), this, SLOT(setCard(DeckIndex)));
252        connect(this, SIGNAL(cardSelected(DeckIndex)), editor, SLOT(setCard(DeckIndex)));
253        connect(this, SIGNAL(fileOpened(bool)), editor, SLOT(setVisible(bool)));
254        // TODO: klaeren, wer den Texteditor irgendwann mal killt
255        // -- ist diese Liste wirklich noetig? (ggf. *ja* wegen Textexport)
256}
257
258void EditorWindow::nextCard() {
259        setCard( getCurrentIndex() + 1);
260}
261
262void EditorWindow::prevCard() {
263        setCard( getCurrentIndex() - 1);
264}
265
266void EditorWindow::setCard(DeckIndex i) {
267        // wenn keine Datei offen und so
268        if(!deck) {
269                qDebug("No card open, skipping setCard broadcasting");
270                return;
271        }
272        if(! i.assertDeck(deck)) {
273                qDebug() << "Index i has wrong deck: " << i;
274                return;
275        }
276        i.normalize();
277
278        // neuen index setzen
279        current_index = i;
280
281        // Signal weitergeben:
282        emit cardSelected(i);
283}
284
285void EditorWindow::newCard() {
286        // append new Card behind current card
287        if(!deck) return;
288        if(deck->insert(current_index)) {
289                setCard( current_index+1 );
290        }
291
292        /*
293        int new_card_index = current_card + 1;
294        if(! deck->isValid(current_card))
295                new_card_index = 0; // insert card at beginning of deck
296        deck->insert( current_card + 1, new Card);
297        // ob das hier geht...
298        emit deck->contentsChanged(current_card, deck->count());
299        setCard( current_card + 1 );
300        */
301}
302
303void EditorWindow::moveCardForwards() {
304        if(!deck) return;
305        if(deck->move(current_index, current_index+1)) {
306                setCard( current_index+1 );
307        }
308        /*
309        //DeckIndex new_index(deck, current_index + 1);
310        if(!deck->isValid(current_card) || !deck->isValid(new_card_index)) {
311                qDebug() << "Invalid indices for moveCardForwards";
312                return;
313        }
314        deck->move(current_card, new_card_index);
315        setCard( new_card_index );
316        */
317}
318
319void EditorWindow::moveCardBackwards() {
320        if(!deck) return;
321        if(deck->move(current_index, current_index-1)) {
322                setCard( current_index-1 );
323        }
324        /*
325        int new_card_index = current_card - 1;
326        if(!deck->isValid(current_card) || !deck->isValid(new_card_index)) {
327                qDebug() << "Invalid indices for moveCardBackwards";
328                return;
329        }
330        deck->move(current_card, new_card_index);
331        setCard( new_card_index );
332        */
333}
334
335void EditorWindow::createActions() {
336        new_file_action = new QAction(tr("&New File (Empty Card Deck)"), this);
337        new_file_action->setShortcuts(QKeySequence::New);
338        new_file_action->setStatusTip(tr("Create a new empty card deck"));
339        connect(new_file_action, SIGNAL(triggered()), this, SLOT(newFile()));
340
341        new_window_action = new QAction(tr("&New Window"), this);
342        new_window_action->setStatusTip(tr("Open a new Application window to edit two card decks concurrently"));
343        connect(new_window_action, SIGNAL(triggered()), this, SLOT(newWindow()));
344
345        open_file_action = new QAction(tr("&Open File..."), this);
346        open_file_action->setShortcuts(QKeySequence::Open);
347        open_file_action->setStatusTip(tr("Open existing card file (any card deck file or text file)"));
348        connect(open_file_action, SIGNAL(triggered()), this, SLOT(openFile()));
349
350        save_file_action = new QAction(tr("&Save File"), this);
351        save_file_action->setShortcuts(QKeySequence::Save);
352        save_file_action->setStatusTip(tr("Save the current file as card deck"));
353        connect(save_file_action, SIGNAL(triggered()), this, SLOT(saveFile()));
354
355        save_file_as_action = new QAction(tr("&Save File as..."), this);
356        save_file_as_action->setShortcuts(QKeySequence::SaveAs);
357        save_file_as_action->setStatusTip(tr("Save the current card deck as another file"));
358        connect(save_file_as_action, SIGNAL(triggered()), this, SLOT(saveFileAs()));
359
360        export_text_action = new QAction(tr("&Export Text..."), this);
361        export_text_action->setStatusTip(tr("Save the decoded plaintext of the current card deck"));
362        connect(export_text_action, SIGNAL(triggered()), this, SLOT(exportText()));
363
364        export_picture_action = new QAction(tr("&Export Picture of Card..."), this);
365        export_picture_action->setStatusTip(tr("Save the visualisation of one or more cards as a picture"));
366        connect(export_picture_action, SIGNAL(triggered()), this, SLOT(exportPicture()));
367
368        close_file_action = new QAction(tr("&Close File"), this);
369        close_file_action->setStatusTip(tr("Close current file while staying in the application"));
370        connect(close_file_action, SIGNAL(triggered()), this, SLOT(closeFile()));
371
372        quit_action = new QAction(tr("&Quit"), this);
373        quit_action->setStatusTip(tr("Quit Application"));
374        connect(quit_action, SIGNAL(triggered()), qApp, SLOT(closeAllWindows()));
375
376        help_action = new QAction(tr("&Help"), this);
377        help_action->setStatusTip(tr("Get Help about the usage of this program"));
378        connect(help_action, SIGNAL(triggered()), this, SLOT(help()));
379
380        about_action = new QAction(tr("&About"), this);
381        about_action->setStatusTip(tr("Display some information about the author and program version"));
382        connect(about_action, SIGNAL(triggered()), this, SLOT(about()));
383
384        new_text_editor_action = new QAction(tr("Open new &Text editor"), this);
385        new_text_editor_action->setStatusTip(tr("Display another text editor for editing the dock using a card code"));
386        connect(new_text_editor_action, SIGNAL(triggered()), this, SLOT(newTextEditor()));
387
388        undo_action = new QAction(tr("&Undo"), this);
389        redo_action = new QAction(tr("&Redo"), this);
390        undo_action->setStatusTip(tr("Undo latest changes"));
391        redo_action->setStatusTip(tr("Redo latest changes"));
392
393        next_card_action = new QAction(tr("&Next Card"), this);
394        next_card_action->setStatusTip(tr("Go to next Card"));
395        connect(next_card_action, SIGNAL(triggered()), this, SLOT(nextCard()));
396
397        prev_card_action = new QAction(tr("&Previous Card"), this);
398        prev_card_action->setStatusTip(tr("Go to previous Card"));
399        connect(prev_card_action, SIGNAL(triggered()), this, SLOT(prevCard()));
400
401        new_card_action = new QAction(tr("Insert &new Card"), this);
402        new_card_action->setStatusTip(tr("Insert new blanco card after current card"));
403        connect(new_card_action, SIGNAL(triggered()), this, SLOT(newCard()));
404
405        move_forwards_action = new QAction(tr("Move forwards"), this);
406        move_forwards_action->setStatusTip(tr("Move current card forwards"));
407        connect(move_forwards_action, SIGNAL(triggered()), this, SLOT(moveCardForwards()));
408
409        move_backwards_action = new QAction(tr("Move backwards"), this);
410        move_backwards_action->setStatusTip(tr("Move current card backwards"));
411        connect(move_backwards_action, SIGNAL(triggered()), this, SLOT(moveCardBackwards()));
412
413        // mehr Signale erst beim oeffnen/schliessen einer Datei
414}
415
416void EditorWindow::createMenus() {
417        file_menu = menuBar()->addMenu(tr("&File"));
418        file_menu->addAction(new_file_action);
419        file_menu->addSeparator();
420        file_menu->addAction(open_file_action);
421        file_menu->addAction(save_file_action);
422        file_menu->addAction(save_file_as_action);
423        file_menu->addSeparator();
424        file_menu->addAction(export_text_action);
425        file_menu->addAction(export_picture_action);
426        file_menu->addSeparator();
427        file_menu->addAction(close_file_action);
428        file_menu->addAction(quit_action);
429
430        edit_menu = menuBar()->addMenu(tr("&Edit"));
431        edit_menu->addAction(undo_action);
432        edit_menu->addAction(redo_action);
433        edit_menu->addSeparator();
434        // ---
435        // Cut, Copy, Insert
436        // --
437        // Insert punch card
438        // usw.
439
440        view_menu = menuBar()->addMenu(tr("&View"));
441        view_menu->addAction(new_text_editor_action);
442        view_menu->addSeparator();
443        // Ansichten:
444        // - Neue Textansicht hinzufuegen
445        // - Eigenschaften der Lochkarten-Ansicht hinzufuegen
446        // - Visualisierungsansicht aendern und so (Qualitaet)
447        // Navigation
448        // - Vor/Zurueck bei Lochkarte oder Spalte (letzteres doof)
449
450        devices_menu = menuBar()->addMenu(tr("&Devices"));
451        // hier alle Geraete auflisten, fuer die es Treiber gibt (=> driver, DriverOverview oder so)
452
453        help_menu = menuBar()->addMenu(tr("&Help"));
454        help_menu->addAction(help_action);
455        help_menu->addAction(tr("About &Qt"), qApp, SLOT(aboutQt()));
456        help_menu->addAction(about_action);
457}
458
459void EditorWindow::createToolBars() {
460        // ja ne... waere momentan noch das gleiche wie die Menus, also
461        // schon irgendwie iditisch. Egal:
462
463        navi_bar = addToolBar(tr("Navigation"));
464        navi_bar->addAction(prev_card_action);
465        navi_bar->addAction(next_card_action);
466        navi_bar->addAction(new_card_action);
467        navi_bar->addAction(this->move_backwards_action);
468        navi_bar->addAction(this->move_forwards_action);
469}
470
471void EditorWindow::createStatusBar() {
472        statusBar()->showMessage(tr("Ready"));
473}
474
475void EditorWindow::createDockWindows() {
476        // Kartenuebersicht:
477        navigator = new Navigator(this);
478        addDockWidget(Qt::LeftDockWidgetArea, navigator);
479        view_menu->addAction(navigator->toggleViewAction());
480        // Signale werden natuerlich dort gemacht und so.
481}
Note: See TracBrowser for help on using the repository browser.
© 2008 - 2013 technikum29 • Sven Köppel • Some rights reserved
Powered by Trac
Expect where otherwise noted, content on this site is licensed under a Creative Commons 3.0 License