示例#1
0
    def error(self, errStr, cfgPath):
        """ Error handler GUI implementation """
        # it must handle two types of error cases:
        # - yandex-disk is not installed (errStr=='' in that case) - just show error message and return
        # - yandex-disk is not configured (errStr!='' in that case) - suggest to configure it and run ya-setup if needed
        if errStr == '':
            text1 = _('Yandex.Disk Indicator: daemon start failed')
            buttons = Gtk.ButtonsType.OK
            text2 = (_(
                'Yandex.Disk utility is not installed.\n' +
                'Visit www.yandex.ru, download and install Yandex.Disk daemon.'
            ))
        else:
            text1 = _('Yandex.Disk Indicator: daemon start failed')
            buttons = Gtk.ButtonsType.OK_CANCEL
            text2 = (_(
                'Yandex.Disk daemon failed to start because it is not' +
                ' configured properly\n\n' + errStr + '\n\n' +
                '  To configure it up: press OK button.\n  Press Cancel to exit.'
            ))
        dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.INFO, buttons,
                                   text1)
        dialog.format_secondary_text(text2)
        dialog.set_icon(APPLOGO)
        response = dialog.run()

        if errStr != '' and response == Gtk.ResponseType.OK:  # Launch Set-up utility
            LOGGER.debug('starting configuration utility')
            retCode = call([pathJoin(APPINSTPATH, 'ya-setup'), cfgPath])
        else:
            retCode = 1
        dialog.destroy()
        return retCode  # 0 when error is not critical or fixed (daemon has been configured via ya-setup)
示例#2
0
 def eventHandler(watch):
     """
     Handles watcher (when watch=False) and and timer (when watch=True) events.
     After receiving and parsing the daemon output it raises outside change event if daemon changes
     at least one of its status values.
     """
     # Enter to critical section through acquiring of the lock as it can be called from two different threads
     self.__lock.acquire()
     # Parse fresh daemon output. Parsing returns true when something changed
     if self.__parseOutput(self.__getOutput()):
         LOGGER.debug('%sEvent raised by %s', self.ID,
                      (' Watcher' if watch else ' Timer'))
         self.change(
             self.__v)  # Call the callback of update event handler
     # --- Handle timer delays ---
     self.__timer.cancel()  # Cancel timer if it still active
     if watch or self.__v['status'] == 'busy':
         delay = 2  # Initial delay
         self.__tCnt = 0  # Reset counter
     else:  # It called by timer
         delay = 2 + self.__tCnt  # Increase interval up to 10 sec (2 + 8)
         self.__tCnt += 1  # Increase counter to increase delay next activation.
     if self.__tCnt < 9:  # Don't start timer after 10 seconds delay
         self.__timer = thTimer(delay, eventHandler, (False, ))
         self.__timer.start()
     # Leave the critical section
     self.__lock.release()
示例#3
0
def appExit():
    """ Exit from application (it closes all APPINDICATORS) """
    # global APPINDICATORS
    LOGGER.debug("Exit started")
    for i in APPINDICATORS:
        i.exit()
    Gtk.main_quit()
示例#4
0
        def update(self, vals, yddir):  # Update information in menu
            self.folder = yddir
            # Update status data on first run or when status has changed
            if vals['statchg'] or vals['laststatus'] == 'unknown':
                self.status.set_label(
                    _('Status: ') + self.YD_STATUS[vals['status']] +
                    (vals['progress'] if vals['status'] == 'busy' else ' '.
                     join((':', vals['error'], shortPath(vals['path'])
                           )) if vals['status'] == 'error' else ''))
                # Update pseudo-static items on first run or when daemon has stopped or started
                if 'none' in (vals['status'], vals['laststatus']
                              ) or vals['laststatus'] == 'unknown':
                    started = vals['status'] != 'none'
                    self.status.set_sensitive(started)
                    # zero-space UTF symbols are used to detect requered action without need to compare translated strings
                    self.daemon_ss.set_label((
                        '\u2060' +
                        _('Stop Yandex.Disk daemon')) if started else (
                            '\u200B' + _('Start Yandex.Disk daemon')))
                    if self.ID != '':  # Set daemon identity row in multidaemon mode
                        self.yddir.set_label(self.ID + _('  Folder: ') +
                                             (shortPath(yddir) if yddir else
                                              '< NOT CONFIGURED >'))
                    self.open_folder.set_sensitive(
                        yddir !=
                        '')  # Activate Open YDfolder if daemon configured
            # Update sizes data on first run or when size data has changed
            if vals['szchg'] or vals['laststatus'] == 'unknown':
                self.used.set_label(
                    _('Used: ') + vals['used'] + '/' + vals['total'])
                self.free.set_label(
                    _('Free: ') + vals['free'] + _(', trash: ') +
                    vals['trash'])
            # Update last synchronized sub-menu on first run or when last data has changed
            if vals['lastchg'] or vals['laststatus'] == 'unknown':
                # Update last synchronized sub-menu
                self.lastItems.destroy(
                )  # Disable showing synchronized sub menu while updating it - temp fix for #197
                self.lastItems = Gtk.Menu()  # Create new/empty Sub-menu:
                for filePath in vals['lastitems']:  # Create new sub-menu items
                    # Create menu label as file path (shorten it down to 50 symbols when path length > 50
                    # symbols), with replaced underscore (to disable menu acceleration feature of GTK menu).
                    widget = Gtk.MenuItem.new_with_label(shortPath(filePath))
                    filePath = pathJoin(yddir,
                                        filePath)  # Make full path to file
                    if pathExists(filePath):
                        widget.set_sensitive(
                            True)  # If it exists then it can be opened
                        widget.connect("activate", self.openPath, filePath)
                    else:
                        widget.set_sensitive(
                            False)  # Don't allow to open non-existing path
                    self.lastItems.append(widget)
                self.last.set_submenu(self.lastItems)
                # Switch off last items menu sensitivity if no items in list
                self.last.set_sensitive(vals['lastitems'])
                LOGGER.debug("Sub-menu 'Last synchronized' has %s items",
                             str(len(vals['lastitems'])))

            self.show_all()  # Renew menu
示例#5
0
 def exit(self):  # Handle daemon/indicator closing
     LOGGER.debug("Indicator %sexit started: ", self.ID)
     self.__watcher.stop()
     self.__timer.cancel()  # stop event timer if it is running
     # Stop yandex-disk daemon if it is required by its configuration
     if self.config.get('stoponexitfromindicator', False):
         self.stop(wait=True)
         LOGGER.info('Demon %sstopped', self.ID)
     LOGGER.debug('Indicator %sexited', self.ID)
示例#6
0
 def send(self, messg):
     # global APPLOGO
     LOGGER.debug('Message: %s | %s', self.title, messg)
     if self.note is not None:
         try:
             self.note.close()
         except:
             pass
         self.note = None
     try:  # Create notification
         self.note = Notify.Notification.new(self.title, messg)
         self.note.set_image_from_pixbuf(APPLOGO)
         self.note.show()  # Display new notification
     except:
         LOGGER.error('Message engine failure')
示例#7
0
 def onButtonToggled(self, _, button, key, dconfig=None, ow=None):
     """ Handle clicks on controls """
     toggleState = button.get_active()
     LOGGER.debug('Togged: %s  val: %s', key, str(toggleState))
     # Update configurations
     if key in [
             'read-only', 'overwrite', 'startonstartofindicator',
             'stoponexitfromindicator'
     ]:
         dconfig[key] = toggleState  # Update daemon config
         dconfig.changed = True
     else:
         APPCONF.changed = True  # Update application config
         APPCONF[key] = toggleState
     if key == 'theme':
         for i in APPINDICATORS:  # Update all APPINDICATORS' icons
             i.setIconTheme(toggleState)  # Update icon theme
             i.updateIcon(i.currentStatus)  # Update current icon
     elif key == 'autostart':
         if toggleState:
             copyFile(APPAUTOSTARTSRC, APPAUTOSTARTDST)
         else:
             deleteFile(APPAUTOSTARTDST)
     elif key == 'fmextensions':
         if not button.get_inconsistent():  # It is a first call
             if not activateActions(toggleState, APPINSTPATH):
                 toggleState = not toggleState  # When activation/deactivation is not success: revert settings back
                 button.set_inconsistent(
                     True)  # set inconsistent state to detect second call
                 button.set_active(
                     toggleState)  # set check-button to reverted status
                 # set_active will raise again the 'toggled' event
         else:  # This is a second call
             button.set_inconsistent(
                 False)  # Just remove inconsistent status
     elif key == 'read-only':
         ow.set_sensitive(toggleState)
示例#8
0
 def change(self, vals):
     """ Updates handler """
     LOGGER.debug('%sUpdate event: %s', self.ID, str(vals))
示例#9
0
 def error(self, errStr, cfgPath):
     """ Error handler """
     LOGGER.debug('%sError %s , path %s', self.ID, errStr, cfgPath)
     return 0
示例#10
0
    # Change the process name
    setProcName(APPHOME)

    # Check for already running instance of the indicator application
    # Get PIDs of all runnig processes (of current user) with name 'yd-tools' and compare it with current process PID
    if str(getpid()) != check_output(
        ["pgrep", '-u', str(geteuid()), APPHOME],
            universal_newlines=True).strip():
        sysExit(_('The indicator instance is already running.'))

    # Set user specified logging level
    LOGGER.setLevel(args.level)

    # Report app version and logging level
    LOGGER.info('%s v.%s', APPNAME, APPVER)
    LOGGER.debug('Logging level: %s', str(args.level))

    # Application configuration
    """
    User configuration is stored in ~/.config/<APPHOME>/<APPNAME>.conf file.
    This file can contain comments (line starts with '#') and config values in
    form: key=value[,value[,value ...]] where keys and values can be quoted ("...") or not.
    The following key words are reserved for configuration:
      autostart, notifications, theme, fmextensions and daemons.

    The dictionary 'config' stores the config settings for usage in code. Its values are saved to
    config file on exit from the Menu.Preferences dialogue or when there is no configuration file
    when application starts.

    Note that daemon settings ('dir', 'read-only', 'overwrite' and 'exclude_dir') are stored
    in ~/ .config/yandex-disk/config.cfg file. They are read in YDDaemon.__init__() method