Exemple #1
0
    def __init__(self, user, database):
        # The database connection parameters are specified in the CONFIG.py file.
        # Contains the reference to the database object.
        self.db = None

        # The database cursor.
        self.cursor = None

        # The current connection timeout limit.
        self.timeout = CONNECTION_TIMEOUT

        # The savepoints.
        self.savepoints = []

        # The user to connect with. If no user is specified, picks the first user
        # in the dictionary.
        self.user = user if user is not None else LOGIN.keys()[0]

        # The name of the database to connect to. If none is specified, use
        # <user>_db as the default database.
        self.database = database if database is not None else "%s_db" % self.user

        # Separate database connection used to terminate queries. If the terminator
        # cannot start, the grading cannot occur.
        try:
            self.terminator = Terminator(self.user, self.database)
        except mysql.connector.errors.Error:
            err("Could not start up terminator connection! Any unruly queries "
                + "must be manually killed!")
Exemple #2
0
    def __init__(self, window):
        """Class initialiser"""
        if isinstance(window.get_child(), Gtk.Notebook):
            err('There is already a Notebook at the top of this window')
            raise (ValueError)

        Container.__init__(self)
        GObject.GObject.__init__(self)
        self.terminator = Terminator()
        self.window = window
        GObject.type_register(Notebook)
        self.register_signals(Notebook)
        self.connect('switch-page', self.deferred_on_tab_switch)
        self.connect('scroll-event', self.on_scroll_event)
        self.configure()

        child = window.get_child()
        window.remove(child)
        window.add(self)
        window_last_active_term = window.last_active_term
        self.newtab(widget=child)
        if window_last_active_term:
            self.set_last_active_term(window_last_active_term)
            window.last_active_term = None

        self.show_all()
Exemple #3
0
    def __init__(self):
        """Class initialiser"""
        self.terminator = Terminator()
        self.terminator.register_window(self)

        Container.__init__(self)
        gtk.Window.__init__(self)
        gobject.type_register(Window)
        self.register_signals(Window)

        self.set_property('allow-shrink', True)
        self.apply_icon()

        self.register_callbacks()
        self.apply_config()

        self.title = WindowTitle(self)
        self.title.update()

        options = self.config.options_get()
        if options:
            if options.forcedtitle is not None:
                self.title.force_title(options.forcedtitle)

            if options.role is not None:
                self.set_role(options.role)

            if options.geometry is not None:
                if not self.parse_geometry(options.geometry):
                    err('Window::__init__: Unable to parse geometry: %s' %
                        options.geometry)

        self.pending_set_rough_geometry_hint = False
    def setup_replicator(self):
        '''
        Target:
            - clone a database in PostgreSQL.
        '''
        connecter = self.get_connecter()
        self.logger.debug(Messenger.BEGINNING_EXE_REPLICATOR)
        replicator = self.get_replicator(connecter)

        pg_superuser = connecter.is_pg_superuser()
        if not pg_superuser:
            connecter.cursor.execute(Queries.GET_PG_DB_SOME_DATA,
                                     (replicator.original_dbname, ))
            db = connecter.cursor.fetchone()
            if db['owner'] != connecter.user:
                self.logger.stop_exe(Messenger.ACTION_DB_NO_SUPERUSER)

        # Terminate every connection to the database which is going to be
        # replicated, if necessary
        if self.args.terminate:
            terminator = Terminator(connecter,
                                    target_dbs=[replicator.original_dbname],
                                    logger=self.logger)
            terminator.terminate_backend_dbs([replicator.original_dbname])

        # Clone the database
        replicator.replicate_pg_db()

        # Close connection to PostgreSQL
        connecter.pg_disconnect()
Exemple #5
0
 def __init__(self):
     """Class initialiser"""
     self.terminator = Terminator()
     self.maker = Factory()
     Container.__init__(self)
     self.signals.append({'name': 'resize-term',
                          'flags': GObject.SignalFlags.RUN_LAST,
                          'return_type': None,
                          'param_types': (GObject.TYPE_STRING,)})
Exemple #6
0
    def __init__(self, addr):
        Thread.__init__(self)
        self.setName("FeedListener")
        self.terminator = Terminator.getInstance()

        certHandler = CertificateHandler("front", 'server')

        publicKey, privateKey = certHandler.getKeyPair()
        clientsPath = certHandler.getEnrolledKeysPath()

        self.ctxHandler = ContextHandler(clientsPath)
        context = self.ctxHandler.getContext()
        self.socket = context.socket(zmq.REP)

        monitorSocket = self.socket.get_monitor_socket()
        monitor = Monitor(monitorSocket, 'front')
        monitor.setDaemon(True)
        monitor.start()

        self.socket.curve_secretkey = privateKey
        self.socket.curve_publickey = publicKey
        self.socket.curve_server = True

        self.socket.bind(addr)
        self.socket.setsockopt(zmq.RCVTIMEO, 10000)
        logging.info('Socket setup, public key: %s', publicKey)
Exemple #7
0
    def __init__(self, window):
        """Class initialiser"""
        if isinstance(window.get_child(), gtk.Notebook):
            err('There is already a Notebook at the top of this window')
            raise(ValueError)

        Container.__init__(self)
        gtk.Notebook.__init__(self)
        self.terminator = Terminator()
        self.window = window
        gobject.type_register(Notebook)
        self.register_signals(Notebook)
        self.connect('switch-page', self.deferred_on_tab_switch)
        self.configure()

        child = window.get_child()
        window.remove(child)
        window.add(self)
        window_last_active_term = window.last_active_term
        self.newtab(widget=child)
        if window_last_active_term:
            self.set_last_active_term(window_last_active_term)
            window.last_active_term = None

        self.show_all()
    def __init__(self, feedID, clientKey):
        Thread.__init__(self)
        self.setName("FeedHandler")
        self.terminator = Terminator.getInstance()

        self.certHandler = CertificateHandler(feedID, 'server')
        self.certHandler.prep()

        self.publicKey, privateKey = self.certHandler.getKeyPair()
        clientsPath = self.certHandler.getEnrolledKeysPath()

        self.ctxHandler = ContextHandler(clientsPath)
        context = self.ctxHandler.getContext()

        self.saveClientKey(clientKey)

        self.socket = context.socket(zmq.REP)
        self.socket.setsockopt(zmq.RCVTIMEO, 20000)

        monitorSocket = self.socket.get_monitor_socket()
        self.monitor = Monitor(monitorSocket, feedID)
        self.monitor.setDaemon(True)
        self.monitor.start()

        self.socket.curve_secretkey = privateKey
        self.socket.curve_publickey = self.publicKey
        self.socket.curve_server = True

        self.port = self.socket.bind_to_random_port('tcp://*',
                                                    min_port=49151,
                                                    max_port=65535)
        self.feedID = feedID
    def toggle_tab_visibility(self, widget):
        """tab visibility"""
        status = self.config['tab_position']
        old_tab_position = self.config['old_tab_position']
        if status == 'hidden':
            if old_tab_position:
                #if there's no oldstatus, hidden is default option
                self.config['tab_position'] = old_tab_position
                self.config.save()
        else:
            self.config['old_tab_position'] = status
            self.config['tab_position'] = 'hidden'
            self.config.save()

        terminator = Terminator()
        terminator.reconfigure()
	def __init__(self, app):
		QMainWindow.__init__(self)

		self.app = app
		authenticated = False

		self.terminator = Terminator.getInstance()

		if os.path.exists(userConfig):
			logging.debug('Authenticating on saved user details')
			authenticated, msg = self.authenticateUserDetails()

		if not authenticated:
			logging.debug('Not already logged in, presenting dialog.')
			loginDialog = LoginDialog()
			authenticated, msg, userID, key = loginDialog.getUserData()

			self.saveUserDetails(userID, key)

		if authenticated:
			logging.debug('User authenticated, initialising tabs.')
			tabs = MainWindowTabs(app)
			self.setCentralWidget(tabs)
		else:
			self.closeEvent(None)
Exemple #11
0
    def __init__(self):
        """Class initialiser"""
        self.terminator = Terminator()
        self.terminator.register_window(self)

        Container.__init__(self)
        gtk.Window.__init__(self)
        gobject.type_register(Window)
        self.register_signals(Window)

        self.set_property("allow-shrink", True)
        self.apply_icon()

        self.register_callbacks()
        self.apply_config()

        self.title = WindowTitle(self)
        self.title.update()

        options = self.config.options_get()
        if options:
            if options.forcedtitle is not None:
                self.title.force_title(options.forcedtitle)

            if options.role is not None:
                self.set_role(options.role)

            if options.geometry is not None:
                if not self.parse_geometry(options.geometry):
                    err("Window::__init__: Unable to parse geometry: %s" % options.geometry)

        self.pending_set_rough_geometry_hint = False
Exemple #12
0
  def __init__(self, user, database):
    # The database connection parameters are specified in the CONFIG.py file.
    # Contains the reference to the database object.
    self.db = None

    # The database cursor.
    self.cursor = None

    # The current connection timeout limit.
    self.timeout = CONNECTION_TIMEOUT

    # The savepoints.
    self.savepoints = []

    # The user to connect with. If no user is specified, picks the first user
    # in the dictionary.
    self.user = user if user is not None else LOGIN.keys()[0]

    # The name of the database to connect to. If none is specified, use
    # <user>_db as the default database.
    self.database = database if database is not None else "%s_db" % self.user

    # Separate database connection used to terminate queries. If the terminator
    # cannot start, the grading cannot occur.
    try:
      self.terminator = Terminator(self.user, self.database)
    except mysql.connector.errors.Error:
      err("Could not start up terminator connection! Any unruly queries " +
          "must be manually killed!")
class LayoutLauncher:
    """Class implementing the various parts of the preferences editor"""
    terminator = None
    config = None
    registry = None
    plugins = None
    keybindings = None
    window = None
    builder = None
    layouttreeview = None
    layouttreestore = None

    def __init__ (self):
        self.terminator = Terminator()
        self.terminator.register_launcher_window(self)

        self.config = config.Config()
        self.config.base.reload()
        self.builder = gtk.Builder()
        try:
            # Figure out where our library is on-disk so we can open our UI
            (head, _tail) = os.path.split(config.__file__)
            librarypath = os.path.join(head, 'layoutlauncher.glade')
            gladefile = open(librarypath, 'r')
            gladedata = gladefile.read()
        except Exception, ex:
            print "Failed to find layoutlauncher.glade"
            print ex
            return

        self.builder.add_from_string(gladedata)
        self.window = self.builder.get_object('layoutlauncherwin')

        icon_theme = gtk.IconTheme()
        try:
            icon = icon_theme.load_icon('terminator-layout', 48, 0)
        except (NameError, gobject.GError):
            dbg('Unable to load 48px Terminator preferences icon')
            icon = self.window.render_icon(gtk.STOCK_DIALOG_INFO, gtk.ICON_SIZE_BUTTON)
        self.window.set_icon(icon)

        self.builder.connect_signals(self)
        self.window.connect('destroy', self.on_destroy_event)
        self.window.show_all()
        self.layouttreeview = self.builder.get_object('layoutlist')
        self.layouttreestore = self.builder.get_object('layoutstore')
        self.update_layouts()
Exemple #14
0
	def on_stone_received(self, stone):
		pid_file = tempfile.mktemp()
		stone = pickle.loads(stone)
		logging.getLogger(__name__).info("received %s task from broker" % stone.name)
		child_pid = os.fork()
		time.sleep(0.1)
		if not child_pid:
			#child
			logging.getLogger(__name__).debug("started child %s" % os.getpid())
			s = Sisyphus(stone, pid_file, ttl=SISYPHUS_JOIN_TTL, logger=logging.getLogger(__name__))
			s.run()
			time.sleep(0.1)
		else:
			#master
			t = Terminator(child_pid, pid_file, ttl=SISYPHUS_WORKER_TTL)
			t.start()
			time.sleep(0.1)
 def __init__(self, parent):
     Thread.__init__(self)
     self.parent = parent
     self.terminator = Terminator.getInstance()
     self.moveTopConnector = GenericConnector(self.parent.moveTop)
     self.progressBarSetup = GenericConnector(self.parent.setupProgressBar)
     self.progressBarUpdate = GenericConnector(
         self.parent.updateProgressBar)
Exemple #16
0
 def unload(self):
     """Handle being removed"""
     if not self.match:
         err('unload called without self.handler_name being set')
         return
     terminator = Terminator()
     for terminal in terminator.terminals:
         terminal.match_remove(self.handler_name)
Exemple #17
0
    def __init__(self, terminal):
        """Class initialiser"""
        GObject.GObject.__init__(self)

        self.terminator = Terminator()
        self.terminal = terminal
        self.config = self.terminal.config

        self.label = EditableLabel()
        self.label.connect('edit-done', self.on_edit_done)
        self.ebox = Gtk.EventBox()
        grouphbox = Gtk.HBox()
        self.grouplabel = Gtk.Label(ellipsize='end')
        self.groupicon = Gtk.Image()
        self.bellicon = Gtk.Image()
        self.bellicon.set_no_show_all(True)

        self.groupentry = Gtk.Entry()
        self.groupentry.set_no_show_all(True)
        self.groupentry.connect('focus-out-event', self.groupentry_cancel)
        self.groupentry.connect('activate', self.groupentry_activate)
        self.groupentry.connect('key-press-event', self.groupentry_keypress)

        groupsend_type = self.terminator.groupsend_type
        if self.terminator.groupsend == groupsend_type['all']:
            icon_name = 'all'
        elif self.terminator.groupsend == groupsend_type['group']:
            icon_name = 'group'
        elif self.terminator.groupsend == groupsend_type['off']:
            icon_name = 'off'
        self.set_from_icon_name('_active_broadcast_%s' % icon_name, 
                Gtk.IconSize.MENU)

        grouphbox.pack_start(self.groupicon, False, True, 2)
        grouphbox.pack_start(self.grouplabel, False, True, 2)
        grouphbox.pack_start(self.groupentry, False, True, 2)

        self.ebox.add(grouphbox)
        self.ebox.show_all()

        self.bellicon.set_from_icon_name('terminal-bell', Gtk.IconSize.MENU)

        viewport = Gtk.Viewport(hscroll_policy='natural')
        viewport.add(self.label)

        hbox = Gtk.HBox()
        hbox.pack_start(self.ebox, False, True, 0)
        hbox.pack_start(Gtk.VSeparator(), False, True, 0)
        hbox.pack_start(viewport, True, True, 0)
        hbox.pack_end(self.bellicon, False, False, 2)

        self.add(hbox)
        hbox.show_all()
        self.set_no_show_all(True)
        self.show()

        self.connect('button-press-event', self.on_clicked)
Exemple #18
0
def create_connection_function(data):
    connection_function = None
    con_type = data[2]
    if con_type == "terminator":
        connection_function = Terminator(data)
    elif con_type == "junction":
        connection_function = Junction(data)
    elif con_type == "connection":
        connection_function = Connection(data)
    return connection_function
Exemple #19
0
    def __init__(self):
        """Class initialiser"""
        self.terminator = Terminator()
        self.terminator.register_window(self)

        Container.__init__(self)
        GObject.GObject.__init__(self)
        GObject.type_register(Window)
        self.register_signals(Window)

        self.get_style_context().add_class("terminator-terminal-window")

        #        self.set_property('allow-shrink', True)  # FIXME FOR GTK3, or do we need this actually?
        icon_to_apply = ''

        self.register_callbacks()
        self.apply_config()

        self.title = WindowTitle(self)
        self.title.update()

        options = self.config.options_get()
        if options:
            if options.forcedtitle:
                self.title.force_title(options.forcedtitle)

            if options.role:
                self.set_role(options.role)


#            if options.classname is not None:
#                self.set_wmclass(options.classname, self.wmclass_class)

            if options.forcedicon is not None:
                icon_to_apply = options.forcedicon

            if options.geometry:
                if not self.parse_geometry(options.geometry):
                    err('Window::__init__: Unable to parse geometry: %s' %
                        options.geometry)

        self.apply_icon(icon_to_apply)
        self.pending_set_rough_geometry_hint = False
Exemple #20
0
    def __init__(self, terminal):
        """Class initialiser"""
        gtk.EventBox.__init__(self)
        self.__gobject_init__()

        self.terminator = Terminator()
        self.terminal = terminal
        self.config = self.terminal.config

        self.label = EditableLabel()
        self.label.connect('edit-done', self.on_edit_done)
        self.ebox = gtk.EventBox()
        grouphbox = gtk.HBox()
        self.grouplabel = gtk.Label()
        self.groupicon = gtk.Image()
        self.bellicon = gtk.Image()
        self.bellicon.set_no_show_all(True)

        self.groupentry = gtk.Entry()
        self.groupentry.set_no_show_all(True)
        self.groupentry.connect('focus-out-event', self.groupentry_cancel)
        self.groupentry.connect('activate', self.groupentry_activate)
        self.groupentry.connect('key-press-event', self.groupentry_keypress)

        groupsend_type = self.terminator.groupsend_type
        if self.terminator.groupsend == groupsend_type['all']:
            icon_name = 'all'
        elif self.terminator.groupsend == groupsend_type['group']:
            icon_name = 'group'
        elif self.terminator.groupsend == groupsend_type['off']:
            icon_name = 'off'
        self.set_from_icon_name('_active_broadcast_%s' % icon_name, 
                gtk.ICON_SIZE_MENU)

        grouphbox.pack_start(self.groupicon, False, True, 2)
        grouphbox.pack_start(self.grouplabel, False, True, 2)
        grouphbox.pack_start(self.groupentry, False, True, 2)

        self.ebox.add(grouphbox)
        self.ebox.show_all()

        self.bellicon.set_from_icon_name('terminal-bell', gtk.ICON_SIZE_MENU)
        hbox = gtk.HBox()
        hbox.pack_start(self.ebox, False, True, 0)
        hbox.pack_start(gtk.VSeparator(), False, True, 0)
        hbox.pack_start(self.label, True, True)
        hbox.pack_end(self.bellicon, False, False, 2)

        self.add(hbox)
        hbox.show_all()
        self.set_no_show_all(True)
        self.show()

        self.connect('button-press-event', self.on_clicked)
    def setup_dropper(self):
        '''
        Target:
            - delete specified databases in PostgreSQL.
        '''
        connecter = self.get_connecter()
        self.logger.debug(Messenger.BEGINNING_EXE_DROPPER)
        dropper = self.get_dropper(connecter)

        # Terminate every connection to the target databases if necessary
        if self.args.terminate:
            terminator = Terminator(connecter, target_dbs=dropper.dbnames,
                                    logger=self.logger)
            terminator.terminate_backend_dbs(dropper.dbnames)

        # Delete the databases
        dropper.drop_pg_dbs(dropper.dbnames)

        # Close connection to PostgreSQL
        connecter.pg_disconnect()
    def setup_vacuumer(self):
        '''
        Target:
            - executes the vacuumer taking into account the value of its
              variables.
        '''
        connecter = self.get_connecter()
        self.logger.debug(Messenger.BEGINNING_EXE_VACUUMER)
        vacuumer = self.get_vacuumer(connecter)

        # Check if the role of user connected to PostgreSQL is superuser
        pg_superuser = connecter.is_pg_superuser()
        if not pg_superuser:
            # Users who are not superusers will only be able to vacuum the
            # databases they own
            vacuumer.db_owner = connecter.user
            self.logger.warning(Messenger.ACTION_DB_NO_SUPERUSER)

        # Get PostgreSQL databases' names, connection permissions and owners
        dbs_all = connecter.get_pg_dbs_data(vacuumer.ex_templates,
                                            vacuumer.db_owner)

        # Show and log their names
        Orchestrator.show_dbs(dbs_all, self.logger)

        # Get the target databases in a list
        vacuum_list = DbSelector.get_filtered_dbs(
            dbs_all, vacuumer.in_dbs, vacuumer.ex_dbs, vacuumer.in_regex,
            vacuumer.ex_regex, vacuumer.in_priority, self.logger)

        # Terminate every connection to these target databases if necessary
        if self.args.terminate:
            terminator = Terminator(connecter, target_dbs=vacuum_list,
                                    logger=self.logger)
            terminator.terminate_backend_dbs(vacuum_list)

        # Vacuum the target databases
        vacuumer.vacuum_dbs(vacuum_list)

        # Close connection to PostgreSQL
        connecter.pg_disconnect()
    def setup_alterer(self):
        '''
        Target:
            - change the owner of the specified databases in PostgreSQL.
        '''
        connecter = self.get_connecter()
        self.logger.debug(Messenger.BEGINNING_EXE_ALTERER)
        alterer = self.get_alterer(connecter)

        # Check if the role of user connected to PostgreSQL is superuser
        pg_superuser = connecter.is_pg_superuser()
        if not pg_superuser:
            # Users who are not superusers will only be able to backup the
            # databases they own
            owner = connecter.user
            self.logger.highlight('warning', Messenger.ACTION_DB_NO_SUPERUSER,
                                  'yellow', effect='bold')
        else:
            owner = ''

        # Get PostgreSQL databases' names, connection permissions and owners
        dbs_all = connecter.get_pg_dbs_data(ex_templates=False, db_owner=owner)
        # Show and log their names
        Orchestrator.show_dbs(dbs_all, self.logger)

        # Get the target databases in a list
        alt_list = DbSelector.get_filtered_dbs(
            dbs_all=dbs_all, in_dbs=alterer.in_dbs, logger=self.logger)

        # Terminate every connection to the target databases if necessary
        if self.args.terminate:
            terminator = Terminator(connecter, target_dbs=alt_list,
                                    logger=self.logger)
            terminator.terminate_backend_dbs(alt_list)

        # Delete the databases
        alterer.alter_dbs_owner(alt_list)

        # Close connection to PostgreSQL
        connecter.pg_disconnect()
class LayoutLauncher:
    """Class implementing the various parts of the preferences editor"""
    terminator = None
    config = None
    registry = None
    plugins = None
    keybindings = None
    window = None
    builder = None
    layouttreeview = None
    layouttreestore = None

    def __init__ (self):
        self.terminator = Terminator()
        self.terminator.register_launcher_window(self)

        self.config = config.Config()
        self.config.base.reload()
        self.builder = gtk.Builder()
        try:
            # Figure out where our library is on-disk so we can open our UI
            (head, _tail) = os.path.split(config.__file__)
            librarypath = os.path.join(head, 'layoutlauncher.glade')
            gladefile = open(librarypath, 'r')
            gladedata = gladefile.read()
        except Exception, ex:
            print "Failed to find layoutlauncher.glade"
            print ex
            return

        self.builder.add_from_string(gladedata)
        self.window = self.builder.get_object('layoutlauncherwin')
        self.builder.connect_signals(self)
        self.window.connect('destroy', self.on_destroy_event)
        self.window.show_all()
        self.layouttreeview = self.builder.get_object('layoutlist')
        self.layouttreestore = self.builder.get_object('layoutstore')
        self.update_layouts()
Exemple #25
0
    def __init__(self, title, notebook):
        """Class initialiser"""
        GObject.GObject.__init__(self)

        self.notebook = notebook
        self.terminator = Terminator()
        self.config = Config()

        self.label = EditableLabel(title)
        self.update_angle()

        self.pack_start(self.label, True, True, 0)

        self.update_button()
        self.show_all()
    def __init__(self):
        Thread.__init__(self)
        self.terminator = Terminator.getInstance()
        self.setName("Authenticator")

        try:
            self.db = sql.connect(os.environ["DBHOST"], os.environ["DBUSER"],
                                  os.environ["DBPASS"], os.environ["DBNAME"])

            self.cursor = self.db.cursor()

            logging.debug('Connected to database')
        except:
            logging.critical('Exception occured connecting to database',
                             exc_info=True)
            self.terminator.autoTerminate()

        try:
            certHandler = CertificateHandler("front", 'server')
            publicKey, privateKey = certHandler.getKeyPair()
            clientKeysPath = certHandler.getEnrolledKeysPath()

            self.ctxHandler = ContextHandler(clientKeysPath)
            context = self.ctxHandler.getContext()
            self.socket = context.socket(zmq.REP)

            try:
                monitorSocket = self.socket.get_monitor_socket()
                self.monitor = Monitor(monitorSocket, 'Registration')
                self.monitor.setDaemon(True)
                self.monitor.start()

                logging.debug('Socket monitor thread started')
            except:
                logging.error(
                    'Exception occured starting socket monitor thread',
                    exc_info=True)

            self.socket.curve_secretkey = privateKey
            self.socket.curve_publickey = publicKey
            self.socket.curve_server = True
            self.socket.setsockopt(zmq.RCVTIMEO, 10000)
            self.socket.bind('tcp://0.0.0.0:5001')

            logging.debug('Socket setup and bound, listening')
        except:
            logging.critical('Exception occured setting up auth socket',
                             exc_info=True)
    def __init__ (self):
        self.terminator = Terminator()
        self.terminator.register_launcher_window(self)

        self.config = config.Config()
        self.config.base.reload()
        self.builder = gtk.Builder()
        try:
            # Figure out where our library is on-disk so we can open our UI
            (head, _tail) = os.path.split(config.__file__)
            librarypath = os.path.join(head, 'layoutlauncher.glade')
            gladefile = open(librarypath, 'r')
            gladedata = gladefile.read()
        except Exception, ex:
            print "Failed to find layoutlauncher.glade"
            print ex
            return
Exemple #28
0
 def prepare_attributes(self):
     """Ensure we are populated"""
     if not self.bus_name:
         dbg('Checking for bus name availability: %s' % BUS_NAME)
         bus = dbus.SessionBus()
         proxy = bus.get_object('org.freedesktop.DBus', 
                                '/org/freedesktop/DBus')
         flags = 1 | 4 # allow replacement | do not queue
         if not proxy.RequestName(BUS_NAME, dbus.UInt32(flags)) in (1, 4):
             dbg('bus name unavailable: %s' % BUS_NAME)
             raise dbus.exceptions.DBusException(
                 "Couldn't get DBus name %s: Name exists" % BUS_NAME)
         self.bus_name = dbus.service.BusName(BUS_NAME, 
                                              bus=dbus.SessionBus())
     if not self.bus_path:
         self.bus_path = BUS_PATH
     if not self.terminator:
         self.terminator = Terminator()
Exemple #29
0
    def __init__(self):
        """Class initialiser"""
        self.terminator = Terminator()
        self.terminator.register_window(self)

        Container.__init__(self)
        GObject.GObject.__init__(self)
        GObject.type_register(Window)
        self.register_signals(Window)

        self.get_style_context().add_class("terminator-terminal-window")

#        self.set_property('allow-shrink', True)  # FIXME FOR GTK3, or do we need this actually?
        icon_to_apply=''

        self.register_callbacks()
        self.apply_config()

        self.title = WindowTitle(self)
        self.title.update()
        
        self.preventHide = False

        options = self.config.options_get()
        if options:
            if options.forcedtitle:
                self.title.force_title(options.forcedtitle)

            if options.role:
                self.set_role(options.role)
            
            if options.forcedicon is not None:
                icon_to_apply = options.forcedicon

            if options.geometry:
                if not self.parse_geometry(options.geometry):
                    err('Window::__init__: Unable to parse geometry: %s' % 
                            options.geometry)

        self.apply_icon(icon_to_apply)
        self.pending_set_rough_geometry_hint = False
	def run(self):
		terminator = Terminator.getInstance()
		while not terminator.isTerminating():
			try:
				msg = recv_monitor_message(self.socket)
			except:
				break
			event = msg.get("event")
			value = msg.get("value")
			endpoint = msg.get("endpoint")

			assigned = False
			for key, val in self.events.items():
				if event == val:
					assigned = True
					logging.debug(str(key) + ' ' + str(endpoint))

			if assigned is False:
				logging.error('Unknown monitor message: %s', msg)

		logging.debug('Monitor thread %s shutting down', self.feedID)
    def __init__(self, feedListener, authListener):
        Thread.__init__(self)
        self.setName("Enroller")

        self.feedListener = feedListener
        self.authListener = authListener

        self.terminator = Terminator.getInstance()

        self.unsecuredCtx = zmq.Context()
        self.unsecuredSocket = self.unsecuredCtx.socket(zmq.REP)

        monitorSocket = self.unsecuredSocket.get_monitor_socket()
        self.monitor = Monitor(monitorSocket, "Enroller")
        self.monitor.setDaemon(True)
        self.monitor.start()

        self.unsecuredSocket.bind('tcp://0.0.0.0:5002')
        self.unsecuredSocket.setsockopt(zmq.RCVTIMEO, 10000)

        self.certHandler = CertificateHandler('front', 'server')
        self.publicKey, _ = self.certHandler.getKeyPair()

        self.publicKey = self.publicKey.decode('utf-8')
    def __init__(self, title, notebook):
        """Class initialiser"""
        GObject.GObject.__init__(self)

        self.notebook = notebook
        self.terminator = Terminator()
        self.config = Config()

        self.label = EditableLabel(title)
        self.label.add_events(2097152)  # SCROLL
        self.label.add_events(4194304)  # TOUCH
        self.label.connect('scroll-event', notebook.on_scroll_event)

        self.update_angle()

        self.pack_start(self.label, True, True, 0)

        self.update_button()
        if self.button:
            self.button.add_events(2097152)  # SCROLL
            self.button.add_events(4194304)  # TOUCH
            self.button.connect('scroll-event', notebook.on_scroll_event)

        self.show_all()
Exemple #33
0
class DBusService(Borg, dbus.service.Object):
    """DBus Server class. This is implemented as a Borg"""
    bus_name = None
    bus_path = None
    terminator = None

    def __init__(self):
        """Class initialiser"""
        Borg.__init__(self, self.__class__.__name__)
        self.prepare_attributes()
        try:
            dbus.service.Object.__init__(self, self.bus_name, BUS_PATH)
        except:
            None

    def prepare_attributes(self):
        """Ensure we are populated"""
        if not self.bus_name:
            dbg('Checking for bus name availability: %s' % BUS_NAME)
            bus = dbus.SessionBus()
            proxy = bus.get_object('org.freedesktop.DBus', 
                                   '/org/freedesktop/DBus')
            flags = 1 | 4 # allow replacement | do not queue
            if not proxy.RequestName(BUS_NAME, dbus.UInt32(flags)) in (1, 4):
                dbg('bus name unavailable: %s' % BUS_NAME)
                raise dbus.exceptions.DBusException(
                    "Couldn't get DBus name %s: Name exists" % BUS_NAME)
            self.bus_name = dbus.service.BusName(BUS_NAME, 
                                                 bus=dbus.SessionBus())
        if not self.bus_path:
            self.bus_path = BUS_PATH
        if not self.terminator:
            self.terminator = Terminator()

    @dbus.service.method(BUS_NAME, in_signature='a{ss}')
    def new_window_cmdline(self, options=dbus.Dictionary()):
        """Create a new Window"""
        dbg('dbus method called: new_window with parameters %s'%(options))
        oldopts = self.terminator.config.options_get()
        oldopts.__dict__ = options
        self.terminator.config.options_set(oldopts)
        self.terminator.create_layout(oldopts.layout)
        self.terminator.layout_done()
            
    @dbus.service.method(BUS_NAME, in_signature='a{ss}')
    def new_tab_cmdline(self, options=dbus.Dictionary()):
        """Create a new tab"""
        dbg('dbus method called: new_tab with parameters %s'%(options))
        oldopts = self.terminator.config.options_get()
        oldopts.__dict__ = options
        self.terminator.config.options_set(oldopts)
        window = self.terminator.get_windows()[0]
        window.tab_new()

    @dbus.service.method(BUS_NAME)
    def new_window(self):
        """Create a new Window"""
        terminals_before = set(self.get_terminals())
        self.terminator.new_window()
        terminals_after = set(self.get_terminals())
        new_terminal_set = list(terminals_after - terminals_before)
        if len(new_terminal_set) != 1:
            return "ERROR: Cannot determine the UUID of the added terminal"
        else:
            return new_terminal_set[0]

    @dbus.service.method(BUS_NAME)
    def new_tab(self, uuid=None):
        """Create a new tab"""
        return self.new_terminal(uuid, 'tab')

    @dbus.service.method(BUS_NAME)
    def hsplit(self, uuid=None):
        """Split a terminal horizontally, by UUID"""
        return self.new_terminal(uuid, 'hsplit')

    @dbus.service.method(BUS_NAME)
    def vsplit(self, uuid=None):
        """Split a terminal vertically, by UUID"""
        return self.new_terminal(uuid, 'vsplit')

    def new_terminal(self, uuid, type):
        """Split a terminal horizontally or vertically, by UUID"""
        dbg('dbus method called: %s' % type)
        if not uuid:
            return "ERROR: No UUID specified"
        terminal = self.terminator.find_terminal_by_uuid(uuid)
        terminals_before = set(self.get_terminals())
        if not terminal:
            return "ERROR: Terminal with supplied UUID not found"
        elif type == 'tab':
            terminal.key_new_tab()
        elif type == 'hsplit':
            terminal.key_split_horiz()
        elif type == 'vsplit':
            terminal.key_split_vert()
        else:
            return "ERROR: Unknown type \"%s\" specified" % (type)
        terminals_after = set(self.get_terminals())
        # Detect the new terminal UUID
        new_terminal_set = list(terminals_after - terminals_before)
        if len(new_terminal_set) != 1:
            return "ERROR: Cannot determine the UUID of the added terminal"
        else:
            return new_terminal_set[0]

    @dbus.service.method(BUS_NAME)
    def get_terminals(self):
        """Return a list of all the terminals"""
        return [x.uuid.urn for x in self.terminator.terminals]

    @dbus.service.method(BUS_NAME)
    def get_window(self, uuid=None):
        """Return the UUID of the parent window of a given terminal"""
        terminal = self.terminator.find_terminal_by_uuid(uuid)
        window = terminal.get_toplevel()
        return window.uuid.urn

    @dbus.service.method(BUS_NAME)
    def get_window_title(self, uuid=None):
        """Return the title of a parent window of a given terminal"""
        terminal = self.terminator.find_terminal_by_uuid(uuid)
        window = terminal.get_toplevel()
        return window.get_title()

    @dbus.service.method(BUS_NAME)
    def get_tab(self, uuid=None):
        """Return the UUID of the parent tab of a given terminal"""
        maker = Factory()
        terminal = self.terminator.find_terminal_by_uuid(uuid)
        window = terminal.get_toplevel()
        root_widget = window.get_children()[0]
        if maker.isinstance(root_widget, 'Notebook'):
            #return root_widget.uuid.urn
            for tab_child in root_widget.get_children():
                terms = [tab_child]
                if not maker.isinstance(terms[0], "Terminal"):
                    terms = enumerate_descendants(tab_child)[1]
                if terminal in terms:
                    # FIXME: There are no uuid's assigned to the the notebook, or the actual tabs!
                    # This would fail: return root_widget.uuid.urn
                    return ""

    @dbus.service.method(BUS_NAME)
    def get_tab_title(self, uuid=None):
        """Return the title of a parent tab of a given terminal"""
        maker = Factory()
        terminal = self.terminator.find_terminal_by_uuid(uuid)
        window = terminal.get_toplevel()
        root_widget = window.get_children()[0]
        if maker.isinstance(root_widget, "Notebook"):
            for tab_child in root_widget.get_children():
                terms = [tab_child]
                if not maker.isinstance(terms[0], "Terminal"):
                    terms = enumerate_descendants(tab_child)[1]
                if terminal in terms:
                    return root_widget.get_tab_label(tab_child).get_label()
Exemple #34
0
class Window(Container, gtk.Window):
    """Class implementing a top-level Terminator window"""

    terminator = None
    title = None
    isfullscreen = None
    ismaximised = None
    hidebound = None
    hidefunc = None
    losefocus_time = 0
    position = None
    ignore_startup_show = None
    set_pos_by_ratio = None

    zoom_data = None

    term_zoomed = False
    __gproperties__ = {
            'term_zoomed': (gobject.TYPE_BOOLEAN,
                            'terminal zoomed',
                            'whether the terminal is zoomed',
                            False,
                            gobject.PARAM_READWRITE)
    }

    def __init__(self):
        """Class initialiser"""
        self.terminator = Terminator()
        self.terminator.register_window(self)

        Container.__init__(self)
        gtk.Window.__init__(self)
        gobject.type_register(Window)
        self.register_signals(Window)

        self.set_property('allow-shrink', True)
        icon_to_apply=''

        self.register_callbacks()
        self.apply_config()

        self.title = WindowTitle(self)
        self.title.update()

        options = self.config.options_get()
        if options:
            if options.forcedtitle:
                self.title.force_title(options.forcedtitle)

            if options.role:
                self.set_role(options.role)
            
            if options.classname is not None:
                self.set_wmclass(options.classname, self.wmclass_class)
            
            if options.forcedicon is not None:
                icon_to_apply = options.forcedicon

            if options.geometry:
                if not self.parse_geometry(options.geometry):
                    err('Window::__init__: Unable to parse geometry: %s' % 
                            options.geometry)

        self.apply_icon(icon_to_apply)
        self.pending_set_rough_geometry_hint = False

    def do_get_property(self, prop):
        """Handle gobject getting a property"""
        if prop.name in ['term_zoomed', 'term-zoomed']:
            return(self.term_zoomed)
        else:
            raise AttributeError('unknown property %s' % prop.name)

    def do_set_property(self, prop, value):
        """Handle gobject setting a property"""
        if prop.name in ['term_zoomed', 'term-zoomed']:
            self.term_zoomed = value
        else:
            raise AttributeError('unknown property %s' % prop.name)

    def register_callbacks(self):
        """Connect the GTK+ signals we care about"""
        self.connect('key-press-event', self.on_key_press)
        self.connect('button-press-event', self.on_button_press)
        self.connect('delete_event', self.on_delete_event)
        self.connect('destroy', self.on_destroy_event)
        self.connect('window-state-event', self.on_window_state_changed)
        self.connect('focus-out-event', self.on_focus_out)
        self.connect('focus-in-event', self.on_focus_in)

        # Attempt to grab a global hotkey for hiding the window.
        # If we fail, we'll never hide the window, iconifying instead.
        if self.config['keybindings']['hide_window'] != None:
            try:
                self.hidebound = keybinder.bind(
                    self.config['keybindings']['hide_window'],
                    self.on_hide_window)
            except (KeyError, NameError):
                pass

            if not self.hidebound:
                err('Unable to bind hide_window key, another instance/window has it.')
                self.hidefunc = self.iconify
            else:
                self.hidefunc = self.hide

    def apply_config(self):
        """Apply various configuration options"""
        options = self.config.options_get()
        maximise = self.config['window_state'] == 'maximise'
        fullscreen = self.config['window_state'] == 'fullscreen'
        hidden = self.config['window_state'] == 'hidden'
        borderless = self.config['borderless']
        skiptaskbar = self.config['hide_from_taskbar']
        alwaysontop = self.config['always_on_top']
        sticky = self.config['sticky']

        if options:
            if options.maximise:
                maximise = True
            if options.fullscreen:
                fullscreen = True
            if options.hidden:
                hidden = True
            if options.borderless:
                borderless = True

        self.set_fullscreen(fullscreen)
        self.set_maximised(maximise)
        self.set_borderless(borderless)
        self.set_always_on_top(alwaysontop)
        self.set_real_transparency()
        self.set_sticky(sticky)
        if self.hidebound:
            self.set_hidden(hidden)
            self.set_skip_taskbar_hint(skiptaskbar)
        else:
            self.set_iconified(hidden)

    def apply_icon(self, requested_icon):
        """Set the window icon"""
        icon_theme = gtk.IconTheme()
        icon = None
        
        if requested_icon:
            try:
                self.set_icon_from_file(requested_icon)
                icon = self.get_icon()
            except (NameError, gobject.GError):
                dbg('Unable to load 48px %s icon as file' % (repr(requested_icon)))
        
        if requested_icon and icon is None:
            try:
                icon = icon_theme.load_icon(requested_icon, 48, 0)
            except (NameError, gobject.GError):
                dbg('Unable to load 48px %s icon' % (repr(requested_icon)))
        
        if icon is None:
            try:
                icon = icon_theme.load_icon(self.wmclass_name, 48, 0)
            except (NameError, gobject.GError):
                dbg('Unable to load 48px %s icon' % (self.wmclass_name))
        
        if icon is None:
            try:
                icon = icon_theme.load_icon(APP_NAME, 48, 0)
            except (NameError, gobject.GError):
                dbg('Unable to load 48px Terminator icon')
                icon = self.render_icon(gtk.STOCK_DIALOG_INFO, gtk.ICON_SIZE_BUTTON)

        self.set_icon(icon)

    def on_key_press(self, window, event):
        """Handle a keyboard event"""
        maker = Factory()

        self.set_urgency_hint(False)

        mapping = self.terminator.keybindings.lookup(event)

        if mapping:
            dbg('Window::on_key_press: looked up %r' % mapping)
            if mapping == 'full_screen':
                self.set_fullscreen(not self.isfullscreen)
            elif mapping == 'close_window':
                if not self.on_delete_event(window,
                        gtk.gdk.Event(gtk.gdk.DELETE)):
                    self.on_destroy_event(window,
                            gtk.gdk.Event(gtk.gdk.DESTROY))
            elif mapping == 'new_tab':
                self.tab_new(self.get_focussed_terminal())
            else:
                return(False)
            return(True)

    def on_button_press(self, window, event):
        """Handle a mouse button event. Mainly this is just a clean way to
        cancel any urgency hints that are set."""
        self.set_urgency_hint(False)
        return(False)

    def on_focus_out(self, window, event):
        """Focus has left the window"""
        for terminal in self.get_visible_terminals():
            terminal.on_window_focus_out()

        self.losefocus_time = time.time()
        if self.config['hide_on_lose_focus'] and self.get_property('visible'):
            self.position = self.get_position()
            self.hidefunc()

    def on_focus_in(self, window, event):
        """Focus has entered the window"""
        self.set_urgency_hint(False)
        # FIXME: Cause the terminal titlebars to update here

    def is_child_notebook(self):
        """Returns True if this Window's child is a Notebook"""
        maker = Factory()
        return(maker.isinstance(self.get_child(), 'Notebook'))

    def tab_new(self, widget=None, debugtab=False, _param1=None, _param2=None):
        """Make a new tab"""
        cwd = None
        profile = None

        if self.get_property('term_zoomed') == True:
            err("You can't create a tab while a terminal is maximised/zoomed")
            return

        if widget:
            cwd = widget.get_cwd()
            profile = widget.get_profile()

        maker = Factory()
        if not self.is_child_notebook():
            dbg('Making a new Notebook')
            notebook = maker.make('Notebook', window=self)
        return self.get_child().newtab(debugtab, cwd=cwd, profile=profile)

    def on_delete_event(self, window, event, data=None):
        """Handle a window close request"""
        maker = Factory()
        if maker.isinstance(self.get_child(), 'Terminal'):
            dbg('Window::on_delete_event: Only one child, closing is fine')
            return(False)
        elif maker.isinstance(self.get_child(), 'Container'):
            return(self.confirm_close(window, _('window')))
        else:
            dbg('unknown child: %s' % self.get_child())

    def confirm_close(self, window, type):
        """Display a confirmation dialog when the user is closing multiple
        terminals in one window"""
        
        return(not (self.construct_confirm_close(window, type) == gtk.RESPONSE_ACCEPT))

    def on_destroy_event(self, widget, data=None):
        """Handle window destruction"""
        dbg('destroying self')
        for terminal in self.get_visible_terminals():
            terminal.close()
        self.cnxids.remove_all()
        self.terminator.deregister_window(self)
        self.destroy()
        del(self)

    def on_hide_window(self, data=None):
        """Handle a request to hide/show the window"""

        if not self.get_property('visible'):
            #Don't show if window has just been hidden because of
            #lost focus
            if (time.time() - self.losefocus_time < 0.1) and \
                self.config['hide_on_lose_focus']:
                return
            if self.position:
                self.move(self.position[0], self.position[1])
            self.show()
        else:
            self.position = self.get_position()
            self.hidefunc()

    # pylint: disable-msg=W0613
    def on_window_state_changed(self, window, event):
        """Handle the state of the window changing"""
        self.isfullscreen = bool(event.new_window_state & 
                                 gtk.gdk.WINDOW_STATE_FULLSCREEN)
        self.ismaximised = bool(event.new_window_state &
                                 gtk.gdk.WINDOW_STATE_MAXIMIZED)
        dbg('Window::on_window_state_changed: fullscreen=%s, maximised=%s' \
                % (self.isfullscreen, self.ismaximised))

        return(False)

    def set_maximised(self, value):
        """Set the maximised state of the window from the supplied value"""
        if value == True:
            self.maximize()
        else:
            self.unmaximize()

    def set_fullscreen(self, value):
        """Set the fullscreen state of the window from the supplied value"""
        if value == True:
            self.fullscreen()
        else:
            self.unfullscreen()

    def set_borderless(self, value):
        """Set the state of the window border from the supplied value"""
        self.set_decorated (not value)

    def set_hidden(self, value):
        """Set the visibility of the window from the supplied value"""
        if value == True:
            self.ignore_startup_show = True
        else:
            self.ignore_startup_show = False

    def set_iconified(self, value):
        """Set the minimised state of the window from the supplied value"""
        if value == True:
            self.iconify()

    def set_always_on_top(self, value):
        """Set the always on top window hint from the supplied value"""
        self.set_keep_above(value)

    def set_sticky(self, value):
        """Set the sticky hint from the supplied value"""
        if value == True:
            self.stick()

    def set_real_transparency(self, value=True):
        """Enable RGBA if supported on the current screen"""
        if self.is_composited() == False:
            value = False

        screen = self.get_screen()
        if value:
            dbg('setting rgba colormap')
            colormap = screen.get_rgba_colormap()
        else:
            dbg('setting rgb colormap')
            colormap = screen.get_rgb_colormap()

        if colormap:
            self.set_colormap(colormap)
    
    def show(self, startup=False):
        """Undo the startup show request if started in hidden mode"""
        #Present is necessary to grab focus when window is hidden from taskbar.
        #It is important to call present() before show(), otherwise the window
        #won't be brought to front if an another application has the focus.
        #Last note: present() will implicitly call gtk.Window.show()
        self.present()

        #Window must be shown, then hidden for the hotkeys to be registered
        if (self.ignore_startup_show and startup == True):
            self.hide()


    def add(self, widget, metadata=None):
        """Add a widget to the window by way of gtk.Window.add()"""
        maker = Factory()
        gtk.Window.add(self, widget)
        if maker.isinstance(widget, 'Terminal'):
            signals = {'close-term': self.closeterm,
                       'title-change': self.title.set_title,
                       'split-horiz': self.split_horiz,
                       'split-vert': self.split_vert,
                       'unzoom': self.unzoom,
                       'tab-change': self.tab_change,
                       'group-all': self.group_all,
                       'ungroup-all': self.ungroup_all,
                       'group-tab': self.group_tab,
                       'ungroup-tab': self.ungroup_tab,
                       'move-tab': self.move_tab,
                       'tab-new': [self.tab_new, widget],
                       'navigate': self.navigate_terminal}

            for signal in signals:
                args = []
                handler = signals[signal]
                if isinstance(handler, list):
                    args = handler[1:]
                    handler = handler[0]
                self.connect_child(widget, signal, handler, *args)

            widget.grab_focus()

    def remove(self, widget):
        """Remove our child widget by way of gtk.Window.remove()"""
        gtk.Window.remove(self, widget)
        self.disconnect_child(widget)
        return(True)

    def get_children(self):
        """Return a single list of our child"""
        children = []
        children.append(self.get_child())
        return(children)

    def hoover(self):
        """Ensure we still have a reason to exist"""
        if not self.get_child():
            self.emit('destroy')

    def closeterm(self, widget):
        """Handle a terminal closing"""
        Container.closeterm(self, widget)
        self.hoover()

    def split_axis(self, widget, vertical=True, cwd=None, sibling=None, widgetfirst=True):
        """Split the window"""
        if self.get_property('term_zoomed') == True:
            err("You can't split while a terminal is maximised/zoomed")
            return

        order = None
        maker = Factory()
        self.remove(widget)

        if vertical:
            container = maker.make('VPaned')
        else:
            container = maker.make('HPaned')
        
        self.set_pos_by_ratio = True

        if not sibling:
            sibling = maker.make('Terminal')
            sibling.set_cwd(cwd)
            sibling.spawn_child()
            if widget.group and self.config['split_to_group']:
                sibling.set_group(None, widget.group)
        if self.config['always_split_with_profile']:
            sibling.force_set_profile(None, widget.get_profile())

        self.add(container)
        container.show_all()

        order = [widget, sibling]
        if widgetfirst is False:
            order.reverse()

        for term in order:
            container.add(term)
        container.show_all()
        sibling.grab_focus()
        
        while gtk.events_pending():
            gtk.main_iteration_do(False)
        self.set_pos_by_ratio = False


    def zoom(self, widget, font_scale=True):
        """Zoom a terminal widget"""
        children = self.get_children()

        if widget in children:
            # This widget is a direct child of ours and we're a Window
            # so zooming is a no-op
            return

        self.zoom_data = widget.get_zoom_data()
        self.zoom_data['widget'] = widget
        self.zoom_data['old_child'] = children[0]
        self.zoom_data['font_scale'] = font_scale

        self.remove(self.zoom_data['old_child'])
        self.zoom_data['old_parent'].remove(widget)
        self.add(widget)
        self.set_property('term_zoomed', True)

        if font_scale:
            widget.cnxids.new(widget, 'size-allocate', 
                    widget.zoom_scale, self.zoom_data)

        widget.grab_focus()

    def unzoom(self, widget):
        """Restore normal terminal layout"""
        if not self.get_property('term_zoomed'):
            # We're not zoomed anyway
            dbg('Window::unzoom: not zoomed, no-op')
            return

        widget = self.zoom_data['widget']
        if self.zoom_data['font_scale']:
            widget.vte.set_font(self.zoom_data['old_font'])

        self.remove(widget)
        self.add(self.zoom_data['old_child'])
        self.zoom_data['old_parent'].add(widget)
        widget.grab_focus()
        self.zoom_data = None
        self.set_property('term_zoomed', False)

    def rotate(self, widget, clockwise):
        """Rotate children in this window"""
        self.set_pos_by_ratio = True
        maker = Factory()
        # collect all paned children in breadth-first order
        paned = []
        for child in self.get_children():
            if maker.isinstance(child, 'Paned'):
                paned.append(child)
        for p in paned:
            for child in p.get_children():
                if child not in paned and maker.isinstance(child, 'Paned'):
                    paned.append(child)
        # then propagate the rotation
        for p in paned:
            p.rotate(widget, clockwise)
        self.show_all()
        widget.grab_focus()
        
        while gtk.events_pending():
            gtk.main_iteration_do(False)
        self.set_pos_by_ratio = False

    def get_visible_terminals(self):
        """Walk down the widget tree to find all of the visible terminals.
        Mostly using Container::get_visible_terminals()"""
        terminals = {}
        if not hasattr(self, 'cached_maker'):
            self.cached_maker = Factory()
        maker = self.cached_maker
        child = self.get_child()

        if not child:
            return([])

        # If our child is a Notebook, reset to work from its visible child
        if maker.isinstance(child, 'Notebook'):
            pagenum = child.get_current_page()
            child = child.get_nth_page(pagenum)

        if maker.isinstance(child, 'Container'):
            terminals.update(child.get_visible_terminals())
        elif maker.isinstance(child, 'Terminal'):
            terminals[child] = child.get_allocation()
        else:
            err('Unknown child type %s' % type(child))

        return(terminals)

    def get_focussed_terminal(self):
        """Find which terminal we want to have focus"""
        terminals = self.get_visible_terminals()
        for terminal in terminals:
            if terminal.vte.is_focus():
                return(terminal)
        return(None)

    def deferred_set_rough_geometry_hints(self):
        # no parameters are used in set_rough_geometry_hints, so we can
        # use the set_rough_geometry_hints
        if self.pending_set_rough_geometry_hint == True:
            return
        self.pending_set_rough_geometry_hint = True
        gobject.idle_add(self.do_deferred_set_rough_geometry_hints)

    def do_deferred_set_rough_geometry_hints(self):
        self.pending_set_rough_geometry_hint = False
        self.set_rough_geometry_hints()

    def set_rough_geometry_hints(self):
        """Walk all the terminals along the top and left edges to fake up how
        many columns/rows we sort of have"""
        if not hasattr(self, 'cached_maker'):
            self.cached_maker = Factory()
        maker = self.cached_maker
        if maker.isinstance(self.get_child(), 'Notebook'):
            dbg("We don't currently support geometry hinting with tabs")
            return

        terminals = self.get_visible_terminals()
        column_sum = 0
        row_sum = 0

        for terminal in terminals:
            rect = terminal.get_allocation()
            if rect.x == 0:
                cols, rows = terminal.get_size()
                row_sum = row_sum + rows
            if rect.y == 0:
                cols, rows = terminal.get_size()
                column_sum = column_sum + cols

        if column_sum == 0 or row_sum == 0:
            dbg('column_sum=%s,row_sum=%s. No terminals found in >=1 axis' %
                (column_sum, row_sum))
            return

        # FIXME: I don't think we should just use whatever font size info is on
        # the last terminal we inspected. Looking up the default profile font
        # size and calculating its character sizes would be rather expensive
        # though.
        font_width, font_height = terminal.get_font_size()
        total_font_width = font_width * column_sum
        total_font_height = font_height * row_sum

        win_width, win_height = self.get_size()
        extra_width = win_width - total_font_width
        extra_height = win_height - total_font_height

        dbg('setting geometry hints: (ewidth:%s)(eheight:%s),\
(fwidth:%s)(fheight:%s)' % (extra_width, extra_height, 
                            font_width, font_height))
        self.set_geometry_hints(self, -1, -1, -1, -1, extra_width,
                extra_height, font_width, font_height, -1.0, -1.0)

    def tab_change(self, widget, num=None):
        """Change to a specific tab"""
        if num is None:
            err('must specify a tab to change to')

        maker = Factory()
        child = self.get_child()

        if not maker.isinstance(child, 'Notebook'):
            dbg('child is not a notebook, nothing to change to')
            return

        if num == -1:
            # Go to the next tab
            cur = child.get_current_page()
            pages = child.get_n_pages()
            if cur == pages - 1:
                num = 0
            else:
                num = cur + 1
        elif num == -2:
            # Go to the previous tab
            cur = child.get_current_page()
            if cur > 0:
                num = cur - 1
            else:
                num = child.get_n_pages() - 1

        child.set_current_page(num)
        # Work around strange bug in gtk-2.12.11 and pygtk-2.12.1
        # Without it, the selection changes, but the displayed page doesn't
        # change
        child.set_current_page(child.get_current_page())

    # FIXME: All of these (un)group_(all|tab) methods need refactoring work
    def group_all(self, widget):
        """Group all terminals"""
        # FIXME: Why isn't this being done by Terminator() ?
        group = _('All')
        self.terminator.create_group(group)
        for terminal in self.terminator.terminals:
            terminal.set_group(None, group)

    def ungroup_all(self, widget):
        """Ungroup all terminals"""
        for terminal in self.terminator.terminals:
            terminal.set_group(None, None)

    def group_tab(self, widget):
        """Group all terminals in the current tab"""
        maker = Factory()
        notebook = self.get_child()

        if not maker.isinstance(notebook, 'Notebook'):
            dbg('not in a notebook, refusing to group tab')
            return

        pagenum = notebook.get_current_page()
        while True:
            group = _('Tab %d') % pagenum
            if group not in self.terminator.groups:
                break
            pagenum += 1
        for terminal in self.get_visible_terminals():
            terminal.set_group(None, group)

    def ungroup_tab(self, widget):
        """Ungroup all terminals in the current tab"""
        maker = Factory()
        notebook = self.get_child()

        if not maker.isinstance(notebook, 'Notebook'):
            dbg('note in a notebook, refusing to ungroup tab')
            return
        
        for terminal in self.get_visible_terminals():
            terminal.set_group(None, None)

    def move_tab(self, widget, direction):
        """Handle a keyboard shortcut for moving tab positions"""
        maker = Factory()
        notebook = self.get_child()

        if not maker.isinstance(notebook, 'Notebook'):
            dbg('not in a notebook, refusing to move tab %s' % direction)
            return

        dbg('moving tab %s' % direction)
        numpages = notebook.get_n_pages()
        page = notebook.get_current_page()
        child = notebook.get_nth_page(page)

        if direction == 'left':
            if page == 0:
                page = numpages
            else:
                page = page - 1
        elif direction == 'right':
            if page == numpages - 1:
                page = 0
            else:
                page = page + 1
        else:
            err('unknown direction: %s' % direction)
            return
        
        notebook.reorder_child(child, page)

    def navigate_terminal(self, terminal, direction):
        """Navigate around terminals"""
        _containers, terminals = util.enumerate_descendants(self)
        visibles = self.get_visible_terminals()
        current = terminals.index(terminal)
        length = len(terminals)
        next = None

        if length <= 1 or len(visibles) <= 1:
            return

        if direction in ['next', 'prev']:
            tmpterms = copy.copy(terminals)
            tmpterms = tmpterms[current+1:]
            tmpterms.extend(terminals[0:current])

            if direction == 'next':
                tmpterms.reverse()

            next = 0
            while len(tmpterms) > 0:
                tmpitem = tmpterms.pop()
                if tmpitem in visibles:
                    next = terminals.index(tmpitem)
                    break
        elif direction in ['left', 'right', 'up', 'down']:
            layout = self.get_visible_terminals()
            allocation = terminal.get_allocation()
            possibles = []

            # Get the co-ordinate of the appropriate edge for this direction
            edge = util.get_edge(allocation, direction)
            # Find all visible terminals which are, in their entirity, in the
            # direction we want to move
            for term in layout:
                rect = layout[term]
                if util.get_nav_possible(edge, rect, direction):
                    possibles.append(term)

            if len(possibles) == 0:
                return

            # Find out how far away each of the possible terminals is, then
            # find the smallest distance. The winning terminals are all of
            # those who are that distance away.
            offsets = {}
            for term in possibles:
                rect = layout[term]
                offsets[term] = util.get_nav_offset(edge, rect, direction)
            keys = offsets.values()
            keys.sort()
            winners = [k for k, v in offsets.iteritems() if v == keys[0]]
            next = terminals.index(winners[0])

            if len(winners) > 1:
                # Break an n-way tie using the cursor position
                term_alloc = terminal.allocation
                cursor_x = term_alloc.x + term_alloc.width / 2
                cursor_y = term_alloc.y + term_alloc.height / 2

                for term in winners:
                    rect = layout[term]
                    if util.get_nav_tiebreak(direction, cursor_x, cursor_y,
                            rect):
                        next = terminals.index(term)
                        break;
        else:
            err('Unknown navigation direction: %s' % direction)

        if next is not None:
            terminals[next].grab_focus()

    def create_layout(self, layout):
        """Apply any config items from our layout"""
        if not layout.has_key('children'):
            err('layout describes no children: %s' % layout)
            return
        children = layout['children']
        if len(children) != 1:
            # We're a Window, we can only have one child
            err('incorrect number of children for Window: %s' % layout)
            return

        child = children[children.keys()[0]]
        terminal = self.get_children()[0]
        dbg('Making a child of type: %s' % child['type'])
        if child['type'] == 'VPaned':
            self.split_axis(terminal, True)
        elif child['type'] == 'HPaned':
            self.split_axis(terminal, False)
        elif child['type'] == 'Notebook':
            self.tab_new()
            i = 2
            while i < len(child['children']):
                self.tab_new()
                i = i + 1
        elif child['type'] == 'Terminal':
            pass
        else:
            err('unknown child type: %s' % child['type'])
            return

        self.get_children()[0].create_layout(child)
Exemple #35
0
class Notebook(Container, gtk.Notebook):
    """Class implementing a gtk.Notebook container"""
    window = None
    last_active_term = None
    pending_on_tab_switch = None
    pending_on_tab_switch_args = None

    def __init__(self, window):
        """Class initialiser"""
        if isinstance(window.get_child(), gtk.Notebook):
            err('There is already a Notebook at the top of this window')
            raise(ValueError)

        Container.__init__(self)
        gtk.Notebook.__init__(self)
        self.terminator = Terminator()
        self.window = window
        gobject.type_register(Notebook)
        self.register_signals(Notebook)
        self.connect('switch-page', self.deferred_on_tab_switch)
        self.configure()

        child = window.get_child()
        window.remove(child)
        window.add(self)
        window_last_active_term = window.last_active_term
        self.newtab(widget=child)
        if window_last_active_term:
            self.set_last_active_term(window_last_active_term)
            window.last_active_term = None

        self.show_all()

    def configure(self):
        """Apply widget-wide settings"""
        # FIXME: The old reordered handler updated Terminator.terminals with
        # the new order of terminals. We probably need to preserve this for
        # navigation to next/prev terminals.
        #self.connect('page-reordered', self.on_page_reordered)
        self.set_property('homogeneous', self.config['homogeneous_tabbar'])
        self.set_scrollable(self.config['scroll_tabbar'])

        if self.config['tab_position'] == 'hidden' or self.config['hide_tabbar']:
            self.set_show_tabs(False)
        else:
            self.set_show_tabs(True)
            pos = getattr(gtk, 'POS_%s' % self.config['tab_position'].upper())
            self.set_tab_pos(pos)

        for tab in xrange(0, self.get_n_pages()):
            label = self.get_tab_label(self.get_nth_page(tab))
            label.update_angle()

        style = gtk.RcStyle()
        style.xthickness = 0
        style.ythickness = 0
        self.modify_style(style)
        self.last_active_term = {}

    def create_layout(self, layout):
        """Apply layout configuration"""
        def child_compare(a, b):
            order_a = children[a]['order']
            order_b = children[b]['order']

            if (order_a == order_b):
                return 0
            if (order_a < order_b):
                return -1
            if (order_a > order_b):
                return 1

        if not layout.has_key('children'):
            err('layout specifies no children: %s' % layout)
            return

        children = layout['children']
        if len(children) <= 1:
            #Notebooks should have two or more children
            err('incorrect number of children for Notebook: %s' % layout)
            return

        num = 0
        keys = children.keys()
        keys.sort(child_compare)

        for child_key in keys:
            child = children[child_key]
            dbg('Making a child of type: %s' % child['type'])
            if child['type'] == 'Terminal':
                pass
            elif child['type'] == 'VPaned':
                page = self.get_nth_page(num)
                self.split_axis(page, True)
            elif child['type'] == 'HPaned':
                page = self.get_nth_page(num)
                self.split_axis(page, False)
            num = num + 1

        num = 0
        for child_key in keys:
            page = self.get_nth_page(num)
            if not page:
                # This page does not yet exist, so make it
                self.newtab(children[child_key])
                page = self.get_nth_page(num)
            if layout.has_key('labels'):
                labeltext = layout['labels'][num]
                if labeltext and labeltext != "None":
                    label = self.get_tab_label(page)
                    label.set_custom_label(labeltext)
            page.create_layout(children[child_key])

            if  layout.get('last_active_term',  None):
                self.last_active_term[page] = make_uuid(layout['last_active_term'][num])
            num = num + 1

        if layout.has_key('active_page'):
            # Need to do it later, or layout changes result
            gobject.idle_add(self.set_current_page, int(layout['active_page']))
        else:
            self.set_current_page(0)

    def split_axis(self, widget, vertical=True, cwd=None, sibling=None, widgetfirst=True):
        """Split the axis of a terminal inside us"""
        dbg('called for widget: %s' % widget)
        order = None
        page_num = self.page_num(widget)
        if page_num == -1:
            err('Notebook::split_axis: %s not found in Notebook' % widget)
            return

        label = self.get_tab_label(widget)
        self.remove(widget)

        maker = Factory()
        if vertical:
            container = maker.make('vpaned')
        else:
            container = maker.make('hpaned')

        self.get_toplevel().set_pos_by_ratio = True

        if not sibling:
            sibling = maker.make('terminal')
            sibling.set_cwd(cwd)
            sibling.spawn_child()
            if widget.group and self.config['split_to_group']:
                sibling.set_group(None, widget.group)
        if self.config['always_split_with_profile']:
            sibling.force_set_profile(None, widget.get_profile())

        self.insert_page(container, None, page_num)
        self.set_tab_reorderable(container, True)
        self.set_tab_label(container, label)
        self.show_all()

        order = [widget, sibling]
        if widgetfirst is False:
            order.reverse()

        for terminal in order:
            container.add(terminal)
        self.set_current_page(page_num)

        self.show_all()

        while gtk.events_pending():
            gtk.main_iteration_do(False)
        self.get_toplevel().set_pos_by_ratio = False

        gobject.idle_add(terminal.ensure_visible_and_focussed)

    def add(self, widget, metadata=None):
        """Add a widget to the container"""
        dbg('adding a new tab')
        self.newtab(widget=widget, metadata=metadata)

    def remove(self, widget):
        """Remove a widget from the container"""
        page_num = self.page_num(widget)
        if page_num == -1:
            err('%s not found in Notebook. Actual parent is: %s' % 
                    (widget, widget.get_parent()))
            return(False)
        self.remove_page(page_num)
        self.disconnect_child(widget)
        return(True)

    def replace(self, oldwidget, newwidget):
        """Replace a tab's contents with a new widget"""
        page_num = self.page_num(oldwidget)
        self.remove(oldwidget)
        self.add(newwidget)
        self.reorder_child(newwidget, page_num)

    def get_child_metadata(self, widget):
        """Fetch the relevant metadata for a widget which we'd need
        to recreate it when it's readded"""
        metadata = {}
        metadata['tabnum'] = self.page_num(widget)
        label = self.get_tab_label(widget)
        if not label:
            dbg('unable to find label for widget: %s' % widget)
        else:
            metadata['label'] = label.get_label()
        return metadata

    def get_children(self):
        """Return an ordered list of our children"""
        children = []
        for page in xrange(0,self.get_n_pages()):
            children.append(self.get_nth_page(page))
        return(children)

    def newtab(self, debugtab=False, widget=None, cwd=None, metadata=None, profile=None):
        """Add a new tab, optionally supplying a child widget"""
        dbg('making a new tab')
        maker = Factory()
        top_window = self.get_toplevel()

        if not widget:
            widget = maker.make('Terminal')
            if cwd:
                widget.set_cwd(cwd)
            widget.spawn_child(debugserver=debugtab)
        if profile and self.config['always_split_with_profile']:
            widget.force_set_profile(None, profile)

        signals = {'close-term': self.wrapcloseterm,
                   'split-horiz': self.split_horiz,
                   'split-vert': self.split_vert,
                   'title-change': self.propagate_title_change,
                   'unzoom': self.unzoom,
                   'tab-change': top_window.tab_change,
                   'group-all': top_window.group_all,
                   'group-all-toggle': top_window.group_all_toggle,
                   'ungroup-all': top_window.ungroup_all,
                   'group-tab': top_window.group_tab,
                   'group-tab-toggle': top_window.group_tab_toggle,
                   'ungroup-tab': top_window.ungroup_tab,
                   'move-tab': top_window.move_tab,
                   'tab-new': [top_window.tab_new, widget],
                   'navigate': top_window.navigate_terminal}

        if maker.isinstance(widget, 'Terminal'):
            for signal in signals:
                args = []
                handler = signals[signal]
                if isinstance(handler, list):
                    args = handler[1:]
                    handler = handler[0]
                self.connect_child(widget, signal, handler, *args)

        if metadata and metadata.has_key('tabnum'):
            tabpos = metadata['tabnum']
        else:
            tabpos = -1

        label = TabLabel(self.window.get_title(), self)
        if metadata and metadata.has_key('label'):
            dbg('creating TabLabel with text: %s' % metadata['label'])
            label.set_custom_label(metadata['label'])
        label.connect('close-clicked', self.closetab)

        label.show_all()
        widget.show_all()

        dbg('inserting page at position: %s' % tabpos)
        self.insert_page(widget, None, tabpos)

        if maker.isinstance(widget, 'Terminal'):
            containers, objects = ([], [widget])
        else:
            containers, objects = enumerate_descendants(widget)

        term_widget = None
        for term_widget in objects:
            if maker.isinstance(term_widget, 'Terminal'):
                self.set_last_active_term(term_widget.uuid)
                break

        self.set_tab_label(widget, label)
        gobject.idle_add(self.set_tab_label_packing,
                             term_widget,
                             not self.config['scroll_tabbar'],
                             not self.config['scroll_tabbar'],
                             gtk.PACK_START)

        self.set_tab_reorderable(widget, True)
        self.set_current_page(tabpos)
        self.show_all()
        if maker.isinstance(term_widget, 'Terminal'):
            widget.grab_focus()

    def wrapcloseterm(self, widget):
        """A child terminal has closed"""
        dbg('Notebook::wrapcloseterm: called on %s' % widget)
        if self.closeterm(widget):
            dbg('Notebook::wrapcloseterm: closeterm succeeded')
            self.hoover()
        else:
            dbg('Notebook::wrapcloseterm: closeterm failed')

    def closetab(self, widget, label):
        """Close a tab"""
        tabnum = None
        try:
            nb = widget.notebook
        except AttributeError:
            err('TabLabel::closetab: called on non-Notebook: %s' % widget)
            return

        for i in xrange(0, nb.get_n_pages() + 1):
            if label == nb.get_tab_label(nb.get_nth_page(i)):
                tabnum = i
                break

        if tabnum is None:
            err('TabLabel::closetab: %s not in %s. Bailing.' % (label, nb))
            return

        maker = Factory()
        child = nb.get_nth_page(tabnum)

        if maker.isinstance(child, 'Terminal'):
            dbg('Notebook::closetab: child is a single Terminal')
            del nb.last_active_term[child]
            child.close()
            # FIXME: We only do this del and return here to avoid removing the
            # page below, which child.close() implicitly does
            del(label)
            return
        elif maker.isinstance(child, 'Container'):
            dbg('Notebook::closetab: child is a Container')
            result = self.construct_confirm_close(self.window, _('tab'))

            if result == gtk.RESPONSE_ACCEPT:
                containers = None
                objects = None
                containers, objects = enumerate_descendants(child)

                while len(objects) > 0:
                    descendant = objects.pop()
                    descendant.close()
                    while gtk.events_pending():
                        gtk.main_iteration()
                return
            else:
                dbg('Notebook::closetab: user cancelled request')
                return
        else:
            err('Notebook::closetab: child is unknown type %s' % child)
            return

    def resizeterm(self, widget, keyname):
        """Handle a keyboard event requesting a terminal resize"""
        raise NotImplementedError('resizeterm')

    def zoom(self, widget, fontscale = False):
        """Zoom a terminal"""
        raise NotImplementedError('zoom')

    def unzoom(self, widget):
        """Unzoom a terminal"""
        raise NotImplementedError('unzoom')

    def find_tab_root(self, widget):
        """Look for the tab child which is or ultimately contains the supplied
        widget"""
        parent = widget.get_parent()
        previous = parent

        while parent is not None and parent is not self:
            previous = parent
            parent = parent.get_parent()

        if previous == self:
            return(widget)
        else:
            return(previous)

    def update_tab_label_text(self, widget, text):
        """Update the text of a tab label"""
        notebook = self.find_tab_root(widget)
        label = self.get_tab_label(notebook)
        if not label:
            err('Notebook::update_tab_label_text: %s not found' % widget)
            return
        
        label.set_label(text)

    def hoover(self):
        """Clean up any empty tabs and if we only have one tab left, die"""
        numpages = self.get_n_pages()
        while numpages > 0:
            numpages = numpages - 1
            page = self.get_nth_page(numpages)
            if not page:
                dbg('Removing empty page: %d' % numpages)
                self.remove_page(numpages)

        if self.get_n_pages() == 1:
            dbg('Last page, removing self')
            child = self.get_nth_page(0)
            self.remove_page(0)
            parent = self.get_parent()
            parent.remove(self)
            self.cnxids.remove_all()
            parent.add(child)
            del(self)
            # Find the last terminal in the new parent and give it focus
            terms = parent.get_visible_terminals()
            terms.keys()[-1].grab_focus()

    def page_num_descendant(self, widget):
        """Find the tabnum of the tab containing a widget at any level"""
        tabnum = self.page_num(widget)
        dbg("widget is direct child if not equal -1 - tabnum: %d" % tabnum)
        while tabnum == -1 and widget.get_parent():
            widget = widget.get_parent()
            tabnum = self.page_num(widget)
        dbg("found tabnum containing widget: %d" % tabnum)
        return tabnum

    def set_last_active_term(self, uuid):
        """Set the last active term for uuid"""
        widget = self.terminator.find_terminal_by_uuid(uuid.urn)
        if not widget:
            err("Cannot find terminal with uuid: %s, so cannot make it active" % (uuid.urn))
            return
        tabnum = self.page_num_descendant(widget)
        if tabnum == -1:
            err("No tabnum found for terminal with uuid: %s" % (uuid.urn))
            return
        nth_page = self.get_nth_page(tabnum)
        self.last_active_term[nth_page] = uuid

    def clean_last_active_term(self):
        """Clean up old entries in last_active_term"""
        if self.terminator.doing_layout == True:
            return
        last_active_term = {}
        for tabnum in xrange(0, self.get_n_pages()):
            nth_page = self.get_nth_page(tabnum)
            if nth_page in self.last_active_term:
                last_active_term[nth_page] = self.last_active_term[nth_page]
        self.last_active_term = last_active_term

    def deferred_on_tab_switch(self, notebook, page,  page_num,  data=None):
        """Prime a single idle tab switch signal, using the most recent set of params"""
        tabs_last_active_term = self.last_active_term.get(self.get_nth_page(page_num),  None)
        data = {'tabs_last_active_term':tabs_last_active_term}
        
        self.pending_on_tab_switch_args = (notebook, page,  page_num,  data)
        if self.pending_on_tab_switch == True:
            return
        gobject.idle_add(self.do_deferred_on_tab_switch)
        self.pending_on_tab_switch = True

    def do_deferred_on_tab_switch(self):
        """Perform the latest tab switch signal, and resetting the pending flag"""
        self.on_tab_switch(*self.pending_on_tab_switch_args)
        self.pending_on_tab_switch = False
        self.pending_on_tab_switch_args = None

    def on_tab_switch(self, notebook, page,  page_num,  data=None):
        """Do the real work for a tab switch"""
        tabs_last_active_term = data['tabs_last_active_term']
        if tabs_last_active_term:
            term = self.terminator.find_terminal_by_uuid(tabs_last_active_term.urn)
            gobject.idle_add(term.ensure_visible_and_focussed)
        return True
class TerminalPopupMenu(object):
    """Class implementing the Terminal context menu"""
    terminal = None
    terminator = None
    config = None

    def __init__(self, terminal):
        """Class initialiser"""
        self.terminal = terminal
        self.terminator = Terminator()
        self.config = Config()

    def show(self, widget, event=None):
        """Display the context menu"""
        terminal = self.terminal

        menu = gtk.Menu()
        url = None
        button = None
        time = None

        self.config.set_profile(terminal.get_profile())

        if event:
            url = terminal.check_for_url(event)
            button = event.button
            time = event.time
        else:
            time = 0
            button = 3

        if url:
            dbg("URL matches id: %d" % url[1])
            if not url[1] in terminal.matches.values():
                err("Unknown URL match id: %d" % url[1])
                dbg("Available matches: %s" % terminal.matches)

            nameopen = None
            namecopy = None
            if url[1] == terminal.matches['email']:
                nameopen = _('_Send email to...')
                namecopy = _('_Copy email address')
            elif url[1] == terminal.matches['voip']:
                nameopen = _('Ca_ll VoIP address')
                namecopy = _('_Copy VoIP address')
            elif url[1] in terminal.matches.values():
                # This is a plugin match
                for pluginname in terminal.matches:
                    if terminal.matches[pluginname] == url[1]:
                        break

                dbg("Found match ID (%d) in terminal.matches plugin %s" %
                    (url[1], pluginname))
                registry = plugin.PluginRegistry()
                registry.load_plugins()
                plugins = registry.get_plugins_by_capability('url_handler')
                for urlplugin in plugins:
                    if urlplugin.handler_name == pluginname:
                        dbg("Identified matching plugin: %s" %
                            urlplugin.handler_name)
                        nameopen = _(urlplugin.nameopen)
                        namecopy = _(urlplugin.namecopy)
                        break

            if not nameopen:
                nameopen = _('_Open link')
            if not namecopy:
                namecopy = _('_Copy address')

            icon = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO,
                                            gtk.ICON_SIZE_MENU)
            item = gtk.ImageMenuItem(nameopen)
            item.set_property('image', icon)
            item.connect('activate', lambda x: terminal.open_url(url, True))
            menu.append(item)

            item = gtk.MenuItem(namecopy)
            item.connect('activate',
                         lambda x: terminal.clipboard.set_text(terminal.prepare_url(url)))
            menu.append(item)

            menu.append(gtk.MenuItem())

        item = gtk.ImageMenuItem(gtk.STOCK_COPY)
        item.connect('activate', lambda x: terminal.vte.copy_clipboard())
        item.set_sensitive(terminal.vte.get_has_selection())
        menu.append(item)

        item = gtk.ImageMenuItem(gtk.STOCK_PASTE)
        item.connect('activate', lambda x: terminal.paste_clipboard())
        menu.append(item)

        menu.append(gtk.MenuItem())

        if not terminal.is_zoomed():
            item = gtk.ImageMenuItem(_('Split H_orizontally'))
            image = gtk.Image()
            image.set_from_icon_name(APP_NAME + '_horiz', gtk.ICON_SIZE_MENU)
            item.set_image(image)
            if hasattr(item, 'set_always_show_image'):
                item.set_always_show_image(True)
            item.connect('activate', lambda x: terminal.emit('split-horiz',
                self.terminator.pid_cwd(self.terminal.pid)))
            menu.append(item)

            item = gtk.ImageMenuItem(_('Split V_ertically'))
            image = gtk.Image()
            image.set_from_icon_name(APP_NAME + '_vert', gtk.ICON_SIZE_MENU)
            item.set_image(image)
            if hasattr(item, 'set_always_show_image'):
                item.set_always_show_image(True)
            item.connect('activate', lambda x: terminal.emit('split-vert',
                self.terminator.pid_cwd(self.terminal.pid)))
            menu.append(item)

            item = gtk.MenuItem(_('Open _Tab'))
            item.connect('activate',
                         lambda x: terminal.emit('tab-new', False, terminal))
            menu.append(item)

            if self.terminator.debug_address is not None:
                item = gtk.MenuItem(_('Open _Debug Tab'))
                item.connect(
                    'activate',
                    lambda x: terminal.emit('tab-new', True, terminal))
                menu.append(item)

            menu.append(gtk.MenuItem())

        item = gtk.ImageMenuItem(gtk.STOCK_CLOSE)
        item.connect('activate', lambda x: terminal.close())
        menu.append(item)

        menu.append(gtk.MenuItem())

        if not terminal.is_zoomed():
            item = gtk.MenuItem(_('_Zoom terminal'))
            item.connect('activate', terminal.zoom)
            menu.append(item)

            item = gtk.MenuItem(_('Ma_ximise terminal'))
            item.connect('activate', terminal.maximise)
            menu.append(item)

            menu.append(gtk.MenuItem())
        else:
            item = gtk.MenuItem(_('_Restore all terminals'))
            item.connect('activate', terminal.unzoom)
            menu.append(item)

            menu.append(gtk.MenuItem())

        if self.config['show_titlebar'] == False:
            item = gtk.MenuItem(_('Grouping'))
            submenu = self.terminal.populate_group_menu()
            submenu.show_all()
            item.set_submenu(submenu)
            menu.append(item)
            menu.append(gtk.MenuItem())

        item = gtk.CheckMenuItem(_('Show _scrollbar'))
        item.set_active(terminal.scrollbar.get_property('visible'))
        item.connect('toggled', lambda x: terminal.do_scrollbar_toggle())
        menu.append(item)

        if hasattr(gtk, 'Builder'):
            item = gtk.MenuItem(_('_Preferences'))
            item.connect('activate', lambda x: PrefsEditor(self.terminal))
            menu.append(item)

        profilelist = self.config.list_profiles()

        if len(profilelist) > 1:
            item = gtk.MenuItem(_('Profiles'))
            submenu = gtk.Menu()
            item.set_submenu(submenu)
            menu.append(item)

            current = terminal.get_profile()

            group = None

            for profile in profilelist:
                item = gtk.RadioMenuItem(group, profile.capitalize())
                if profile == current:
                    item.set_active(True)
                item.connect('activate', terminal.force_set_profile, profile)
                submenu.append(item)

        self.add_encoding_items(menu)

        try:
            menuitems = []
            registry = plugin.PluginRegistry()
            registry.load_plugins()
            plugins = registry.get_plugins_by_capability('terminal_menu')
            for menuplugin in plugins:
                menuplugin.callback(menuitems, menu, terminal)

            if len(menuitems) > 0:
                menu.append(gtk.MenuItem())

            for menuitem in menuitems:
                menu.append(menuitem)
        except Exception, ex:
            err('TerminalPopupMenu::show: %s' % ex)

        menu.show_all()
        menu.popup(None, None, None, button, time)

        return (True)
 def __init__(self, terminal):
     """Class initialiser"""
     self.terminal = terminal
     self.terminator = Terminator()
     self.config = Config()
Exemple #38
0
class DBTools:
  """
  Class: DBTools
  --------------
  Handles requests to a particular database (as specified in the CONFIG file).
  """

  def __init__(self, user, database):
    # The database connection parameters are specified in the CONFIG.py file.
    # Contains the reference to the database object.
    self.db = None

    # The database cursor.
    self.cursor = None

    # The current connection timeout limit.
    self.timeout = CONNECTION_TIMEOUT

    # The savepoints.
    self.savepoints = []

    # The user to connect with. If no user is specified, picks the first user
    # in the dictionary.
    self.user = user if user is not None else LOGIN.keys()[0]

    # The name of the database to connect to. If none is specified, use
    # <user>_db as the default database.
    self.database = database if database is not None else "%s_db" % self.user

    # Separate database connection used to terminate queries. If the terminator
    # cannot start, the grading cannot occur.
    try:
      self.terminator = Terminator(self.user, self.database)
    except mysql.connector.errors.Error:
      err("Could not start up terminator connection! Any unruly queries " +
          "must be manually killed!")

  # --------------------------- Database Utilities --------------------------- #

  def close_db_connection(self):
    """
    Function: close_db_connection
    -----------------------------
    Close the database connection (only if it is already open) and any running
    queries.
    """
    if self.db:
      # Consume remaining output.
      for _ in self.cursor:
        pass

      # Kill any remaining queries and close the database connection.
      try:
        self.kill_query()
        self.cursor.close()
        self.db.close()
      # Can't do anything if there is a database error.
      except mysql.connector.errors.Error:
        pass


  def commit(self):
    """
    Function: commit
    ----------------
    Commits the current transaction. Destroys any savepoints.
    """
    try:
      self.db.commit()
    except mysql.connector.errors.Error as e:
      raise DatabaseError(e)
    self.savepoints = []


  def get_cursor(self):
    """
    Function: get_cursor
    --------------------
    Gets the cursor. Assumes the database has already been connected.
    """
    return self.cursor


  def get_db_connection(self, timeout=None, close=True):
    """
    Function: get_db_connection
    ---------------------------
    Get a new database connection with a specified timeout (defaults to
    CONNECTION_TIMEOUT specified in the CONFIG file). Closes the old connection
    if there was one.

    timeout: The connection timeout.
    close: Whether or not to close the old database connection beforehand.
           Should set to False if a timeout occurred just before the call to
           this function.
    returns: A database connection object.
    """
    if self.db and self.db.is_connected():
      # If timeout isn't specified, check if we're already at the default.
      if timeout is None and self.timeout == CONNECTION_TIMEOUT:
        return self.db
      # If the timeout is the same as before, then don't change anything.
      if timeout is not None and timeout == self.timeout:
        return self.db

    # Close any old connections and make another one with the new setting.
    if close:
      self.close_db_connection()
    self.timeout = timeout or CONNECTION_TIMEOUT
    log("New timeout: %d" % self.timeout)
    try:
      self.db = mysql.connector.connect(user=self.user,
                                        password=LOGIN[self.user],
                                        host=HOST,
                                        database=self.database,
                                        port=PORT,
                                        connection_timeout=self.timeout,
                                        autocommit=False)
      self.cursor = self.db.cursor(buffered=True)
    except mysql.connector.errors.Error as e:
      raise DatabaseError(e)
    return self


  def get_state(self):
    """
    Function: get_state
    -------------------
    Gets the current state of the database, which includes the tables, foreign,
    keys, views, functions, procedures, and triggers.

    returns: A DatabaseState object which contains the current state.
    """
    state = DatabaseState()

    try:
      # Get tables and their foreign keys.
      state.tables = self.execute_sql(
        "SELECT table_name FROM information_schema.tables "
        "WHERE table_type='BASE TABLE'"
      ).results
      state.foreign_keys = self.execute_sql(
        "SELECT DISTINCT table_name, constraint_name FROM "
        "information_schema.table_constraints WHERE constraint_type='FOREIGN KEY'"
      ).results
  
      # Get views, functions, procedures, and triggers.
      state.views = self.execute_sql(
        "SELECT table_name FROM information_schema.views"
      ).results
      state.functions = self.execute_sql(
        "SELECT routine_name FROM information_schema.routines "
        "WHERE routine_type='FUNCTION'"
      ).results
      state.procedures = self.execute_sql(
        "SELECT routine_name FROM information_schema.routines "
        "WHERE routine_type='PROCEDURE'"
      ).results
      state.triggers = self.execute_sql(
        "SELECT trigger_name FROM information_schema.triggers"
      ).results
    except (mysql.connector.errors.Error, DatabaseError, TimeoutError):
      raise

    return state


  def kill_query(self):
    """
    Function: kill_query
    --------------------
    Kills the running query by terminating the connection.
    """
    if not self.db or not self.db.is_connected():
      return

    thread_id = self.db.connection_id
    try:
      self.terminator.terminate(thread_id)
    except mysql.connector.errors.Error:
      err("Unable to kill %d (was probably already killed)." % thread_id)
    # If the terminator doesn't even exist, then this is a problem.
    except AttributeError:
      err("Terminator doesn't exist to kill queries!", True)
    self.savepoints = []


  def purge_db(self):
    """
    Function: purge_db
    ------------------
    Remove everything from the database.
    """
    state = self.get_state()
    self.reset_state(DatabaseState(), state)


  def release(self, savepoint):
    """
    Function: release
    -----------------
    Releases the named savepoint.

    savepoint: The savepoint to release.
    """
    if savepoint not in self.savepoints:
      return

    self.savepoints.remove(savepoint)
    try:
      self.execute_sql("RELEASE SAVEPOINT %s" % savepoint)
    except mysql.connector.errors.Error:
      pass


  def reset_state(self, old, new):
    """
    Function: reset_state
    ---------------------
    Resets the state of the database from 'new' back to 'old'. This involves
    removing all functions, views, functions, procedures, and triggers that
    have been newly created.

    old: The old state of the database to be reverted back to.
    new: The new (current) state of the database.
    """
    new.subtract(old)

    try:
      # Drop all functions procedures, and triggers first.
      # if VERBOSE:
      #   print("-" * 78)
      #   print("Resetting state.")
          
      for trig in new.triggers:
        sql = "DROP TRIGGER IF EXISTS %s" % trig
        # if VERBOSE:
        #   print(sql)
          
        self.execute_sql(sql)
        
      for proc in new.procedures:
        sql = "DROP PROCEDURE IF EXISTS %s" % proc
        # if VERBOSE:
        #   print(sql)
          
        self.execute_sql(sql)
        
      for func in new.functions:
        sql = "DROP FUNCTION IF EXISTS %s" % func
        
        # if VERBOSE:
        #   print(sql)
          
        self.execute_sql(sql)

      # Drop views.
      for view in new.views:
        sql = "DROP VIEW IF EXISTS %s" % view

        # if VERBOSE:
        #   print(sql)
        
        self.execute_sql(sql)

      # Drop tables. First must drop foreign keys on the tables in order to be
      # able to drop the tables without any errors.
      for (table, fk) in new.foreign_keys:
        self.execute_sql("ALTER TABLE %s DROP FOREIGN KEY %s" % (table, fk))
      for table in new.tables:
        self.execute_sql("DROP TABLE IF EXISTS %s" % table)
    except (mysql.connector.errors.Error, DatabaseError, TimeoutError):
      err("Could not reset database state. Possible errors in future grading.")

    # Remove all savepoints.
    self.savepoints = []


  def rollback(self, savepoint=None):
    """
    Function: rollback
    ------------------
    Rolls back a database transaction, if currently in one. If a savepoint is
    named, rolls back to the named savepoint, otherwise, does a normal rollback
    which will remove all savepoints.

    savepoint: The savepoint to rollback to, if specified.
    """
    if self.db.in_transaction:
      # Roll back to the named savepoint. All savepoints created after this
      # savepoint are deleted.
      if savepoint and savepoint in self.savepoints:
        # If rolling back a savepoint failed, then a commit must have occurred
        # at some point. Rollback as far as we can just to be safe.
        try:
          self.execute_sql("ROLLBACK TO %s" % savepoint)
        except:
          self.db.rollback()
        self.savepoints = self.savepoints[0:self.savepoints.index(savepoint)+1]
      else:
        try:
          self.db.rollback()
        except mysql.connector.errors.Error as e:
          raise DatabaseError(e)
        self.savepoints = []


  def savepoint(self, savepoint):
    """
    Function: savepoint
    -------------------
    Creates a savepoint with the specified name.

    savepoint: The name of the savepoint.
    """
    try:
      self.execute_sql("SAVEPOINT %s" % savepoint)
    except mysql.connector.errors.Error:
      err("Could not create savepoint %s!" % savepoint)

    # If this savepoint name already exists, add and remove it.
    if savepoint in self.savepoints:
      self.savepoints.remove(savepoint)
    self.savepoints.append(savepoint)


  def start_transaction(self):
    """
    Function: start_transaction
    ---------------------------
    Starts a database transaction, if not already in one.
    """
    self.db.commit()
    if not self.db.in_transaction:
      try:
        self.db.start_transaction()
      except mysql.connector.errors.Error as e:
        raise DatabaseError(e)

  # ----------------------------- Query Utilities ---------------------------- #

  def clear_cursor(self):
    try:
      self.cursor.fetchall()
    except Exception as e:
      if str(e) == 'No result set to fetch from.':
          pass
      else:
          raise

  def execute_sql(self, sql, setup=None, teardown=None, cached=False):
    """
    Function: execute_sql
    ---------------------
    Runs one or more queries as well as the setup and teardown necessary for
    that query (if provided).

    sql: The SQL query to run.
    setup: The setup query to run before executing the actual query.
    teardown: The teardown query to run after executing the actual query.
    cached: Whether or not the result should be pulled from the cache. True if
            so, False otherwise.

    returns: A Result object containing the result.
    """
    # Run the query setup.
    result = Result()
    if setup is not None:
      self.run_multi(setup)

    try:
      # if VERBOSE:
      #   print("-" * 78)
      #   print("Running SQL statement:\n%s\n(use cached result = %s)" % (sql, str(cached)))

      result = self.run_multi(sql, cached)

    # Run the query teardown.
    finally:
      if teardown is not None:
        # if VERBOSE:
        #   print("-" * 78)
        #   print("Running teardown:\n%s" % teardown)

        self.run_multi(teardown)
    return result


  def get_column_names(self):
    """
    Function: get_column_names
    --------------------------
    Gets the column names of the result.
    """
    if self.cursor.description is None:
      return []
    return [col[0] for col in self.cursor.description]


  def get_column_types(self):
    """
    Function: get_column_types
    --------------------------
    Gets the column types of the result.
    """
    if self.cursor.description is None:
      return []
    return [
      (float if col[1] in FLOAT_FIELD_TYPES else str) \
      for col in self.cursor.description
    ]


  def get_results(self):
    """
    Function: results
    -----------------
    Get the results of a query.
    """
    result = Result()

    # Get the query results and schema.
    rows = [row for row in self.cursor]
    if len(rows) > 0:
      result.results = rows
      result.schema = self.get_schema()
      result.col_names = self.get_column_names()
      result.col_types = self.get_column_types()

      # Pretty-printed output.
      result.output = prettyprint(result.results, self.get_column_names())

    return result


  def get_schema(self):
    """
    Function: get_schema
    --------------------
    Gets the schema of the result. Returns a list of tuples, where each tuple is
    of the form (column_name, type, None, None, None, None, null_ok, flags).
    """
    return self.cursor.description


  def run_multi(self, queries, cached=False):
    """
    Function: run_multi
    -------------------
    Runs multiple SQL statements at once.
    """
    # Consume old results if needed.
    [row for row in self.cursor]
    sql_list = split(queries)

    # Consume any additional result-sets that might have been left
    # on the connection.
    # try:
    #     while self.cursor.nextset():
    #         pass
    # except Error:
    #     pass

    result = Result()
    for sql in sql_list:
      sql = sql.rstrip().rstrip(";")
      if len(sql) == 0:
        continue

      query_results = Cache.get(sql)

      # Results are not to be cached or are not in the cache and needs to
      # be cached. Run the query.
      if not query_results or not cached:
        try:
          self.clear_cursor()
          self.cursor.execute(sql)

        # except DatabaseError as e:
        #     if 'already exists' in str(e):
        #         print("[warning: %s]" % str(e))
        #     else:
        #         # Reraise the exception
        #         raise e

        # If the query times out.
        except mysql.connector.errors.OperationalError as e:
          raise TimeoutError(e)

        # If something is wrong with their query.
        except mysql.connector.errors.ProgrammingError as e:
          if 'already exists' in str(e):
              log("[warning: %s]" % str(e))
          else:
              raise DatabaseError(e)

        # If the query can't be run as a single query, attempt to do it with a
        # multi-line query.
        except mysql.connector.errors.Error as e:
          print("ERROR while executing SQL:  %s" % sql)
          print(str(e))
          raise DatabaseError(e)

        query_results = self.get_results()
        if cached:
          Cache.put(sql, query_results)

      result = query_results

    # If no longer in a transaction, remove all savepoints.
    if not self.db.in_transaction:
      self.savepoints = []

    return result

  # ----------------------------- File Utilities ----------------------------- #

  def import_file(self, assignment, f):
    """
    Function: import_files
    ----------------------
    Imports raw data files into the database. This uses the "mysqlimport"
    command on the terminal. We will have to invoke the command via Python.

    assignment: The assignment name, which is prepended to all the files.
    f: The file to import.
    """
    log("\nImporting file " + f + "...\n")
    filename = ASSIGNMENT_DIR + assignment + "/" + f

    # Make sure the file exists.
    if not os.path.exists(filename):
      err("File to import %s does not exist!" % filename, True)
    try:
      subprocess.call("mysqlimport -h " + HOST + " -P " + PORT + " -u " +
                      self.user + " -p" + LOGIN[self.user] +
                      " --delete --local " + self.database + " " + filename, shell=True)
    except OSError:
      err("Could not import file %s! The 'mysqlimport' utility does not exist!" % filename,
          True)


  def source_file(self, assignment, f):
    """
    Function: source_file
    ---------------------
    Sources a file into the database. Since the "source" command is for the
    MySQL command-line interface, we have to parse the source file and run
    each command one at a time.

    assignment: The assignment name, which is prepended to all the files.
    f: The source file to source.
    """
    try:
      fname = ASSIGNMENT_DIR + assignment + "/" + f
      f = codecs.open(fname, "r", "utf-8")
    except IOError:
      err("Could not find or open sourced file %s!" % fname, True)

    sql_list = split(preprocess_sql(f))
    for sql in sql_list:
      # Skip this line if there is nothing in it.
      if len(sql.strip()) == 0:
        continue
      # Otherwise execute each line. Output must be consumed for the query
      # to actually be executed.
      sql = sql.rstrip()
      # if VERBOSE:
      #   print("-" * 78)
      #   print("source_file(%s):  Running SQL command:\n%s" % (fname, sql))
      for _ in self.cursor.execute(sql, multi=True): self.clear_cursor()
      self.commit()
    f.close()
Exemple #39
0
class DBusService(Borg, dbus.service.Object):
    """DBus Server class. This is implemented as a Borg"""
    bus_name = None
    bus_path = None
    terminator = None

    def __init__(self):
        """Class initialiser"""
        Borg.__init__(self, self.__class__.__name__)
        self.prepare_attributes()
        dbus.service.Object.__init__(self, self.bus_name, BUS_PATH)

    def prepare_attributes(self):
        """Ensure we are populated"""
        if not self.bus_name:
            dbg('Checking for bus name availability: %s' % BUS_NAME)
            bus = dbus.SessionBus()
            proxy = bus.get_object('org.freedesktop.DBus', 
                                   '/org/freedesktop/DBus')
            flags = 1 | 4 # allow replacement | do not queue
            if not proxy.RequestName(BUS_NAME, dbus.UInt32(flags)) in (1, 4):
                dbg('bus name unavailable: %s' % BUS_NAME)
                raise dbus.exceptions.DBusException(
                    "Couldn't get DBus name %s: Name exists" % BUS_NAME)
            self.bus_name = dbus.service.BusName(BUS_NAME, 
                                                 bus=dbus.SessionBus())
        if not self.bus_path:
            self.bus_path = BUS_PATH
        if not self.terminator:
            self.terminator = Terminator()

    @dbus.service.method(BUS_NAME)
    def new_window(self, layout='default'):
        """Create a new Window"""
        dbg('dbus method called: new_window')
        self.terminator.create_layout(layout)
        self.terminator.layout_done()

    @dbus.service.method(BUS_NAME)
    def terminal_hsplit(self, uuid=None):
        """Split a terminal horizontally, by UUID"""
        return self.terminal_split(uuid, True)

    @dbus.service.method(BUS_NAME)
    def terminal_vsplit(self, uuid=None):
        """Split a terminal vertically, by UUID"""
        return self.terminal_split(uuid, False)

    def terminal_split(self, uuid, horiz):
        """Split a terminal horizontally or vertically, by UUID"""
        dbg('dbus method called: terminal_hsplit')
        if not uuid:
            return "ERROR: No UUID specified"
        terminal = self.terminator.find_terminal_by_uuid(uuid)
        if not terminal:
            return "ERROR: Terminal with supplied UUID not found"
        if horiz:
            terminal.key_split_horiz()
        else:
            terminal.key_split_vert()

    @dbus.service.method(BUS_NAME)
    def get_terminals(self, uuid):
        """Return a list of all the terminals"""
        return [x.uuid.urn for x in self.terminator.terminals]
Exemple #40
0
class Titlebar(gtk.EventBox):
    """Class implementing the Titlebar widget"""

    terminator = None
    terminal = None
    config = None
    oldtitle = None
    termtext = None
    sizetext = None
    label = None
    ebox = None
    groupicon = None
    grouplabel = None
    groupentry = None
    bellicon = None

    __gsignals__ = {
            'clicked': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
            'edit-done': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
            'create-group': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                (gobject.TYPE_STRING,)),
    }

    def __init__(self, terminal):
        """Class initialiser"""
        gtk.EventBox.__init__(self)
        self.__gobject_init__()

        self.terminator = Terminator()
        self.terminal = terminal
        self.config = self.terminal.config

        self.label = EditableLabel()
        self.label.connect('edit-done', self.on_edit_done)
        self.ebox = gtk.EventBox()
        grouphbox = gtk.HBox()
        self.grouplabel = gtk.Label()
        self.groupicon = gtk.Image()
        self.bellicon = gtk.Image()
        self.bellicon.set_no_show_all(True)

        self.groupentry = gtk.Entry()
        self.groupentry.set_no_show_all(True)
        self.groupentry.connect('focus-out-event', self.groupentry_cancel)
        self.groupentry.connect('activate', self.groupentry_activate)
        self.groupentry.connect('key-press-event', self.groupentry_keypress)

        groupsend_type = self.terminator.groupsend_type
        if self.terminator.groupsend == groupsend_type['all']:
            icon_name = 'all'
        elif self.terminator.groupsend == groupsend_type['group']:
            icon_name = 'group'
        elif self.terminator.groupsend == groupsend_type['off']:
            icon_name = 'off'
        self.set_from_icon_name('_active_broadcast_%s' % icon_name, 
                gtk.ICON_SIZE_MENU)

        grouphbox.pack_start(self.groupicon, False, True, 2)
        grouphbox.pack_start(self.grouplabel, False, True, 2)
        grouphbox.pack_start(self.groupentry, False, True, 2)

        self.ebox.add(grouphbox)
        self.ebox.show_all()

        self.bellicon.set_from_icon_name('terminal-bell', gtk.ICON_SIZE_MENU)
        hbox = gtk.HBox()
        hbox.pack_start(self.ebox, False, True, 0)
        hbox.pack_start(gtk.VSeparator(), False, True, 0)
        hbox.pack_start(self.label, True, True)
        hbox.pack_end(self.bellicon, False, False, 2)

        self.add(hbox)
        hbox.show_all()
        self.set_no_show_all(True)
        self.show()

        self.connect('button-press-event', self.on_clicked)

    def connect_icon(self, func):
        """Connect the supplied function to clicking on the group icon"""
        self.ebox.connect('button-press-event', func)

    def update(self, other=None):
        """Update our contents"""
        default_bg = False
        if self.config['title_hide_sizetext']:
            self.label.set_text("%s" % self.termtext)
        else:
            self.label.set_text("%s %s" % (self.termtext, self.sizetext))

        if other:
            term = self.terminal
            terminator = self.terminator
            if other == 'window-focus-out':
                title_fg = self.config['title_inactive_fg_color']
                title_bg = self.config['title_inactive_bg_color']
                icon = '_receive_off'
                default_bg = True
                group_fg = self.config['title_inactive_fg_color']
                group_bg = self.config['title_inactive_bg_color']
            elif term != other and term.group and term.group == other.group:
                if terminator.groupsend == terminator.groupsend_type['off']:
                    title_fg = self.config['title_inactive_fg_color']
                    title_bg = self.config['title_inactive_bg_color']
                    icon = '_receive_off'
                    default_bg = True
                else:
                    title_fg = self.config['title_receive_fg_color']
                    title_bg = self.config['title_receive_bg_color']
                    icon = '_receive_on'
                group_fg = self.config['title_receive_fg_color']
                group_bg = self.config['title_receive_bg_color']
            elif term != other and not term.group or term.group != other.group:
                if terminator.groupsend == terminator.groupsend_type['all']:
                    title_fg = self.config['title_receive_fg_color']
                    title_bg = self.config['title_receive_bg_color']
                    icon = '_receive_on'
                else:
                    title_fg = self.config['title_inactive_fg_color']
                    title_bg = self.config['title_inactive_bg_color']
                    icon = '_receive_off'
                    default_bg = True
                group_fg = self.config['title_inactive_fg_color']
                group_bg = self.config['title_inactive_bg_color']
            else:
                # We're the active terminal
                title_fg = self.config['title_transmit_fg_color']
                title_bg = self.config['title_transmit_bg_color']
                if terminator.groupsend == terminator.groupsend_type['all']:
                    icon = '_active_broadcast_all'
                elif terminator.groupsend == terminator.groupsend_type['group']:
                    icon = '_active_broadcast_group'
                else:
                    icon = '_active_broadcast_off'
                group_fg = self.config['title_transmit_fg_color']
                group_bg = self.config['title_transmit_bg_color']

            self.label.modify_fg(gtk.STATE_NORMAL,
                    gtk.gdk.color_parse(title_fg))
            self.grouplabel.modify_fg(gtk.STATE_NORMAL,
                    gtk.gdk.color_parse(group_fg))
            self.modify_bg(gtk.STATE_NORMAL, 
                    gtk.gdk.color_parse(title_bg))
            if not self.get_desired_visibility():
                if default_bg == True:
                    color = term.get_style().bg[gtk.STATE_NORMAL]
                else:
                    color = gtk.gdk.color_parse(title_bg)
            self.update_visibility()
            self.ebox.modify_bg(gtk.STATE_NORMAL,
                    gtk.gdk.color_parse(group_bg))
            self.set_from_icon_name(icon, gtk.ICON_SIZE_MENU)

    def update_visibility(self):
        """Make the titlebar be visible or not"""
        if not self.get_desired_visibility():
            dbg('hiding titlebar')
            self.hide()
            self.label.hide()
        else:
            dbg('showing titlebar')
            self.show()
            self.label.show()

    def get_desired_visibility(self):
        """Returns True if the titlebar is supposed to be visible. False if
        not"""
        if self.editing() == True or self.terminal.group:
            dbg('implicit desired visibility')
            return(True)
        else:
            dbg('configured visibility: %s' % self.config['show_titlebar'])
            return(self.config['show_titlebar'])

    def set_from_icon_name(self, name, size = gtk.ICON_SIZE_MENU):
        """Set an icon for the group label"""
        if not name:
            self.groupicon.hide()
            return
        
        self.groupicon.set_from_icon_name(APP_NAME + name, size)
        self.groupicon.show()

    def update_terminal_size(self, width, height):
        """Update the displayed terminal size"""
        self.sizetext = "%sx%s" % (width, height)
        self.update()

    def set_terminal_title(self, widget, title):
        """Update the terminal title"""
        self.termtext = title
        self.update()
        # Return False so we don't interrupt any chains of signal handling
        return False

    def set_group_label(self, name):
        """Set the name of the group"""
        if name:
            self.grouplabel.set_text(name)
            self.grouplabel.show()
        else:
            self.grouplabel.set_text('')
            self.grouplabel.hide()
        self.update_visibility()

    def on_clicked(self, widget, event):
        """Handle a click on the label"""
        self.show()
        self.label.show()
        self.emit('clicked')

    def on_edit_done(self, widget):
        """Re-emit an edit-done signal from an EditableLabel"""
        self.emit('edit-done')

    def editing(self):
        """Determine if we're currently editing a group name or title"""
        return(self.groupentry.get_property('visible') or self.label.editing())

    def create_group(self):
        """Create a new group"""
        if self.terminal.group:
            self.groupentry.set_text(self.terminal.group)
        else:
            defaultmembers=['Alpha','Beta','Gamma','Delta','Epsilon','Zeta','Eta',
                           'Theta','Iota','Kappa','Lambda','Mu','Nu','Xi',
                           'Omnicron','Pi','Rho','Sigma','Tau','Upsilon','Phi',
                           'Chi','Psi','Omega']
            currentgroups=set(self.terminator.groups)
            for i in range(1,4):
                defaultgroups=set(map(''.join, list(itertools.product(defaultmembers,repeat=i))))
                freegroups = list(defaultgroups-currentgroups)
                if freegroups:
                    self.groupentry.set_text(random.choice(freegroups))
                    break
            else:
                self.groupentry.set_text('')
        self.groupentry.show()
        self.grouplabel.hide()
        self.groupentry.grab_focus()
        self.update_visibility()

    def groupentry_cancel(self, widget, event):
        """Hide the group name entry"""
        self.groupentry.set_text('')
        self.groupentry.hide()
        self.grouplabel.show()
        self.get_parent().grab_focus()

    def groupentry_activate(self, widget):
        """Actually cause a group to be created"""
        groupname = self.groupentry.get_text() or None
        dbg('Titlebar::groupentry_activate: creating group: %s' % groupname)
        self.groupentry_cancel(None, None)
        last_focused_term=self.terminator.last_focused_term
        if self.terminal.targets_for_new_group:
            [term.titlebar.emit('create-group', groupname) for term in self.terminal.targets_for_new_group]
            self.terminal.targets_for_new_group = None
        else:
            self.emit('create-group', groupname)
        last_focused_term.grab_focus()
        self.terminator.focus_changed(last_focused_term)

    def groupentry_keypress(self, widget, event):
        """Handle keypresses on the entry widget"""
        key = gtk.gdk.keyval_name(event.keyval)
        if key == 'Escape':
            self.groupentry_cancel(None, None)

    def icon_bell(self):
        """A bell signal requires we display our bell icon"""
        self.bellicon.show()
        gobject.timeout_add(1000, self.icon_bell_hide)

    def icon_bell_hide(self):
        """Handle a timeout which means we now hide the bell icon"""
        self.bellicon.hide()
        return(False)

    def get_custom_string(self):
        """If we have a custom string set, return it, otherwise None"""
        if self.label.is_custom():
            return(self.label.get_text())
        else:
            return(None)

    def set_custom_string(self, string):
        """Set a custom string"""
        self.label.set_text(string)
        self.label.set_custom()
Exemple #41
0
class DBusService(Borg, dbus.service.Object):
    """DBus Server class. This is implemented as a Borg"""
    bus_name = None
    bus_path = None
    terminator = None

    def __init__(self):
        """Class initialiser"""
        Borg.__init__(self, self.__class__.__name__)
        self.prepare_attributes()
        dbus.service.Object.__init__(self, self.bus_name, BUS_PATH)

    def prepare_attributes(self):
        """Ensure we are populated"""
        if not self.bus_name:
            dbg('Checking for bus name availability: %s' % BUS_NAME)
            bus = dbus.SessionBus()
            proxy = bus.get_object('org.freedesktop.DBus', 
                                   '/org/freedesktop/DBus')
            flags = 1 | 4 # allow replacement | do not queue
            if not proxy.RequestName(BUS_NAME, dbus.UInt32(flags)) in (1, 4):
                dbg('bus name unavailable: %s' % BUS_NAME)
                raise dbus.exceptions.DBusException(
                    "Couldn't get DBus name %s: Name exists" % BUS_NAME)
            self.bus_name = dbus.service.BusName(BUS_NAME, 
                                                 bus=dbus.SessionBus())
        if not self.bus_path:
            self.bus_path = BUS_PATH
        if not self.terminator:
            self.terminator = Terminator()

    @dbus.service.method(BUS_NAME, in_signature='a{ss}')
    def new_window(self, options=dbus.Dictionary()):
        """Create a new Window"""
        dbg('dbus method called: new_window with parameters %s'%(options))
        oldopts = self.terminator.config.options_get()
        oldopts.__dict__ = options
        self.terminator.config.options_set(oldopts)
        self.terminator.create_layout(oldopts.layout)
        self.terminator.layout_done()
            
    @dbus.service.method(BUS_NAME, in_signature='a{ss}')
    def new_tab(self, options=dbus.Dictionary()):
        """Create a new tab"""
        dbg('dbus method called: new_tab with parameters %s'%(options))
        oldopts = self.terminator.config.options_get()
        oldopts.__dict__ = options
        self.terminator.config.options_set(oldopts)
        window = self.terminator.get_windows()[0]
        window.tab_new()

    @dbus.service.method(BUS_NAME)
    def terminal_hsplit(self, uuid=None):
        """Split a terminal horizontally, by UUID"""
        return self.terminal_split(uuid, True)

    @dbus.service.method(BUS_NAME)
    def terminal_vsplit(self, uuid=None):
        """Split a terminal vertically, by UUID"""
        return self.terminal_split(uuid, False)

    def terminal_split(self, uuid, horiz):
        """Split a terminal horizontally or vertically, by UUID"""
        dbg('dbus method called: terminal_hsplit')
        if not uuid:
            return "ERROR: No UUID specified"
        terminal = self.terminator.find_terminal_by_uuid(uuid)
        if not terminal:
            return "ERROR: Terminal with supplied UUID not found"
        if horiz:
            terminal.key_split_horiz()
        else:
            terminal.key_split_vert()

    @dbus.service.method(BUS_NAME)
    def get_terminals(self, uuid):
        """Return a list of all the terminals"""
        return [x.uuid.urn for x in self.terminator.terminals]

    @dbus.service.method(BUS_NAME)
    def get_terminal_tab(self, uuid):
        """Return the UUID of the parent tab of a given terminal"""
        maker = Factory()
        terminal = self.terminator.find_terminal_by_uuid(uuid)
        window = terminal.get_toplevel()
        root_widget = window.get_children()[0]
        if maker.isinstance(root_widget, 'Notebook'):
            return root_widget.uuid.urn

    @dbus.service.method(BUS_NAME)
    def get_terminal_tab_title(self, uuid):
        """Return the title of a parent tab of a given terminal"""
        maker = Factory()
        terminal = self.terminator.find_terminal_by_uuid(uuid)
        window = terminal.get_toplevel()
        root_widget = window.get_children()[0]
        if maker.isinstance(root_widget, "Notebook"):
            return root_widget.get_tab_label(terminal).get_label()
    def setup_backer(self):
        '''
        Target:
            - executes the backer depending on the type of backup to make, the
              role of the user who is connected to PostgreSQL and the rest of
              the conditions. It calls a terminator if necessary.
        '''
        connecter = self.get_connecter()

        # Get databases or clusters' backer depending on the option selected
        # by the user in console
        if self.args.cluster:
            self.logger.debug(Messenger.BEGINNING_EXE_CL_BACKER)
            backer = self.get_cl_backer(connecter)
        else:
            self.logger.debug(Messenger.BEGINNING_EXE_DB_BACKER)
            backer = self.get_db_backer(connecter)

        # If necessary, add group and bkp_path to the mailer to be sent within
        # the process information
        if self.args.config_mailer:
            self.logger.mailer.add_group(backer.group)
            path = backer.bkp_path + backer.group
            self.logger.mailer.add_bkp_path(path)

        # Check if the role of user connected to PostgreSQL is superuser
        pg_superuser = connecter.is_pg_superuser()
        if not pg_superuser:
            if self.args.cluster is False:
                # Users who are not superusers will only be able to backup the
                # databases they own
                backer.db_owner = connecter.user
                self.logger.highlight(
                    'warning', Messenger.ACTION_DB_NO_SUPERUSER,
                    'yellow', effect='bold')
            else:  # Backup the cluster can only be made by superuser
                self.logger.stop_exe(Messenger.ACTION_CL_NO_SUPERUSER)

        # Make the backups
        if self.args.cluster is False:  # Backup databases

            # Get PostgreSQL databases' names, connection permissions and
            # owners
            dbs_all = connecter.get_pg_dbs_data(backer.ex_templates,
                                                backer.db_owner)
            # Show and log their names
            Orchestrator.show_dbs(dbs_all, self.logger)

            # Get the target databases in a list
            bkp_list = DbSelector.get_filtered_dbs(
                dbs_all, backer.in_dbs, backer.ex_dbs, backer.in_regex,
                backer.ex_regex, backer.in_priority, self.logger)

            # Terminate every connection to these target databases if necessary
            if self.args.terminate:
                terminator = Terminator(connecter, target_dbs=bkp_list,
                                        logger=self.logger)
                terminator.terminate_backend_dbs(bkp_list)

            backer.backup_dbs(bkp_list)  # Make databases' backup

        else:  # Backup a cluster
            # Terminate every connection to any database of the cluster if
            # necessary
            if self.args.terminate:
                terminator = Terminator(connecter, target_all=True,
                                        logger=self.logger)
                terminator.terminate_backend_all()

            backer.backup_cl()  # Make cluster's backup

        # Close connection to PostgreSQL
        connecter.pg_disconnect()