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

Revision 228, 20.6 KB checked in by bretzel_parpg, 10 years ago (diff)

Fixed whether or not the save buttons were enabled. Update the example dialog

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