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

Last change on this file since 49 was 49, checked in by sven, 10 years ago
  • Text editing part:

Improved Column counting
80 column line bar

  • Saving with Jones Format works
File size: 15.2 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        const FileFormat* format = FileFormatFactory::createFormat(
121                                FileFormatFactory::autoDetectFormat(file)
122                             );
123        Deck* new_deck = new Deck(format);
124        // Leser anschmeissen
125        if( new_deck->read(file) ) {
126                statusBar()->showMessage(QString(tr("Deck read in successfully")), 4000);
127        } else
128                qDebug() << "Errors while reading in the Deck.";
129        // Alte Datei rausschmeissen
130        closeDeck();
131        // Neue setzen
132        deck = new_deck;
133        this->file.setFileName( file.fileName() );
134        notifyFileOpened();
135}
136
137void EditorWindow::notifyFileOpened() {
138        if(deck) {
139                emit fileOpened(deck);
140                if(deck->count() > 0)
141                        emit setCard( deck->createIndex(0) );
142                else {
143                        // naja, das Deck ist *leer*. gibt also nix.
144                }
145        } else
146                qDebug("notifyFileOpened is supposed to be called when a file was *opened*");
147}
148
149void EditorWindow::newFile() {
150        if(maybeSave()) {
151                // alte Datei schliessen.
152                // d.h. defakto: Deck loeschen, neues erstellen.
153                // und dann alle darueber informieren. Sehr kompliziert.
154                closeDeck();
155                deck = new Deck();
156                notifyFileOpened();
157        }
158}
159
160void EditorWindow::openFile() {
161        if(maybeSave()) {
162                // Oeffnen-Dialog anzeigen.
163                QString filename = QFileDialog::getOpenFileName(this,
164                        tr("Open Card Deck File..."),
165                        QFileInfo(file).absolutePath(),
166                        tr("Jones Emulated Card Decks (*);;Card Editor XML-Files (*.xml *.cml)"));
167                if(!filename.isEmpty()) {
168                        loadDeck(filename);
169                }
170        }
171}
172
173bool EditorWindow::saveFile() {
174        if(!file.exists() || !deck->canSave())
175                return saveFileAs();
176        else
177                return deck->save(file);
178}
179
180bool EditorWindow::saveFileAs() {
181        // GUI anzeigen zum Speichern
182        QString filename = QFileDialog::getSaveFileName(this,
183                tr("Save Card Deck File..."),
184                QFileInfo(file).absolutePath(),
185                tr("Jones Emulator Card Decks (*);;Card Editor XML-Files (*.xml *.cml)"));
186        if(filename.isEmpty())
187                return false;
188        // Eigentlich jetzt: Nachschauen, welches Dateiformat zum Benutzen und so.
189        // stattdessen jetzt mal billig:
190        file.setFileName(filename);
191        if(deck->canSave()) {
192                // Nutze das bekannte Dateiformat
193                return deck->save(file);
194        } else {
195                // Nutze einfach mal
196                deck->setFormat( new JonesFileFormat );
197                if(deck->save(file)) {
198                        statusBar()->showMessage(QString(tr("Deck written successfully to %1").arg(filename)), 4000);
199                        return true;
200                } else {
201                        // todo: das hier als qmessagewindow oder so
202                        statusBar()->showMessage(QString(tr("Error while writing the deck")), 4000);
203                        return false;
204                }
205        }
206}
207
208void EditorWindow::exportText() {
209        // Strategie: In die text_editors-Liste schauen, wenn nur ein Editor
210        // drin ist, ist der zu nutzende Codec klar definiert. Sonst fragen,
211        // welchen Codec benutzen.
212        // Dann abspeichern oder so... hier waere natuerlich auch interessant,
213        // auf bestehende Dateinamen zurueckgreifen zu koennen...
214}
215
216void EditorWindow::exportPicture() {
217        // das haupteditorwidget bzw. nach Auswahl alle/bestimmte Karten als PNG/SVG/...
218        // rendern.
219}
220
221void EditorWindow::closeFile() {
222        if(maybeSave()) {
223                // Deck schliessen und fertig.
224                closeDeck();
225        }
226}
227
228void EditorWindow::quit() {
229        if(maybeSave()) {
230                // Deck schliesst automatisch ;-)
231                qApp->quit();
232        }
233}
234
235void EditorWindow::closeEvent(QCloseEvent* event) {
236        if(maybeSave()) {
237                event->accept();
238        } else
239                event->ignore();
240}
241
242void EditorWindow::help() {
243
244}
245
246void EditorWindow::about() {
247        QMessageBox::about(this, tr("About the Punch Card Editor"),
248                tr("<big><b>Punch Card Editor</b></big><br>Development version"
249                   "<br>This application is GPLv3 licensed"
250                   "<br>Copyright Sven Koeppel"));
251}
252
253void EditorWindow::newTextEditor() {
254        TextEditorDock* editor = new TextEditorDock(this);
255        addDockWidget(Qt::BottomDockWidgetArea, editor);
256        view_menu->addAction(editor->toggleViewAction());
257        text_editors.push_back(editor);
258
259        // Signale anschalten:
260        connect(editor, SIGNAL(cardSelected(DeckIndex)), this, SLOT(setCard(DeckIndex)));
261        connect(this, SIGNAL(cardSelected(DeckIndex)), editor, SLOT(setCard(DeckIndex)));
262        connect(this, SIGNAL(fileOpened(bool)), editor, SLOT(setVisible(bool)));
263        // TODO: klaeren, wer den Texteditor irgendwann mal killt
264        // -- ist diese Liste wirklich noetig? (ggf. *ja* wegen Textexport)
265}
266
267void EditorWindow::nextCard() {
268        setCard( getCurrentIndex() + 1);
269}
270
271void EditorWindow::prevCard() {
272        setCard( getCurrentIndex() - 1);
273}
274
275void EditorWindow::setCard(DeckIndex i) {
276        // wenn keine Datei offen und so
277        if(!deck) {
278                qDebug("No card open, skipping setCard broadcasting");
279                return;
280        }
281        if(! i.assertDeck(deck)) {
282                qDebug() << "Index i has wrong deck: " << i;
283                return;
284        }
285        i.normalize();
286
287        // neuen index setzen
288        current_index = i;
289
290        // Signal weitergeben:
291        emit cardSelected(i);
292}
293
294void EditorWindow::newCard() {
295        // append new Card behind current card
296        if(!deck) return;
297        if(deck->insert(current_index)) {
298                setCard( current_index+1 );
299        }
300
301        /*
302        int new_card_index = current_card + 1;
303        if(! deck->isValid(current_card))
304                new_card_index = 0; // insert card at beginning of deck
305        deck->insert( current_card + 1, new Card);
306        // ob das hier geht...
307        emit deck->contentsChanged(current_card, deck->count());
308        setCard( current_card + 1 );
309        */
310}
311
312void EditorWindow::moveCardForwards() {
313        if(!deck) return;
314        if(deck->move(current_index, current_index+1)) {
315                setCard( current_index+1 );
316        }
317        /*
318        //DeckIndex new_index(deck, current_index + 1);
319        if(!deck->isValid(current_card) || !deck->isValid(new_card_index)) {
320                qDebug() << "Invalid indices for moveCardForwards";
321                return;
322        }
323        deck->move(current_card, new_card_index);
324        setCard( new_card_index );
325        */
326}
327
328void EditorWindow::moveCardBackwards() {
329        if(!deck) return;
330        if(deck->move(current_index, current_index-1)) {
331                setCard( current_index-1 );
332        }
333        /*
334        int new_card_index = current_card - 1;
335        if(!deck->isValid(current_card) || !deck->isValid(new_card_index)) {
336                qDebug() << "Invalid indices for moveCardBackwards";
337                return;
338        }
339        deck->move(current_card, new_card_index);
340        setCard( new_card_index );
341        */
342}
343
344void EditorWindow::createActions() {
345        new_file_action = new QAction(tr("&New File (Empty Card Deck)"), this);
346        new_file_action->setShortcuts(QKeySequence::New);
347        new_file_action->setStatusTip(tr("Create a new empty card deck"));
348        connect(new_file_action, SIGNAL(triggered()), this, SLOT(newFile()));
349
350        new_window_action = new QAction(tr("&New Window"), this);
351        new_window_action->setStatusTip(tr("Open a new Application window to edit two card decks concurrently"));
352        connect(new_window_action, SIGNAL(triggered()), this, SLOT(newWindow()));
353
354        open_file_action = new QAction(tr("&Open File..."), this);
355        open_file_action->setShortcuts(QKeySequence::Open);
356        open_file_action->setStatusTip(tr("Open existing card file (any card deck file or text file)"));
357        connect(open_file_action, SIGNAL(triggered()), this, SLOT(openFile()));
358
359        save_file_action = new QAction(tr("&Save File"), this);
360        save_file_action->setShortcuts(QKeySequence::Save);
361        save_file_action->setStatusTip(tr("Save the current file as card deck"));
362        connect(save_file_action, SIGNAL(triggered()), this, SLOT(saveFile()));
363
364        save_file_as_action = new QAction(tr("&Save File as..."), this);
365        save_file_as_action->setShortcuts(QKeySequence::SaveAs);
366        save_file_as_action->setStatusTip(tr("Save the current card deck as another file"));
367        connect(save_file_as_action, SIGNAL(triggered()), this, SLOT(saveFileAs()));
368
369        export_text_action = new QAction(tr("&Export Text..."), this);
370        export_text_action->setStatusTip(tr("Save the decoded plaintext of the current card deck"));
371        connect(export_text_action, SIGNAL(triggered()), this, SLOT(exportText()));
372
373        export_picture_action = new QAction(tr("&Export Picture of Card..."), this);
374        export_picture_action->setStatusTip(tr("Save the visualisation of one or more cards as a picture"));
375        connect(export_picture_action, SIGNAL(triggered()), this, SLOT(exportPicture()));
376
377        close_file_action = new QAction(tr("&Close File"), this);
378        close_file_action->setStatusTip(tr("Close current file while staying in the application"));
379        connect(close_file_action, SIGNAL(triggered()), this, SLOT(closeFile()));
380
381        quit_action = new QAction(tr("&Quit"), this);
382        quit_action->setStatusTip(tr("Quit Application"));
383        connect(quit_action, SIGNAL(triggered()), qApp, SLOT(closeAllWindows()));
384
385        help_action = new QAction(tr("&Help"), this);
386        help_action->setStatusTip(tr("Get Help about the usage of this program"));
387        connect(help_action, SIGNAL(triggered()), this, SLOT(help()));
388
389        about_action = new QAction(tr("&About"), this);
390        about_action->setStatusTip(tr("Display some information about the author and program version"));
391        connect(about_action, SIGNAL(triggered()), this, SLOT(about()));
392
393        new_text_editor_action = new QAction(tr("Open new &Text editor"), this);
394        new_text_editor_action->setStatusTip(tr("Display another text editor for editing the dock using a card code"));
395        connect(new_text_editor_action, SIGNAL(triggered()), this, SLOT(newTextEditor()));
396
397        undo_action = new QAction(tr("&Undo"), this);
398        redo_action = new QAction(tr("&Redo"), this);
399        undo_action->setStatusTip(tr("Undo latest changes"));
400        redo_action->setStatusTip(tr("Redo latest changes"));
401
402        next_card_action = new QAction(tr("&Next Card"), this);
403        next_card_action->setStatusTip(tr("Go to next Card"));
404        connect(next_card_action, SIGNAL(triggered()), this, SLOT(nextCard()));
405
406        prev_card_action = new QAction(tr("&Previous Card"), this);
407        prev_card_action->setStatusTip(tr("Go to previous Card"));
408        connect(prev_card_action, SIGNAL(triggered()), this, SLOT(prevCard()));
409
410        new_card_action = new QAction(tr("Insert &new Card"), this);
411        new_card_action->setStatusTip(tr("Insert new blanco card after current card"));
412        connect(new_card_action, SIGNAL(triggered()), this, SLOT(newCard()));
413
414        move_forwards_action = new QAction(tr("Move forwards"), this);
415        move_forwards_action->setStatusTip(tr("Move current card forwards"));
416        connect(move_forwards_action, SIGNAL(triggered()), this, SLOT(moveCardForwards()));
417
418        move_backwards_action = new QAction(tr("Move backwards"), this);
419        move_backwards_action->setStatusTip(tr("Move current card backwards"));
420        connect(move_backwards_action, SIGNAL(triggered()), this, SLOT(moveCardBackwards()));
421
422        // mehr Signale erst beim oeffnen/schliessen einer Datei
423}
424
425void EditorWindow::createMenus() {
426        file_menu = menuBar()->addMenu(tr("&File"));
427        file_menu->addAction(new_file_action);
428        file_menu->addSeparator();
429        file_menu->addAction(open_file_action);
430        file_menu->addAction(save_file_action);
431        file_menu->addAction(save_file_as_action);
432        file_menu->addSeparator();
433        file_menu->addAction(export_text_action);
434        file_menu->addAction(export_picture_action);
435        file_menu->addSeparator();
436        file_menu->addAction(close_file_action);
437        file_menu->addAction(quit_action);
438
439        edit_menu = menuBar()->addMenu(tr("&Edit"));
440        edit_menu->addAction(undo_action);
441        edit_menu->addAction(redo_action);
442        edit_menu->addSeparator();
443        // ---
444        // Cut, Copy, Insert
445        // --
446        // Insert punch card
447        // usw.
448
449        view_menu = menuBar()->addMenu(tr("&View"));
450        view_menu->addAction(new_text_editor_action);
451        view_menu->addSeparator();
452        // Ansichten:
453        // - Neue Textansicht hinzufuegen
454        // - Eigenschaften der Lochkarten-Ansicht hinzufuegen
455        // - Visualisierungsansicht aendern und so (Qualitaet)
456        // Navigation
457        // - Vor/Zurueck bei Lochkarte oder Spalte (letzteres doof)
458
459        devices_menu = menuBar()->addMenu(tr("&Devices"));
460        // hier alle Geraete auflisten, fuer die es Treiber gibt (=> driver, DriverOverview oder so)
461
462        help_menu = menuBar()->addMenu(tr("&Help"));
463        help_menu->addAction(help_action);
464        help_menu->addAction(tr("About &Qt"), qApp, SLOT(aboutQt()));
465        help_menu->addAction(about_action);
466}
467
468void EditorWindow::createToolBars() {
469        // ja ne... waere momentan noch das gleiche wie die Menus, also
470        // schon irgendwie iditisch. Egal:
471
472        navi_bar = addToolBar(tr("Navigation"));
473        navi_bar->addAction(prev_card_action);
474        navi_bar->addAction(next_card_action);
475        navi_bar->addAction(new_card_action);
476        navi_bar->addAction(this->move_backwards_action);
477        navi_bar->addAction(this->move_forwards_action);
478}
479
480void EditorWindow::createStatusBar() {
481        statusBar()->showMessage(tr("Ready"));
482}
483
484void EditorWindow::createDockWindows() {
485        // Kartenuebersicht:
486        navigator = new Navigator(this);
487        addDockWidget(Qt::LeftDockWidgetArea, navigator);
488        view_menu->addAction(navigator->toggleViewAction());
489        // Signale werden natuerlich dort gemacht und so.
490}
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