def __init__(self, parent, config_name=None, buttons=[], *args): """Creates dialog. 'config_name' is used to get/set default window size from Config object 'buttons' can be a list of names or (QPixmapWrapper,name[,tooltip]) tuples to provide custom buttons at the bottom of the dialog. When a button is clicked, the dialog emits SIGNAL("name"). A "Close" button is always provided, this simply hides the dialog. """ QDialog.__init__(self, parent, *args) self.setModal(False) lo = QVBoxLayout(self) # create viewer self.label = QLabel(self) self.label.setMargin(5) self.label.setWordWrap(True) lo.addWidget(self.label) self.label.hide() self.viewer = QTextBrowser(self) lo.addWidget(self.viewer) # self.viewer.setReadOnly(True) self.viewer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) QObject.connect(self.viewer, SIGNAL("anchorClicked(const QUrl &)"), self._urlClicked) self._source = None lo.addSpacing(5) # create button bar btnfr = QFrame(self) btnfr.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed) # btnfr.setMargin(5) lo.addWidget(btnfr) lo.addSpacing(5) btnfr_lo = QHBoxLayout(btnfr) btnfr_lo.setMargin(5) # add user buttons self._user_buttons = {} for name in buttons: if isinstance(name, str): btn = QPushButton(name, btnfr) elif isinstance(name, (list, tuple)): if len(name) < 3: pixmap, name = name tip = None else: pixmap, name, tip = name btn = QPushButton(pixmap.icon(), name, btnfr) if tip: btn.setToolTip(tip) self._user_buttons[name] = btn btn._clicked = Kittens.utils.curry(self.emit, SIGNAL(name)) self.connect(btn, SIGNAL("clicked()"), btn._clicked) btnfr_lo.addWidget(btn, 1) # add a Close button btnfr_lo.addStretch(100) closebtn = QPushButton(pixmaps.grey_round_cross.icon(), "Close", btnfr) self.connect(closebtn, SIGNAL("clicked()"), self.hide) btnfr_lo.addWidget(closebtn, 1) # resize selves self.config_name = config_name or "html-viewer" width = Config.getint('%s-width' % self.config_name, 512) height = Config.getint('%s-height' % self.config_name, 512) self.resize(QSize(width, height))
def __init__ (self,parent,*args): QDialog.__init__(self,parent,*args); self.setWindowTitle("Adding Log Entry"); self.setWindowIcon(pixmaps.purr_logo.icon()); self.setModal(False); ## create pop-up tip #self._has_tip = None; #self._dialog_tip = self.DialogTip(self); # create editor lo = QVBoxLayout(self); lo.setMargin(5); # lo.setResizeMode(QLayout.Minimum); self.editor = LogEntryEditor(self); self.dropDataProducts = self.editor.dropDataProducts; self.connect(self.editor,SIGNAL("filesSelected"),self,SIGNAL("filesSelected")); # connect draggedAwayFiles() signal so that files dragged away are removed from # the list self.connect(self.editor,SIGNAL("draggedAwayFiles"),self.editor.dropDataProducts); lo.addWidget(self.editor); lo.addSpacing(5); # create button bar btnfr = QFrame(self); btnfr.setSizePolicy(QSizePolicy.MinimumExpanding,QSizePolicy.Fixed); # btnfr.setMargin(5); lo.addWidget(btnfr); lo.addSpacing(5); btnfr_lo = QHBoxLayout(btnfr); btnfr_lo.setMargin(0); newbtn = QPushButton(pixmaps.filesave.icon(),"Add new entry",btnfr); newbtn.setToolTip("""<P>Saves new log entry, along with any data products not marked as "ignore" or "banish".<P>"""); self.ignorebtn = QPushButton(pixmaps.red_round_cross.icon(),"Ignore all",btnfr); self.ignorebtn.setEnabled(False); self.ignorebtn.setToolTip("""<P>Tells PURR to ignore all listed data products. PURR will not pounce on these files again until they have been modified.<P>"""); cancelbtn = QPushButton(pixmaps.grey_round_cross.icon(),"Hide",btnfr); cancelbtn.setToolTip("""<P>Hides this dialog.<P>"""); QObject.connect(newbtn,SIGNAL("clicked()"),self.addNewEntry); QObject.connect(self.ignorebtn,SIGNAL("clicked()"),self.ignoreAllDataProducts); QObject.connect(cancelbtn,SIGNAL("clicked()"),self.hide); for btn in (newbtn,self.ignorebtn,cancelbtn): btn.setAutoDefault(False); btnfr_lo.setMargin(0); btnfr_lo.addWidget(newbtn,2); btnfr_lo.addStretch(1); btnfr_lo.addWidget(self.ignorebtn,2); btnfr_lo.addStretch(1); btnfr_lo.addWidget(cancelbtn,2); self.setSizePolicy(QSizePolicy.MinimumExpanding,QSizePolicy.MinimumExpanding); # resize selves self.setMinimumSize(256,512); width = Config.getint('entry-editor-width',512); height = Config.getint('entry-editor-height',512); self.resize(QSize(width,height));
def setWatchedFilePatterns(self, watch, ignore=[]): self._watch = watch self._ignore = ignore self._watch_patterns = set() for desc, patts in self._watch: self._watch_patterns.update(patts) dprint(1, "watching patterns", self._watch_patterns) self._ignore_patterns = set() for desc, patts in self._ignore: self._ignore_patterns.update(patts) dprint(1, "ignoring patterns", self._ignore_patterns) Config.set("watch-patterns", make_pattern_list(self._watch)) Config.set("ignore-patterns", make_pattern_list(self._ignore))
def __init__(self, purrlog, watchdirs=None): QObject.__init__(self) # load and parse configuration # watched files watch = Config.get( "watch-patterns", "Images=*fits,*FITS,*jpg,*png;TDL configuration=.tdl.conf") self._watch = parse_pattern_list(watch) self._watch_patterns = set() for desc, patts in self._watch: self._watch_patterns.update(patts) dprint(1, "watching patterns", self._watch_patterns) # quietly watched files (dialog is not popped up) watch = Config.get("watch-patterns-quiet", "TDL configuration=.tdl.conf") self._quiet = parse_pattern_list(watch) self._quiet_patterns = set() for desc, patts in self._quiet: self._quiet_patterns.update(patts) dprint(1, "quietly watching patterns", self._quiet_patterns) # ignored files ignore = Config.get( "ignore-patterns", "Hidden files=.*;Purr logs=*purrlog;MeqTree logs=meqtree.log;Python files=*.py*;Backup files=*~,*.bck;Measurement sets=*.MS,*.ms;CASA tables=table.f*,table.dat,table.info,table.lock" ) self._ignore = parse_pattern_list(ignore) self._ignore_patterns = set() for desc, patts in self._ignore: self._ignore_patterns.update(patts) dprint(1, "ignoring patterns", self._ignore_patterns) # watched subdirectories subdirs = Config.get("watch-subdirs", "MEP tables=*mep/funklets,table.dat") _re_patt = re.compile("^(.*)=(.*)/(.*)$") self._subdir_patterns = [] for ss in subdirs.split(';'): match = _re_patt.match(ss) if match: desc = match.group(1) dir_patt = match.group(2).split(',') canary_patt = match.group(3).split(',') self._subdir_patterns.append((desc, dir_patt, canary_patt)) dprint(1, "watching subdirectories", self._subdir_patterns) # attach to directories self.attached = False # will be True when we successfully attach self.other_lock = None # will be not None if another PURR holds a lock on this directory self.lockfile_fd = None self.lockfile_fobj = None self._attach(purrlog, watchdirs)
def __init__(self, purrlog, watchdirs=None): QObject.__init__(self) # load and parse configuration # watched files watch = Config.get("watch-patterns", "Images=*fits,*FITS,*jpg,*png;TDL configuration=.tdl.conf") self._watch = parse_pattern_list(watch) self._watch_patterns = set() for desc, patts in self._watch: self._watch_patterns.update(patts) dprint(1, "watching patterns", self._watch_patterns) # quietly watched files (dialog is not popped up) watch = Config.get("watch-patterns-quiet", "TDL configuration=.tdl.conf") self._quiet = parse_pattern_list(watch) self._quiet_patterns = set() for desc, patts in self._quiet: self._quiet_patterns.update(patts) dprint(1, "quietly watching patterns", self._quiet_patterns) # ignored files ignore = Config.get("ignore-patterns", "Hidden files=.*;Purr logs=*purrlog;MeqTree logs=meqtree.log;Python files=*.py*;Backup files=*~,*.bck;Measurement sets=*.MS,*.ms;CASA tables=table.f*,table.dat,table.info,table.lock") self._ignore = parse_pattern_list(ignore) self._ignore_patterns = set() for desc, patts in self._ignore: self._ignore_patterns.update(patts) dprint(1, "ignoring patterns", self._ignore_patterns) # watched subdirectories subdirs = Config.get("watch-subdirs", "MEP tables=*mep/funklets,table.dat") _re_patt = re.compile("^(.*)=(.*)/(.*)$") self._subdir_patterns = [] for ss in subdirs.split(';'): match = _re_patt.match(ss) if match: desc = match.group(1) dir_patt = match.group(2).split(',') canary_patt = match.group(3).split(',') self._subdir_patterns.append((desc, dir_patt, canary_patt)) dprint(1, "watching subdirectories", self._subdir_patterns) # attach to directories self.attached = False; # will be True when we successfully attach self.other_lock = None; # will be not None if another PURR holds a lock on this directory self.lockfile_fd = None self.lockfile_fobj = None self._attach(purrlog, watchdirs)
def __init__ (self,parent,directories=False): QFileDialog.__init__(self); self.setWindowTitle("PURR: Add Data Products"); self.dirlist = None; # add filters #self._dirfilter = "Any directories (*)"; #if hasattr(self,'setNameFilters'): # qt4.4+ # self.setNameFilters(["Any files (*)",self._dirfilter]); #else: # self.setFilters(["Any files (*)",self._dirfilter]); # connect signals (translates into a SIGNAL with string arguments) self.connect(self,SIGNAL("filesSelected(const QStringList&)"),self._filesSelected); # self.connect(self,SIGNAL("fileSelected(const QString&)"),self._fileSelected); self.connect(self,SIGNAL("currentChanged(const QString&)"),self._fileHighlighted); # self.connect(self,SIGNAL("filterSelected(const QString&)"),self._filterSelected); # resize selves self.config_name = "add-file-dialog"; width = Config.getint('%s-width'%self.config_name,768); height = Config.getint('%s-height'%self.config_name,512); self.resize(QSize(width,height));
def resizeEvent (self,ev): QDialog.resizeEvent(self,ev); sz = ev.size(); Config.set('entry-editor-width',sz.width()); Config.set('entry-editor-height',sz.height());
def resizeEvent (self,ev): QFileDialog.resizeEvent(self,ev); sz = ev.size(); Config.set('%s-width'%self.config_name,sz.width()); Config.set('%s-height'%self.config_name,sz.height());
def __init__ (self,parent,*args): QDialog.__init__(self,parent,*args); self.setModal(False); # make stack for viewer and editor components lo = QVBoxLayout(self); lo.setMargin(5); self.wstack = QStackedWidget(self); lo.addWidget(self.wstack); self.wstack.setSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding); # make editor panel self.editor_panel = QWidget(self.wstack); self.editor_panel.setSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding); self.wstack.addWidget(self.editor_panel); lo = QVBoxLayout(self.editor_panel); lo.setMargin(0); # create editor self.editor = LogEntryEditor(self.editor_panel); self.connect(self.editor,SIGNAL("updated"),self._entryUpdated); self.connect(self.editor,SIGNAL("filesSelected"),self,SIGNAL("filesSelected")); self.connect(self.editor,SIGNAL("creatingDataProduct"), self,SIGNAL("creatingDataProduct")); lo.addWidget(self.editor); self.dropDataProducts = self.editor.dropDataProducts; # create button bar for editor btnfr = QFrame(self.editor_panel); btnfr.setSizePolicy(QSizePolicy.MinimumExpanding,QSizePolicy.Fixed); # btnfr.setMargin(5); lo.addWidget(btnfr); lo.addSpacing(5); btnfr_lo = QHBoxLayout(btnfr); self.wsave = QPushButton(pixmaps.filesave.icon(),"Save",btnfr); QObject.connect(self.wsave,SIGNAL("clicked()"),self._saveEntry); cancelbtn = QPushButton(pixmaps.grey_round_cross.icon(),"Cancel",btnfr); QObject.connect(cancelbtn,SIGNAL("clicked()"),self._cancelEntry); for btn in (self.wsave,cancelbtn): btn.setAutoDefault(False); btnfr_lo.setMargin(0); btnfr_lo.addWidget(self.wsave,1); btnfr_lo.addStretch(1); btnfr_lo.addWidget(cancelbtn,1); # create viewer panel self.viewer_panel = QWidget(self.wstack); self.viewer_panel.setSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding); self.wstack.addWidget(self.viewer_panel); lo = QVBoxLayout(self.viewer_panel); lo.setMargin(0); label = QLabel("""<P>Below is an HTML rendering of your log entry. Note that this is only a bare-bones viewer, so only some links will work. In particular, you may click on a link associated with a saved data product to get a menu of related actions. To edit this entry, click the Edit button below. </P>""",self.viewer_panel); label.setWordWrap(True); label.setMargin(5); lo.addWidget(label); self.viewer = self.EntryTextBrowser(self.viewer_panel); self.viewer.setOpenLinks(False); self.viewer.setSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding); self._viewer_source = None; QObject.connect(self.viewer,SIGNAL("anchorClicked(const QUrl &)"),self._urlClicked); lo.addWidget(self.viewer); lo.addSpacing(5); # create button bar btnfr = QFrame(self.viewer_panel); btnfr.setSizePolicy(QSizePolicy.MinimumExpanding,QSizePolicy.Fixed); # btnfr.setMargin(5); lo.addWidget(btnfr); lo.addSpacing(5); btnfr_lo = QHBoxLayout(btnfr); btnfr_lo.setMargin(0); btn = self.wprev = QPushButton(pixmaps.previous.icon(),"Previous",btnfr); QObject.connect(btn,SIGNAL("clicked()"),self,SIGNAL("previous()")); btnfr_lo.addWidget(btn,1); btnfr_lo.addSpacing(5); btn = self.wnext = QPushButton(pixmaps.next.icon(),"Next",btnfr); QObject.connect(btn,SIGNAL("clicked()"),self,SIGNAL("next()")); btnfr_lo.addWidget(btn,1); btnfr_lo.addSpacing(5); btn = self.wedit = QPushButton(pixmaps.edit.icon(),"Edit",btnfr); QObject.connect(btn,SIGNAL("clicked()"),self._editEntry); btnfr_lo.addWidget(btn,1); btnfr_lo.addStretch(1) btn = self.wclose = QPushButton(pixmaps.grey_round_cross.icon(),"Close",btnfr); QObject.connect(btn,SIGNAL("clicked()"),self.hide); btnfr_lo.addWidget(btn,1); # create popup menu for data products self._dp_menu = menu = QMenu(self); self._dp_menu_title = QLabel(); self._dp_menu_title.setMargin(5); self._dp_menu_title_wa = wa=QWidgetAction(self); wa.setDefaultWidget(self._dp_menu_title); menu.addAction(wa); menu.addSeparator(); menu.addAction(pixmaps.editcopy.icon(),"Restore file(s) from archived copy",self._restoreDPFromArchive); menu.addAction(pixmaps.editpaste.icon(),"Copy pathname of archived copy to clipboard",self._copyDPToClipboard); menu.addAction("Drag-and-drop archived copy",self._startDPDrag); self._dp_menu_on = None; # resize selves width = Config.getint('entry-viewer-width',512); height = Config.getint('entry-viewer-height',512); self.resize(QSize(width,height)); # other init self.entry = None; self.updated = False;
def resizeEvent(self, ev): QMainWindow.resizeEvent(self, ev) sz = ev.size() Config.set('main-window-width', sz.width()) Config.set('main-window-height', sz.height())
def __init__(self, parent, hide_on_close=False): QMainWindow.__init__(self, parent) self._hide_on_close = hide_on_close # replace the BusyIndicator class with a GUI-aware one Purr.BusyIndicator = BusyIndicator self._pounce = False # we keep a small stack of previously active purrers. This makes directory changes # faster (when going back and forth between dirs) # current purrer self.purrer = None self.purrer_stack = [] # Purr pipes for receiving remote commands self.purrpipes = {} # init GUI self.setWindowTitle("PURR") self.setWindowIcon(pixmaps.purr_logo.icon()) cw = QWidget(self) self.setCentralWidget(cw) cwlo = QVBoxLayout(cw) cwlo.setContentsMargins(0, 0, 0, 0) cwlo.setMargin(5) cwlo.setSpacing(0) toplo = QHBoxLayout(); cwlo.addLayout(toplo) # About dialog self._about_dialog = QMessageBox(self) self._about_dialog.setWindowTitle("About PURR") self._about_dialog.setText(self.about_message + """ <P>PURR is not watching any directories right now. You may need to restart it, and give it some directory names on the command line.</P>""") self._about_dialog.setIconPixmap(pixmaps.purr_logo.pm()) # Log viewer dialog self.viewer_dialog = HTMLViewerDialog(self, config_name="log-viewer", buttons=[(pixmaps.blue_round_reload, "Regenerate", """<P>Regenerates your log's HTML code from scratch. This can be useful if your PURR version has changed, or if there was an error of some kind the last time the files were generated.</P> """)]) self._viewer_timestamp = None self.connect(self.viewer_dialog, SIGNAL("Regenerate"), self._regenerateLog) self.connect(self.viewer_dialog, SIGNAL("viewPath"), self._viewPath) # Log title toolbar title_tb = QToolBar(cw) title_tb.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) title_tb.setIconSize(QSize(16, 16)) cwlo.addWidget(title_tb) title_label = QLabel("Purrlog title:", title_tb) title_tb.addWidget(title_label) self.title_editor = QLineEdit(title_tb) title_tb.addWidget(self.title_editor) self.connect(self.title_editor, SIGNAL("editingFinished()"), self._titleChanged) tip = """<P>This is your current log title. To rename the log, enter new name here and press Enter.</P>""" title_label.setToolTip(tip) self.title_editor.setToolTip(tip) self.wviewlog = title_tb.addAction(pixmaps.openbook.icon(), "View", self._showViewerDialog) self.wviewlog.setToolTip("Click to see an HTML rendering of your current log.") qa = title_tb.addAction(pixmaps.purr_logo.icon(), "About...", self._about_dialog.exec_) qa.setToolTip("<P>Click to see the About... dialog, which will tell you something about PURR.</P>") self.wdirframe = QFrame(cw) cwlo.addWidget(self.wdirframe) self.dirs_lo = QVBoxLayout(self.wdirframe) self.dirs_lo.setMargin(5) self.dirs_lo.setContentsMargins(5, 0, 5, 5) self.dirs_lo.setSpacing(0) self.wdirframe.setFrameStyle(QFrame.Box | QFrame.Raised) self.wdirframe.setLineWidth(1) ## Directories toolbar dirs_tb = QToolBar(self.wdirframe) dirs_tb.setToolButtonStyle(Qt.ToolButtonIconOnly) dirs_tb.setIconSize(QSize(16, 16)) self.dirs_lo.addWidget(dirs_tb) label = QLabel("Monitoring directories:", dirs_tb) self._dirs_tip = """<P>PURR can monitor your working directories for new or updated files. If there's a checkmark next to the directory name in this list, PURR is monitoring it.</P> <P>If the checkmark is grey, PURR is monitoring things unobtrusively. When a new or updated file is detected in he monitored directory, it is quietly added to the list of files in the "New entry" window, even if this window is not currently visible.</P> <P>If the checkmark is black, PURR will be more obtrusive. Whenever a new or updated file is detected, the "New entry" window will pop up automatically. This is called "pouncing", and some people find it annoying.</P> """ label.setToolTip(self._dirs_tip) label.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum) dirs_tb.addWidget(label) # add directory list widget self.wdirlist = DirectoryListWidget(self.wdirframe) self.wdirlist.setToolTip(self._dirs_tip) QObject.connect(self.wdirlist, SIGNAL("directoryStateChanged"), self._changeWatchedDirState) self.dirs_lo.addWidget(self.wdirlist) # self.wdirlist.setMaximumSize(1000000,64) # add directory button add = dirs_tb.addAction(pixmaps.list_add.icon(), "Add", self._showAddDirectoryDialog) add.setToolTip("<P>Click to add another directory to be monitored.</P>") # remove directory button delbtn = dirs_tb.addAction(pixmaps.list_remove.icon(), "Remove", self.wdirlist.removeCurrent) delbtn.setEnabled(False) delbtn.setToolTip("<P>Click to removed the currently selected directory from the list.</P>") QObject.connect(self.wdirlist, SIGNAL("hasSelection"), delbtn.setEnabled) # # qa = dirs_tb.addAction(pixmaps.blue_round_reload.icon(),"Rescan",self._forceRescan) # # qa.setToolTip("Click to rescan the directories for any new or updated files.") # self.wshownew = QCheckBox("show new files",dirs_tb) # dirs_tb.addWidget(self.wshownew) # self.wshownew.setCheckState(Qt.Checked) # self.wshownew.setToolTip("""<P>If this is checked, the "New entry" window will pop up automatically whenever # new or updated files are detected. If this is unchecked, the files will be added to the window quietly # and unobtrusively; you can show the window manually by clicking on the "New entry..." button below.</P>""") # self._dir_entries = {} cwlo.addSpacing(5) wlogframe = QFrame(cw) cwlo.addWidget(wlogframe) log_lo = QVBoxLayout(wlogframe) log_lo.setMargin(5) log_lo.setContentsMargins(5, 5, 5, 5) log_lo.setSpacing(0) wlogframe.setFrameStyle(QFrame.Box | QFrame.Raised) wlogframe.setLineWidth(1) # listview of log entries self.etw = LogEntryTree(cw) log_lo.addWidget(self.etw, 1) self.etw.header().setDefaultSectionSize(128) self.etw.header().setMovable(False) self.etw.setHeaderLabels(["date", "entry title", "comment"]) if hasattr(QHeaderView, 'ResizeToContents'): self.etw.header().setResizeMode(0, QHeaderView.ResizeToContents) else: self.etw.header().setResizeMode(0, QHeaderView.Custom) self.etw.header().resizeSection(0, 120) self.etw.header().setResizeMode(1, QHeaderView.Interactive) self.etw.header().setResizeMode(2, QHeaderView.Stretch) self.etw.header().show() try: self.etw.setAllColumnsShowFocus(True) except AttributeError: pass; # Qt 4.2+ # self.etw.setShowToolTips(True) self.etw.setSortingEnabled(False) # self.etw.setColumnAlignment(2,Qt.AlignLeft|Qt.AlignTop) self.etw.setSelectionMode(QTreeWidget.ExtendedSelection) self.etw.setRootIsDecorated(True) self.connect(self.etw, SIGNAL("itemSelectionChanged()"), self._entrySelectionChanged) self.connect(self.etw, SIGNAL("itemActivated(QTreeWidgetItem*,int)"), self._viewEntryItem) self.connect(self.etw, SIGNAL("itemContextMenuRequested"), self._showItemContextMenu) # create popup menu for data products self._archived_dp_menu = menu = QMenu(self) self._archived_dp_menu_title = QLabel() self._archived_dp_menu_title.setMargin(5) self._archived_dp_menu_title_wa = wa = QWidgetAction(self) wa.setDefaultWidget(self._archived_dp_menu_title) menu.addAction(wa) menu.addSeparator() menu.addAction(pixmaps.editcopy.icon(), "Restore file(s) from archived copy", self._restoreItemFromArchive) menu.addAction(pixmaps.editpaste.icon(), "Copy pathname of archived copy to clipboard", self._copyItemToClipboard) self._current_item = None # create popup menu for entries self._entry_menu = menu = QMenu(self) self._entry_menu_title = QLabel() self._entry_menu_title.setMargin(5) self._entry_menu_title_wa = wa = QWidgetAction(self) wa.setDefaultWidget(self._entry_menu_title) menu.addAction(wa) menu.addSeparator() menu.addAction(pixmaps.filefind.icon(), "View this log entry", self._viewEntryItem) menu.addAction(pixmaps.editdelete.icon(), "Delete this log entry", self._deleteSelectedEntries) # buttons at bottom log_lo.addSpacing(5) btnlo = QHBoxLayout() log_lo.addLayout(btnlo) self.wnewbtn = QPushButton(pixmaps.filenew.icon(), "New entry...", cw) self.wnewbtn.setToolTip("Click to add a new log entry.") # self.wnewbtn.setFlat(True) self.wnewbtn.setEnabled(False) btnlo.addWidget(self.wnewbtn) btnlo.addSpacing(5) self.weditbtn = QPushButton(pixmaps.filefind.icon(), "View entry...", cw) self.weditbtn.setToolTip("Click to view or edit the selected log entry/") # self.weditbtn.setFlat(True) self.weditbtn.setEnabled(False) self.connect(self.weditbtn, SIGNAL("clicked()"), self._viewEntryItem) btnlo.addWidget(self.weditbtn) btnlo.addSpacing(5) self.wdelbtn = QPushButton(pixmaps.editdelete.icon(), "Delete", cw) self.wdelbtn.setToolTip("Click to delete the selected log entry or entries.") # self.wdelbtn.setFlat(True) self.wdelbtn.setEnabled(False) self.connect(self.wdelbtn, SIGNAL("clicked()"), self._deleteSelectedEntries) btnlo.addWidget(self.wdelbtn) # enable status line self.statusBar().show() Purr.progressMessage = self.message self._prev_msg = None # editor dialog for new entry self.new_entry_dialog = Purr.Editors.NewLogEntryDialog(self) self.connect(self.new_entry_dialog, SIGNAL("newLogEntry"), self._newLogEntry) self.connect(self.new_entry_dialog, SIGNAL("filesSelected"), self._addDPFiles) self.connect(self.wnewbtn, SIGNAL("clicked()"), self.new_entry_dialog.show) self.connect(self.new_entry_dialog, SIGNAL("shown"), self._checkPounceStatus) # entry viewer dialog self.view_entry_dialog = Purr.Editors.ExistingLogEntryDialog(self) self.connect(self.view_entry_dialog, SIGNAL("previous()"), self._viewPrevEntry) self.connect(self.view_entry_dialog, SIGNAL("next()"), self._viewNextEntry) self.connect(self.view_entry_dialog, SIGNAL("viewPath"), self._viewPath) self.connect(self.view_entry_dialog, SIGNAL("filesSelected"), self._addDPFilesToOldEntry) self.connect(self.view_entry_dialog, SIGNAL("entryChanged"), self._entryChanged) # saving a data product to an older entry will automatically drop it from the # new entry dialog self.connect(self.view_entry_dialog, SIGNAL("creatingDataProduct"), self.new_entry_dialog.dropDataProducts) # resize selves width = Config.getint('main-window-width', 512) height = Config.getint('main-window-height', 512) self.resize(QSize(width, height)) # create timer for pouncing self._timer = QTimer(self) self.connect(self._timer, SIGNAL("timeout()"), self._rescan) # create dict mapping index.html paths to entry numbers self._index_paths = {}
def resizeEvent(self, ev): QDialog.resizeEvent(self, ev) sz = ev.size() Config.set('%s-width' % self.config_name, sz.width()) Config.set('%s-height' % self.config_name, sz.height())
def __init__(self, parent, hide_on_close=False): QMainWindow.__init__(self, parent) self._hide_on_close = hide_on_close # replace the BusyIndicator class with a GUI-aware one Purr.BusyIndicator = BusyIndicator self._pounce = False # we keep a small stack of previously active purrers. This makes directory changes # faster (when going back and forth between dirs) # current purrer self.purrer = None self.purrer_stack = [] # Purr pipes for receiving remote commands self.purrpipes = {} # init GUI self.setWindowTitle("PURR") self.setWindowIcon(pixmaps.purr_logo.icon()) cw = QWidget(self) self.setCentralWidget(cw) cwlo = QVBoxLayout(cw) cwlo.setContentsMargins(0, 0, 0, 0) cwlo.setMargin(5) cwlo.setSpacing(0) toplo = QHBoxLayout() cwlo.addLayout(toplo) # About dialog self._about_dialog = QMessageBox(self) self._about_dialog.setWindowTitle("About PURR") self._about_dialog.setText(self.about_message + """ <P>PURR is not watching any directories right now. You may need to restart it, and give it some directory names on the command line.</P>""") self._about_dialog.setIconPixmap(pixmaps.purr_logo.pm()) # Log viewer dialog self.viewer_dialog = HTMLViewerDialog( self, config_name="log-viewer", buttons= [(pixmaps.blue_round_reload, "Regenerate", """<P>Regenerates your log's HTML code from scratch. This can be useful if your PURR version has changed, or if there was an error of some kind the last time the files were generated.</P> """)]) self._viewer_timestamp = None self.connect(self.viewer_dialog, SIGNAL("Regenerate"), self._regenerateLog) self.connect(self.viewer_dialog, SIGNAL("viewPath"), self._viewPath) # Log title toolbar title_tb = QToolBar(cw) title_tb.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) title_tb.setIconSize(QSize(16, 16)) cwlo.addWidget(title_tb) title_label = QLabel("Purrlog title:", title_tb) title_tb.addWidget(title_label) self.title_editor = QLineEdit(title_tb) title_tb.addWidget(self.title_editor) self.connect(self.title_editor, SIGNAL("editingFinished()"), self._titleChanged) tip = """<P>This is your current log title. To rename the log, enter new name here and press Enter.</P>""" title_label.setToolTip(tip) self.title_editor.setToolTip(tip) self.wviewlog = title_tb.addAction(pixmaps.openbook.icon(), "View", self._showViewerDialog) self.wviewlog.setToolTip( "Click to see an HTML rendering of your current log.") qa = title_tb.addAction(pixmaps.purr_logo.icon(), "About...", self._about_dialog.exec_) qa.setToolTip( "<P>Click to see the About... dialog, which will tell you something about PURR.</P>" ) self.wdirframe = QFrame(cw) cwlo.addWidget(self.wdirframe) self.dirs_lo = QVBoxLayout(self.wdirframe) self.dirs_lo.setMargin(5) self.dirs_lo.setContentsMargins(5, 0, 5, 5) self.dirs_lo.setSpacing(0) self.wdirframe.setFrameStyle(QFrame.Box | QFrame.Raised) self.wdirframe.setLineWidth(1) ## Directories toolbar dirs_tb = QToolBar(self.wdirframe) dirs_tb.setToolButtonStyle(Qt.ToolButtonIconOnly) dirs_tb.setIconSize(QSize(16, 16)) self.dirs_lo.addWidget(dirs_tb) label = QLabel("Monitoring directories:", dirs_tb) self._dirs_tip = """<P>PURR can monitor your working directories for new or updated files. If there's a checkmark next to the directory name in this list, PURR is monitoring it.</P> <P>If the checkmark is grey, PURR is monitoring things unobtrusively. When a new or updated file is detected in he monitored directory, it is quietly added to the list of files in the "New entry" window, even if this window is not currently visible.</P> <P>If the checkmark is black, PURR will be more obtrusive. Whenever a new or updated file is detected, the "New entry" window will pop up automatically. This is called "pouncing", and some people find it annoying.</P> """ label.setToolTip(self._dirs_tip) label.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum) dirs_tb.addWidget(label) # add directory list widget self.wdirlist = DirectoryListWidget(self.wdirframe) self.wdirlist.setToolTip(self._dirs_tip) QObject.connect(self.wdirlist, SIGNAL("directoryStateChanged"), self._changeWatchedDirState) self.dirs_lo.addWidget(self.wdirlist) # self.wdirlist.setMaximumSize(1000000,64) # add directory button add = dirs_tb.addAction(pixmaps.list_add.icon(), "Add", self._showAddDirectoryDialog) add.setToolTip( "<P>Click to add another directory to be monitored.</P>") # remove directory button delbtn = dirs_tb.addAction(pixmaps.list_remove.icon(), "Remove", self.wdirlist.removeCurrent) delbtn.setEnabled(False) delbtn.setToolTip( "<P>Click to removed the currently selected directory from the list.</P>" ) QObject.connect(self.wdirlist, SIGNAL("hasSelection"), delbtn.setEnabled) # # qa = dirs_tb.addAction(pixmaps.blue_round_reload.icon(),"Rescan",self._forceRescan) # # qa.setToolTip("Click to rescan the directories for any new or updated files.") # self.wshownew = QCheckBox("show new files",dirs_tb) # dirs_tb.addWidget(self.wshownew) # self.wshownew.setCheckState(Qt.Checked) # self.wshownew.setToolTip("""<P>If this is checked, the "New entry" window will pop up automatically whenever # new or updated files are detected. If this is unchecked, the files will be added to the window quietly # and unobtrusively; you can show the window manually by clicking on the "New entry..." button below.</P>""") # self._dir_entries = {} cwlo.addSpacing(5) wlogframe = QFrame(cw) cwlo.addWidget(wlogframe) log_lo = QVBoxLayout(wlogframe) log_lo.setMargin(5) log_lo.setContentsMargins(5, 5, 5, 5) log_lo.setSpacing(0) wlogframe.setFrameStyle(QFrame.Box | QFrame.Raised) wlogframe.setLineWidth(1) # listview of log entries self.etw = LogEntryTree(cw) log_lo.addWidget(self.etw, 1) self.etw.header().setDefaultSectionSize(128) self.etw.header().setMovable(False) self.etw.setHeaderLabels(["date", "entry title", "comment"]) if hasattr(QHeaderView, 'ResizeToContents'): self.etw.header().setResizeMode(0, QHeaderView.ResizeToContents) else: self.etw.header().setResizeMode(0, QHeaderView.Custom) self.etw.header().resizeSection(0, 120) self.etw.header().setResizeMode(1, QHeaderView.Interactive) self.etw.header().setResizeMode(2, QHeaderView.Stretch) self.etw.header().show() try: self.etw.setAllColumnsShowFocus(True) except AttributeError: pass # Qt 4.2+ # self.etw.setShowToolTips(True) self.etw.setSortingEnabled(False) # self.etw.setColumnAlignment(2,Qt.AlignLeft|Qt.AlignTop) self.etw.setSelectionMode(QTreeWidget.ExtendedSelection) self.etw.setRootIsDecorated(True) self.connect(self.etw, SIGNAL("itemSelectionChanged()"), self._entrySelectionChanged) self.connect(self.etw, SIGNAL("itemActivated(QTreeWidgetItem*,int)"), self._viewEntryItem) self.connect(self.etw, SIGNAL("itemContextMenuRequested"), self._showItemContextMenu) # create popup menu for data products self._archived_dp_menu = menu = QMenu(self) self._archived_dp_menu_title = QLabel() self._archived_dp_menu_title.setMargin(5) self._archived_dp_menu_title_wa = wa = QWidgetAction(self) wa.setDefaultWidget(self._archived_dp_menu_title) menu.addAction(wa) menu.addSeparator() menu.addAction(pixmaps.editcopy.icon(), "Restore file(s) from archived copy", self._restoreItemFromArchive) menu.addAction(pixmaps.editpaste.icon(), "Copy pathname of archived copy to clipboard", self._copyItemToClipboard) self._current_item = None # create popup menu for entries self._entry_menu = menu = QMenu(self) self._entry_menu_title = QLabel() self._entry_menu_title.setMargin(5) self._entry_menu_title_wa = wa = QWidgetAction(self) wa.setDefaultWidget(self._entry_menu_title) menu.addAction(wa) menu.addSeparator() menu.addAction(pixmaps.filefind.icon(), "View this log entry", self._viewEntryItem) menu.addAction(pixmaps.editdelete.icon(), "Delete this log entry", self._deleteSelectedEntries) # buttons at bottom log_lo.addSpacing(5) btnlo = QHBoxLayout() log_lo.addLayout(btnlo) self.wnewbtn = QPushButton(pixmaps.filenew.icon(), "New entry...", cw) self.wnewbtn.setToolTip("Click to add a new log entry.") # self.wnewbtn.setFlat(True) self.wnewbtn.setEnabled(False) btnlo.addWidget(self.wnewbtn) btnlo.addSpacing(5) self.weditbtn = QPushButton(pixmaps.filefind.icon(), "View entry...", cw) self.weditbtn.setToolTip( "Click to view or edit the selected log entry/") # self.weditbtn.setFlat(True) self.weditbtn.setEnabled(False) self.connect(self.weditbtn, SIGNAL("clicked()"), self._viewEntryItem) btnlo.addWidget(self.weditbtn) btnlo.addSpacing(5) self.wdelbtn = QPushButton(pixmaps.editdelete.icon(), "Delete", cw) self.wdelbtn.setToolTip( "Click to delete the selected log entry or entries.") # self.wdelbtn.setFlat(True) self.wdelbtn.setEnabled(False) self.connect(self.wdelbtn, SIGNAL("clicked()"), self._deleteSelectedEntries) btnlo.addWidget(self.wdelbtn) # enable status line self.statusBar().show() Purr.progressMessage = self.message self._prev_msg = None # editor dialog for new entry self.new_entry_dialog = Purr.Editors.NewLogEntryDialog(self) self.connect(self.new_entry_dialog, SIGNAL("newLogEntry"), self._newLogEntry) self.connect(self.new_entry_dialog, SIGNAL("filesSelected"), self._addDPFiles) self.connect(self.wnewbtn, SIGNAL("clicked()"), self.new_entry_dialog.show) self.connect(self.new_entry_dialog, SIGNAL("shown"), self._checkPounceStatus) # entry viewer dialog self.view_entry_dialog = Purr.Editors.ExistingLogEntryDialog(self) self.connect(self.view_entry_dialog, SIGNAL("previous()"), self._viewPrevEntry) self.connect(self.view_entry_dialog, SIGNAL("next()"), self._viewNextEntry) self.connect(self.view_entry_dialog, SIGNAL("viewPath"), self._viewPath) self.connect(self.view_entry_dialog, SIGNAL("filesSelected"), self._addDPFilesToOldEntry) self.connect(self.view_entry_dialog, SIGNAL("entryChanged"), self._entryChanged) # saving a data product to an older entry will automatically drop it from the # new entry dialog self.connect(self.view_entry_dialog, SIGNAL("creatingDataProduct"), self.new_entry_dialog.dropDataProducts) # resize selves width = Config.getint('main-window-width', 512) height = Config.getint('main-window-height', 512) self.resize(QSize(width, height)) # create timer for pouncing self._timer = QTimer(self) self.connect(self._timer, SIGNAL("timeout()"), self._rescan) # create dict mapping index.html paths to entry numbers self._index_paths = {}