← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~googol/openlp/bug-807657 into lp:openlp

 

Andreas Preikschat has proposed merging lp:~googol/openlp/bug-807657 into lp:openlp.

Requested reviews:
  Tim Bentley (trb143)
Related bugs:
  Bug #807657 in OpenLP: "Offline Help on all platforms "
  https://bugs.launchpad.net/openlp/+bug/807657

For more details, see:
https://code.launchpad.net/~googol/openlp/bug-807657/+merge/72621

Hello,

- Bug #807657: Offline Help on all platforms

There has to be a "help" directory in the same directory as the "i18n" directory is. So on arch linux this would be /usr/share/openlp/help/ and on windows it should be C:\Programme\OpenLP\help\

To be done afterwards (packaging):
- The qt_help_<lang>.qm files need to be packaged (like the qt_<lang>.qm) files.
- The help files have to be generated and included.
  1) bzr checkout lp:openlp/documentation
  2) cd documentation/manual
  3) make qthelp
  4) qcollectiongenerator build/qthelp/OpenLP.qhcp
The "build/qthelp" folder has to be packaged.


NOTE (possible on relevant for packaging):
The Qt documentation mentions a dll file the help system need to so work. See http://doc.qt.nokia.com/4.7/qhelpenginecore.html#setupData
-- 
https://code.launchpad.net/~googol/openlp/bug-807657/+merge/72621
Your team OpenLP Core is subscribed to branch lp:openlp.
=== modified file 'openlp.pyw'
--- openlp.pyw	2011-07-30 16:00:11 +0000
+++ openlp.pyw	2011-08-23 20:23:24 +0000
@@ -262,7 +262,7 @@
             + "/qt4_plugins")
     # i18n Set Language
     language = LanguageManager.get_language()
-    app_translator, default_translator = \
+    app_translator, default_translator, help_translator = \
         LanguageManager.get_translator(language)
     if not app_translator.isEmpty():
         app.installTranslator(app_translator)
@@ -270,6 +270,10 @@
         app.installTranslator(default_translator)
     else:
         log.debug(u'Could not find default_translator.')
+    if not help_translator.isEmpty():
+        app.installTranslator(help_translator)
+    else:
+        log.debug(u'Could not find help_translator.')
     if not options.no_error_form:
         sys.excepthook = app.hookException
     sys.exit(app.run(qt_args))

=== modified file 'openlp/core/ui/__init__.py'
--- openlp/core/ui/__init__.py	2011-07-30 07:34:37 +0000
+++ openlp/core/ui/__init__.py	2011-08-23 20:23:24 +0000
@@ -74,7 +74,8 @@
 from mediadockmanager import MediaDockManager
 from servicemanager import ServiceManager
 from thememanager import ThemeManager
+from offlinehelpform import OfflineHelpForm
 
 __all__ = ['SplashScreen', 'AboutForm', 'SettingsForm', 'MainDisplay',
     'SlideController', 'ServiceManager', 'ThemeManager', 'MediaDockManager',
-    'ServiceItemEditForm', u'FirstTimeForm']
+    'ServiceItemEditForm', u'FirstTimeForm', u'OfflineHelpForm']

=== modified file 'openlp/core/ui/mainwindow.py'
--- openlp/core/ui/mainwindow.py	2011-08-20 19:36:51 +0000
+++ openlp/core/ui/mainwindow.py	2011-08-23 20:23:24 +0000
@@ -39,7 +39,7 @@
     icon_action, shortcut_action
 from openlp.core.ui import AboutForm, SettingsForm, ServiceManager, \
     ThemeManager, SlideController, PluginForm, MediaDockManager, \
-    ShortcutListForm, FormattingTagForm
+    ShortcutListForm, FormattingTagForm, OfflineHelpForm
 from openlp.core.utils import AppLocation, add_actions, LanguageManager, \
     get_application_version, delete_file
 from openlp.core.utils.actions import ActionList, CategoryOrder
@@ -289,8 +289,12 @@
             [QtGui.QKeySequence(u'Ctrl+F1')], self.onAboutItemClicked,
             u':/system/system_about.png', category=UiStrings().Help)
         if os.name == u'nt':
-            self.localHelpFile = os.path.join(
-                AppLocation.get_directory(AppLocation.AppDir), 'OpenLP.chm')
+            self.localHelpFileAvailable = os.path.exists(os.path.join(
+                AppLocation.get_directory(AppLocation.HelpDir), u'OpenLP.chm'))
+        else:
+            self.localHelpFileAvailable = os.path.exists(os.path.join(
+                AppLocation.get_directory(AppLocation.HelpDir), u'OpenLP.qhc'))
+        if self.localHelpFileAvailable:
             self.offlineHelpItem = shortcut_action(
                 mainWindow, u'offlineHelpItem', [QtGui.QKeySequence(u'F1')],
                 self.onOfflineHelpClicked,
@@ -335,7 +339,7 @@
         add_actions(self.toolsMenu, (self.toolsOpenDataFolder, None))
         add_actions(self.toolsMenu, (self.toolsFirstTimeWizard, None))
         add_actions(self.toolsMenu, [self.updateThemeImages])
-        if os.name == u'nt':
+        if self.localHelpFileAvailable:
             add_actions(self.helpMenu, (self.offlineHelpItem,
             self.onlineHelpItem, None, self.webSiteItem,
             self.aboutItem))
@@ -461,7 +465,7 @@
         self.aboutItem.setText(translate('OpenLP.MainWindow', '&About'))
         self.aboutItem.setStatusTip(
             translate('OpenLP.MainWindow', 'More information about OpenLP'))
-        if os.name == u'nt':
+        if self.localHelpFileAvailable:
             self.offlineHelpItem.setText(
                 translate('OpenLP.MainWindow', '&User Guide'))
         self.onlineHelpItem.setText(
@@ -782,7 +786,7 @@
                     translate('OpenLP.MainWindow',
                         'OpenLP Main Display Blanked'),
                     translate('OpenLP.MainWindow',
-                         'The Main Display has been blanked out'))
+                        'The Main Display has been blanked out'))
 
     def onErrorMessage(self, data):
         Receiver.send_message(u'close_splash')
@@ -807,7 +811,15 @@
         """
         Load the local OpenLP help file
         """
-        os.startfile(self.localHelpFile)
+        if os.name == u'nt':
+            localHelpFile= os.path.join(
+                AppLocation.get_directory(AppLocation.HelpDir), u'OpenLP.chm')
+            os.startfile(localHelpFile)
+        else:
+            localHelpFile = os.path.join(
+                AppLocation.get_directory(AppLocation.HelpDir), u'OpenLP.qhc')
+            offlineHelpDialog = OfflineHelpForm(self, localHelpFile)
+            offlineHelpDialog.show()
 
     def onOnlineHelpClicked(self):
         """

=== added file 'openlp/core/ui/offlinehelpdialog.py'
--- openlp/core/ui/offlinehelpdialog.py	1970-01-01 00:00:00 +0000
+++ openlp/core/ui/offlinehelpdialog.py	2011-08-23 20:23:24 +0000
@@ -0,0 +1,86 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection                                      #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2011 Raoul Snyman                                        #
+# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan      #
+# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan,      #
+# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias     #
+# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith,    #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund             #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it     #
+# under the terms of the GNU General Public License as published by the Free  #
+# Software Foundation; version 2 of the License.                              #
+#                                                                             #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    #
+# more details.                                                               #
+#                                                                             #
+# You should have received a copy of the GNU General Public License along     #
+# with this program; if not, write to the Free Software Foundation, Inc., 59  #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
+###############################################################################
+
+from openlp.core.lib import translate
+
+from PyQt4 import QtGui, QtCore, QtWebKit
+
+class Ui_OfflineHelpDialog(object):
+    def setupUi(self, dialog):
+        dialog.setObjectName(u'dialog')
+        dialog.resize(800, 550)
+        dialog.setWindowFlags(QtCore.Qt.Window)
+        self.horizontalLayout = QtGui.QHBoxLayout(dialog)
+        self.horizontalLayout.setObjectName(u'horizontalLayout')
+        self.splitter = QtGui.QSplitter(dialog)
+        self.splitter.setObjectName(u'splitter')
+        self.splitter.setOrientation(QtCore.Qt.Horizontal)
+        self.contentTableWidget = QtGui.QWidget(self.splitter)
+        self.contentTableWidget.setObjectName(u'contentTableWidget')
+        self.contentTableLayout = QtGui.QVBoxLayout(self.contentTableWidget)
+        self.contentTableLayout.setSpacing(0)
+        self.contentTableLayout.setMargin(0)
+        self.contentTableLayout.setObjectName(u'contentTableLayout')
+        self.verticalLayout = QtGui.QVBoxLayout()
+        self.verticalLayout.setObjectName(u'verticalLayout')
+        self.searchField = self.engine.searchEngine().queryWidget()
+        self.searchField.setFixedWidth(300)
+        # Hide the toolbuttons which allow the user to go back/forward in the
+        # query history.
+        for child in self.searchField.children():
+            if isinstance(child, QtGui.QToolButton) and child.arrowType() in \
+                (QtCore.Qt.LeftArrow, QtCore.Qt.RightArrow):
+                child.setHidden(True)
+        self.searchField.setObjectName(u'searchField')
+        self.verticalLayout.addWidget(self.searchField)
+        self.tabWidget = QtGui.QTabWidget(self.contentTableWidget)
+        self.tabWidget.setObjectName(u'tabWidget')
+        self.indexTab = self.engine.contentWidget()
+        self.indexTab.setObjectName(u'indexTab')
+        self.tabWidget.addTab(self.indexTab, (u''))
+        self.searchTab = self.engine.searchEngine().resultWidget()
+        self.searchTab.setObjectName(u'searchTab')
+        self.tabWidget.addTab(self.searchTab, (u''))
+        self.verticalLayout.addWidget(self.tabWidget)
+        self.contentTableLayout.addLayout(self.verticalLayout)
+        self.contentView = QtWebKit.QWebView(self.splitter)
+        self.contentView.setObjectName(u'contentView')
+        self.horizontalLayout.addWidget(self.splitter)
+
+        self.retranslateUi(dialog)
+        self.tabWidget.setCurrentIndex(0)
+        QtCore.QMetaObject.connectSlotsByName(dialog)
+
+    def retranslateUi(self, dialog):
+        dialog.setWindowTitle(
+            translate('OpenLP.OfflineHelpDialog', 'User Guide'))
+        self.tabWidget.setTabText(
+            self.tabWidget.indexOf(self.indexTab),
+            translate('OpenLP.OfflineHelpDialog', 'Content'))
+        self.tabWidget.setTabText(
+            self.tabWidget.indexOf(self.searchTab),
+            translate('OpenLP.OfflineHelpDialog', 'Search'))

=== added file 'openlp/core/ui/offlinehelpform.py'
--- openlp/core/ui/offlinehelpform.py	1970-01-01 00:00:00 +0000
+++ openlp/core/ui/offlinehelpform.py	2011-08-23 20:23:24 +0000
@@ -0,0 +1,79 @@
+# -*- coding: utf-8 -*-
+# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
+
+###############################################################################
+# OpenLP - Open Source Lyrics Projection                                      #
+# --------------------------------------------------------------------------- #
+# Copyright (c) 2008-2011 Raoul Snyman                                        #
+# Portions copyright (c) 2008-2011 Tim Bentley, Gerald Britton, Jonathan      #
+# Corwin, Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan,      #
+# Armin Köhler, Joshua Miller, Stevan Pettit, Andreas Preikschat, Mattias     #
+# Põldaru, Christian Richter, Philip Ridout, Simon Scudder, Jeffrey Smith,    #
+# Maikel Stuivenberg, Martin Thompson, Jon Tibble, Frode Woldsund             #
+# --------------------------------------------------------------------------- #
+# This program is free software; you can redistribute it and/or modify it     #
+# under the terms of the GNU General Public License as published by the Free  #
+# Software Foundation; version 2 of the License.                              #
+#                                                                             #
+# This program is distributed in the hope that it will be useful, but WITHOUT #
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    #
+# more details.                                                               #
+#                                                                             #
+# You should have received a copy of the GNU General Public License along     #
+# with this program; if not, write to the Free Software Foundation, Inc., 59  #
+# Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
+###############################################################################
+import os
+
+from PyQt4 import QtGui, QtHelp, QtCore
+
+from openlp.core.ui.offlinehelpdialog import Ui_OfflineHelpDialog
+
+class OfflineHelpForm(QtGui.QDialog, Ui_OfflineHelpDialog):
+    def __init__(self, parent, collectionFile):
+        """
+        Constructor.
+
+        ``collectionFile``
+            The collection file's extension (in binary form) is **.qhc**.
+        """
+        QtGui.QDialog.__init__(self, parent)
+        self.html_directory = os.path.dirname(collectionFile)
+        self.engine = QtHelp.QHelpEngine(collectionFile, parent)
+        self.engine.setupData()
+        self.setupUi(self)
+        self.contentView.load(
+            QtCore.QUrl(os.path.join(self.html_directory, u'index.html')))
+        # Signals
+        QtCore.QObject.connect(self.searchTab,
+            QtCore.SIGNAL(u'requestShowLink(const QUrl&)'),
+            self.showHelpContent)
+        QtCore.QObject.connect(self.indexTab,
+            QtCore.SIGNAL(u'linkActivated(const QUrl&)'), self.showHelpContent)
+        QtCore.QObject.connect(self.engine.searchEngine().queryWidget(),
+            QtCore.SIGNAL(u'search()'), self.onSearchButtonPressed)
+
+    def onSearchButtonPressed(self):
+        """
+        Called when the user pressed the search button. We obtain the query and
+        tell the search engine to search.
+        """
+        query = self.engine.searchEngine().queryWidget().query()
+        self.engine.searchEngine().search(query)
+        self.tabWidget.setCurrentIndex(1)
+
+    def showHelpContent(self, url):
+        """
+        Called when new help content is supposed to be shown. Some parts of the
+        given ``url`` have to be removed and cleaned up.
+
+        ``url``
+            The url to open::
+
+                ``qthelp://org.sphinx.openlp.2.0/doc/introduction.html#about``
+        """
+        url = unicode(url.toString())
+        url = url.replace(u'qthelp://org.sphinx.openlp.2.0/doc', u'file://' +
+            self.html_directory)
+        self.contentView.load(QtCore.QUrl(url))

=== modified file 'openlp/core/utils/__init__.py'
--- openlp/core/utils/__init__.py	2011-08-12 14:54:16 +0000
+++ openlp/core/utils/__init__.py	2011-08-23 20:23:24 +0000
@@ -126,9 +126,10 @@
     VersionDir = 5
     CacheDir = 6
     LanguageDir = 7
+    HelpDir = 8
 
     @staticmethod
-    def get_directory(dir_type=1):
+    def get_directory(dir_type=AppDir):
         """
         Return the appropriate directory according to the directory type.
 
@@ -152,6 +153,11 @@
                 os.path.abspath(os.path.split(sys.argv[0])[0]),
                 _get_os_dir_path(dir_type))
             return os.path.join(app_path, u'i18n')
+        elif dir_type == AppLocation.HelpDir:
+            app_path = _get_frozen_path(
+                os.path.abspath(os.path.split(sys.argv[0])[0]),
+                _get_os_dir_path(dir_type))
+            return os.path.join(app_path, u'help')
         else:
             return _get_os_dir_path(dir_type)
 
@@ -183,7 +189,7 @@
         if dir_type == AppLocation.DataDir:
             return os.path.join(unicode(os.getenv(u'APPDATA'), encoding),
                 u'openlp', u'data')
-        elif dir_type == AppLocation.LanguageDir:
+        elif dir_type in (AppLocation.LanguageDir, AppLocation.HelpDir):
             return os.path.split(openlp.__file__)[0]
         return os.path.join(unicode(os.getenv(u'APPDATA'), encoding),
             u'openlp')
@@ -191,12 +197,12 @@
         if dir_type == AppLocation.DataDir:
             return os.path.join(unicode(os.getenv(u'HOME'), encoding),
                 u'Library', u'Application Support', u'openlp', u'Data')
-        elif dir_type == AppLocation.LanguageDir:
+        elif dir_type in (AppLocation.LanguageDir, AppLocation.HelpDir):
             return os.path.split(openlp.__file__)[0]
         return os.path.join(unicode(os.getenv(u'HOME'), encoding),
             u'Library', u'Application Support', u'openlp')
     else:
-        if dir_type == AppLocation.LanguageDir:
+        if dir_type in (AppLocation.LanguageDir, AppLocation.HelpDir):
             return os.path.join(u'/usr', u'share', u'openlp')
         if XDG_BASE_AVAILABLE:
             if dir_type == AppLocation.ConfigDir:

=== modified file 'openlp/core/utils/languagemanager.py'
--- openlp/core/utils/languagemanager.py	2011-06-12 16:02:52 +0000
+++ openlp/core/utils/languagemanager.py	2011-08-23 20:23:24 +0000
@@ -56,6 +56,7 @@
         if LanguageManager.auto_language:
             language = QtCore.QLocale.system().name()
         lang_path = AppLocation.get_directory(AppLocation.LanguageDir)
+        # Our own translations.
         app_translator = QtCore.QTranslator()
         app_translator.load(language, lang_path)
         # A translator for buttons and other default strings provided by Qt.
@@ -64,7 +65,10 @@
                 QtCore.QLibraryInfo.TranslationsPath)
         default_translator = QtCore.QTranslator()
         default_translator.load(u'qt_%s' % language, lang_path)
-        return app_translator, default_translator
+        # Strings for the help dialog are provided by Qt.
+        help_translator = QtCore.QTranslator()
+        help_translator.load(u'qt_help_%s' % language, lang_path)
+        return app_translator, default_translator, help_translator
 
     @staticmethod
     def find_qm_files():

=== added file 'resources/forms/offlineHelpDialog.ui'
--- resources/forms/offlineHelpDialog.ui	1970-01-01 00:00:00 +0000
+++ resources/forms/offlineHelpDialog.ui	2011-08-23 20:23:24 +0000
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Dialog</class>
+ <widget class="QDialog" name="Dialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>580</width>
+    <height>473</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QHBoxLayout" name="horizontalLayout">
+   <item>
+    <widget class="QSplitter" name="splitter">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <widget class="QWidget" name="contentSearch" native="true">
+      <layout class="QVBoxLayout" name="PreviewPaneLayout">
+       <property name="spacing">
+        <number>0</number>
+       </property>
+       <property name="margin">
+        <number>0</number>
+       </property>
+       <item>
+        <layout class="QVBoxLayout" name="verticalLayout">
+         <item>
+          <widget class="QLineEdit" name="searchField"/>
+         </item>
+         <item>
+          <widget class="QTabWidget" name="tabWidget">
+           <property name="currentIndex">
+            <number>0</number>
+           </property>
+           <widget class="QWidget" name="indexTab">
+            <attribute name="title">
+             <string>Tab 1</string>
+            </attribute>
+           </widget>
+           <widget class="QWidget" name="searchTab">
+            <property name="enabled">
+             <bool>true</bool>
+            </property>
+            <attribute name="title">
+             <string>Tab 2</string>
+            </attribute>
+           </widget>
+          </widget>
+         </item>
+        </layout>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWebView" name="contentView">
+      <property name="url">
+       <url>
+        <string>about:blank</string>
+       </url>
+      </property>
+     </widget>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>QWebView</class>
+   <extends>QWidget</extends>
+   <header>QtWebKit/QWebView</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>

=== modified file 'resources/windows/OpenLP-2.0.iss'
--- resources/windows/OpenLP-2.0.iss	2011-05-23 15:41:22 +0000
+++ resources/windows/OpenLP-2.0.iss	2011-08-23 20:23:24 +0000
@@ -71,7 +71,7 @@
 [Icons]
 Name: {group}\{#AppName}; Filename: {app}\{#AppExeName}
 Name: {group}\{#AppName} (Debug); Filename: {app}\{#AppExeName}; Parameters: -l debug
-Name: {group}\{#AppName} Help; Filename: {app}\{#AppName}.chm; Check: FileExists(ExpandConstant('{app}\{#AppName}.chm'))
+Name: {group}\{#AppName} Help; Filename: {app}\help\{#AppName}.chm; Check: FileExists(ExpandConstant('{app}\help\{#AppName}.chm'))
 Name: {group}\{cm:ProgramOnTheWeb,{#AppName}}; Filename: {#AppURL}
 Name: {group}\{cm:UninstallProgram,{#AppName}}; Filename: {uninstallexe}
 Name: {commondesktop}\{#AppName}; Filename: {app}\{#AppExeName}; Tasks: desktopicon

=== modified file 'scripts/windows-builder.py'
--- scripts/windows-builder.py	2011-07-23 12:11:11 +0000
+++ scripts/windows-builder.py	2011-08-23 20:23:24 +0000
@@ -173,7 +173,7 @@
     pyinstaller = Popen((python_exe, pyi_build,
         u'--noconfirm',
         u'--windowed',
-        u'--noupx', 
+        u'--noupx',
         u'-o', branch_path,
         u'-i', win32_icon,
         u'-p', branch_path,
@@ -236,7 +236,7 @@
     if os.path.isfile(os.path.join(helpfile_path, u'OpenLP.chm')):
         print u'        Windows help file found'
         copy(os.path.join(helpfile_path, u'OpenLP.chm'),
-            os.path.join(dist_path, u'OpenLP.chm'))
+            os.path.join(dist_path, u'help', u'OpenLP.chm'))
     else:
         print u'  WARNING ---- Windows help file not found ---- WARNING'
 
@@ -288,6 +288,8 @@
 
 def run_htmlhelp():
     print u'Running HTML Help Workshop...'
+    if not os.path.exists(os.path.join(dist_path, u'help')):
+        os.makedirs(os.path.join(dist_path, u'help'))
     os.chdir(os.path.join(manual_build_path, u'htmlhelp'))
     hhc = Popen((hhc_exe, u'OpenLP.chm'), stdout=PIPE)
     output, error = hhc.communicate()


Follow ups