source: trunk/tools/Writing Editor/scripts/writingEditor.py @ 242

Revision 234, 21.0 KB checked in by bretzel_parpg, 10 years ago (diff)

Started on the parser and dialog map

Line 
1#!/usr/bin/python
2
3#   This file is part of PARPG.
4
5#   PARPG is free software: you can redistribute it and/or modify
6#   it under the terms of the GNU General Public License as published by
7#   the Free Software Foundation, either version 3 of the License, or
8#   (at your option) any later version.
9
10#   PARPG is distributed in the hope that it will be useful,
11#   but WITHOUT ANY WARRANTY; without even the implied warranty of
12#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13#   GNU General Public License for more details.
14
15#   You should have received a copy of the GNU General Public License
16#   along with PARPG.  If not, see <http://www.gnu.org/licenses/>.
17
18import sys, os, codecs
19
20from PyQt4 import QtGui, QtCore
21from ui.editor_ui import Ui_writingEditor
22from ui.popupWindows import *
23from scripts.syntaxHighlight import SyntaxHighlighter
24from scripts.settings import Settings
25from scripts.dialogMap import DialogMap
26
27class WritingEditor(QtGui.QMainWindow):
28    """
29    The main class for the writing editor
30    """
31    def __init__(self, parent=None):
32        """
33        Initialize the editor
34        """
35        QtGui.QWidget.__init__(self, parent)
36       
37        self.settings = Settings()
38        self.settings.readSettingsFromFile('data/options.txt')
39        self.resize(int(self.settings.res_width), int(self.settings.res_height))
40
41        self.ui = Ui_writingEditor()
42        self.ui.setupUi(self)
43        self.dialogMap = DialogMap(self.settings, self.ui.main_edit, self.ui.dialog_map_tab)
44        self.syntax = SyntaxHighlighter(self.ui.main_edit.document())
45        self.syntaxCreated = True
46        self.changes = False
47        self.connectSignals()
48        self.setupMenus()
49
50        self.open_file_name = None
51        self.saveEnabled(False)
52        self.title_asterisk = False
53        self.ui.actionNone.setEnabled(False)
54        self.getRecentItems('data/recent_files.txt')
55
56
57    def setupMenus(self):
58        """
59        Setup the menus:
60        Add the shortcuts to all the menu's and also create the shorcuts
61        Add the images for the icons
62        @return: None
63        """
64        self.ui.actionNew_File.setText('&New File\tCtrl+N')
65        self.ui.actionOpen_File.setText('&Open File\tCtrl+O')
66        self.ui.actionSave.setText('&Save\tCtrl+S')
67        self.ui.actionSave_As.setText('Save &As\tCtrl+Shift+S')
68        self.ui.actionPrint.setText('&Print\tCtrl+P')
69        self.ui.actionExit.setText('&Exit\tCtrl+Q')
70        self.ui.actionUndo.setText('&Undo\tCtrl+Z')
71        self.ui.actionRedo.setText('&Redo\tCtrl+Y')
72        self.ui.actionCopy.setText('&Copy\tCtrl+C')
73        self.ui.actionCut.setText('C&ut\tCtrl+X')
74        self.ui.actionPaste.setText('&Paste\tCtrl+V')
75        self.ui.actionPreferences.setText('P&references\tCtrl+Shift+P')
76        self.ui.actionHelp.setText("&Help\tF1")
77        self.ui.actionAbout.setText('&About\tF2')
78        self.ui.actionNone.setText('None')
79
80        self.ui.actionNew_File.setShortcut(QtGui.QKeySequence('Ctrl+N'))
81        self.ui.actionOpen_File.setShortcut(QtGui.QKeySequence('Ctrl+O'))
82        self.ui.actionSave.setShortcut(QtGui.QKeySequence('Ctrl+S'))
83        self.ui.actionSave_As.setShortcut(QtGui.QKeySequence('Ctrl+Shift+S'))
84        self.ui.actionPrint.setShortcut(QtGui.QKeySequence('Ctrl+P'))
85        self.ui.actionExit.setShortcut(QtGui.QKeySequence('Ctrl+Q'))
86        self.ui.actionUndo.setShortcut(QtGui.QKeySequence('Ctrl+Z'))
87        self.ui.actionRedo.setShortcut(QtGui.QKeySequence('Ctrl+Y'))
88        self.ui.actionCopy.setShortcut(QtGui.QKeySequence('Ctrl+C'))
89        self.ui.actionCut.setShortcut(QtGui.QKeySequence('Ctrl+X'))
90        self.ui.actionPaste.setShortcut(QtGui.QKeySequence('Ctrl+V'))
91        self.ui.actionPreferences.setShortcut(QtGui.QKeySequence('Ctrl+Shift+P'))
92        self.ui.actionHelp.setShortcut(QtGui.QKeySequence('F1'))
93        self.ui.actionAbout.setShortcut(QtGui.QKeySequence('F2'))
94
95        self.ui.actionNew_File.setIcon(self.createIcon('new.png'))
96        self.ui.actionOpen_File.setIcon(self.createIcon('open.png'))
97        self.ui.actionSave.setIcon(self.createIcon('save.png'))
98        self.ui.actionSave_As.setIcon(self.createIcon('save_as.png'))
99        self.ui.actionPrint.setIcon(self.createIcon('printer.png'))
100        self.ui.actionExit.setIcon(self.createIcon('close.png'))
101        self.ui.actionUndo.setIcon(self.createIcon('undo.png'))
102        self.ui.actionRedo.setIcon(self.createIcon('redo.png'))
103        self.ui.actionCopy.setIcon(self.createIcon('copy.png'))
104        self.ui.actionCut.setIcon(self.createIcon('cut.png'))
105        self.ui.actionPaste.setIcon(self.createIcon('paste.png'))
106        self.ui.actionPreferences.setIcon(self.createIcon('preferences.png'))
107        self.ui.actionHelp.setIcon(self.createIcon('help.png'))
108        self.ui.actionAbout.setIcon(self.createIcon('about.png'))
109
110        self.ui.actionNew_File.setStatusTip('Create a new file')
111        self.ui.actionOpen_File.setStatusTip('Open a file')
112        self.ui.actionSave.setStatusTip('Save the open file to disk')
113        self.ui.actionSave_As.setStatusTip('Save the contents of the open file to a new file on the disk')
114        self.ui.actionPrint.setStatusTip('Print the open file')
115        self.ui.actionExit.setStatusTip('Exit the editor')
116        self.ui.actionUndo.setStatusTip('Undo the last action within the text editor')
117        self.ui.actionRedo.setStatusTip('Redo the last action within the text editor')
118        self.ui.actionCopy.setStatusTip('Copy the selected text to the clipboard')
119        self.ui.actionCut.setStatusTip('Delete the selected text and copy it to the clipboard')
120        self.ui.actionPaste.setStatusTip('Paste the text on the clipboard')
121        self.ui.actionPreferences.setStatusTip('Edit preferences with the editor')
122        self.ui.actionHelp.setStatusTip('Help with the editor and scripting language itself')
123        self.ui.actionAbout.setStatusTip('About the editor')
124        self.ui.actionNone.setStatusTip('There are no recent files')
125
126    def connectSignals(self):
127        """
128        Connect all the buttons, widgets, etc to their respective functions
129        @return: None
130        """
131        QtCore.QObject.connect(self.ui.main_tabs, QtCore.SIGNAL("currentChanged(int)"),
132                               self.onTabChanged)
133        QtCore.QObject.connect(self.ui.main_edit, QtCore.SIGNAL("textChanged()"),
134                               self.onTextChanged)
135
136        QtCore.QObject.connect(self.ui.actionNew_File, QtCore.SIGNAL("triggered()"),
137                               self.newFile)
138        QtCore.QObject.connect(self.ui.actionOpen_File, QtCore.SIGNAL("triggered()"),
139                               self.openFile)
140        QtCore.QObject.connect(self.ui.actionSave, QtCore.SIGNAL("triggered()"),
141                               self.saveFile)
142        QtCore.QObject.connect(self.ui.actionPrint, QtCore.SIGNAL("triggered()"),
143                               self.printFile)
144        QtCore.QObject.connect(self.ui.actionExit, QtCore.SIGNAL("triggered()"),
145                               lambda: self.quit('data/recent_files.txt'))
146
147        QtCore.QObject.connect(self.ui.actionCopy, QtCore.SIGNAL("triggered()"),
148                               self.ui.main_edit.copy)
149        QtCore.QObject.connect(self.ui.actionCut, QtCore.SIGNAL("triggered()"),
150                               self.ui.main_edit.cut)
151        QtCore.QObject.connect(self.ui.actionPaste, QtCore.SIGNAL("triggered()"),
152                               self.ui.main_edit.paste)
153        QtCore.QObject.connect(self.ui.actionRedo, QtCore.SIGNAL("triggered()"),
154                               self.ui.main_edit.redo)
155        QtCore.QObject.connect(self.ui.actionUndo, QtCore.SIGNAL("triggered()"),
156                               self.ui.main_edit.undo)
157        QtCore.QObject.connect(self.ui.actionPreferences, QtCore.SIGNAL("triggered()"),
158                               self.createPrefWindow)
159
160        QtCore.QObject.connect(self.ui.actionAbout, QtCore.SIGNAL("triggered()"),
161                               self.createAboutWindow)
162        QtCore.QObject.connect(self.ui.actionHelp, QtCore.SIGNAL("triggered()"),
163                               self.createHelpWindow)
164
165    def onTextChanged(self):
166        """
167        Function called when text is changed
168        """
169        if (self.syntaxCreated):
170            self.syntaxCreated = False
171
172        else:
173            self.saveEnabled(True)
174            self.changes = True
175            if (self.windowTitle() == "PARPG Writing Editor - Untitled"):
176                return
177
178            if (self.open_file_name == None):
179                self.setWindowTitle("PARPG Writing Editor - Untitled")
180                return
181
182            if (self.title_asterisk == False):
183                self.setWindowTitle(self.windowTitle() + " *")
184                self.title_asterisk = True
185           
186    def onTabChanged(self, index):
187        """
188        Check if the tab is the editor or the map viewer and disable/enable actions
189        accordingly
190        @type index: int
191        @param index: The index of the tab
192        @return: None
193        """
194        # it's the main editor
195        if (index == 0):
196            self.ui.actionCopy.setEnabled(True)
197            self.ui.actionCut.setEnabled(True)
198            self.ui.actionPaste.setEnabled(True)
199        # it's the dialog map
200        elif (index == 1):
201            self.dialogMap.parser.parse()
202            self.ui.actionCopy.setEnabled(False)
203            self.ui.actionCut.setEnabled(False)
204            self.ui.actionPaste.setEnabled(False)
205        else:
206            print 'Parameter index should be either 0 or 1. Got %d' % index
207
208    def createIcon(self, name):
209        """
210        Creates a QIcon object from the path name
211        @type name: string
212        @param name: the name of the file
213        @rtype: QtGui.QIcon
214        @return: The QIcon object
215        """
216        path = 'data/images/' + name
217        icon = QtGui.QIcon(path)
218        return icon
219
220    def newFile(self):
221        """
222        Start a new file
223        @return: None
224        """
225        self.open_file_name = None
226        self.ui.main_edit.setText("")
227        self.saveEnabled(False)
228
229    def saveFile(self, filename=None):
230        """
231        Save the contents of self.ui.main_edit to filename
232        If filename is None, then open a save dialog
233        @type filename: string
234        @param filename: the file to save to
235        @return: None
236        """
237        # if no filename argument is specified and there is no open file, open the save dialog
238        if (filename == None and self.open_file_name == None):
239            file_dialog = QtGui.QFileDialog(self)
240            file_dialog.setDefaultSuffix("dialog")
241            file_dialog.setNameFilter("Dialog Files (*.dialog)")
242            self.save_file_name = file_dialog.getSaveFileName()
243            self.open_file_name = self.save_file_name
244        # otherwise just save the file
245        else:
246            self.save_file_name = self.open_file_name
247
248        try:
249            text = self.ui.main_edit.toPlainText()
250            codec_file = codecs.open(self.save_file_name, 'w', 'utf-8')
251            codec_file.write(text)
252            codec_file.close()
253            self.saveEnabled(False)
254            last_slash = self.findLastSlash(self.save_file_name)
255            self.setWindowTitle("PARPG Writing Editor - " + self.save_file_name[last_slash+1:])
256            self.title_asterisk = False
257           
258        except IOError:
259            print 'Unable to save to file: %s' % self.save_file_name
260
261    def saveAs(self):
262        """
263        Open a dialog to save the current file as a new file
264        @return: None
265        """
266        self.saveFile()
267
268    def openFile(self, filename=None):
269        """
270        Open a file
271        @type filename: String
272        @param filename: the file to open
273        @return: None
274        """
275        old_file_name = self.open_file_name
276        if (filename == None):
277            file_dialog = QtGui.QFileDialog(self)
278            self.open_file_name = file_dialog.getOpenFileName()
279        else:
280            self.open_file_name = filename
281        try:
282            codec_file = codecs.open(self.open_file_name, 'r', 'utf-8')
283            codec_contents = codec_file.read()
284            self.ui.main_edit.setText(codec_contents)
285            self.saveEnabled(False)
286
287            new_dict = {}
288
289            try:
290                recent_length = len(self.recent_items)
291                keys = self.recent_items.keys()
292                if (recent_length != 0):
293                    keys.remove(keys[recent_length-1])
294                for key in keys:
295                    value = self.recent_items[key]
296                    new_dict[key] = value
297            except:
298                recent_length = 0
299               
300            last_slash = self.findLastSlash(self.open_file_name)
301            before = self.open_file_name[:last_slash+1]
302            after = self.open_file_name[last_slash+1:]
303            new_dict[after] = before
304               
305            self.recent_items = new_dict
306            self.updateRecentItems()
307
308            slash = self.findLastSlash(self.open_file_name)
309            window_title = 'PARPG Writing Editor - ' + self.open_file_name[slash+1:]
310            self.ui.writingEditor.setWindowTitle(window_title)
311            self.title_asterisk = False
312
313        except IOError:
314            print 'Unable to open file: %s' % self.open_file_name
315            self.open_file_name = old_file_name           
316
317    def printFile(self):
318        """
319        Print the currently open file
320        """
321        qprinter = QtGui.QPrinter()
322        print_dialog = PrintDialog(qprinter)
323        ret = print_dialog.run()
324        if (ret == QtGui.QDialog.Accepted):
325            self.ui.main_edit.document().print_(qprinter)
326
327    def saveEnabled(self, value):
328        """
329        Change whether save is enabled
330        @type value: bool
331        @param value: whether to enable or disable save
332        @return: None
333        """
334        self.ui.actionSave.setEnabled(value)
335        self.ui.actionSave_As.setEnabled(value)
336
337    def createAboutWindow(self):
338        """
339        Create the about the program window
340        @return: None
341        """
342        if (not hasattr(self, "about_window")):
343            self.about_window = AboutWindow(self)
344        self.about_window.show()
345
346    def createPrefWindow(self):
347        """
348        Create the preferences window
349        @return: None
350        """
351        if (not hasattr(self, "pref_window")):
352            self.pref_window = PrefWindow(self, self.settings)
353        self.pref_window.show()
354        self.pref_window.button_apply.setEnabled(True)
355
356    def createHelpWindow(self):
357        """
358        Create the help window
359        @return: None
360        """
361        if (not hasattr(self, "help_window")):
362            self.help_window = HelpWindow(self.settings, self)
363        self.help_window.show()
364
365    def getRecentItems(self, filename):
366        """
367        Reads all the filenames from the file filename that contains all the recent files
368        @type filename: string
369        @param filename: the path to the file
370        @return: None
371        """
372        self.recent_items = {}
373        try:
374            recent_files = open(filename, 'r').read().strip()
375           
376            if (recent_files == ""):
377                self.recent_items = None
378                return
379
380            recent_list = recent_files.split('\n')
381
382            for item in recent_list:
383                last_slash = self.findLastSlash(item)                       
384                before = item[:last_slash+1]
385                after = item[last_slash+1:]
386                self.recent_items[after] = before
387
388            self.updateRecentItems()
389            self.ui.menuRecent_Files.removeAction(self.ui.actionNone)
390
391        except IOError:
392            print 'Unable to read the recent files from file: %s\n'\
393                'No recent files will be displayed' % str(filename)
394           
395
396    def updateRecentItems(self):
397        """
398        Make the recent items show up in the gui
399        @return: None
400        """
401        try:
402            self.ui.menuRecent_files.removeAction(self.recent_1)
403        except:
404            print "Cannot remove action self.recent_1"
405        try:
406            self.ui.menuRecent_files.removeAction(self.recent_2)
407        except:
408            print "Cannot remove action self.recent_2"
409        try:
410            self.ui.menuRecent_files.removeAction(self.recent_3)
411        except:
412            print "Cannot remove action self.recent_3"
413        try:
414            self.ui.menuRecent_files.removeAction(self.recent_4)
415        except:
416            print "Cannot remove action self.recent_4"
417
418        recent_keys = []
419        for key in self.recent_items:
420            recent_keys.append(key)
421           
422        try:
423            self.recent_1 = QtGui.QAction(self)
424            self.recent_1.setObjectName(recent_keys[0])
425            self.recent_1.setText(recent_keys[0])
426            self.ui.menuRecent_Files.addAction(self.recent_1)
427            full_path_1 = self.recent_items[recent_keys[0]] + recent_keys[0]
428            QtCore.QObject.connect(self.recent_1, QtCore.SIGNAL('triggered()'),
429                                   lambda: self.openFile(full_path_1))
430           
431        except:
432            print 'Error generating widgets for recent item 1'
433           
434        try:
435            self.recent_2 = QtGui.QAction(self)
436            self.recent_2.setObjectName(recent_keys[1])
437            self.recent_2.setText(recent_keys[1])
438            self.ui.menuRecent_Files.addAction(self.recent_2, 0)
439            full_path_2 = self.recent_items[recent_keys[1]] + recent_keys[1]
440            QtCore.QObject.connect(self.recent_2, QtCore.SIGNAL('triggered()'),
441                                   lambda: self.openFile(full_path_2))
442                   
443        except:
444            print 'Error generating widgets for recent item 2'
445           
446        try:
447            self.recent_3 = QtGui.QAction(self)
448            self.recent_3.setObjectName(recent_keys[2])
449            self.recent_3.setText(recent_keys[2])
450            self.ui.menuRecent_Files.addAction(self.recent_3)
451            full_path_3 = self.recent_items[recent_keys[2]] + recent_keys[2]
452            QtCore.QObject.connect(self.recent_3, QtCore.SIGNAL('triggered()'),
453                                   lambda: self.openFile(full_path_3))
454       
455        except:
456            print 'Error generating widgets for recent item 3'
457
458        try:
459            self.recent_4 = QtGui.QAction(self)
460            self.recent_4.setObjectName(recent_keys[3])
461            self.recent_4.setText(recent_keys[3])
462            self.ui.menuRecent_Files.addAction(self.recent_4)
463            full_path_4 = self.recent_items[recent_keys[3]] + recent_keys[3]
464            QtCore.QObject.connect(self.recent_4, QtCore.SIGNAL('triggered()'),
465                                   lambda: self.openFile(full_path_4))
466       
467        except:
468            print 'Error generating widgets for recent item 4'
469           
470
471    def writeRecentItems(self, filename):
472        """
473        Write the recent items to the file filename
474        @type filename: string
475        @param filename: the file to write to
476        @return: None
477        """
478        if self.recent_items == None:
479            return
480        else:
481            try:
482                file_open = open(filename, 'w')
483                text = ""
484                for key in self.recent_items:
485                    full_path = self.recent_items[key] + key
486                    new_line = full_path + '\n'
487                    text += new_line
488                file_open.write(text)
489                file_open.close()
490                   
491            except IOError:
492                print 'Unable to write the recent files to file: %s\n'\
493                    'No recent files will be written' % str(filename)
494
495    def findLastSlash(self, string):
496        """
497        Find the last slash in string string
498        @type string: string
499        @param string: The string to find the last slash in
500        @return: None
501        """
502        back_num = 1
503        start = len(string)
504        while (True):
505            new_num = start - back_num
506            if (string[new_num] == '/'):
507                last_slash = new_num
508                break
509            else:
510                back_num += 1
511        return last_slash
512
513    def closeEvent(self, event):
514        """
515        Overrides the normal close event so it will ask if you want to save changes etc
516        @type event: QCloseEvent
517        @param event: the event (its provided by the qt system)
518        @return: None
519        """
520        if (self.changes):
521            window = ChangesWindow()
522            ret = window.run()
523            if (ret == QtGui.QMessageBox.Save):
524                self.saveFile()
525                self.writeRecentItems("data/recent_files.txt")
526                event.accept()
527            elif (ret == QtGui.QMessageBox.Discard):
528                self.writeRecentItems("data/recent_files.txt")
529                event.accept()
530            elif (ret == QtGui.QMessageBox.Cancel):
531                event.ignore()
532               
533                       
534    def quit(self, filename):
535        """
536        Quit and then write the recent files to filename and ask about changes
537        @type filename: string
538        @param filename: the file to write to
539        @return: None
540        """
541        self.ui.writingEditor.close()
Note: See TracBrowser for help on using the repository browser.