Example #1
0
	def __init__(self, main_window, theme=None):
	
		"""
		Constructor
		
		Arguments:
		main_window -- the main_window object
		
		Keyword arguments:
		theme -- the theme to be used or None to use config (default=None)
		"""

		self.main_window = main_window
		if theme == None:
			self.theme = config.get_config(u"theme")
		else:
			self.theme = theme
		self.theme_folder = misc.resource(os.path.join(u"theme", \
			self.theme))
		debug.msg(u"theme = '%s' (%s)" % (self.theme, self.theme_folder))			
		if self.theme_folder == None or not os.path.exists(self.theme_folder):			
			debug.msg(u"theme '%s' does not exist, using 'default'" % theme, \
				reason=u"warning")
			self.theme = u"default"
			self.theme_folder = misc.resource(os.path.join(u"theme", \
				self.theme))						
		self.theme_info = os.path.join(self.theme_folder, u"__theme__.py")
		if os.path.exists(self.theme_info):						
			info = imp.load_source(self.theme, self.theme_info)
			self._qss = path = \
				open(os.path.join(self.theme_folder, info.qss)).read()
			self._icon_map = info.icon_map
			self._icon_theme = info.icon_theme									
		self.load_icon_map()
		self.apply_theme(self.main_window)			
Example #2
0
    def __init__(self, main_window, theme=None):
        """
		Constructor
		
		Arguments:
		main_window -- the main_window object
		
		Keyword arguments:
		theme -- the theme to be used or None to use config (default=None)
		"""

        self.main_window = main_window
        if theme == None:
            self.theme = config.get_config(u"theme")
        else:
            self.theme = theme
        self.theme_folder = misc.resource(os.path.join(u"theme", \
         self.theme))
        debug.msg(u"theme = '%s' (%s)" % (self.theme, self.theme_folder))
        if self.theme_folder == None or not os.path.exists(self.theme_folder):
            debug.msg(u"theme '%s' does not exist, using 'default'" % theme, \
             reason=u"warning")
            self.theme = u"default"
            self.theme_folder = misc.resource(os.path.join(u"theme", \
             self.theme))
        self.theme_info = os.path.join(self.theme_folder, u"__theme__.py")
        if os.path.exists(self.theme_info):
            info = imp.load_source(self.theme, self.theme_info)
            self._qss = path = \
             open(os.path.join(self.theme_folder, info.qss)).read()
            self._icon_map = info.icon_map
            self._icon_theme = info.icon_theme
        self.load_icon_map()
        self.apply_theme(self.main_window)
Example #3
0
	def qpixmap(self, icon, size=None):
	
		"""
		Get an icon from the theme
		
		Arguments:
		icon -- the icon name
		
		Keyword arguments:
		size -- the size of the icon or None for default (default=None)
		
		Returns:
		A QPixmap		
		"""	
		
		if size == None:
			if icon in self.icon_map:
				name, size = self.icon_map[icon]
			else:
				name = icon
				size = self.default_icon_size			
		else:
			if icon in self.icon_map:
				name = self.icon_map[icon][0]
			else:
				name = icon					
		return QtGui.QIcon.fromTheme(name, QtGui.QIcon(os.path.join( \
			misc.resource(u"theme"), u"fallback.png"))).pixmap(size)
Example #4
0
	def load_ui(self, ui=None):

		"""
		desc:
			Dynamically loads the ui, if any.

		keywords:
			ui:			An id for a user-interface file, or None.
		"""

		if ui is not None:
			# If the UI file has been explicitly registered, which is the case
			# for extensions
			if hasattr(self, u'experiment') and ui in self.experiment.resources:
				ui_path = self.experiment.resources[ui]
			else:
				# Dot-split the ui id, append a `.ui` extension, and assume it's
				# relative to the resources/ui subfolder.
				path_list = [u'ui'] + ui.split(u'.')
				if hasattr(self, u'experiment'):
					# If an experiment object is available, use that to find the
					# resources ...
					ui_path = self.experiment.resource(
						os.path.join(*path_list)+u'.ui')
				else:
					# ... otherwise use the static resources function.
					from libopensesame import misc
					ui_path = misc.resource(os.path.join(*path_list)+u'.ui')
			debug.msg(u'dynamically loading ui: %s' % ui_path)
			with open(ui_path) as fd:
				self.ui = uic.loadUi(fd, self)
		else:
			self.ui = None
Example #5
0
	def resource(self, name):

		"""
		Retrieves a file from the resources folder.

		Arguments:
		name	--	The file name.

		Returns:
		A Unicode string with the full path to the file in the resources
		folder.
		"""

		name = self.unistr(name)
		if self != None:
			if name in self.resources:
				return self.resources[name]
			if os.path.exists(self.get_file(name)):
				return self.get_file(name)
		path = misc.resource(name)
		if path == None:
			raise Exception( \
				u"The resource '%s' could not be found in libopensesame.experiment.resource()" \
				% name)
		return path
Example #6
0
    def init_cache(self):
        """
		desc:
			Initializes the webbrowser cache, if available.
		"""

        import pickle

        cache_file = misc.resource(u'webbrowser-cache.pkl')
        if cache_file is None:
            self.extension_manager.fire(
                u'notify',
                message=_(u'No webbrowser cache available'),
                category=u'info')
            self._cache = {}
            return
        with open(cache_file) as fd:
            try:
                self._cache = pickle.load(fd)
            except:
                self._cache = {}
                return
        if not isinstance(self._cache, dict):
            self.extension_manager.fire(
                u'notify',
                message=_(u'Webbrowser cache is corrupt'),
                category=u'warning')
            self._cache = {}
            return
Example #7
0
    def qpixmap(self, icon, size=None):
        """
		Get an icon from the theme
		
		Arguments:
		icon -- the icon name
		
		Keyword arguments:
		size -- the size of the icon or None for default (default=None)
		
		Returns:
		A QPixmap		
		"""

        if size == None:
            if icon in self.icon_map:
                name, size = self.icon_map[icon]
            else:
                name = icon
                size = self.default_icon_size
        else:
            if icon in self.icon_map:
                name = self.icon_map[icon][0]
            else:
                name = icon
        return QtGui.QIcon.fromTheme(name, QtGui.QIcon(os.path.join( \
         misc.resource(u"theme"), u"fallback.png"))).pixmap(size)
Example #8
0
    def load_ui(self, ui=None):
        """
		desc:
			Dynamically loads the ui, if any.

		keywords:
			ui:			An id for a user-interface file, or None.
		"""

        if ui is not None:
            # If the UI file has been explicitly registered, which is the case
            # for extensions
            if hasattr(self,
                       u'experiment') and ui in self.experiment.resources:
                ui_path = self.experiment.resources[ui]
            else:
                # Dot-split the ui id, append a `.ui` extension, and assume it's
                # relative to the resources/ui subfolder.
                path_list = [u'ui'] + ui.split(u'.')
                if hasattr(self, u'experiment'):
                    # If an experiment object is available, use that to find the
                    # resources ...
                    ui_path = self.experiment.resource(
                        os.path.join(*path_list) + u'.ui')
                else:
                    # ... otherwise use the static resources function.
                    from libopensesame import misc
                    ui_path = misc.resource(os.path.join(*path_list) + u'.ui')
            debug.msg(u'dynamically loading ui: %s' % ui_path)
            with open(ui_path) as fd:
                self.ui = uic.loadUi(fd, self)
        else:
            self.ui = None
Example #9
0
	def resource(self, name):

		"""
		Retrieves a file from the resources folder.

		Arguments:
		name	--	The file name.

		Returns:
		A Unicode string with the full path to the file in the resources
		folder.
		"""

		name = self.unistr(name)
		if self != None:
			if name in self.resources:
				return self.resources[name]
			if os.path.exists(self.get_file(name)):
				return self.get_file(name)
		path = misc.resource(name)
		if path == None:
			raise Exception( \
				u"The resource '%s' could not be found in libopensesame.experiment.resource()" \
				% name)
		return path
Example #10
0
	def init_cache(self):

		"""
		desc:
			Initializes the webbrowser cache, if available.
		"""

		import pickle

		cache_file = misc.resource(u'webbrowser-cache.pkl')
		if cache_file is None:
			self.extension_manager.fire(u'notify',
				message=_(u'No webbrowser cache available'),
				category=u'info')
			self._cache = {}
			return
		with open(cache_file) as fd:
			try:
				self._cache = pickle.load(fd)
			except:
				self._cache = {}
				return
		if not isinstance(self._cache, dict):
			self.extension_manager.fire(u'notify',
				message=_(u'Webbrowser cache is corrupt'),
				category=u'warning')
			self._cache = {}
			return
Example #11
0
	def __init__(self, main_window, theme=None):

		"""
		Constructor

		Arguments:
		main_window -- the main_window object

		Keyword arguments:
		theme -- the theme to be used or None to use config (default=None)
		"""

		self.main_window = main_window
		self.fallback_icon = QtGui.QIcon(os.path.join(misc.resource(u"theme"),
			u"fallback.png"))
		if theme is None:
			self.theme = config.get_config(u"theme")
		else:
			self.theme = theme
		self.theme_folder = misc.resource(os.path.join(u"theme", \
			self.theme))
		debug.msg(u"theme = '%s' (%s)" % (self.theme, self.theme_folder))
		# The theme folder must exist, and contain a file called __theme__.py,
		# if not, we fall back to the default theme, which is assumed to always
		# exist.
		if self.theme_folder is None or not os.path.exists(
			os.path.join(self.theme_folder, u'__theme__.py')):
			debug.msg(u"theme '%s' does not exist, using 'default'" % theme, \
				reason=u"warning")
			self.theme = u"default"
			self.theme_folder = misc.resource(os.path.join(u"theme", \
				self.theme))
		self.theme_info = os.path.join(self.theme_folder, u"__theme__.py")
		if os.path.exists(self.theme_info):
			info = imp.load_source(self.theme,
				safe_str(self.theme_info, enc=misc.filesystem_encoding()))
			with open(os.path.join(self.theme_folder, info.qss)) as fd:
				self._qss = fd.read()
			self._icon_map = info.icon_map
			self._icon_theme = info.icon_theme
		self.load_icon_map()
		self.apply_theme(self.main_window)
Example #12
0
    def __init__(self, main_window, theme=None):
        """
		Constructor

		Arguments:
		main_window -- the main_window object

		Keyword arguments:
		theme -- the theme to be used or None to use config (default=None)
		"""

        self.main_window = main_window
        self.fallback_icon = QtGui.QIcon(
            os.path.join(misc.resource(u"theme"), u"fallback.png"))
        if theme is None:
            self.theme = config.get_config(u"theme")
        else:
            self.theme = theme
        self.theme_folder = misc.resource(os.path.join(u"theme", \
         self.theme))
        debug.msg(u"theme = '%s' (%s)" % (self.theme, self.theme_folder))
        # The theme folder must exist, and contain a file called __theme__.py,
        # if not, we fall back to the default theme, which is assumed to always
        # exist.
        if self.theme_folder is None or not os.path.exists(
                os.path.join(self.theme_folder, u'__theme__.py')):
            debug.msg(u"theme '%s' does not exist, using 'default'" % theme, \
             reason=u"warning")
            self.theme = u"default"
            self.theme_folder = misc.resource(os.path.join(u"theme", \
             self.theme))
        self.theme_info = os.path.join(self.theme_folder, u"__theme__.py")
        if os.path.exists(self.theme_info):
            info = imp.load_source(
                self.theme,
                safe_str(self.theme_info, enc=misc.filesystem_encoding()))
            with safe_open(os.path.join(self.theme_folder, info.qss)) as fd:
                self._qss = fd.read()
            self._icon_map = info.icon_map
            self._icon_theme = info.icon_theme
        self.load_icon_map()
        self.apply_theme(self.main_window)
Example #13
0
    def qicon(self, icon):
        """
		Get an icon from the theme
		
		Arguments:
		icon -- the icon name
		
		Returns:
		A QIcon
		"""

        if icon in self.icon_map:
            name, size = self.icon_map[icon]
        else:
            name = icon
        return QtGui.QIcon.fromTheme(name, QtGui.QIcon(os.path.join( \
         misc.resource(u"theme"), u"fallback.png")))
	def set_controls(self):

		"""
		desc:
			Updates the controls.
		"""

		if self.lock:
			return
		self.lock = True
		self.ui.checkbox_autoresponse.setChecked(
			self.experiment.auto_response)
		self.ui.checkbox_toolbar_text.setChecked(
			self.main_window.ui.toolbar_main.toolButtonStyle() == \
			QtCore.Qt.ToolButtonTextUnderIcon)
		self.ui.checkbox_small_toolbar.setChecked(cfg.toolbar_size == 16)
		self.ui.combobox_runner.setCurrentIndex(
			self.ui.combobox_runner.findText(cfg.runner,
			flags=QtCore.Qt.MatchContains))
		# Set the locale combobox
		self.ui.combobox_locale.addItem(u'[Default]')
		self.ui.combobox_locale.setCurrentIndex(0)
		locales = sorted(
			[
				locale[:-3]
				for locale in os.listdir(misc.resource(u'locale'))
				if locale != u'translatables.qm'
			] + [u'en_US']
		)
		for i, locale in enumerate(locales):
			self.ui.combobox_locale.addItem(locale)
			if cfg.locale == locale:
				self.ui.combobox_locale.setCurrentIndex(i+1)
		# Set the style combobox
		self.ui.combobox_style.addItem(u"[Default]")
		self.ui.combobox_style.setCurrentIndex(0)
		for i, style in enumerate(QtWidgets.QStyleFactory.keys()):
			self.ui.combobox_style.addItem(style)
			if cfg.style == style:
				self.ui.combobox_style.setCurrentIndex(i+1)
		# Set the theme combobox
		for i, _theme in enumerate(theme.available_themes):
			self.ui.combobox_theme.addItem(_theme)
			if cfg.theme == _theme:
				self.ui.combobox_theme.setCurrentIndex(i+1)
		self.lock = False
Example #15
0
	def qicon(self, icon):
	
		"""
		Get an icon from the theme
		
		Arguments:
		icon -- the icon name
		
		Returns:
		A QIcon
		"""	
	
		if icon in self.icon_map:
			name, size = self.icon_map[icon]
		else:
			name = icon
		return QtGui.QIcon.fromTheme(name, QtGui.QIcon(os.path.join( \
			misc.resource(u"theme"), u"fallback.png")))
Example #16
0
	def set_controls(self):

		"""
		desc:
			Updates the controls.
		"""

		if self.lock:
			return
		self.lock = True
		self.ui.checkbox_autoresponse.setChecked(
			self.experiment.auto_response)
		self.ui.checkbox_toolbar_text.setChecked(
			self.main_window.ui.toolbar_main.toolButtonStyle() == \
			QtCore.Qt.ToolButtonTextUnderIcon)
		self.ui.checkbox_small_toolbar.setChecked(cfg.toolbar_size == 16)
		self.ui.combobox_runner.setCurrentIndex(
			self.ui.combobox_runner.findText(cfg.runner,
			flags=QtCore.Qt.MatchContains))
		# Set the locale combobox
		self.ui.combobox_locale.addItem(u'[Default]')
		self.ui.combobox_locale.setCurrentIndex(0)
		locales = [locale[:-3] \
			for locale in os.listdir(misc.resource(u'locale')) \
			if locale != u'translatables']
		for i, locale in enumerate(locales):
			self.ui.combobox_locale.addItem(locale)
			if cfg.locale == locale:
				self.ui.combobox_locale.setCurrentIndex(i+1)
		# Set the style combobox
		self.ui.combobox_style.addItem(u"[Default]")
		self.ui.combobox_style.setCurrentIndex(0)
		for i, style in enumerate(QtWidgets.QStyleFactory.keys()):
			self.ui.combobox_style.addItem(style)
			if cfg.style == style:
				self.ui.combobox_style.setCurrentIndex(i+1)
		# Set the theme combobox
		for i, _theme in enumerate(theme.available_themes):
			self.ui.combobox_theme.addItem(_theme)
			if cfg.theme == _theme:
				self.ui.combobox_theme.setCurrentIndex(i+1)
		self.lock = False
Example #17
0
    def resource(self, name):

        """
		Retrieve a file from the resources folder

		Arguments:
		name -- the file name

		Returns:
		The full path to the file in the resources folder
		"""

        if self != None:
            if name in self.resources:
                return self.resources[name]
            if os.path.exists(self.get_file(name)):
                return self.get_file(name)
        path = misc.resource(name)
        if path == None:
            raise Exception("The resource '%s' could not be found in libopensesame.experiment.resource()" % name)
        return path
Example #18
0
    def resource(self, name):
        """
		Retrieve a file from the resources folder

		Arguments:
		name -- the file name

		Returns:
		The full path to the file in the resources folder
		"""

        if self != None:
            if name in self.resources:
                return self.resources[name]
            if os.path.exists(self.get_file(name)):
                return self.get_file(name)
        path = misc.resource(name)
        if path == None:
            raise Exception( \
             "The resource '%s' could not be found in libopensesame.experiment.resource()" \
             % name)
        return path
Example #19
0
    def resume_init(self):
        """Resume GUI initialization"""

        from libopensesame import misc
        from libqtopensesame.misc import theme
        from libqtopensesame.extensions import extension_manager
        import platform
        import random

        # Set some initial variables
        self.current_path = None
        self.version = misc.version
        self.codename = misc.codename
        self.lock_refresh = False
        self.unsaved_changes = False

        # Make sure that QProgEdit doesn't complain about some standard names
        from QProgEdit import validate
        validate.addPythonBuiltins([u'exp', u'win', u'self'])

        # Initialize random number generator
        random.seed()

        # Check the filesystem encoding for debugging purposes
        debug.msg(u'filesystem encoding: %s' % misc.filesystem_encoding())

        # Parse the command line
        self.parse_command_line()

        # Restore the configuration
        self.restore_config()

        # Setup the UI
        self.load_ui(u'misc.main_window')
        self.ui.itemtree.setup(self)
        self.ui.tabwidget.main_window = self

        # Load a theme
        self.theme = theme.theme(self, self.options._theme)

        # Determine the home folder
        self.home_folder = libopensesame.misc.home_folder()

        # Create .opensesame folder if it doesn't exist yet
        if not os.path.exists(os.path.join(self.home_folder, u".opensesame")):
            os.mkdir(os.path.join(self.home_folder, u".opensesame"))

        # Set the filter-string for opening and saving files
        self.file_type_filter = \
         u"OpenSesame files (*.opensesame.tar.gz *.opensesame);;OpenSesame script and file pool (*.opensesame.tar.gz);;OpenSesame script (*.opensesame)"
        self.file_type_filter_script = u"OpenSesame script (*.opensesame)"
        self.file_type_filter_pool = \
         u"OpenSesame script and file pool (*.opensesame.tar.gz)"

        # Set the window message
        self.window_message(_(u"Welcome to OpenSesame %s") % self.version)

        # Set the window icon
        self.setWindowIcon(self.theme.qicon(u"opensesame"))

        # Make the connections
        self.ui.itemtree.structure_change.connect(self.update_overview_area)
        self.ui.action_quit.triggered.connect(self.close)
        self.ui.action_new.triggered.connect(self.new_file)
        self.ui.action_open.triggered.connect(self.open_file)
        self.ui.action_save.triggered.connect(self.save_file)
        self.ui.action_save_as.triggered.connect(self.save_file_as)
        self.ui.action_run.triggered.connect(self.run_experiment)
        self.ui.action_run_in_window.triggered.connect(
            self.run_experiment_in_window)
        self.ui.action_run_quick.triggered.connect(self.run_quick)
        self.ui.action_enable_auto_response.triggered.connect(
            self.set_auto_response)
        self.ui.action_close_current_tab.triggered.connect(
            self.ui.tabwidget.close_current)
        self.ui.action_close_all_tabs.triggered.connect(
            self.ui.tabwidget.close_all)
        self.ui.action_close_other_tabs.triggered.connect(
            self.ui.tabwidget.close_other)
        self.ui.action_onetabmode.triggered.connect(
            self.ui.tabwidget.toggle_onetabmode)
        self.ui.action_show_overview.triggered.connect(self.toggle_overview)
        self.ui.action_show_variable_inspector.triggered.connect(
            self.refresh_variable_inspector)
        self.ui.action_show_pool.triggered.connect(self.refresh_pool)
        self.ui.action_show_stdout.triggered.connect(self.refresh_stdout)
        self.ui.action_preferences.triggered.connect(
            self.ui.tabwidget.open_preferences)
        self.ui.button_help_stdout.clicked.connect(
            self.ui.tabwidget.open_stdout_help)

        # Setup the overview area
        self.ui.dock_overview.show()
        self.ui.dock_overview.visibilityChanged.connect( \
         self.ui.action_show_overview.setChecked)

        # Setup the variable inspector
        from libqtopensesame.widgets.variable_inspector import \
         variable_inspector
        self.ui.variable_inspector = variable_inspector(self)
        self.ui.dock_variable_inspector.hide()
        self.ui.dock_variable_inspector.visibilityChanged.connect(
            self.ui.action_show_variable_inspector.setChecked)
        self.ui.dock_variable_inspector.setWidget(self.ui.variable_inspector)

        # Setup the file pool
        from libqtopensesame.widgets.pool_widget import pool_widget
        self.ui.dock_pool.hide()
        self.ui.dock_pool.visibilityChanged.connect(
            self.ui.action_show_pool.setChecked)
        self.ui.pool_widget = pool_widget(self)
        self.ui.dock_pool.setWidget(self.ui.pool_widget)

        # Uncheck the debug window button on debug window close
        self.ui.dock_stdout.visibilityChanged.connect( \
         self.ui.action_show_stdout.setChecked)

        # Initialize keyboard shortcuts
        self.ui.shortcut_itemtree = QtGui.QShortcut( \
         QtGui.QKeySequence(), self, self.ui.itemtree.setFocus)
        self.ui.shortcut_tabwidget = QtGui.QShortcut( \
         QtGui.QKeySequence(), self, self.ui.tabwidget.setFocus)
        self.ui.shortcut_stdout = QtGui.QShortcut( \
         QtGui.QKeySequence(), self, self.ui.edit_stdout.setFocus)
        self.ui.shortcut_variables = QtGui.QShortcut( \
         QtGui.QKeySequence(), self, \
         self.ui.variable_inspector.set_focus())
        self.ui.shortcut_pool = QtGui.QShortcut( \
         QtGui.QKeySequence(), self, \
         self.ui.pool_widget.ui.edit_pool_filter.setFocus)

        # Create the initial experiment, which is the default template.
        self.experiment = experiment.experiment(self, u"New experiment", \
         open(misc.resource(os.path.join(u"templates", \
          u"default.opensesame")), u"r").read())
        self.experiment.build_item_tree()

        # Miscellaneous initialization
        self.restore_state()
        self.update_recent_files()
        self.set_unsaved(False)
        self.init_custom_fonts()
        self.ui.variable_inspector.refresh()

        # Initialize extensions
        self.extension_manager = extension_manager(self)
        self.extension_manager.fire(u'startup')
Example #20
0
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 OpenSesame.  If not, see <http://www.gnu.org/licenses/>.
"""

import sys

if "--catch-translatables" in sys.argv:

    # Automatically catches all strings that require translation
    from libopensesame import misc
    import os.path

    path = misc.resource(os.path.join(u"ts", u"translatables.txt"))

    def _(s):
        l = open(path).read().split(u"\n")
        if s not in l:
            f = open(path, u"a")
            f.write(s + u"\n")
            print u"New translatable: " + s
            f.close()
        return s


else:
    # A simple wrapper arround the translate function
    from PyQt4.QtCore import QCoreApplication
Example #21
0
	def resume_init(self):

		"""Resume GUI initialization"""

		from libopensesame import misc
		from libqtopensesame.misc import theme
		from libqtopensesame.extensions import extension_manager
		import platform
		import random

		# Set some initial variables
		self.current_path = None
		self.version = misc.version
		self.codename = misc.codename
		self.lock_refresh = False
		self.unsaved_changes = False

		# Make sure that QProgEdit doesn't complain about some standard names
		from QProgEdit import validate
		validate.addPythonBuiltins([u'exp', u'win', u'self'])

		# Initialize random number generator
		random.seed()

		# Check the filesystem encoding for debugging purposes
		debug.msg(u'filesystem encoding: %s' % misc.filesystem_encoding())

		# Parse the command line
		self.parse_command_line()

		# Restore the configuration
		self.restore_config()

		# Setup the UI
		self.load_ui(u'misc.main_window')
		self.ui.itemtree.setup(self)
		self.ui.tabwidget.main_window = self

		# Load a theme
		self.theme = theme.theme(self, self.options._theme)

		# Determine the home folder
		self.home_folder = libopensesame.misc.home_folder()

		# Create .opensesame folder if it doesn't exist yet
		if not os.path.exists(os.path.join(self.home_folder, u".opensesame")):
			os.mkdir(os.path.join(self.home_folder, u".opensesame"))

		# Set the filter-string for opening and saving files
		self.file_type_filter = \
			u"OpenSesame files (*.opensesame.tar.gz *.opensesame);;OpenSesame script and file pool (*.opensesame.tar.gz);;OpenSesame script (*.opensesame)"

		# Set the window message
		self.window_message(_(u"Welcome to OpenSesame %s") % self.version)

		# Set the window icon
		self.setWindowIcon(self.theme.qicon(u"opensesame"))

		# Make the connections
		self.ui.itemtree.structure_change.connect(self.update_overview_area)
		self.ui.action_quit.triggered.connect(self.close)
		self.ui.action_new.triggered.connect(self.new_file)
		self.ui.action_open.triggered.connect(self.open_file)
		self.ui.action_save.triggered.connect(self.save_file)
		self.ui.action_save_as.triggered.connect(self.save_file_as)
		self.ui.action_run.triggered.connect(self.run_experiment)
		self.ui.action_run_in_window.triggered.connect(
			self.run_experiment_in_window)
		self.ui.action_run_quick.triggered.connect(self.run_quick)
		self.ui.action_enable_auto_response.triggered.connect(
			self.set_auto_response)
		self.ui.action_close_current_tab.triggered.connect(
			self.ui.tabwidget.close_current)
		self.ui.action_close_all_tabs.triggered.connect(
			self.ui.tabwidget.close_all)
		self.ui.action_close_other_tabs.triggered.connect(
			self.ui.tabwidget.close_other)
		self.ui.action_onetabmode.triggered.connect(
			self.ui.tabwidget.toggle_onetabmode)
		self.ui.action_show_overview.triggered.connect(self.toggle_overview)
		self.ui.action_show_variable_inspector.triggered.connect(
			self.refresh_variable_inspector)
		self.ui.action_show_pool.triggered.connect(self.refresh_pool)
		self.ui.action_show_stdout.triggered.connect(self.refresh_stdout)
		self.ui.action_preferences.triggered.connect(
			self.ui.tabwidget.open_preferences)
		self.ui.button_help_stdout.clicked.connect(
			self.ui.tabwidget.open_stdout_help)

		# Setup the overview area
		self.ui.dock_overview.show()
		self.ui.dock_overview.visibilityChanged.connect( \
			self.ui.action_show_overview.setChecked)

		# Setup the variable inspector
		from libqtopensesame.widgets.variable_inspector import \
			variable_inspector
		self.ui.variable_inspector = variable_inspector(self)
		self.ui.dock_variable_inspector.hide()
		self.ui.dock_variable_inspector.visibilityChanged.connect(
			self.ui.action_show_variable_inspector.setChecked)
		self.ui.dock_variable_inspector.setWidget(self.ui.variable_inspector)

		# Setup the file pool
		from libqtopensesame.widgets.pool_widget import pool_widget
		self.ui.dock_pool.hide()
		self.ui.dock_pool.visibilityChanged.connect(
			self.ui.action_show_pool.setChecked)
		self.ui.pool_widget = pool_widget(self)
		self.ui.dock_pool.setWidget(self.ui.pool_widget)

		# Uncheck the debug window button on debug window close
		self.ui.dock_stdout.visibilityChanged.connect( \
			self.ui.action_show_stdout.setChecked)

		# Initialize keyboard shortcuts
		self.ui.shortcut_itemtree = QtGui.QShortcut( \
			QtGui.QKeySequence(), self, self.ui.itemtree.setFocus)
		self.ui.shortcut_tabwidget = QtGui.QShortcut( \
			QtGui.QKeySequence(), self, self.ui.tabwidget.setFocus)
		self.ui.shortcut_stdout = QtGui.QShortcut( \
			QtGui.QKeySequence(), self, self.ui.edit_stdout.setFocus)
		self.ui.shortcut_variables = QtGui.QShortcut( \
			QtGui.QKeySequence(), self, \
			self.ui.variable_inspector.set_focus())
		self.ui.shortcut_pool = QtGui.QShortcut( \
			QtGui.QKeySequence(), self, \
			self.ui.pool_widget.ui.edit_pool_filter.setFocus)

		# Create the initial experiment, which is the default template.
		self.experiment = experiment.experiment(self, u"New experiment", \
			open(misc.resource(os.path.join(u"templates", \
				u"default.opensesame")), u"r").read())
		self.experiment.build_item_tree()

		# Miscellaneous initialization
		self.restore_state()
		self.update_recent_files()
		self.set_unsaved(False)		
		self.init_custom_fonts()

		# Initialize extensions
		self.extension_manager = extension_manager(self)
		self.extension_manager.fire(u'startup')
Example #22
0
	def resume_init(self):

		"""Resume GUI initialization"""

		from libopensesame import misc
		from libqtopensesame.misc import theme
		from libqtopensesame.extensions import extension_manager
		import random

		# Make sure that icons are shown in context menu, regardless of the
		# system settings. This is necessary, because Ubuntu doesn't show menu
		# icons by default.
		QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_DontShowIconsInMenus,
			False)
		# Add the Qt plugin folders to the library path, if they exists. Where
		# these folders are depends on the version of Qt4, but these are two
		# possible locations.
		qt_plugin_path = os.path.join(
			os.path.dirname(sys.executable), 'Library', 'plugins')
		if os.path.isdir(qt_plugin_path):
			QtCore.QCoreApplication.addLibraryPath(qt_plugin_path)
		qt_plugin_path = os.path.join(
			os.path.dirname(sys.executable), 'Library', 'lib', 'qt4', 'plugins')
		if os.path.isdir(qt_plugin_path):
			QtCore.QCoreApplication.addLibraryPath(qt_plugin_path)
		# Do a few things to customize QProgEdit behavior:
		# - Register the bundled monospace font (Droid Sans Mono)
		# - Make sure that QProgEdit doesn't complain about some standard names
		# - Ignore undefined name warnings, which don't play well with
		#   OpenSesame's single workspace
		QtGui.QFontDatabase.addApplicationFont(misc.resource(u'mono.ttf'))
		from QProgEdit import validate
		validate.addPythonBuiltins([u'exp', u'win', u'self'])
		if hasattr(validate, u'setPyFlakesFilter'):
			validate.setPyFlakesFilter(
				lambda msg: msg.message == u'undefined name %r')
		# Initialize random number generator
		random.seed()

		# Check the filesystem encoding for debugging purposes
		debug.msg(u'filesystem encoding: %s' % misc.filesystem_encoding())

		# # Parse the command line
		# self.parse_command_line()
		# 
		# # Restore the configuration
		# self.restore_config()
		self.set_style()
		self.set_warnings()
		# self.set_locale()

		# Setup the UI
		self.load_ui(u'misc.main_window')
		self.theme = theme.theme(self, self.options._theme)
		self.ui.itemtree.setup(self)
		self.ui.console.setup(self)
		self.ui.tabwidget.main_window = self

		# Determine the home folder
		self.home_folder = libopensesame.misc.home_folder()

		# Create .opensesame folder if it doesn't exist yet
		if not os.path.exists(os.path.join(self.home_folder, u".opensesame")):
			os.mkdir(os.path.join(self.home_folder, u".opensesame"))

		# Set the filter-string for opening and saving files
		self.save_file_filter =u'OpenSesame files (*.osexp)'
		self.open_file_filter = \
			u'OpenSesame files (*.osexp *.opensesame.tar.gz *.opensesame)'

		# Set the window message
		self._read_only = False
		self.window_message(_(u"New experiment"))

		# Set the window icon
		self.setWindowIcon(self.theme.qicon(u"opensesame"))

		# Make the connections
		self.ui.itemtree.structure_change.connect(self.update_overview_area)
		self.ui.action_quit.triggered.connect(self.close)
		self.ui.action_open.triggered.connect(self.open_file)
		self.ui.action_save.triggered.connect(self.save_file)
		self.ui.action_save_as.triggered.connect(self.save_file_as)
		self.ui.action_run.triggered.connect(self.run_experiment)
		self.ui.action_run_in_window.triggered.connect(
			self.run_experiment_in_window)
		self.ui.action_run_quick.triggered.connect(self.run_quick)
		self.ui.action_enable_auto_response.triggered.connect(
			self.set_auto_response)
		self.ui.action_close_current_tab.triggered.connect(
			self.ui.tabwidget.close_current)
		self.ui.action_close_all_tabs.triggered.connect(
			self.ui.tabwidget.close_all)
		self.ui.action_close_other_tabs.triggered.connect(
			self.ui.tabwidget.close_other)
		self.ui.action_onetabmode.triggered.connect(
			self.ui.tabwidget.toggle_onetabmode)
		self.ui.action_show_overview.triggered.connect(self.toggle_overview)
		self.ui.action_show_pool.triggered.connect(
			self.toggle_pool)
		self.ui.action_show_stdout.triggered.connect(self.refresh_stdout)
		self.ui.action_preferences.triggered.connect(
			self.ui.tabwidget.open_preferences)

		# Setup console
		self.ui.button_help_console.clicked.connect(
			self.ui.tabwidget.open_stdout_help)
		self.ui.button_reset_console.clicked.connect(
			self.ui.console.reset)

		# Setup the overview area
		self.ui.dock_overview.show()
		self.ui.dock_overview.visibilityChanged.connect(
			self.ui.action_show_overview.setChecked)

		# Setup the file pool
		from libqtopensesame.widgets.pool_widget import pool_widget
		self.ui.dock_pool.hide()
		self.ui.dock_pool.visibilityChanged.connect(
			self.ui.action_show_pool.setChecked)
		self.ui.pool_widget = pool_widget(self)
		self.ui.dock_pool.setWidget(self.ui.pool_widget)

		# Uncheck the debug window button on debug window close
		self.ui.dock_stdout.hide()
		self.ui.dock_stdout.visibilityChanged.connect(
			self.ui.action_show_stdout.setChecked)

		# Initialize keyboard shortcuts
		self.ui.shortcut_itemtree = QtWidgets.QShortcut(QtGui.QKeySequence(), self,
			self.focus_overview_area)
		self.ui.shortcut_tabwidget = QtWidgets.QShortcut(
			QtGui.QKeySequence(), self, self.ui.tabwidget.focus)
		self.ui.shortcut_stdout = QtWidgets.QShortcut(QtGui.QKeySequence(), self,
			self.focus_debug_window)
		self.ui.shortcut_pool = QtWidgets.QShortcut(QtGui.QKeySequence(), self,
			self.focus_file_pool)

		# Create the initial experiment, which is the default template. Because
		# not all backends are supported under Python 3, we use a different
		# backend for each.
		if py3:
			tmpl = u'default-py3.osexp'
		else:
			tmpl = u'default.osexp'
		with safe_open(misc.resource(os.path.join(u'templates', tmpl)), u'r') as fd:
			self.experiment = experiment.experiment(self, u'New experiment',
				fd.read())
		self.experiment.build_item_tree()
		self.ui.itemtree.default_fold_state()

		# Miscellaneous initialization
		self.restore_state()
		self.update_recent_files()
		self.set_unsaved(False)
		self.init_custom_fonts()

		# Initialize extensions
		self.extension_manager = extension_manager(self)
		self.extension_manager.fire(u'startup')
Example #23
0
def opensesame():

    import os, sys, platform
    # Add the folder that contains the OpenSesame modules to the path. This is
    # generally only necessary if OpenSesame is directly run from source,
    # instead from an installation.
    if os.path.exists(os.path.join(os.getcwd(), 'libopensesame')):
        sys.path.insert(0, os.getcwd())
    # Support for multiprocessing when packaged
    # In OS X the multiprocessing module is horribly broken, but a fixed
    # version has been released as the 'billiard' module
    if platform.system() == 'Darwin':
        # Use normal multirpocessing module from python 3.4 and on
        if sys.version_info >= (3, 4):
            from multiprocessing import freeze_support, set_start_method
            freeze_support()
            set_start_method('forkserver')
        else:
            from billiard import freeze_support, forking_enable
            freeze_support()
            forking_enable(0)
    else:
        from multiprocessing import freeze_support
        freeze_support()
    # Parse the (optional) environment file that contains special paths, etc.
    from libopensesame.misc import resource, filesystem_encoding, \
     parse_environment_file
    parse_environment_file()
    # Force the new-style Qt API
    import sip
    import qtpy
    sip.setapi('QString', 2)
    sip.setapi('QVariant', 2)
    # Load debug package (this must be after the working directory change)
    from libopensesame import debug
    # Do the basic window initialization
    from qtpy.QtWidgets import QApplication

    # From Qt 5.6 on, QtWebEngine is the default way to render web pages
    # QtWebEngineWidgets must be imported before a QCoreApplication instance is created
    try:
        from qtpy import QtWebEngineWidgets
    except ImportError:
        pass

    app = QApplication(sys.argv)
    # Enable High DPI display with PyQt5
    if hasattr(qtpy.QtCore.Qt, 'AA_UseHighDpiPixmaps'):
        app.setAttribute(qtpy.QtCore.Qt.AA_UseHighDpiPixmaps)
    from libqtopensesame.qtopensesame import qtopensesame
    opensesame = qtopensesame(app)
    opensesame.__script__ = __file__
    app.processEvents()
    # Import the remaining modules
    from qtpy.QtCore import QObject, QLocale, QTranslator
    import os.path
    # Load the locale for UI translation. The locale can be specified on the
    # command line using the --locale parameter
    locale = QLocale().system().name()
    for i in range(len(sys.argv) - 1):
        if sys.argv[i] == '--locale':
            locale = sys.argv[i + 1]
    qm = resource(os.path.join(u'locale', locale) + u'.qm')
    # Say that we're trying to load de_AT, and it is not found, then we'll try
    # de_DE as fallback.
    if qm is None:
        l = locale.split(u'_')
        if len(l):
            _locale = l[0] + u'_' + l[0].upper()
            qm = resource(os.path.join(u'locale', _locale + u'.qm'))
            if qm is not None:
                locale = _locale
    opensesame._locale = locale
    if qm is not None:
        debug.msg(u'installing %s translator' % qm)
        translator = QTranslator()
        translator.load(qm)
        app.installTranslator(translator)
    else:
        debug.msg(u'no translator found for %s' % locale)
    # Now that the window is shown, load the remaining modules and resume the
    # GUI initialization.
    opensesame.resume_init()
    opensesame.restore_window_state()
    opensesame.refresh()
    opensesame.show()
    # Added for OS X, otherwise Window will not appear
    opensesame.raise_()
    # Exit using the application exit status
    sys.exit(app.exec_())
Example #24
0
    def resume_init(self):
        """Resume GUI initialization"""

        from libopensesame import misc
        from libqtopensesame.misc import theme
        from libqtopensesame.extensions import extension_manager
        import random

        # Make sure that icons are shown in context menu, regardless of the
        # system settings. This is necessary, because Ubuntu doesn't show menu
        # icons by default.
        QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_DontShowIconsInMenus,
                                            False)
        # Do a few things to customize QProgEdit behavior:
        # - Register the bundled monospace font (Droid Sans Mono)
        # - Make sure that QProgEdit doesn't complain about some standard names
        # - Ignore undefined name warnings, which don't play well with
        #   OpenSesame's single workspace
        QtGui.QFontDatabase.addApplicationFont(misc.resource(u'mono.ttf'))
        from QProgEdit import validate
        validate.addPythonBuiltins([u'exp', u'win', u'self'])
        if hasattr(validate, u'setPyFlakesFilter'):
            validate.setPyFlakesFilter(
                lambda msg: msg.message == u'undefined name %r')
        # Initialize random number generator
        random.seed()

        # Check the filesystem encoding for debugging purposes
        debug.msg(u'filesystem encoding: %s' % misc.filesystem_encoding())

        # # Parse the command line
        # self.parse_command_line()
        #
        # # Restore the configuration
        # self.restore_config()
        self.set_style()
        self.set_warnings()
        # self.set_locale()

        # Setup the UI
        self.load_ui(u'misc.main_window')
        self.theme = theme.theme(self, self.options._theme)
        self.ui.itemtree.setup(self)
        self.ui.console.setup(self)
        self.ui.tabwidget.main_window = self

        # Determine the home folder
        self.home_folder = libopensesame.misc.home_folder()

        # Create .opensesame folder if it doesn't exist yet
        if not os.path.exists(os.path.join(self.home_folder, u".opensesame")):
            os.mkdir(os.path.join(self.home_folder, u".opensesame"))

        # Set the filter-string for opening and saving files
        self.save_file_filter = u'OpenSesame files (*.osexp)'
        self.open_file_filter = \
         u'OpenSesame files (*.osexp *.opensesame.tar.gz *.opensesame)'

        # Set the window message
        self._read_only = False
        self.window_message(_(u"New experiment"))

        # Set the window icon
        self.setWindowIcon(self.theme.qicon(u"opensesame"))

        # Make the connections
        self.ui.itemtree.structure_change.connect(self.update_overview_area)
        self.ui.action_quit.triggered.connect(self.close)
        self.ui.action_open.triggered.connect(self.open_file)
        self.ui.action_save.triggered.connect(self.save_file)
        self.ui.action_save_as.triggered.connect(self.save_file_as)
        self.ui.action_run.triggered.connect(self.run_experiment)
        self.ui.action_run_in_window.triggered.connect(
            self.run_experiment_in_window)
        self.ui.action_run_quick.triggered.connect(self.run_quick)
        self.ui.action_kill.triggered.connect(self.kill_experiment)
        self.ui.action_enable_auto_response.triggered.connect(
            self.set_auto_response)
        self.ui.action_close_current_tab.triggered.connect(
            self.ui.tabwidget.close_current)
        self.ui.action_close_all_tabs.triggered.connect(
            self.ui.tabwidget.close_all)
        self.ui.action_close_other_tabs.triggered.connect(
            self.ui.tabwidget.close_other)
        self.ui.action_onetabmode.triggered.connect(
            self.ui.tabwidget.toggle_onetabmode)
        self.ui.action_show_overview.triggered.connect(self.toggle_overview)
        self.ui.action_show_pool.triggered.connect(self.toggle_pool)
        self.ui.action_show_stdout.triggered.connect(self.refresh_stdout)
        self.ui.action_preferences.triggered.connect(
            self.ui.tabwidget.open_preferences)

        # Setup console
        self.ui.button_help_console.clicked.connect(
            self.ui.tabwidget.open_stdout_help)
        self.ui.button_reset_console.clicked.connect(self.ui.console.reset)

        # Setup the overview area
        self.ui.dock_overview.show()
        self.ui.dock_overview.visibilityChanged.connect(
            self.ui.action_show_overview.setChecked)

        # Setup the file pool
        from libqtopensesame.widgets.pool_widget import pool_widget
        self.ui.dock_pool.hide()
        self.ui.dock_pool.visibilityChanged.connect(
            self.ui.action_show_pool.setChecked)
        self.ui.pool_widget = pool_widget(self)
        self.ui.dock_pool.setWidget(self.ui.pool_widget)

        # Uncheck the debug window button on debug window close
        self.ui.dock_stdout.hide()
        self.ui.dock_stdout.visibilityChanged.connect(
            self.ui.action_show_stdout.setChecked)

        # Initialize keyboard shortcuts
        self.ui.shortcut_itemtree = QtWidgets.QShortcut(
            QtGui.QKeySequence(), self, self.focus_overview_area)
        self.ui.shortcut_tabwidget = QtWidgets.QShortcut(
            QtGui.QKeySequence(), self, self.ui.tabwidget.focus)
        self.ui.shortcut_stdout = QtWidgets.QShortcut(QtGui.QKeySequence(),
                                                      self,
                                                      self.focus_debug_window)
        self.ui.shortcut_pool = QtWidgets.QShortcut(QtGui.QKeySequence(), self,
                                                    self.focus_file_pool)

        # Create the initial experiment, which is the default template. Because
        # not all backends are supported under Python 3, we use a different
        # backend for each.
        if py3:
            tmpl = u'default-py3.osexp'
        else:
            tmpl = u'default.osexp'
        with safe_open(misc.resource(os.path.join(u'templates', tmpl)),
                       u'r') as fd:
            self.experiment = experiment.experiment(self, u'New experiment',
                                                    fd.read())
        self.experiment.build_item_tree()
        self.ui.itemtree.default_fold_state()

        # Miscellaneous initialization
        self.restore_state()
        self.update_recent_files()
        self.set_unsaved(False)
        self.init_custom_fonts()

        # Initialize extensions
        self.extension_manager = extension_manager(self)
        self.extension_manager.fire(u'startup')
Example #25
0
def opensesame():

	import os, sys, platform
	# Add the folder that contains the OpenSesame modules to the path. This is
	# generally only necessary if OpenSesame is directly run from source,
	# instead from an installation.
	if os.path.exists(os.path.join(os.getcwd(), 'libopensesame')):
		sys.path.insert(0, os.getcwd())
	# Support for multiprocessing when packaged
	# In OS X the multiprocessing module is horribly broken, but a fixed
	# version has been released as the 'billiard' module
	if platform.system() == 'Darwin':
		# Use normal multirpocessing module from python 3.4 and on
		if sys.version_info >= (3,4):
			from multiprocessing import freeze_support, set_start_method
			freeze_support()
			set_start_method('forkserver')
		else:
			from billiard import freeze_support, forking_enable
			freeze_support()
			forking_enable(0)
	else:
		from multiprocessing import freeze_support
		freeze_support()
	# Parse the (optional) environment file that contains special paths, etc.
	from libopensesame.misc import resource, filesystem_encoding, \
		parse_environment_file
	parse_environment_file()
	# Force the new-style Qt API
	import sip
	import qtpy
	sip.setapi('QString', 2)
	sip.setapi('QVariant', 2)
	# Load debug package (this must be after the working directory change)
	from libopensesame import debug
	# Do the basic window initialization
	from qtpy.QtWidgets import QApplication

	# From Qt 5.6 on, QtWebEngine is the default way to render web pages
	# QtWebEngineWidgets must be imported before a QCoreApplication instance is created
	try:
		from qtpy import QtWebEngineWidgets
	except ImportError:
		pass
	
	app = QApplication(sys.argv)
	# Enable High DPI display with PyQt5
	if hasattr(qtpy.QtCore.Qt, 'AA_UseHighDpiPixmaps'):
		app.setAttribute(qtpy.QtCore.Qt.AA_UseHighDpiPixmaps)
	from libqtopensesame.qtopensesame import qtopensesame
	opensesame = qtopensesame(app)
	opensesame.__script__ = __file__
	app.processEvents()
	# Import the remaining modules
	from qtpy.QtCore import QObject, QLocale, QTranslator
	import os.path
	# Load the locale for UI translation. The locale can be specified on the
	# command line using the --locale parameter
	locale = str(QLocale().system().name())
	for i in range(len(sys.argv)-1):
		if sys.argv[i] == '--locale':
			locale = sys.argv[i+1]
	opensesame._locale = locale
	qm = resource(os.path.join(u'locale', locale) + u'.qm')
	if qm is not None:
		debug.msg(u'installing %s translator' % qm)
		translator = QTranslator()
		translator.load(qm)
		app.installTranslator(translator)
	else:
		debug.msg(u'no translator found for %s' % locale)
	# Now that the window is shown, load the remaining modules and resume the
	# GUI initialization.
	opensesame.resume_init()
	opensesame.restore_window_state()
	opensesame.refresh()
	opensesame.show()
	# Added for OS X, otherwise Window will not appear
	opensesame.raise_()
	# Exit using the application exit status
	sys.exit(app.exec_())
Example #26
0
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 OpenSesame.  If not, see <http://www.gnu.org/licenses/>.
"""

__author__ = "Sebastiaan Mathot"
__license__ = "GPLv3"

import sys
if '--catch-translatables' in sys.argv:

	# Automatically catches all strings that require translation
	from libopensesame import misc
	import os.path
	path = misc.resource(os.path.join('ts', 'translatables.txt'))
	def _(s):
		l = open(path).read().split('\n')
		if s not in l:
			f = open(path, 'a')
			f.write(s+'\n')
			print 'New translatable: '+s
			f.close()
		return s

else:
	# A simple wrapper arround the translate function
	from PyQt4.QtCore import QCoreApplication
	_ = lambda s: unicode(QCoreApplication.translate('script', s))
Example #27
0
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with OpenSesame.  If not, see <http://www.gnu.org/licenses/>.
"""

__author__ = "Sebastiaan Mathot"
__license__ = "GPLv3"

import sys
if '--catch-translatables' in sys.argv:

    # Automatically catches all strings that require translation
    from libopensesame import misc
    import os.path
    path = misc.resource(os.path.join('ts', 'translatables.txt'))

    def _(s):
        l = open(path).read().split('\n')
        if s not in l:
            f = open(path, 'a')
            f.write(s + '\n')
            print 'New translatable: ' + s
            f.close()
        return s

else:
    # A simple wrapper arround the translate function
    from PyQt4.QtCore import QCoreApplication
    _ = lambda s: unicode(QCoreApplication.translate('script', s))