diff --git a/openlp/core/ui/firsttimeform.py b/openlp/core/ui/firsttimeform.py index dc1932015..dade26cf9 100644 --- a/openlp/core/ui/firsttimeform.py +++ b/openlp/core/ui/firsttimeform.py @@ -140,6 +140,8 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard): return FirstTimePage.Songs elif self.currentId() == FirstTimePage.Progress: return -1 + elif self.currentId() == FirstTimePage.NoInternet: + return FirstTimePage.Progress else: return self.currentId() + 1 @@ -147,11 +149,7 @@ class FirstTimeForm(QtGui.QWizard, Ui_FirstTimeWizard): """ Detects Page changes and updates as approprate. """ - if pageId == FirstTimePage.NoInternet: - self.finishButton.setVisible(True) - self.finishButton.setEnabled(True) - self.nextButton.setVisible(False) - elif pageId == FirstTimePage.Defaults: + if pageId == FirstTimePage.Defaults: self.themeComboBox.clear() for iter in xrange(self.themesListWidget.count()): item = self.themesListWidget.item(iter) diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index 3931139d1..c413ec8c9 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -34,7 +34,7 @@ from PyQt4 import QtCore, QtGui, QtWebKit from PyQt4.phonon import Phonon from openlp.core.lib import Receiver, build_html, ServiceItem, image_to_byte, \ - build_icon, translate + translate from openlp.core.ui import HideMode @@ -69,8 +69,6 @@ class MainDisplay(DisplayWidget): self.hideMode = None self.videoHide = False self.override = {} - mainIcon = build_icon(u':/icon/openlp-logo-16x16.png') - self.setWindowIcon(mainIcon) self.retranslateUi() self.setStyleSheet(u'border: 0px; margin: 0px; padding: 0px;') self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.Tool | diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 32a28d474..cb01e37a1 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -71,7 +71,7 @@ class Ui_MainWindow(object): mainWindow.setObjectName(u'MainWindow') mainWindow.resize(self.settingsmanager.width, self.settingsmanager.height) - mainWindow.setWindowIcon(build_icon(u':/icon/openlp-logo-16x16.png')) + mainWindow.setWindowIcon(build_icon(u':/icon/openlp-logo-64x64.png')) mainWindow.setDockNestingEnabled(True) # Set up the main container, which contains all the other form widgets. self.MainContent = QtGui.QWidget(mainWindow) diff --git a/openlp/core/ui/shortcutlistform.py b/openlp/core/ui/shortcutlistform.py index 26bfddadd..3136c9b1f 100644 --- a/openlp/core/ui/shortcutlistform.py +++ b/openlp/core/ui/shortcutlistform.py @@ -29,6 +29,7 @@ import re from PyQt4 import QtCore, QtGui +from openlp.core.lib import Receiver from openlp.core.utils import translate from openlp.core.utils.actions import ActionList from shortcutlistdialog import Ui_ShortcutListDialog @@ -95,43 +96,7 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog): QtCore.Qt.ShiftModifier: key_string = u'Shift+' + key_string key_sequence = QtGui.QKeySequence(key_string) - # The action we are attempting to change. - changing_action = self._currentItemAction() - shortcut_valid = True - for category in self.action_list.categories: - for action in category.actions: - shortcuts = self._actionShortcuts(action) - if key_sequence not in shortcuts: - continue - if action is changing_action: - if self.primaryPushButton.isChecked() and \ - shortcuts.index(key_sequence) == 0: - continue - if self.alternatePushButton.isChecked() and \ - shortcuts.index(key_sequence) == 1: - continue - # Have the same parent, thus they cannot have the same shortcut. - if action.parent() is changing_action.parent(): - shortcut_valid = False - # The new shortcut is already assigned, but if both shortcuts - # are only valid in a different widget the new shortcut is - # vaild, because they will not interfere. - if action.shortcutContext() in [QtCore.Qt.WindowShortcut, - QtCore.Qt.ApplicationShortcut]: - shortcut_valid = False - if changing_action.shortcutContext() in \ - [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]: - shortcut_valid = False - if not shortcut_valid: - QtGui.QMessageBox.warning(self, - translate('OpenLP.ShortcutListDialog', 'Duplicate Shortcut'), - unicode(translate('OpenLP.ShortcutListDialog', 'The shortcut ' - '"%s" is already assigned to another action, please ' - 'use a different shortcut.')) % key_sequence.toString(), - QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok), - QtGui.QMessageBox.Ok - ) - else: + if self._validiate_shortcut(self._currentItemAction(), key_sequence): if self.primaryPushButton.isChecked(): self._adjustButton(self.primaryPushButton, False, text=key_sequence.toString()) @@ -227,6 +192,12 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog): new_shortcuts.append( QtGui.QKeySequence(self.alternatePushButton.text())) self.changedActions[action] = new_shortcuts + if not self.primaryPushButton.text(): + # When we do not have a primary shortcut, the just entered alternate + # shortcut will automatically become the primary shortcut. That is + # why we have to adjust the primary button's text. + self.primaryPushButton.setText(self.alternatePushButton.text()) + self.alternatePushButton.setText(u'') self.refreshShortcutList() def onItemDoubleClicked(self, item, column): @@ -374,6 +345,16 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog): new_shortcuts = [] if len(action.defaultShortcuts) != 0: new_shortcuts.append(action.defaultShortcuts[0]) + # We have to check if the primary default shortcut is available. But + # we only have to check, if the action has a default primary + # shortcut (an "empty" shortcut is always valid and if the action + # does not have a default primary shortcut, then the alternative + # shortcut (not the default one) will become primary shortcut, thus + # the check will assume that an action were going to have the same + # shortcut twice. + if not self._validiate_shortcut(action, new_shortcuts[0]) and \ + new_shortcuts[0] != shortcuts[0]: + return if len(shortcuts) == 2: new_shortcuts.append(shortcuts[1]) self.changedActions[action] = new_shortcuts @@ -394,10 +375,60 @@ class ShortcutListForm(QtGui.QDialog, Ui_ShortcutListDialog): new_shortcuts.append(shortcuts[0]) if len(action.defaultShortcuts) == 2: new_shortcuts.append(action.defaultShortcuts[1]) + if len(new_shortcuts) == 2: + if not self._validiate_shortcut(action, new_shortcuts[1]): + return self.changedActions[action] = new_shortcuts self.refreshShortcutList() self.onCurrentItemChanged(self.treeWidget.currentItem()) + def _validiate_shortcut(self, changing_action, key_sequence): + """ + Checks if the given ``changing_action `` can use the given + ``key_sequence``. Returns ``True`` if the ``key_sequence`` can be used + by the action, otherwise displays a dialog and returns ``False``. + + ``changing_action`` + The action which wants to use the ``key_sequence``. + + ``key_sequence`` + The key sequence which the action want so use. + """ + is_valid = True + for category in self.action_list.categories: + for action in category.actions: + shortcuts = self._actionShortcuts(action) + if key_sequence not in shortcuts: + continue + if action is changing_action: + if self.primaryPushButton.isChecked() and \ + shortcuts.index(key_sequence) == 0: + continue + if self.alternatePushButton.isChecked() and \ + shortcuts.index(key_sequence) == 1: + continue + # Have the same parent, thus they cannot have the same shortcut. + if action.parent() is changing_action.parent(): + is_valid = False + # The new shortcut is already assigned, but if both shortcuts + # are only valid in a different widget the new shortcut is + # vaild, because they will not interfere. + if action.shortcutContext() in [QtCore.Qt.WindowShortcut, + QtCore.Qt.ApplicationShortcut]: + is_valid = False + if changing_action.shortcutContext() in \ + [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]: + is_valid = False + if not is_valid: + Receiver.send_message(u'openlp_warning_message', { + u'title': translate('OpenLP.ShortcutListDialog', + 'Duplicate Shortcut'), + u'message': unicode(translate('OpenLP.ShortcutListDialog', + 'The shortcut "%s" is already assigned to another action, ' + 'please use a different shortcut.')) % key_sequence.toString() + }) + return is_valid + def _actionShortcuts(self, action): """ This returns the shortcuts for the given ``action``, which also includes diff --git a/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp index 93e7b17d9..a679df582 100644 --- a/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp +++ b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include #include @@ -88,7 +90,12 @@ DllExport BOOL CheckInstalled() char cmdLine[MAX_PATH * 2]; DEBUG("CheckInstalled\n"); - return GetPPTViewerPath(cmdLine, sizeof(cmdLine)); + BOOL found = GetPPTViewerPath(cmdLine, sizeof(cmdLine)); + if(found) + { + DEBUG("Exe: %s\n", cmdLine); + } + return found; } // Open the PointPoint, count the slides and take a snapshot of each slide @@ -160,7 +167,7 @@ DllExport int OpenPPT(char *filename, HWND hParentWnd, RECT rect, pptView[id].rect.bottom = rect.bottom; pptView[id].rect.right = rect.right; } - strcat_s(cmdLine, MAX_PATH * 2, "/F /S \""); + strcat_s(cmdLine, MAX_PATH * 2, " /F /S \""); strcat_s(cmdLine, MAX_PATH * 2, filename); strcat_s(cmdLine, MAX_PATH * 2, "\""); memset(&si, 0, sizeof(si)); @@ -189,7 +196,7 @@ DllExport int OpenPPT(char *filename, HWND hParentWnd, RECT rect, Sleep(10); if (!CreateProcess(NULL, cmdLine, NULL, NULL, FALSE, 0, 0, NULL, &si, &pi)) { - DEBUG("OpenPPT: CreateProcess failed\n"); + DEBUG("OpenPPT: CreateProcess failed: %s\n", cmdLine); ClosePPT(id); return -1; } @@ -344,16 +351,71 @@ BOOL SavePPTInfo(int id) // Get the path of the PowerPoint viewer from the registry BOOL GetPPTViewerPath(char *pptViewerPath, int stringSize) +{ + char cwd[MAX_PATH]; + + DEBUG("GetPPTViewerPath: start\n"); + if(GetPPTViewerPathFromReg(pptViewerPath, stringSize)) + { + if(_access(pptViewerPath, 0) != -1) + { + DEBUG("GetPPTViewerPath: exit registry\n"); + return TRUE; + } + } + // This is where it gets ugly. PPT2007 it seems no longer stores its + // location in the registry. So we have to use the defaults which will + // upset those who like to put things somewhere else + + // Viewer 2007 in 64bit Windows: + if(_access("C:\\Program Files (x86)\\Microsoft Office\\Office12\\PPTVIEW.EXE", + 0) != -1) + { + strcpy_s( + "C:\\Program Files (x86)\\Microsoft Office\\Office12\\PPTVIEW.EXE", + stringSize, pptViewerPath); + DEBUG("GetPPTViewerPath: exit 64bit 2007\n"); + return TRUE; + } + // Viewer 2007 in 32bit Windows: + if(_access("C:\\Program Files\\Microsoft Office\\Office12\\PPTVIEW.EXE", 0) + != -1) + { + strcpy_s("C:\\Program Files\\Microsoft Office\\Office12\\PPTVIEW.EXE", + stringSize, pptViewerPath); + DEBUG("GetPPTViewerPath: exit 32bit 2007\n"); + return TRUE; + } + // Give them the opportunity to place it in the same folder as the app + _getcwd(cwd, MAX_PATH); + strcat_s(cwd, MAX_PATH, "\\PPTVIEW.EXE"); + if(_access(cwd, 0) != -1) + { + strcpy_s(pptViewerPath, stringSize, cwd); + DEBUG("GetPPTViewerPath: exit local\n"); + return TRUE; + } + DEBUG("GetPPTViewerPath: exit fail\n"); + return FALSE; +} +BOOL GetPPTViewerPathFromReg(char *pptViewerPath, int stringSize) { HKEY hKey; DWORD dwType, dwSize; LRESULT lResult; - DEBUG("GetPPTViewerPath: start\n"); + // The following registry settings are for, respectively, (I think) + // PPT Viewer 2007 (older versions. Latest not in registry) & PPT Viewer 2010 + // PPT Viewer 2003 (recent versions) + // PPT Viewer 2003 (older versions) + // PPT Viewer 97 if ((RegOpenKeyEx(HKEY_CLASSES_ROOT, "PowerPointViewer.Show.12\\shell\\Show\\command", 0, KEY_READ, &hKey) != ERROR_SUCCESS) && (RegOpenKeyEx(HKEY_CLASSES_ROOT, + "PowerPointViewer.Show.11\\shell\\Show\\command", 0, KEY_READ, &hKey) + != ERROR_SUCCESS) + && (RegOpenKeyEx(HKEY_CLASSES_ROOT, "Applications\\PPTVIEW.EXE\\shell\\open\\command", 0, KEY_READ, &hKey) != ERROR_SUCCESS) && (RegOpenKeyEx(HKEY_CLASSES_ROOT, @@ -373,7 +435,6 @@ BOOL GetPPTViewerPath(char *pptViewerPath, int stringSize) } // remove "%1" from end of key value pptViewerPath[strlen(pptViewerPath) - 4] = '\0'; - DEBUG("GetPPTViewerPath: exit ok\n"); return TRUE; } diff --git a/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.dll b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.dll deleted file mode 100644 index 36581e00b..000000000 Binary files a/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.dll and /dev/null differ diff --git a/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h index 4c98f8bb3..98b0a21ab 100644 --- a/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h +++ b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h @@ -49,6 +49,7 @@ LRESULT CALLBACK CbtProc(int nCode, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK CwpProc(int nCode, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam); BOOL GetPPTViewerPath(char *pptViewerPath, int stringSize); +BOOL GetPPTViewerPathFromReg(char *pptViewerPath, int stringSize); HBITMAP CaptureWindow(HWND hWnd); VOID SaveBitmap(CHAR* filename, HBITMAP hBmp) ; VOID CaptureAndSaveWindow(HWND hWnd, CHAR* filename); diff --git a/openlp/plugins/songs/forms/songmaintenanceform.py b/openlp/plugins/songs/forms/songmaintenanceform.py index 48e614eeb..c1437ce0e 100644 --- a/openlp/plugins/songs/forms/songmaintenanceform.py +++ b/openlp/plugins/songs/forms/songmaintenanceform.py @@ -386,7 +386,8 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog): existing_author = self.manager.get_object_filtered(Author, and_(Author.first_name == old_author.first_name, Author.last_name == old_author.last_name, - Author.display_name == old_author.display_name)) + Author.display_name == old_author.display_name, + Author.id != old_author.id)) # Find the songs, which have the old_author as author. songs = self.manager.get_all_objects(Song, Song.authors.contains(old_author)) @@ -408,7 +409,7 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog): """ # Find the duplicate. existing_topic = self.manager.get_object_filtered(Topic, - Topic.name == old_topic.name) + and_(Topic.name == old_topic.name, Topic.id != old_topic.id)) # Find the songs, which have the old_topic as topic. songs = self.manager.get_all_objects(Song, Song.topics.contains(old_topic)) @@ -431,7 +432,8 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog): # Find the duplicate. existing_book = self.manager.get_object_filtered(Book, and_(Book.name == old_book.name, - Book.publisher == old_book.publisher)) + Book.publisher == old_book.publisher, + Book.id != old_book.id)) # Find the songs, which have the old_book as book. songs = self.manager.get_all_objects(Song, Song.song_book_id == old_book.id) @@ -503,4 +505,5 @@ class SongMaintenanceForm(QtGui.QDialog, Ui_SongMaintenanceDialog): editButton.setEnabled(False) else: deleteButton.setEnabled(True) - editButton.setEnabled(True) \ No newline at end of file + editButton.setEnabled(True) + diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index 0cace4977..85294dee2 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -65,10 +65,12 @@ class SongsPlugin(Plugin): def initialise(self): log.info(u'Songs Initialising') Plugin.initialise(self) + self.songImportItem.setVisible(True) + self.songExportItem.setVisible(True) self.toolsReindexItem.setVisible(True) action_list = ActionList.get_instance() - action_list.add_action(self.SongImportItem, UiStrings().Import) - action_list.add_action(self.SongExportItem, UiStrings().Export) + action_list.add_action(self.songImportItem, UiStrings().Import) + action_list.add_action(self.songExportItem, UiStrings().Export) action_list.add_action(self.toolsReindexItem, UiStrings().Tools) def addImportMenuItem(self, import_menu): @@ -81,13 +83,13 @@ class SongsPlugin(Plugin): use it as their parent. """ # Main song import menu item - will eventually be the only one - self.SongImportItem = base_action(import_menu, u'SongImportItem') - self.SongImportItem.setText(translate('SongsPlugin', '&Song')) - self.SongImportItem.setToolTip(translate('SongsPlugin', + self.songImportItem = base_action(import_menu, u'songImportItem') + self.songImportItem.setText(translate('SongsPlugin', '&Song')) + self.songImportItem.setToolTip(translate('SongsPlugin', 'Import songs using the import wizard.')) - import_menu.addAction(self.SongImportItem) + import_menu.addAction(self.songImportItem) # Signals and slots - QtCore.QObject.connect(self.SongImportItem, + QtCore.QObject.connect(self.songImportItem, QtCore.SIGNAL(u'triggered()'), self.onSongImportItemClicked) def addExportMenuItem(self, export_menu): @@ -100,13 +102,13 @@ class SongsPlugin(Plugin): use it as their parent. """ # Main song import menu item - will eventually be the only one - self.SongExportItem = base_action(export_menu, u'SongExportItem') - self.SongExportItem.setText(translate('SongsPlugin', '&Song')) - self.SongExportItem.setToolTip(translate('SongsPlugin', + self.songExportItem = base_action(export_menu, u'songExportItem') + self.songExportItem.setText(translate('SongsPlugin', '&Song')) + self.songExportItem.setToolTip(translate('SongsPlugin', 'Exports songs using the export wizard.')) - export_menu.addAction(self.SongExportItem) + export_menu.addAction(self.songExportItem) # Signals and slots - QtCore.QObject.connect(self.SongExportItem, + QtCore.QObject.connect(self.songExportItem, QtCore.SIGNAL(u'triggered()'), self.onSongExportItemClicked) def addToolsMenuItem(self, tools_menu): @@ -256,9 +258,12 @@ class SongsPlugin(Plugin): """ log.info(u'Songs Finalising') self.manager.finalise() + self.songImportItem.setVisible(False) + self.songExportItem.setVisible(False) self.toolsReindexItem.setVisible(False) action_list = ActionList.get_instance() - action_list.remove_action(self.SongImportItem, UiStrings().Import) - action_list.remove_action(self.SongExportItem, UiStrings().Export) + action_list.remove_action(self.songImportItem, UiStrings().Import) + action_list.remove_action(self.songExportItem, UiStrings().Export) action_list.remove_action(self.toolsReindexItem, UiStrings().Tools) - Plugin.finalise(self) \ No newline at end of file + Plugin.finalise(self) + diff --git a/scripts/windows-builder.py b/scripts/windows-builder.py index 83154c5ac..ef5528cd7 100644 --- a/scripts/windows-builder.py +++ b/scripts/windows-builder.py @@ -52,6 +52,12 @@ UPX http://upx.sourceforge.net/, extract it into C:\%PROGRAMFILES%\UPX, and then add that directory to your PATH environment variable. +Sphinx + This is used to build the documentation + +HTML Help Workshop + This is used to create the help file + PyInstaller PyInstaller should be a checkout of revision 844 of trunk, and in a directory called, "pyinstaller" on the same level as OpenLP's Bazaar shared @@ -81,6 +87,10 @@ OpenLP shared repository directory. This means your code should be in a directory structure like this: "openlp\branch-name". +Visual C++ 2008 Express Edition + This is to build pptviewlib.dll, the library for controlling the + PowerPointViewer + windows-builder.py This script, of course. It should be in the "scripts" directory of OpenLP. @@ -98,6 +108,8 @@ sphinx_exe = os.path.join(os.path.split(python_exe)[0], u'Scripts', u'sphinx-build.exe') hhc_exe = os.path.join(os.getenv(u'PROGRAMFILES'), 'HTML Help Workshop', u'hhc.exe') +vcbuild_exe = os.path.join(os.getenv(u'PROGRAMFILES'), + u'Microsoft Visual Studio 9.0', u'VC', u'vcpackages', u'vcbuild.exe') # Base paths script_path = os.path.split(os.path.abspath(__file__))[0] @@ -119,6 +131,8 @@ winres_path = os.path.join(branch_path, u'resources', u'windows') build_path = os.path.join(branch_path, u'build', u'pyi.win32', u'OpenLP') dist_path = os.path.join(branch_path, u'dist', u'OpenLP') enchant_path = os.path.join(site_packages, u'enchant') +pptviewlib_path = os.path.join(source_path, u'plugins', u'presentations', + u'lib', u'pptviewlib') def update_code(): os.chdir(branch_path) @@ -264,17 +278,40 @@ def run_innosetup(): if code != 0: raise Exception(u'Error running Inno Setup') +def build_pptviewlib(): + print u'Building PPTVIEWLIB.DLL...' + vcbuild = Popen((vcbuild_exe, u'/rebuild', + os.path.join(pptviewlib_path, u'pptviewlib.vcproj'), u'Release|Win32')) + code = vcbuild.wait() + if code != 0: + raise Exception(u'Error building pptviewlib.dll') + copy(os.path.join(pptviewlib_path, u'Release', u'pptviewlib.dll'), + pptviewlib_path) + def main(): + skip_update = False import sys - if len(sys.argv) > 1 and (sys.argv[1] == u'-v' or sys.argv[1] == u'--verbose'): - print "Script path:", script_path - print "Branch path:", branch_path - print "Source path:", source_path - print "\"dist\" path:", dist_path - print "PyInstaller:", pyi_build - print "Inno Setup path:", innosetup_path - print "Windows resources:", winres_path - update_code() + for arg in sys.argv: + if arg == u'-v' or arg == u'--verbose': + print "Script path:", script_path + print "Branch path:", branch_path + print "Source path:", source_path + print "\"dist\" path:", dist_path + print "PyInstaller:", pyi_build + print "Inno Setup path:", innosetup_exe + print "Windows resources:", winres_path + print "VCBuild path:", vcbuild_exe + print "PPTVIEWLIB path:", pptviewlib_path + elif arg == u'--skip-update': + skip_update = True + elif arg == u'/?' or arg == u'-h' or arg == u'--help': + print u'Command options:' + print u' -v --verbose : More verbose output' + print u' --skip-update : Do not update or revert current branch' + exit() + if not skip_update: + update_code() + build_pptviewlib() run_pyinstaller() write_version_file() copy_enchant()