~ubuntu-branches/ubuntu/raring/pybik/raring-updates

« back to all changes in this revision

Viewing changes to .pc/do-not-run-with-pyside.patch/pybiklib/main.py

  • Committer: Package Import Robot
  • Author(s): B. Clausius
  • Date: 2013-07-13 22:50:19 UTC
  • Revision ID: package-import@ubuntu.com-20130713225019-0ubztj6rxn9f0wvt
Tags: 1.0.1-1ubuntu0.1
Remove the ability to run with pyside and require pyqt4
to prevent segmentation fault in preferences dialog (LP: #1189664)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#-*- coding:utf-8 -*-
 
2
 
 
3
#  Pybik -- A 3 dimensional magic cube game.
 
4
#  Copyright © 2009, 2011-2012  B. Clausius <barcc@gmx.de>
 
5
#
 
6
#  This program is free software: you can redistribute it and/or modify
 
7
#  it under the terms of the GNU General Public License as published by
 
8
#  the Free Software Foundation, either version 3 of the License, or
 
9
#  (at your option) any later version.
 
10
#
 
11
#  This program is distributed in the hope that it will be useful,
 
12
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
#  GNU General Public License for more details.
 
15
#
 
16
#  You should have received a copy of the GNU General Public License
 
17
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
18
 
 
19
# Ported from GNUbik
 
20
# Original filename: main.c
 
21
# Original copyright and license: 1998, 2003--2004  John Darrington, GPL3+
 
22
 
 
23
from __future__ import print_function, division, unicode_literals
 
24
 
 
25
import sys, os
 
26
from collections import namedtuple
 
27
 
 
28
from . import debug, config
 
29
 
 
30
N_ = lambda s: s
 
31
 
 
32
 
 
33
def format_opts(opts):
 
34
    opts = ((o + o.strip('--')[0].upper() if o.endswith('=') else o) for o in opts)
 
35
    return '  ' + ', '.join(opts)
 
36
    
 
37
def format_help(text, indent=0):
 
38
    try:
 
39
        width = int(os.environ['COLUMNS']) - 2
 
40
    except (KeyError, ValueError):
 
41
        width = 78
 
42
    width -= indent
 
43
    def split(text):
 
44
        lines = text.split('\n')
 
45
        for line in lines:
 
46
            res = None
 
47
            words = line.split(' ')
 
48
            for word in words:
 
49
                if res is None:
 
50
                    res = word
 
51
                elif len(res + word) + 1 <= width:
 
52
                    res = ' '.join((res, word))
 
53
                else:
 
54
                    yield res
 
55
                    res = word
 
56
            yield res
 
57
    return '\n'.ljust(indent+1).join(split(text))
 
58
    
 
59
def print_usage(unused_value, unused_opts):
 
60
    print('Usage:', sys.argv[0], '[options]')
 
61
    for args, unused_func, text in arg_info:
 
62
        if args is None:
 
63
            print()
 
64
            print(format_help(text))
 
65
        else:
 
66
            opts = format_opts(args)
 
67
            if len(opts) > 18:
 
68
                text = '\n' + text
 
69
            else:
 
70
                opts = opts.ljust(20)
 
71
            text = format_help(text, 20)
 
72
            print(opts + text)
 
73
    sys.exit(0)
 
74
    
 
75
def print_version(*unused_args):
 
76
    print(config.APPNAME, config.VERSION)
 
77
    print()
 
78
    print(config.COPYRIGHT.replace('©', '(C)')) #XXX: help2man cannot handle unicode
 
79
    print()
 
80
    print(config.wrap(config.LICENSE_INFO))
 
81
    print()
 
82
    print(config.wrap(config.LICENSE_NOT_FOUND))
 
83
    sys.exit(0)
 
84
    
 
85
debug_level_names = [__a[6:].lower() for __a in debug.__all__ if __a.startswith('DEBUG_')]
 
86
 
 
87
arg_info = [
 
88
        (None, None, config.LONG_DESCRIPTION.replace('ő', 'o')), #XXX: help2man cannot handle unicode
 
89
        (None, None, 'Pybik can be fully controlled and configured via the graphical user interface.'
 
90
                     ' The options listed here are intended primarily for testing and debugging.'),
 
91
        (None, None, 'Options:'),
 
92
        (['-h', '--help'], print_usage,
 
93
                            'Show help message and exit'),
 
94
        (['--version'], print_version,
 
95
                            'Show version number and exit'),
 
96
        (['--config-file='], lambda value, opts: opts.setdefault('config-file', value),
 
97
                            'Specify the configuration file to use instead of the default location'),
 
98
        (['--defaultconfig'], lambda value, opts: opts.setdefault('defaultconfig', True),
 
99
                            'Print default settings to stdout and exit'),
 
100
        (['--pyside'], lambda value, opts: opts.setdefault('pyside', True),
 
101
                            'Use PySide, cannot combined with --pyqt4'),
 
102
        (['--pyqt4'], lambda value, opts: opts.setdefault('pyqt4', True),
 
103
                            'Use PyQt4, cannot be combined with --pyside,'
 
104
                            ' is neither --pyside nor --pyqt4 is given, the application'
 
105
                            ' first imports PySide and if that fails it imports PyQt4'),
 
106
        (['--pure-python'], lambda value, opts: opts.setdefault('pure-python', True),
 
107
                            'Use python module for rendering (very slow)'),
 
108
        (['--debug='], lambda value, opts: opts.setdefault('debug', value),
 
109
                            'Enable debug output, D is a comma-separated list of debug flags:\n{0}'
 
110
                            .format(' '.join(debug_level_names))),
 
111
        (None, None,  'Qt-Options, for a full list refer to the Qt-Reference,'
 
112
                ' but not all options make sense for this application:'),
 
113
        (['-style S'], None,
 
114
                            'sets the application GUI style. Possible values are'
 
115
                            ' motif, windows, and platinum.'),
 
116
        (['-widgetcount'], None,
 
117
                            'prints debug message at the end about number of widgets left'
 
118
                            ' undestroyed and maximum number of widgets existed at the same time'),
 
119
        (['-reverse'], None,
 
120
                            "sets the application's layout direction to left-to-right"),
 
121
        (['-graphicssystem G'], None,
 
122
                            'sets the backend to be used for on-screen widgets and pixmaps.'
 
123
                            ' Available options are raster and opengl.'),
 
124
    ]
 
125
    
 
126
def parse_args(args):
 
127
    arg_functs = {o: f for opts, f, h in arg_info for o in opts or [] if f is not None}
 
128
    opts = {}
 
129
    ui_args = []
 
130
    for arg in args:
 
131
        try:
 
132
            index = arg.index('=')
 
133
        except ValueError:
 
134
            value = None
 
135
        else:
 
136
            arg, value = arg[:index+1], arg[index+1:]
 
137
        try:
 
138
            func = arg_functs[arg]
 
139
        except KeyError:
 
140
            ui_args.append(arg)
 
141
        else:
 
142
            func(value, opts)
 
143
            
 
144
    if 'pyside' in opts:
 
145
        if 'pyqt4' in opts:
 
146
            print('You cannot use both --pyside and --pyqt4')
 
147
            sys.exit(1)
 
148
        else:
 
149
            pythonqt = 'pyside'
 
150
    else:
 
151
        if 'pyqt4' in opts:
 
152
            pythonqt = 'pyqt4'
 
153
        else:
 
154
            pythonqt = None
 
155
            
 
156
    debug_flags = opts.get('debug', None)
 
157
    if debug_flags is not None:
 
158
        debug_flags = [f for f in debug_flags.split(',') if f]
 
159
        for d in debug_flags:
 
160
            if d not in debug_level_names:
 
161
                print('unknown debug option:', d)
 
162
                sys.exit(1)
 
163
            
 
164
    Opts = namedtuple('Opts', 'debug_flags pythonqt pure_python ui_args config_file defaultconfig')
 
165
    return Opts(debug_flags, pythonqt, opts.get('pure-python', False), ui_args,
 
166
                opts.get('config-file', config.USER_SETTINGS_FILE), opts.get('defaultconfig', False))
 
167
    
 
168
def import_ext(pythonqt, pure_python):
 
169
    if pythonqt != 'pyqt4':
 
170
        debug.debug('Importing PySide')
 
171
        try:
 
172
            import PySide, PySide.QtCore, PySide.QtGui, PySide.QtOpenGL
 
173
        except ImportError as e:
 
174
            debug.debug('  Failed')
 
175
            if pythonqt == 'pyside':
 
176
                print('PySide not found.', e)
 
177
                sys.exit(1)
 
178
            pythonqt = 'pyqt4'
 
179
    if pythonqt == 'pyqt4':
 
180
        debug.debug('Importing PyQt4')
 
181
        try:
 
182
            import sip
 
183
            sip.setapi('QString', 2)
 
184
            sip.setapi('QVariant', 2)
 
185
            import PyQt4
 
186
            import PyQt4.QtCore
 
187
            import PyQt4.QtGui
 
188
            import PyQt4.QtOpenGL
 
189
        except ImportError as e:
 
190
            debug.debug('  Failed')
 
191
            print('Python bindings for Qt4 not found.', e)
 
192
            sys.exit(1)
 
193
        sys.modules[b'PySide'] = PyQt4
 
194
        sys.modules[b'PySide.QtCore'] = PyQt4.QtCore
 
195
        sys.modules[b'PySide.QtGui'] = PyQt4.QtGui
 
196
        sys.modules[b'PySide.QtOpenGL'] = PyQt4.QtOpenGL
 
197
        # Monkey patch QtCore
 
198
        # pylint: disable=E1101
 
199
        PyQt4.QtCore.Signal = PyQt4.QtCore.pyqtSignal
 
200
        PyQt4.QtCore.Slot = PyQt4.QtCore.pyqtSlot
 
201
        PyQt4.QtCore.Qt.CursorShape.CrossCursor = PyQt4.QtCore.Qt.CrossCursor
 
202
        PyQt4.QtCore.Qt.TransformationMode.SmoothTransformation = \
 
203
                        PyQt4.QtCore.Qt.SmoothTransformation
 
204
        # Monkey patch QtOpenGL
 
205
        PyQt4.QtOpenGL.QGLContext.BindOption.LinearFilteringBindOption = \
 
206
                            PyQt4.QtOpenGL.QGLContext.LinearFilteringBindOption
 
207
        PyQt4.QtOpenGL.QGLContext.BindOption.MipmapBindOption = PyQt4.QtOpenGL.QGLContext.MipmapBindOption
 
208
        # pylint: enable=E1101
 
209
        
 
210
    if debug.DEBUG:
 
211
        import PySide, PySide.QtCore, PySide.QtGui, PySide.QtOpenGL # pylint: disable=W0404
 
212
        debug.debug('Qt modules:', PySide.__name__, PySide.QtCore.__name__,
 
213
                                   PySide.QtGui.__name__, PySide.QtOpenGL.__name__)
 
214
        
 
215
    if not pure_python:
 
216
        try:
 
217
            import _gldraw
 
218
            sys.modules[b'pybiklib.gldraw'] = _gldraw
 
219
            sys.modules[b'_gldraw'] = _gldraw
 
220
        except ImportError as e:
 
221
            print(e)
 
222
            print('Unable to import module _gldraw, using slow fallback.')
 
223
            pure_python = True
 
224
    if not pure_python:
 
225
        try:
 
226
            import _glarea
 
227
            sys.modules[b'pybiklib.glarea'] = _glarea
 
228
        except ImportError as e:
 
229
            del sys.modules[b'pybiklib.gldraw']
 
230
            del sys.modules[b'_gldraw']
 
231
            print(e)
 
232
            print('Unable to import module _glarea, using slow fallback.')
 
233
    if pure_python:
 
234
        try:
 
235
            from OpenGL import GL as unused_GL
 
236
        except ImportError as e:
 
237
            print('Python bindings for OpenGL not found.', e)
 
238
            sys.exit(1)
 
239
 
 
240
 
 
241
def run_app(root_dir, args, config_file):
 
242
    import gettext
 
243
    from PySide.QtCore import QLocale, QTranslator, QTimer
 
244
    from PySide.QtGui import QApplication, QPalette, QColor
 
245
    
 
246
    # initialize QApplication
 
247
    app = QApplication(args)
 
248
    args = app.arguments()[1:]
 
249
    if args:
 
250
        print('Unknown arguments:', ' '.join(args))
 
251
        sys.exit(1)
 
252
    app.setOrganizationName(config.PACKAGE)
 
253
    app.setApplicationName(config.APPNAME)
 
254
    app.setApplicationVersion(config.VERSION)
 
255
    
 
256
    # Workaround for whatsThis-Text (white text on light background)
 
257
    palette = app.palette()
 
258
    colorfg = palette.color(QPalette.Active, QPalette.ToolTipText)
 
259
    colorbg = palette.color(QPalette.Active, QPalette.ToolTipBase)
 
260
    valuefg = colorfg.value()
 
261
    valuebg = (valuefg + 255) // 2 if valuefg < 128 else valuefg // 2
 
262
    colorbg = QColor.fromHsv(colorbg.hue(), colorbg.saturation(), valuebg)
 
263
    palette.setColor(QPalette.Active, QPalette.ToolTipBase, colorbg)
 
264
    app.setPalette(palette)
 
265
    
 
266
    # initialize translation
 
267
    language = QLocale.system().name()
 
268
    # standard Qt translation, used for e.g. standard buttons and shortcut names
 
269
    translator = QTranslator()
 
270
    translator.load('qt_' + language, config.QT_LOCALE_DIR)
 
271
    app.installTranslator(translator)
 
272
    # the rest of the app use gettext for translation
 
273
    if root_dir == sys.prefix:
 
274
        # normal installation
 
275
        LOCALEDIR = None
 
276
    else:
 
277
        # different root, e.g. /usr/local, source directory
 
278
        LOCALEDIR = config.LOCALE_DIR
 
279
    t = gettext.translation(config.PACKAGE, LOCALEDIR, languages=[language], fallback=True)
 
280
    t.install(unicode=True, names=['ngettext'])
 
281
    
 
282
    # initialize settings
 
283
    from .settings import settings
 
284
    try:
 
285
        settings.load(config_file)
 
286
    except EnvironmentError as e:
 
287
        error_message = N_('An error occurred while reading the settings:\n'
 
288
                        '{error_message}').format(error_message=e)
 
289
        debug.debug(error_message)
 
290
        settings.load('')
 
291
        QTimer.singleShot(0, lambda: window.error_dialog(_(error_message)))
 
292
        
 
293
    # create main window
 
294
    # The application module can be imported only if a QApplication object is created
 
295
    from .application import MainWindow
 
296
    window = MainWindow()
 
297
    
 
298
    # run the application
 
299
    app.exec_()
 
300
    
 
301
    
 
302
def run(root_dir=None):
 
303
    opts = parse_args(sys.argv)
 
304
    
 
305
    if opts.debug_flags is not None:
 
306
        print(config.PACKAGE, config.VERSION)
 
307
        debug.set_flags(opts.debug_flags)
 
308
        print('debug flags:', *opts.debug_flags)
 
309
        debug.debug('Qt args:', opts.ui_args)
 
310
    
 
311
    if opts.defaultconfig:
 
312
        from .settings import settings
 
313
        settings.load('')
 
314
        settings.keystore.dump(sys.stdout, all=True)
 
315
        sys.exit(0)
 
316
        
 
317
    import_ext(opts.pythonqt, opts.pure_python)
 
318
    
 
319
    run_app(root_dir, opts.ui_args, opts.config_file)
 
320
    
 
321