class RouteTableApp(QWidget): """ Main view class This class composes the widgets for the user to choose the logs files to compare and the options for the output """ def __init__(self, parent=None, controller=None, *args, **kwargs): super(RouteTableApp, self).__init__(parent, *args, **kwargs) self._parent = parent self._controller = controller self._options = self.__Options() self.initUI() logging.debug("Main RouteTableApp created {}".format(self)) def initUI(self): self.setWindowTitle("Routa Table comparison") logo = QIcon('img/icon/logo.png') self.setWindowIcon(logo) self.qw_router1 = LogFileWidget(parent=self) self.qw_router1.setTitle("Previous info") self.qw_router2 = LogFileWidget(parent=self) self.qw_router2.setTitle("New info") self.btn_process = QPushButton("Process") self.btn_process.setMaximumWidth(70) # self.btn_process.setEnabled(False) self.btn_process.clicked.connect(self._process) self.chk_protocol = QCheckBox("include protocol?") self.chk_protocol.setChecked(self._options.getattribute("includeProtocolFlag")) self.chk_next = QCheckBox("include nexthop?") self.chk_next.setChecked(self._options.getattribute("includeNexthopFlag")) icon = QIcon('img/icon/process.svg') self.btn_process.setIcon(icon) self.menubar = QMenuBar(self) preferenceMenu = self.menubar.addMenu('Preferences') self.routerIdComparisonAction = QAction('Same Router Id', self) self.routerIdComparisonAction.setCheckable(True) self.routerIdComparisonAction.setChecked(self._options.getattribute("routerIdComparison")) preferenceMenu.addAction(self.routerIdComparisonAction) separatorMenu = preferenceMenu.addMenu("Separator") parserMenu = preferenceMenu.addMenu("Log type") # Parsers options self.parserAction = QActionGroup(self) autoAction = QAction('auto', self) autoAction.setCheckable(True) autoAction.setChecked("auto" == self._options.getattribute("parser")) timosAction = QAction('sros', self) timosAction.setCheckable(True) timosAction.setChecked("sros" == self._options.getattribute("parser")) timosBgpAction = QAction('sros bgp', self) timosBgpAction.setCheckable(True) timosBgpAction.setChecked("sros bgp" == self._options.getattribute("parser")) hvrpAction = QAction('hvrp', self) hvrpAction.setCheckable(True) hvrpAction.setChecked("hvrp" == self._options.getattribute("parser")) autoAction.triggered.connect(self._selectParser) timosAction.triggered.connect(self._selectParser) timosBgpAction.triggered.connect(self._selectParser) hvrpAction.triggered.connect(self._selectParser) self.parserAction.addAction(autoAction) self.parserAction.addAction(timosAction) self.parserAction.addAction(timosBgpAction) self.parserAction.addAction(hvrpAction) self.parserAction.setExclusive(True) parserMenu.addAction(autoAction) parserMenu.addAction(timosAction) parserMenu.addAction(timosBgpAction) parserMenu.addAction(hvrpAction) # set separators menu, mutually exclusive, and get persistent value self.separatorAction = QActionGroup(self) commaAction = QAction('comma (,)', self) commaAction.setCheckable(True) commaAction.setChecked("," in self._options.getattribute("separator")) semicolonAction = QAction('semicolon (;)', self) semicolonAction.setCheckable(True) semicolonAction.setChecked(";" in self._options.getattribute("separator")) spaceAction = QAction('space ( )', self) spaceAction.setCheckable(True) spaceAction.setChecked(" " in self._options.getattribute("separator")) self.separatorAction.addAction(commaAction) self.separatorAction.addAction(spaceAction) self.separatorAction.addAction(semicolonAction) self.separatorAction.setExclusive(True) commaAction.triggered.connect(self._selectSeparator) semicolonAction.triggered.connect(self._selectSeparator) spaceAction.triggered.connect(self._selectSeparator) separatorMenu.addAction(spaceAction) separatorMenu.addAction(commaAction) separatorMenu.addAction(semicolonAction) self.layout = QVBoxLayout() self.hlayout = QHBoxLayout() self.hlayout.addWidget(self.btn_process) self.hlayout.addWidget(self.chk_protocol) self.hlayout.addWidget(self.chk_next) self.layout.addWidget(self.menubar) self.layout.addWidget(self.qw_router1) self.layout.addWidget(self.qw_router2) self.layout.addLayout(self.hlayout) self.setLayout(self.layout) self.show() def _process(self): logging.debug("Button clicked {}".format(self.btn_process)) self._controller.process() class __Options(object): """ Hold local widget options """ width = 200 height = 100 currentPath = "" compareByKey = True includeProtocolFlag = False includeNexthopFlag = False separator = " " parser = "auto" routerIdComparison = True def __init__(self): """ Load default values then get the values from serialized file if any """ import pickle try: with open('options.pickle', 'rb') as f: self.__dict__ = pickle.load(f) logging.debug("Load options widget. options {}".format(self.__dict__)) except FileNotFoundError: pass def getattribute(self, name): return getattr(self, name) def setattr(self, name, value): setattr(self, name, value) logging.debug("Set Attr <{}> value <{}> object {}".format(name, value, self)) def save(self): """ Memento save class __dict__ over a persistent file """ import pickle with open('options.pickle', 'wb') as f: pickle.dump(self.__dict__, f) def includeProtocol(self): return self.chk_protocol.isChecked() def includeNexthop(self): return self.chk_next.isChecked() def separatorChar(self): return self._options.separator def routerIdComparison(self): return self.routerIdComparisonAction.isChecked() def parserSelect(self): return self._options.parser def _selectSeparator(self): t = self.separatorAction.checkedAction().text() logging.debug("_selectSeparator separator <{}>".format(t)) if ',' in t: self._options.setattr("separator", ',') elif ';' in t: self._options.setattr("separator", ';') else: self._options.setattr("separator", ' ') def _selectParser(self): t = self.parserAction.checkedAction().text() logging.debug("_selectParser parser <{}>".format(t)) if 'auto' in t: self._options.setattr("parser", 'auto') elif 'sros' == t.strip(): self._options.setattr("parser", 'sros') elif 'sros bgp' == t.strip(): self._options.setattr("parser", 'sros bgp') elif 'hvrp' == t: self._options.setattr("parser", 'hvrp') else: self._options.setattr("parser", 'auto') def closeEvent(self, event): logging.debug("closing widget <{}> event <{}>".format(self, event)) self._options.setattr("includeProtocolFlag", self.chk_protocol.isChecked()) self._options.setattr("includeNexthopFlag", self.chk_next.isChecked()) self._options.setattr("width", self.width()) self._options.setattr("height", self.height()) self._selectSeparator() self._selectParser() self._options.setattr("routerIdComparison", self.routerIdComparisonAction.isChecked()) self._options.save() event.accept()
class LocationManager(QObject): # {{{ locations_changed = pyqtSignal() unmount_device = pyqtSignal() location_selected = pyqtSignal(object) configure_device = pyqtSignal() update_device_metadata = pyqtSignal() def __init__(self, parent=None): QObject.__init__(self, parent) self.free = [-1, -1, -1] self.count = 0 self.location_actions = QActionGroup(self) self.location_actions.setExclusive(True) self.current_location = 'library' self._mem = [] self.tooltips = {} self.all_actions = [] def ac(name, text, icon, tooltip): icon = QIcon(I(icon)) ac = self.location_actions.addAction(icon, text) setattr(self, 'location_' + name, ac) ac.setAutoRepeat(False) ac.setCheckable(True) receiver = partial(self._location_selected, name) ac.triggered.connect(receiver) self.tooltips[name] = tooltip m = QMenu(parent) self._mem.append(m) a = m.addAction(icon, tooltip) a.triggered.connect(receiver) if name != 'library': self._mem.append(a) a = m.addAction(QIcon(I('eject.png')), _('Eject this device')) a.triggered.connect(self._eject_requested) self._mem.append(a) a = m.addAction(QIcon(I('config.png')), _('Configure this device')) a.triggered.connect(self._configure_requested) self._mem.append(a) a = m.addAction(QIcon(I('sync.png')), _('Update cached metadata on device')) a.triggered.connect( lambda x: self.update_device_metadata.emit()) self._mem.append(a) else: ac.setToolTip(tooltip) ac.setMenu(m) ac.calibre_name = name self.all_actions.append(ac) return ac self.library_action = ac('library', _('Library'), 'lt.png', _('Show books in calibre library')) ac('main', _('Device'), 'reader.png', _('Show books in the main memory of the device')) ac('carda', _('Card A'), 'sd.png', _('Show books in storage card A')) ac('cardb', _('Card B'), 'sd.png', _('Show books in storage card B')) def set_switch_actions(self, quick_actions, rename_actions, delete_actions, switch_actions, choose_action): self.switch_menu = self.library_action.menu() if self.switch_menu: self.switch_menu.addSeparator() else: self.switch_menu = QMenu() self.switch_menu.addAction(choose_action) self.cs_menus = [] for t, acs in [(_('Quick switch'), quick_actions), (_('Rename library'), rename_actions), (_('Delete library'), delete_actions)]: if acs: self.cs_menus.append(QMenu(t)) for ac in acs: self.cs_menus[-1].addAction(ac) self.switch_menu.addMenu(self.cs_menus[-1]) self.switch_menu.addSeparator() for ac in switch_actions: self.switch_menu.addAction(ac) if self.switch_menu != self.library_action.menu(): self.library_action.setMenu(self.switch_menu) def _location_selected(self, location, *args): if location != self.current_location and hasattr( self, 'location_' + location): self.current_location = location self.location_selected.emit(location) getattr(self, 'location_' + location).setChecked(True) def _eject_requested(self, *args): self.unmount_device.emit() def _configure_requested(self): self.configure_device.emit() def update_devices(self, cp=(None, None), fs=[-1, -1, -1], icon=None): if icon is None: icon = I('reader.png') self.location_main.setIcon(QIcon(icon)) had_device = self.has_device if cp is None: cp = (None, None) if isinstance(cp, (str, unicode)): cp = (cp, None) if len(fs) < 3: fs = list(fs) + [0] self.free[0] = fs[0] self.free[1] = fs[1] self.free[2] = fs[2] cpa, cpb = cp self.free[1] = fs[1] if fs[1] is not None and cpa is not None else -1 self.free[2] = fs[2] if fs[2] is not None and cpb is not None else -1 self.update_tooltips() if self.has_device != had_device: self.location_library.setChecked(True) self.locations_changed.emit() if not self.has_device: self.location_library.trigger() def update_tooltips(self): for i, loc in enumerate(('main', 'carda', 'cardb')): t = self.tooltips[loc] if self.free[i] > -1: t += u'\n\n%s ' % human_readable(self.free[i]) + _('available') ac = getattr(self, 'location_' + loc) ac.setToolTip(t) ac.setWhatsThis(t) ac.setStatusTip(t) @property def has_device(self): return max(self.free) > -1 @property def available_actions(self): ans = [self.location_library] for i, loc in enumerate(('main', 'carda', 'cardb')): if self.free[i] > -1: ans.append(getattr(self, 'location_' + loc)) return ans
class LocationManager(QObject): # {{{ locations_changed = pyqtSignal() unmount_device = pyqtSignal() location_selected = pyqtSignal(object) configure_device = pyqtSignal() update_device_metadata = pyqtSignal() def __init__(self, parent=None): QObject.__init__(self, parent) self.free = [-1, -1, -1] self.count = 0 self.location_actions = QActionGroup(self) self.location_actions.setExclusive(True) self.current_location = 'library' self._mem = [] self.tooltips = {} self.all_actions = [] def ac(name, text, icon, tooltip): icon = QIcon(I(icon)) ac = self.location_actions.addAction(icon, text) setattr(self, 'location_'+name, ac) ac.setAutoRepeat(False) ac.setCheckable(True) receiver = partial(self._location_selected, name) ac.triggered.connect(receiver) self.tooltips[name] = tooltip m = QMenu(parent) self._mem.append(m) a = m.addAction(icon, tooltip) a.triggered.connect(receiver) if name != 'library': self._mem.append(a) a = m.addAction(QIcon(I('eject.png')), _('Eject this device')) a.triggered.connect(self._eject_requested) self._mem.append(a) a = m.addAction(QIcon(I('config.png')), _('Configure this device')) a.triggered.connect(self._configure_requested) self._mem.append(a) a = m.addAction(QIcon(I('sync.png')), _('Update cached metadata on device')) a.triggered.connect(lambda x : self.update_device_metadata.emit()) self._mem.append(a) else: ac.setToolTip(tooltip) ac.setMenu(m) ac.calibre_name = name self.all_actions.append(ac) return ac self.library_action = ac('library', _('Library'), 'lt.png', _('Show books in calibre library')) ac('main', _('Device'), 'reader.png', _('Show books in the main memory of the device')) ac('carda', _('Card A'), 'sd.png', _('Show books in storage card A')) ac('cardb', _('Card B'), 'sd.png', _('Show books in storage card B')) def set_switch_actions(self, quick_actions, rename_actions, delete_actions, switch_actions, choose_action): self.switch_menu = self.library_action.menu() if self.switch_menu: self.switch_menu.addSeparator() else: self.switch_menu = QMenu() self.switch_menu.addAction(choose_action) self.cs_menus = [] for t, acs in [(_('Quick switch'), quick_actions), (_('Rename library'), rename_actions), (_('Delete library'), delete_actions)]: if acs: self.cs_menus.append(QMenu(t)) for ac in acs: self.cs_menus[-1].addAction(ac) self.switch_menu.addMenu(self.cs_menus[-1]) self.switch_menu.addSeparator() for ac in switch_actions: self.switch_menu.addAction(ac) if self.switch_menu != self.library_action.menu(): self.library_action.setMenu(self.switch_menu) def _location_selected(self, location, *args): if location != self.current_location and hasattr(self, 'location_'+location): self.current_location = location self.location_selected.emit(location) getattr(self, 'location_'+location).setChecked(True) def _eject_requested(self, *args): self.unmount_device.emit() def _configure_requested(self): self.configure_device.emit() def update_devices(self, cp=(None, None), fs=[-1, -1, -1], icon=None): if icon is None: icon = I('reader.png') self.location_main.setIcon(QIcon(icon)) had_device = self.has_device if cp is None: cp = (None, None) if isinstance(cp, (str, unicode)): cp = (cp, None) if len(fs) < 3: fs = list(fs) + [0] self.free[0] = fs[0] self.free[1] = fs[1] self.free[2] = fs[2] cpa, cpb = cp self.free[1] = fs[1] if fs[1] is not None and cpa is not None else -1 self.free[2] = fs[2] if fs[2] is not None and cpb is not None else -1 self.update_tooltips() if self.has_device != had_device: self.location_library.setChecked(True) self.locations_changed.emit() if not self.has_device: self.location_library.trigger() def update_tooltips(self): for i, loc in enumerate(('main', 'carda', 'cardb')): t = self.tooltips[loc] if self.free[i] > -1: t += u'\n\n%s '%human_readable(self.free[i]) + _('available') ac = getattr(self, 'location_'+loc) ac.setToolTip(t) ac.setWhatsThis(t) ac.setStatusTip(t) @property def has_device(self): return max(self.free) > -1 @property def available_actions(self): ans = [self.location_library] for i, loc in enumerate(('main', 'carda', 'cardb')): if self.free[i] > -1: ans.append(getattr(self, 'location_'+loc)) return ans