~jelmer/qbrz/relative

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# -*- coding: utf-8 -*-
#
# QBzr - Qt frontend to Bazaar commands
#
# 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; either version 2
# of the License, or (at your option) any later version.
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

from PyQt4 import QtCore, QtGui
from breezy.plugins.qbrz.lib.i18n import gettext
from breezy.plugins.qbrz.lib.util import QBzrWindow

from breezy.help import HelpIndices, NoHelpTopic
try:
    from docutils.core import publish_string
    from docutils.writers.html4css1 import Writer as BaseHTMLWriter
    have_docutils = True
except ImportError:
    have_docutils = False

if have_docutils:
    # We run into issues in Windows binaries where docutils may be in a .zip
    # file, so template and .css files can't be located.  This is OK for now,
    # as the HTML we generate is so basic we don't need stylesheets.
    class CustomWriter(BaseHTMLWriter):
        # This is the context of template.txt from distutils.
        template = """%(head_prefix)s
            %(head)s
            %(stylesheet)s
            %(body_prefix)s
            %(body_pre_docinfo)s
            %(docinfo)s
            %(body)s
            %(body_suffix)s
            """

        def apply_template(self):
            # Docutils expects to find this on disk, but its not there
            subs = self.interpolation_dict()
            return self.template % subs


def get_help_topic_as_html(topic):
    topics = HelpIndices()
    try:
        results = topics.search(topic)
    except NoHelpTopic:
        tpl = gettext("No help can be found for <i>%s</i>")
        return tpl % topic

    # assert len(results)==1, "what does more than one result mean?"
    # An example of when one might get more than one result, is if you have
    # bzrtools plugin install, you will get a second result for it command,
    # if you search for "Branches". We (like bzr help) only want to show the
    # first result.
    
    index, topic = results[0]
    if have_docutils:
        # we can make pretty HTML on the fly
        text = topic.get_help_text(plain=False)
        html = publish_string(text, writer=CustomWriter(),
                              settings_overrides={'stylesheet': None,
                                                  'stylesheet_path': None})
    else:
        # No docutils - we don't try too hard here - installing docutils is
        # easy!  But we do try and make the line-breaks correct at least.
        text = topic.get_help_text(plain=True)
        bits = ['''<p><small>(Please install the Python <i>docutils</i> package for
                improved formatting)</p></small>''']
        bits.append('<pre>%s</pre>' % text)
        html = ' '.join(bits)
    return html


class QBzrHelpWindow(QBzrWindow):

    def __init__(self, parent=None):
        """Create help window.
        @param  parent:   If None, a normal top-level window will be opened.
                          If not None, a 'tool' style window will be opened, be
                          'always on top' of the parent and have no taskbar
                          entry.
        """
        if parent is None:
            # a normal window.
            window_id = "help"
            default_size = (780, 580)
        else:
            # a smallish tooltop window.
            window_id = "help-popup"
            default_size = (500, 400)
        QBzrWindow.__init__(self, [gettext("Help")], parent,
                            centralwidget=QtGui.QTextBrowser())
        self.restoreSize(window_id, default_size)
        if parent is not None:
            # make it a tool window for the parent.
            self.setWindowFlags(QtCore.Qt.Tool)
        # Without this, the window object remains alive even after its closed.
        # There's no good reason for that...
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)

    def move_next_to(self, parent):
        """Move next to a parent window so we aren't obscuring any widgets"""

        # We move to the right of the parent if room for the window to be
        # full visible on the same screen as the parent.
        # Get the geometry for the screen holding the parent.
        desktop = QtGui.QApplication.desktop()
        geo = desktop.screenGeometry(parent)

        pt = parent.pos()
        parent_size = parent.size()
        my_size = self.size()
        new_pt = QtCore.QPoint(pt.x()+parent_size.width()+15, pt.y())
        if geo.contains(QtCore.QRect(new_pt, my_size)):
            self.move(new_pt)
        else:
            # see if we can make it fit on the left.
            new_pt = QtCore.QPoint(pt.x()-my_size.width()-15, pt.y())
            if geo.contains(QtCore.QRect(new_pt, my_size)):
                self.move(new_pt)
            else:
                # coulnd't fit it to the left *or* right - give up.
                pass

    def load_help_topic(self, topic):
        html = get_help_topic_as_html(topic)
        self.centralwidget.setHtml(html)


def show_help(topic, parent=None):
    """Create a help window displaying the specified topic.
    
    If a parent is given, the window will be a 'tool' window for the parent,
    otherwise a normal MainWindow.
    """
    # find an existing one with the same parent.
    for window in QtGui.QApplication.topLevelWidgets():
        if isinstance(window, QBzrHelpWindow) and window.parentWidget()==parent:
            break
    else:
        # create a new one.
        window = QBzrHelpWindow(parent)

    window.load_help_topic(topic)
    # If a parent is specified and the window isn't visible, move it next to
    # the parent before displaying it.  If the window is visible, its probably
    # exactly where the user wants it already...
    if parent is not None and not window.isVisible():
        window.move_next_to(parent)
    window.show()
    return window