changeset 477:3b5421d40f9b

Translator: major changes and additions. Moved Close Project menu item to Project menu. Added Save, Save All, Close and Close All menu items. Added class Document which all forms inherit from. Documents can indicated that they have been modified, they can be saved and closed. They are displayed as pages in the main tab widget. Fix: signals from changing the text in text controls programatically are ignored now. Fix: text taken from text controls must be passed to unicode() Catching errors from yaml.load() in classes LangFile and Project.
author Aziz K?ksal <aziz.koeksal@gmail.com>
date Sat, 10 Nov 2007 23:50:09 +0100
parents 773ddddb583d
children 2949146f2781
files trunk/src/translator/langfile.py trunk/src/translator/make_uis.sh trunk/src/translator/project.py trunk/src/translator/translator.py trunk/src/translator/translator.ui trunk/src/translator/ui_translator.py
diffstat 6 files changed, 268 insertions(+), 56 deletions(-) [+]
line wrap: on
line diff
--- a/trunk/src/translator/langfile.py	Fri Nov 09 16:06:06 2007 +0100
+++ b/trunk/src/translator/langfile.py	Sat Nov 10 23:50:09 2007 +0100
@@ -14,12 +14,19 @@
 
 class LangFile:
   def __init__(self, filePath):
-    self.filePath = filePath
+    from os import path
+    self.filePath = path.abspath(filePath)
     self.isSource = False
     self.source = None
     # Load language file and check data integrity.
-    doc = yaml.load(open(filePath, "r"))
-    self.doc = doc
+    try:
+      self.doc = yaml.load(open(filePath, "r"))
+    except yaml.YAMLError, e:
+      raise LoadingError(str(e))
+    self.verify()
+
+  def verify(self):
+    doc = self.doc
     self.checkType(doc, dict)
     try:
       self.langCode = str(doc["LangCode"])
@@ -77,4 +84,14 @@
     return {"ID":ID,"Text":"","Annot":"","LastEd":""}
 
   def save(self):
-    pass
+    #langFile = open(self.filePath, "w")
+    print "Saved", self.filePath
+    #print yaml.dump(self.doc, allow_unicode=True)
+    #langFile.close()
+
+  def getFileName(self):
+    from os import path
+    return path.basename(self.filePath)
+
+  def getFilePath(self):
+    return self.filePath
--- a/trunk/src/translator/make_uis.sh	Fri Nov 09 16:06:06 2007 +0100
+++ b/trunk/src/translator/make_uis.sh	Sat Nov 10 23:50:09 2007 +0100
@@ -1,6 +1,5 @@
 #!/bin/bash
 
 for ui_file in *.ui; do
-  echo $ui_file \> ui_`basename $ui_file .ui`.py
-  pyuic4 $ui_file > ui_`basename $ui_file .ui`.py
+  ./make_ui.sh $ui_file
 done
\ No newline at end of file
--- a/trunk/src/translator/project.py	Fri Nov 09 16:06:06 2007 +0100
+++ b/trunk/src/translator/project.py	Sat Nov 10 23:50:09 2007 +0100
@@ -28,8 +28,14 @@
   def __init__(self, projectPath):
     self.projectPath = projectPath
     # Load project file and check data integrity.
-    doc = yaml.load(open(projectPath, "r"))
-    self.doc = doc
+    try:
+      self.doc = yaml.load(open(projectPath, "r"))
+    except yaml.YAMLError, e:
+      raise LoadingError(str(e))
+    self.verify()
+
+  def verify(self):
+    doc = self.doc
     self.checkType(doc, dict)
     try:
       self.name = str(doc["Name"])
--- a/trunk/src/translator/translator.py	Fri Nov 09 16:06:06 2007 +0100
+++ b/trunk/src/translator/translator.py	Sat Nov 10 23:50:09 2007 +0100
@@ -22,6 +22,12 @@
 g_settingsFile = os.path.join(g_scriptDir, "settings.yaml")
 g_settings = {}
 
+Qt = QtCore.Qt
+Qt.connect = QtCore.QObject.connect
+Qt.disconnect = QtCore.QObject.disconnect
+Qt.SIGNAL = QtCore.SIGNAL
+Qt.SLOT = QtCore.SLOT
+
 def QTabWidgetCloseAll(self):
  for i in range(0, self.count()):
    widget = self.widget(0)
@@ -44,16 +50,20 @@
     self.projectDock.setWidget(self.projectTree)
     self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.projectDock)
     # Custom connections
-    QtCore.QObject.connect(self.action_About, QtCore.SIGNAL("triggered()"), self.showAboutDialog)
-    QtCore.QObject.connect(self.action_New_Project, QtCore.SIGNAL("triggered()"), self.createNewProject)
-    QtCore.QObject.connect(self.action_Open_Project, QtCore.SIGNAL("triggered()"), self.openProjectAction)
-    QtCore.QObject.connect(self.action_Close_Project, QtCore.SIGNAL("triggered()"), self.closeProject)
-    QtCore.QObject.connect(self.action_Properties, QtCore.SIGNAL("triggered()"), self.showProjectProperties)
-    QtCore.QObject.connect(self.action_Add_Catalogue, QtCore.SIGNAL("triggered()"), self.addCatalogue)
-    QtCore.QObject.connect(self.action_Add_New_Catalogue, QtCore.SIGNAL("triggered()"), self.addNewCatalogue)
-    QtCore.QObject.connect(self.projectTree, QtCore.SIGNAL("itemDoubleClicked(QTreeWidgetItem*,int)"), self.projectTreeItemDblClicked)
-    QtCore.QObject.connect(self.projectTree, QtCore.SIGNAL("onKeyEnter"), self.projectTreeItemActivated)
-    QtCore.QObject.connect(self.projectTree, QtCore.SIGNAL("onKeyDelete"), self.projectTreeItemDeleted)
+    Qt.connect(self.action_About, Qt.SIGNAL("triggered()"), self.showAboutDialog)
+    Qt.connect(self.action_New_Project, Qt.SIGNAL("triggered()"), self.createNewProject)
+    Qt.connect(self.action_Open_Project, Qt.SIGNAL("triggered()"), self.openProjectAction)
+    Qt.connect(self.action_Close_Project, Qt.SIGNAL("triggered()"), self.closeProject)
+    Qt.connect(self.action_Save, Qt.SIGNAL("triggered()"), self.saveForm)
+    Qt.connect(self.action_Save_All, Qt.SIGNAL("triggered()"), self.saveAllForms)
+    Qt.connect(self.action_Close, Qt.SIGNAL("triggered()"), self.closeForm)
+    Qt.connect(self.action_Close_All, Qt.SIGNAL("triggered()"), self.closeAllForms)
+    Qt.connect(self.action_Properties, Qt.SIGNAL("triggered()"), self.showProjectProperties)
+    Qt.connect(self.action_Add_Catalogue, Qt.SIGNAL("triggered()"), self.addCatalogue)
+    Qt.connect(self.action_Add_New_Catalogue, QtCore.SIGNAL("triggered()"), self.addNewCatalogue)
+    Qt.connect(self.projectTree, Qt.SIGNAL("itemDoubleClicked(QTreeWidgetItem*,int)"), self.projectTreeItemDblClicked)
+    Qt.connect(self.projectTree, Qt.SIGNAL("onKeyEnter"), self.projectTreeItemActivated)
+    Qt.connect(self.projectTree, Qt.SIGNAL("onKeyDelete"), self.projectTreeItemDeleted)
 
     self.readSettings()
 
@@ -108,9 +118,9 @@
   def closeProject(self):
     if self.project == None:
       return True
-
-    button = QtGui.QMessageBox.question(self, "Closing", "Close the current project?", QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Cancel)
-    if button == QtGui.QMessageBox.Cancel:
+    MB = QtGui.QMessageBox
+    button = MB.question(self, "Closing", "Close the current project?", MB.Ok | MB.Cancel, MB.Cancel)
+    if button == MB.Cancel:
       return False
 
     del self.project
@@ -121,11 +131,21 @@
     return True
 
   def enableMenuItems(self):
-    self.action_Close_Project.setEnabled(True)
+    #self.action_Close_Project.setEnabled(True)
+    for action in [ self.action_Save,
+                    self.action_Save_All,
+                    self.action_Close,
+                    self.action_Close_All ]:
+      action.setEnabled(True)
     self.menubar.insertMenu(self.menu_Help.menuAction(), self.menu_Project)
 
   def disableMenuItems(self):
-    self.action_Close_Project.setEnabled(False)
+    #self.action_Close_Project.setEnabled(False)
+    for action in [ self.action_Save,
+                    self.action_Save_All,
+                    self.action_Close,
+                    self.action_Close_All ]:
+      action.setEnabled(False)
     self.menubar.removeAction(self.menu_Project.menuAction())
 
   def projectTreeItemDblClicked(self, item, int):
@@ -136,21 +156,66 @@
       return
 
     if isinstance(item, LangFileItem):
-      index = self.pages.indexOf(item.msgForm)
+      msgForm = None
+      if not item.isDocOpen():
+        msgForm = item.openDoc()
+        msgForm.setModifiedCallback(self.formModified)
+      index = self.pages.indexOf(msgForm)
       if index == -1:
-        index = self.pages.addTab(item.msgForm, item.text(0))
+        index = self.pages.addTab(msgForm, msgForm.getDocumentTitle())
       self.pages.setCurrentIndex(index)
-      item.msgForm.updateData()
+      msgForm.updateData()
 
   def projectTreeItemDeleted(self, item):
     pass
 
+  def formModified(self, form):
+    # Append an asterisk to the tab label
+    index = self.pages.indexOf(form)
+    text = form.getDocumentTitle() + "*"
+    self.pages.setTabText(index, text)
+
+  def saveForm(self):
+    self.saveDocument(self.pages.currentWidget())
+
+  def saveAllForms(self):
+    for i in range(0, self.pages.count()):
+      self.saveDocument(self.pages.widget(i))
+
+  def saveDocument(self, form):
+    if form.isModified:
+      index = self.pages.indexOf(form)
+      text = form.getDocumentTitle()
+      self.pages.setTabText(index, text)
+      form.save()
+
+  def closeForm(self):
+    if self.pages.currentWidget():
+      self.closeDocument(self.pages.currentWidget())
+
+  def closeAllForms(self):
+    for i in range(0, self.pages.count()):
+      self.closeDocument(self.pages.widget(i))
+
+  def closeDocument(self, form):
+    if form.isModified:
+      MB = QtGui.QMessageBox
+      button = MB.question(self, "Closing Document", "The document '%s' has been modified.\nDo you want to save the changes?" % form.getDocumentFullPath(), MB.Save | MB.Discard | MB.Cancel, MB.Cancel)
+      if button == MB.Cancel:
+        return False
+      if button == MB.Save:
+        self.saveDocument(form)
+    index = self.pages.indexOf(form)
+    self.pages.removeTab(index)
+    form.close()
+    return True
+
   def closeEvent(self, event):
     if self.closeProject() == False:
       event.ignore()
       return
-    # Exitting
     self.writeSettings()
+    # Closing application
 
   def moveToCenterOfDesktop(self):
     rect = QtGui.QApplication.desktop().geometry()
@@ -187,6 +252,7 @@
     }
     yaml.dump(g_settings, open(g_settingsFile, "w")) #default_flow_style=False
 
+
 class MessageItem(QtGui.QTreeWidgetItem):
   def __init__(self, msg):
     QtGui.QTreeWidgetItem.__init__(self, [str(msg["ID"]), msg["Text"]])
@@ -201,9 +267,41 @@
   def setMsgAnnot(self, text):
     self.msg["Annot"] = text
 
-class MsgForm(QtGui.QWidget, Ui_MsgForm):
+
+class Document(QtGui.QWidget):
+  def __init__(self):
+    QtGui.QWidget.__init__(self)
+    self.isModified = False
+    self.modifiedCallback = None
+    self.documentTitle = ""
+    self.documentFullPath = ""
+
+  def modified(self):
+    if not self.isModified:
+      self.isModified = True
+      self.modifiedCallback(self)
+
+  def setModifiedCallback(self, func):
+    self.modifiedCallback = func
+
+  def save(self):
+    self.isModified = False
+
+  def close(self):
+    self.emit(Qt.SIGNAL("closed()"))
+    QtGui.QWidget.close(self)
+
+  def getDocumentTitle(self):
+    return self.documentTitle
+
+  def getDocumentFullPath(self):
+    return self.documentFullPath
+
+class MsgForm(Document, Ui_MsgForm):
   def __init__(self, langFile):
-    QtGui.QWidget.__init__(self)
+    Document.__init__(self)
+    self.documentTitle = langFile.getFileName()
+    self.documentFullPath = langFile.getFilePath()
     self.setupUi(self)
     self.vboxlayout.setMargin(0)
 
@@ -216,21 +314,24 @@
     for msg in self.langFile.messages:
       self.treeWidget.addTopLevelItem(MessageItem(msg))
 
-    QtCore.QObject.connect(self.treeWidget, QtCore.SIGNAL("currentItemChanged (QTreeWidgetItem *,QTreeWidgetItem *)"), self.treeItemChanged)
-    QtCore.QObject.connect(self.translEdit, QtCore.SIGNAL("textChanged()"), self.translEditTextChanged)
-    QtCore.QObject.connect(self.translAnnotEdit, QtCore.SIGNAL("textChanged()"), self.translAnnotEditTextChanged)
+    Qt.connect(self.treeWidget, Qt.SIGNAL("currentItemChanged (QTreeWidgetItem *,QTreeWidgetItem *)"), self.treeItemChanged)
+    Qt.connect(self.translEdit, Qt.SIGNAL("textChanged()"), self.translEditTextChanged)
+    Qt.connect(self.translAnnotEdit, Qt.SIGNAL("textChanged()"), self.translAnnotEditTextChanged)
 
     #self.translEdit.focusOutEvent = self.translEditFocusOut
 
   def treeItemChanged(self, current, previous):
-    self.currentItem = current
     if current == None:
       self.setTranslMsg("")
       self.setSourceMsg("")
       return
     ID = current.getID()
+    # Set the text controls.
+    # The slots receiving text changed signals do nothing if self.currentItem is None.
+    self.currentItem = None
     self.setTranslMsg(self.langFile.getMsg(ID))
     self.setSourceMsg(self.langFile.source.getMsg(ID))
+    self.currentItem = current
 
   def setTranslMsg(self, msg):
     self.translEdit.setText(msg["Text"])
@@ -250,14 +351,16 @@
 
   def translEditTextChanged(self):
     if self.currentItem:
-      text = self.translEdit.toPlainText()
+      text = unicode(self.translEdit.toPlainText())
       self.currentItem.setText(self.colText, text)
       self.currentItem.setMsgText(text)
+      self.modified()
 
   def translAnnotEditTextChanged(self):
     if self.currentItem:
-      text = self.translAnnotEdit.toPlainText()
+      text = unicode(self.translAnnotEdit.toPlainText())
       self.currentItem.setMsgAnnot(text)
+      self.modified()
 
   def updateData(self):
     if self.currentItem == None:
@@ -271,6 +374,11 @@
     if text != msg["Annot"]:
       self.sourceAnnotEdit.setText(msg["Annot"])
 
+  def save(self):
+    Document.save(self)
+    self.langFile.save()
+
+
 class MsgFormSource(MsgForm):
   def __init__(self, langFile):
     MsgForm.__init__(self, langFile)
@@ -281,28 +389,31 @@
               self.label_5]:
       x.close()
 
-    QtCore.QObject.connect(self.sourceEdit, QtCore.SIGNAL("textChanged()"), self.sourceEditTextChanged)
-    QtCore.QObject.connect(self.sourceAnnotEdit, QtCore.SIGNAL("textChanged()"), self.sourceAnnotEditTextChanged)
+    Qt.connect(self.sourceEdit, Qt.SIGNAL("textChanged()"), self.sourceEditTextChanged)
+    Qt.connect(self.sourceAnnotEdit, Qt.SIGNAL("textChanged()"), self.sourceAnnotEditTextChanged)
 
   def treeItemChanged(self, current, previous):
-    self.currentItem = current
     if current == None:
       self.setSourceMsg("")
       return
     ID = current.getID()
+    self.currentItem = None
     self.setSourceMsg(self.langFile.getMsg(ID))
+    self.currentItem = current
 
   def sourceEditTextChanged(self):
     if self.currentItem:
-      text = self.sourceEdit.toPlainText()
+      text = unicode(self.sourceEdit.toPlainText())
       self.currentItem.setText(self.colText, text)
       self.currentItem.setMsgText(text)
+      self.modified()
 
   def sourceAnnotEditTextChanged(self):
     if self.currentItem:
-      text = self.sourceAnnotEdit.toPlainText()
+      text = unicode(self.sourceAnnotEdit.toPlainText())
       #self.currentItem.setText(self.colAnnot, text)
       self.currentItem.setMsgAnnot(text)
+      self.modified()
 
 
 class MsgIDItem(QtGui.QTreeWidgetItem):
@@ -313,10 +424,23 @@
   def __init__(self, parent, langFile):
     QtGui.QTreeWidgetItem.__init__(self, parent, [langFile.langCode])
     self.langFile = langFile
-    if langFile.isSource:
-      self.msgForm = MsgFormSource(langFile)
-    else:
-      self.msgForm = MsgForm(langFile)
+    self.msgForm = None
+
+  def isDocOpen(self):
+    return self.msgForm != None
+
+  def openDoc(self):
+    if self.msgForm == None:
+      if self.langFile.isSource:
+        self.msgForm = MsgFormSource(self.langFile)
+      else:
+        self.msgForm = MsgForm(self.langFile)
+      Qt.connect(self.msgForm, Qt.SIGNAL("closed()"), self.docClosed)
+    return self.msgForm
+
+  def docClosed(self):
+    print "docClosed()"
+    self.msgForm = None
 
 class ProjectItem(QtGui.QTreeWidgetItem):
   def __init__(self, text):
@@ -333,9 +457,9 @@
     Qt = QtCore.Qt
     key = event.key()
     if key in [Qt.Key_Enter, Qt.Key_Return]:
-      self.emit(QtCore.SIGNAL("onKeyEnter"), self.currentItem())
+      self.emit(Qt.SIGNAL("onKeyEnter"), self.currentItem())
     elif key == Qt.Key_Delete:
-      self.emit(QtCore.SIGNAL("onKeyDelete"), self.currentItem())
+      self.emit(Qt.SIGNAL("onKeyDelete"), self.currentItem())
 
   def setProject(self, project):
     self.project = project
@@ -383,7 +507,7 @@
     QtGui.QDialog.__init__(self)
     self.setupUi(self)
 
-    QtCore.QObject.connect(self.pickFileButton, QtCore.SIGNAL("clicked()"), self.pickFilePath)
+    Qt.connect(self.pickFileButton, Qt.SIGNAL("clicked()"), self.pickFilePath)
 
   def pickFilePath(self):
     filePath = QtGui.QFileDialog.getSaveFileName(self, "New Project File", g_CWD, "Translator Project (*%s)" % g_projectExt);
--- a/trunk/src/translator/translator.ui	Fri Nov 09 16:06:06 2007 +0100
+++ b/trunk/src/translator/translator.ui	Sat Nov 10 23:50:09 2007 +0100
@@ -30,7 +30,12 @@
     </property>
     <addaction name="action_Open_Project" />
     <addaction name="action_New_Project" />
-    <addaction name="action_Close_Project" />
+    <addaction name="separator" />
+    <addaction name="action_Save" />
+    <addaction name="action_Save_All" />
+    <addaction name="separator" />
+    <addaction name="action_Close" />
+    <addaction name="action_Close_All" />
     <addaction name="separator" />
     <addaction name="action_Quit" />
    </widget>
@@ -49,6 +54,8 @@
     <addaction name="action_Build_Project" />
     <addaction name="separator" />
     <addaction name="action_Properties" />
+    <addaction name="separator" />
+    <addaction name="action_Close_Project" />
    </widget>
    <addaction name="menu_File" />
    <addaction name="menu_Project" />
@@ -99,9 +106,9 @@
     <string>Ctrl+O</string>
    </property>
   </action>
-  <action name="action_Close_Project" >
+  <action name="action_Close" >
    <property name="text" >
-    <string>&amp;Close Project</string>
+    <string>&amp;Close</string>
    </property>
    <property name="shortcut" >
     <string>Ctrl+W</string>
@@ -112,6 +119,38 @@
     <string>Add new catalogue...</string>
    </property>
   </action>
+  <action name="action_Close_Project" >
+   <property name="text" >
+    <string>&amp;Close Project</string>
+   </property>
+   <property name="shortcut" >
+    <string>Ctrl+F4</string>
+   </property>
+  </action>
+  <action name="action_Save" >
+   <property name="text" >
+    <string>&amp;Save</string>
+   </property>
+   <property name="shortcut" >
+    <string>Ctrl+S</string>
+   </property>
+  </action>
+  <action name="action_Save_All" >
+   <property name="text" >
+    <string>Save &amp;All</string>
+   </property>
+   <property name="shortcut" >
+    <string>Ctrl+Shift+S</string>
+   </property>
+  </action>
+  <action name="action_Close_All" >
+   <property name="text" >
+    <string>Clos&amp;e All</string>
+   </property>
+   <property name="shortcut" >
+    <string>Ctrl+Shift+W</string>
+   </property>
+  </action>
  </widget>
  <resources/>
  <connections>
--- a/trunk/src/translator/ui_translator.py	Fri Nov 09 16:06:06 2007 +0100
+++ b/trunk/src/translator/ui_translator.py	Sat Nov 10 23:50:09 2007 +0100
@@ -2,7 +2,7 @@
 
 # Form implementation generated from reading ui file 'translator.ui'
 #
-# Created: Sun Oct 21 17:33:29 2007
+# Created: Fri Nov  9 20:02:57 2007
 #      by: PyQt4 UI code generator 4.1
 #
 # WARNING! All changes made in this file will be lost!
@@ -61,14 +61,31 @@
         self.action_Open_Project = QtGui.QAction(MainWindow)
         self.action_Open_Project.setObjectName("action_Open_Project")
 
+        self.action_Close = QtGui.QAction(MainWindow)
+        self.action_Close.setObjectName("action_Close")
+
+        self.action_Add_New_Catalogue = QtGui.QAction(MainWindow)
+        self.action_Add_New_Catalogue.setObjectName("action_Add_New_Catalogue")
+
         self.action_Close_Project = QtGui.QAction(MainWindow)
         self.action_Close_Project.setObjectName("action_Close_Project")
 
-        self.action_Add_New_Catalogue = QtGui.QAction(MainWindow)
-        self.action_Add_New_Catalogue.setObjectName("action_Add_New_Catalogue")
+        self.action_Save = QtGui.QAction(MainWindow)
+        self.action_Save.setObjectName("action_Save")
+
+        self.action_Save_All = QtGui.QAction(MainWindow)
+        self.action_Save_All.setObjectName("action_Save_All")
+
+        self.action_Close_All = QtGui.QAction(MainWindow)
+        self.action_Close_All.setObjectName("action_Close_All")
         self.menu_File.addAction(self.action_Open_Project)
         self.menu_File.addAction(self.action_New_Project)
-        self.menu_File.addAction(self.action_Close_Project)
+        self.menu_File.addSeparator()
+        self.menu_File.addAction(self.action_Save)
+        self.menu_File.addAction(self.action_Save_All)
+        self.menu_File.addSeparator()
+        self.menu_File.addAction(self.action_Close)
+        self.menu_File.addAction(self.action_Close_All)
         self.menu_File.addSeparator()
         self.menu_File.addAction(self.action_Quit)
         self.menu_Help.addAction(self.action_About)
@@ -77,6 +94,8 @@
         self.menu_Project.addAction(self.action_Build_Project)
         self.menu_Project.addSeparator()
         self.menu_Project.addAction(self.action_Properties)
+        self.menu_Project.addSeparator()
+        self.menu_Project.addAction(self.action_Close_Project)
         self.menubar.addAction(self.menu_File.menuAction())
         self.menubar.addAction(self.menu_Project.menuAction())
         self.menubar.addAction(self.menu_Help.menuAction())
@@ -100,7 +119,15 @@
         self.action_Build_Project.setText(QtGui.QApplication.translate("MainWindow", "&Build Project", None, QtGui.QApplication.UnicodeUTF8))
         self.action_Open_Project.setText(QtGui.QApplication.translate("MainWindow", "&Open Project...", None, QtGui.QApplication.UnicodeUTF8))
         self.action_Open_Project.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+O", None, QtGui.QApplication.UnicodeUTF8))
+        self.action_Close.setText(QtGui.QApplication.translate("MainWindow", "&Close", None, QtGui.QApplication.UnicodeUTF8))
+        self.action_Close.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+W", None, QtGui.QApplication.UnicodeUTF8))
+        self.action_Add_New_Catalogue.setText(QtGui.QApplication.translate("MainWindow", "Add new catalogue...", None, QtGui.QApplication.UnicodeUTF8))
         self.action_Close_Project.setText(QtGui.QApplication.translate("MainWindow", "&Close Project", None, QtGui.QApplication.UnicodeUTF8))
-        self.action_Close_Project.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+W", None, QtGui.QApplication.UnicodeUTF8))
-        self.action_Add_New_Catalogue.setText(QtGui.QApplication.translate("MainWindow", "Add new catalogue...", None, QtGui.QApplication.UnicodeUTF8))
+        self.action_Close_Project.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+F4", None, QtGui.QApplication.UnicodeUTF8))
+        self.action_Save.setText(QtGui.QApplication.translate("MainWindow", "&Save", None, QtGui.QApplication.UnicodeUTF8))
+        self.action_Save.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+S", None, QtGui.QApplication.UnicodeUTF8))
+        self.action_Save_All.setText(QtGui.QApplication.translate("MainWindow", "Save &All", None, QtGui.QApplication.UnicodeUTF8))
+        self.action_Save_All.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+Shift+S", None, QtGui.QApplication.UnicodeUTF8))
+        self.action_Close_All.setText(QtGui.QApplication.translate("MainWindow", "Clos&e All", None, QtGui.QApplication.UnicodeUTF8))
+        self.action_Close_All.setShortcut(QtGui.QApplication.translate("MainWindow", "Ctrl+Shift+W", None, QtGui.QApplication.UnicodeUTF8))