source: orange/Orange/OrangeCanvas/main.py @ 11174:320e10833c36

Revision 11174:320e10833c36, 7.7 KB checked in by Ales Erjavec <ales.erjavec@…>, 18 months ago (diff)

Fixed a possible segfault on exit.

Line 
1"""
2Orange Canvas main entry point
3
4"""
5
6import os
7import sys
8import gc
9import re
10import logging
11import optparse
12import cPickle
13from contextlib import nested
14
15import pkg_resources
16
17from PyQt4.QtGui import QFont, QColor
18from PyQt4.QtCore import QRect, QSettings, QDir
19
20from Orange import OrangeCanvas
21from Orange.OrangeCanvas.application.application import CanvasApplication
22from Orange.OrangeCanvas.application.canvasmain import CanvasMainWindow
23
24from Orange.OrangeCanvas.gui.splashscreen import SplashScreen, QPixmap
25from Orange.OrangeCanvas.config import cache_dir
26from Orange.OrangeCanvas import config
27from Orange.OrangeCanvas.utils.redirect import redirect_stdout, redirect_stderr
28
29from Orange.OrangeCanvas.registry import qt
30from Orange.OrangeCanvas.registry import WidgetRegistry, set_global_registry
31from Orange.OrangeCanvas.registry import cache
32
33log = logging.getLogger(__name__)
34
35
36def qt_logging_handle(msg_type, message):
37    print msg_type, message
38
39
40def main(argv=None):
41    if argv is None:
42        argv = sys.argv[1:]
43
44    usage = "usage: %prog [options] [scheme_file]"
45    parser = optparse.OptionParser(usage=usage)
46
47    parser.add_option("--no-discovery",
48                      action="store_true",
49                      help="Don't run widget discovery "
50                           "(use full cache instead)")
51
52    parser.add_option("--force-discovery",
53                      action="store_true",
54                      help="Force full widget discovery "
55                           "(invalidate cache)")
56    parser.add_option("--no-welcome",
57                      action="store_true",
58                      help="Don't show welcome dialog.")
59    parser.add_option("--no-splash",
60                      action="store_true",
61                      help="Don't show splash screen.")
62    parser.add_option("-l", "--log-level",
63                      help="Logging level (0, 1, 2, 3)",
64                      type="int", default=1)
65    parser.add_option("--no-redirect",
66                      action="store_true",
67                      help="Do not redirect stdout/err to canvas output view.")
68    parser.add_option("--style",
69                      help="QStyle to use",
70                      type="str", default=None)
71    parser.add_option("--stylesheet",
72                      help="Application level CSS style sheet to use",
73                      type="str", default="orange.qss")
74    parser.add_option("--qt",
75                      help="Additional arguments for QApplication",
76                      type="str", default=None)
77
78    (options, args) = parser.parse_args(argv)
79
80    levels = [logging.CRITICAL,
81              logging.WARN,
82              logging.INFO,
83              logging.DEBUG]
84
85    logging.basicConfig(level=levels[options.log_level])
86
87    log.info("Starting 'Orange Canvas' application.")
88
89    qt_argv = ["orange-canvas"]
90
91    if options.style is not None:
92        qt_argv += ["-style", options.style]
93
94    if options.qt is not None:
95        qt_argv += options.qt.split()
96
97    log.debug("Starting CanvasApplicaiton with argv = %r.", qt_argv)
98    app = CanvasApplication(qt_argv)
99
100    # Note: config.init must be called after the QApplication constructor
101    config.init()
102    settings = QSettings()
103
104    stylesheet = options.stylesheet
105    stylesheet_string = None
106
107    if stylesheet != "none":
108        if os.path.isfile(stylesheet):
109            stylesheet_string = open(stylesheet, "rb").read()
110        else:
111            if not os.path.splitext(stylesheet)[1]:
112                # no extension
113                stylesheet = os.path.extsep.join([stylesheet, "qss"])
114
115            pkg_name = OrangeCanvas.__name__
116            resource = os.path.join("styles", stylesheet)
117
118            if pkg_resources.resource_exists(pkg_name, resource):
119                stylesheet_string = pkg_resources.resource_string(
120                                        pkg_name, resource)
121                base = pkg_resources.resource_filename(pkg_name, "styles")
122
123                matches = re.findall(
124                    r"^\s@([a-zA-Z0-9_]+?)=([a-zA-Z0-9_/]+?)$",
125                    stylesheet_string,
126                    re.MULTILINE)
127
128                for prefix, search_path in matches:
129                    QDir.addSearchPath(prefix, os.path.join(base, search_path))
130                    log.info("Adding search path %r for prefix, %r",
131                             search_path, prefix)
132            else:
133                log.info("%r style sheet not found.", stylesheet)
134
135    if stylesheet_string is not None:
136        app.setStyleSheet(stylesheet_string)
137
138    # Add the default canvas_icons search path
139    dirpath = os.path.abspath(os.path.dirname(OrangeCanvas.__file__))
140    QDir.addSearchPath("canvas_icons", os.path.join(dirpath, "icons"))
141
142    canvas_window = CanvasMainWindow()
143    canvas_window.resize(1024, 650)
144
145    if not options.force_discovery:
146        reg_cache = cache.registry_cache()
147    else:
148        reg_cache = None
149
150    widget_discovery = qt.QtWidgetDiscovery(cached_descriptions=reg_cache)
151
152    widget_registry = qt.QtWidgetRegistry()
153
154    widget_discovery.found_category.connect(
155        widget_registry.register_category
156    )
157    widget_discovery.found_widget.connect(
158        widget_registry.register_widget
159    )
160
161    want_splash = \
162        settings.value("startup/show-splash-screen", True).toPyObject() and \
163        not options.no_splash
164
165    if want_splash:
166        pm = QPixmap(pkg_resources.resource_filename(
167                        __name__, "icons/orange-splash-screen.png")
168                     )
169        # Text rectangle in which to fit the message.
170        rect = QRect(88, 193, 200, 20)
171        splash_screen = SplashScreen(pixmap=pm, textRect=rect)
172        splash_screen.setFont(QFont("Helvetica", 12))
173        color = QColor("#FFD39F")
174
175        def show_message(message):
176            splash_screen.showMessage(message, color=color)
177
178        widget_discovery.discovery_start.connect(splash_screen.show)
179        widget_discovery.discovery_process.connect(show_message)
180        widget_discovery.discovery_finished.connect(splash_screen.hide)
181
182    log.info("Running widget discovery process.")
183
184    cache_filename = os.path.join(cache_dir(), "widget-registry.pck")
185    if options.no_discovery:
186        widget_registry = cPickle.load(open(cache_filename, "rb"))
187        widget_registry = qt.QtWidgetRegistry(widget_registry)
188    else:
189        widget_discovery.run()
190        # Store cached descriptions
191        cache.save_registry_cache(widget_discovery.cached_descriptions)
192        cPickle.dump(WidgetRegistry(widget_registry),
193                     open(cache_filename, "wb"))
194    set_global_registry(widget_registry)
195    canvas_window.set_widget_registry(widget_registry)
196    canvas_window.show()
197
198    want_welcome = \
199        settings.value("welcomedialog/show-at-startup", True).toBool() \
200        and not options.no_welcome
201
202    canvas_window.raise_()
203
204    if want_welcome and not args:
205        canvas_window.welcome_dialog()
206
207    elif args:
208        log.info("Loading a scheme from the command line argument %r",
209                 args[0])
210        canvas_window.load_scheme(args[0])
211
212    disable_redirect = \
213        settings.value("mainwindow/no-stdout-redirect", False).toBool() or \
214        options.no_redirect
215
216    if not disable_redirect:
217        output = canvas_window.output_view()
218    else:
219        output = None
220
221    with nested(redirect_stdout(output), redirect_stderr(output)):
222        log.info("Entering main event loop.")
223        try:
224            status = app.exec_()
225        except BaseException:
226            log.error("Error in main event loop.", exc_info=True)
227
228    canvas_window.deleteLater()
229    app.processEvents()
230    app.flush()
231    del canvas_window
232
233    # Collect any cycles before deleting the QApplication instance
234    gc.collect()
235
236    del app
237    return status
238
239
240if __name__ == "__main__":
241    sys.exit(main())
Note: See TracBrowser for help on using the repository browser.