class CaseList(QWidget): def __init__(self): QWidget.__init__(self) addHelpToWidget(self, "init/case_list") layout = QVBoxLayout() self._list = QListWidget(self) self._list.setMinimumHeight(100) self._list.setMaximumHeight(250) self._default_selection_mode = self._list.selectionMode() self.setSelectable(False) layout.addWidget(QLabel("Available Cases:")) layout.addWidget(self._list) self._addRemoveWidget = AddRemoveWidget(self.addItem, self.removeItem, horizontal=True) self._addRemoveWidget.enableRemoveButton(False) layout.addWidget(self._addRemoveWidget) self._title = "New keyword" self._description = "Enter name of keyword:" self.setLayout(layout) ERT.ertChanged.connect(self.updateList) self.updateList() def setSelectable(self, selectable): if selectable: self._list.setSelectionMode(self._default_selection_mode) else: self._list.setSelectionMode(QAbstractItemView.NoSelection) def addItem(self): dialog = ValidatedDialog("New case", "Enter name of new case:", getAllCases()) new_case_name = dialog.showAndTell() if not new_case_name == "": selectOrCreateNewCase(new_case_name) def removeItem(self): message = "Support for removal of items has not been implemented!" QMessageBox.information(self, "Not implemented!", message) def updateList(self): """Retrieves data from the model and inserts it into the list""" case_list = getAllCases() self._list.clear() for case in case_list: self._list.addItem(case)
def createListOption(self): def addItem(label, icon_pixmap, width, height): item = QListWidgetItem(list_option) item.setText(label) item.setTextAlignment(Qt.AlignHCenter) item.setIcon(QIcon(icon_pixmap)) item.setSizeHint(QSize(width, height)) list_option = QListWidget() list_option.setAutoFillBackground(True) list_option.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) list_option.setTextElideMode(Qt.ElideNone) list_option.setMovement(QListView.Static) list_option.setFlow(QListView.TopToBottom) list_option.setProperty("isWrapping", QVariant(False)) list_option.setSpacing(3) list_option.setViewMode(QListView.IconMode) items = [] items.append((QApplication.translate("option", "Connections"), "connections.png")) items.append((QApplication.translate("option", "Accounts"), "accounts.png")) items.append((QApplication.translate("option", "Aliases"), "aliases.png")) items.append((QApplication.translate("option", "Macros"), "macros.png")) items.append((QApplication.translate("option", "Keypad"), "keypad.png")) items.append((QApplication.translate("option", "Triggers"), "triggers.png")) items.append((QApplication.translate("option", "Preferences"), "preferences.png")) max_width = 0 for label, icon_name in items: w = list_option.fontMetrics().boundingRect(label).width() if w > max_width: max_width = w # An empiric method to align element in the center of the QListWidget max_width += 15 total_height = 0 for label, icon_name in items: icon_pixmap = QPixmap(":/images/" + icon_name) height = icon_pixmap.height() + list_option.fontMetrics().height() + 3 total_height += height + 5 addItem(label, icon_pixmap, max_width, height) list_option.setUniformItemSizes(True) list_option.setFixedWidth(max_width + 10) list_option.setMinimumHeight(total_height) return list_option
class CodeCompletionWidget(QFrame): def __init__(self, editor): super(CodeCompletionWidget, self).__init__( None, Qt.FramelessWindowHint | Qt.ToolTip) self._editor = editor self._revision = 0 self._block = 0 self.stack_layout = QStackedLayout(self) self.stack_layout.setContentsMargins(0, 0, 0, 0) self.stack_layout.setSpacing(0) self.completion_list = QListWidget() self.completion_list.setMinimumHeight(200) self.completion_list.setAlternatingRowColors(True) self._list_index = self.stack_layout.addWidget(self.completion_list) self._icons = {'a': resources.IMAGES['attribute'], 'f': resources.IMAGES['function'], 'c': resources.IMAGES['class'], 'm': resources.IMAGES['module']} self.cc = code_completion.CodeCompletion() self._completion_results = {} self._prefix = u'' self.setVisible(False) self.source = '' self._key_operations = { Qt.Key_Up: self._select_previous_row, Qt.Key_Down: self._select_next_row, Qt.Key_PageUp: (lambda: self._select_previous_row(6)), Qt.Key_PageDown: (lambda: self._select_next_row(6)), Qt.Key_Right: lambda: None, Qt.Key_Left: lambda: None, Qt.Key_Enter: self.pre_key_insert_completion, Qt.Key_Return: self.pre_key_insert_completion, Qt.Key_Tab: self.pre_key_insert_completion, Qt.Key_Space: self.hide_completer, Qt.Key_Escape: self.hide_completer, Qt.Key_Backtab: self.hide_completer, Qt.NoModifier: self.hide_completer, Qt.ShiftModifier: self.hide_completer, } self.desktop = QApplication.instance().desktop() self.connect(self.completion_list, SIGNAL("itemClicked(QListWidgetItem*)"), self.pre_key_insert_completion) self.connect(self._editor.document(), SIGNAL("cursorPositionChanged(QTextCursor)"), self.update_metadata) def _select_next_row(self, move=1): new_row = self.completion_list.currentRow() + move if new_row < self.completion_list.count(): self.completion_list.setCurrentRow(new_row) else: self.completion_list.setCurrentRow(0) return True def _select_previous_row(self, move=1): new_row = self.completion_list.currentRow() - move if new_row >= 0: self.completion_list.setCurrentRow(new_row) else: self.completion_list.setCurrentRow( self.completion_list.count() - move) return True def update_metadata(self, cursor): if settings.CODE_COMPLETION: if self._editor.document().revision() != self._revision and \ cursor.block().blockNumber() != self._block: source = self._editor.get_text() source = source.encode(self._editor.encoding) self.cc.analyze_file(self._editor.ID, source) self._revision = self._editor.document().revision() self._block = cursor.block().blockNumber() def insert_completion(self, insert, type_=ord('a')): if insert != self._prefix: closing = '' if type_ in (ord('f'), ord('c')): closing = '()' extra = len(self._prefix) - len(insert) insertion = '%s%s' % (insert[extra:], closing) self._editor.textCursor().insertText(insertion) self.hide_completer() def _get_geometry(self): cr = self._editor.cursorRect() desktop_geometry = self.desktop.availableGeometry(self._editor) point = self._editor.mapToGlobal(cr.topLeft()) cr.moveTopLeft(point) #Check new position according desktop geometry width = (self.completion_list.sizeHintForColumn(0) + self.completion_list.verticalScrollBar().sizeHint().width() + 10) height = 200 orientation = (point.y() + height) < desktop_geometry.height() if orientation: cr.moveTop(cr.bottom()) cr.setWidth(width) cr.setHeight(height) if not orientation: cr.moveBottom(cr.top()) xpos = desktop_geometry.width() - (point.x() + width) if xpos < 0: cr.moveLeft(cr.left() + xpos) return cr def complete(self, results): self.add_list_items(results) self.completion_list.setCurrentRow(0) cr = self._get_geometry() self.setGeometry(cr) self.completion_list.updateGeometries() self.show() def add_list_items(self, proposals): self.completion_list.clear() for p in proposals: self.completion_list.addItem( QListWidgetItem( QIcon(self._icons.get(p[0], resources.IMAGES['attribute'])), p[1], type=ord(p[0]))) def set_completion_prefix(self, prefix, valid=True): self._prefix = prefix proposals = [] proposals += [('m', item) for item in self._completion_results.get('modules', []) if item.startswith(prefix)] proposals += [('c', item) for item in self._completion_results.get('classes', []) if item.startswith(prefix)] proposals += [('a', item) for item in self._completion_results.get('attributes', []) if item.startswith(prefix)] proposals += [('f', item) for item in self._completion_results.get('functions', []) if item.startswith(prefix)] if proposals and valid: self.complete(proposals) else: self.hide_completer() def _invalid_completion_position(self): result = False cursor = self._editor.textCursor() cursor.movePosition(QTextCursor.StartOfLine, QTextCursor.KeepAnchor) selection = unicode(cursor.selectedText())[:-1].split(' ') if len(selection) == 0 or selection[-1] == '' or \ selection[-1].isdigit(): result = True return result def fill_completer(self, force_completion=False): if not force_completion and (self._editor.cursor_inside_string() or self._editor.cursor_inside_comment() or self._invalid_completion_position()): return source = self._editor.get_text() source = source.encode(self._editor.encoding) offset = self._editor.textCursor().position() results = self.cc.get_completion(source, offset) self._completion_results = results if force_completion: cursor = self._editor.textCursor() cursor.movePosition(QTextCursor.StartOfWord, QTextCursor.KeepAnchor) prefix = cursor.selectedText() else: prefix = self._editor._text_under_cursor() self.set_completion_prefix(prefix) def hide_completer(self): self._prefix = '' self.hide() def pre_key_insert_completion(self): type_ = ord('a') current = self.completion_list.currentItem() insert = unicode(current.text()) if not insert.endswith(')'): type_ = current.type() self.insert_completion(insert, type_) self.hide_completer() return True def process_pre_key_event(self, event): if not self.isVisible() or self._editor.lang != "python": return False skip = self._key_operations.get(event.key(), lambda: False)() self._key_operations.get(event.modifiers(), lambda: False)() if skip is None: skip = False return skip def process_post_key_event(self, event): if not settings.CODE_COMPLETION or self._editor.lang != "python": return if self.isVisible(): source = self._editor.get_text() source = source.encode(self._editor.encoding) offset = self._editor.textCursor().position() prefix, valid = self.cc.get_prefix(source, offset) self.set_completion_prefix(prefix, valid) self.completion_list.setCurrentRow(0) force_completion = (event.key() == Qt.Key_Space and event.modifiers() == Qt.ControlModifier) if event.key() == Qt.Key_Period or force_completion: self.fill_completer(force_completion)
class CodeCompletionWidget(QFrame): def __init__(self, editor): super(CodeCompletionWidget, self).__init__(None, Qt.FramelessWindowHint | Qt.ToolTip) self._editor = editor self._revision = 0 self._block = 0 self.stack_layout = QStackedLayout(self) self.stack_layout.setContentsMargins(0, 0, 0, 0) self.stack_layout.setSpacing(0) self.completion_list = QListWidget() self.completion_list.setMinimumHeight(200) self.completion_list.setAlternatingRowColors(True) self._list_index = self.stack_layout.addWidget(self.completion_list) self._icons = { 'a': resources.IMAGES['attribute'], 'f': resources.IMAGES['function'], 'c': resources.IMAGES['class'], 'm': resources.IMAGES['module'] } self.cc = code_completion.CodeCompletion() self._completion_results = {} self._prefix = '' self.setVisible(False) self.source = '' self._key_operations = { Qt.Key_Up: self._select_previous_row, Qt.Key_Down: self._select_next_row, Qt.Key_PageUp: (lambda: self._select_previous_row(6)), Qt.Key_PageDown: (lambda: self._select_next_row(6)), Qt.Key_Right: lambda: None, Qt.Key_Left: lambda: None, Qt.Key_Enter: self.pre_key_insert_completion, Qt.Key_Return: self.pre_key_insert_completion, Qt.Key_Tab: self.pre_key_insert_completion, Qt.Key_Space: self.hide_completer, Qt.Key_Escape: self.hide_completer, Qt.Key_Backtab: self.hide_completer, Qt.NoModifier: self.hide_completer, Qt.ShiftModifier: self.hide_completer, } self.desktop = QApplication.instance().desktop() self.connect(self.completion_list, SIGNAL("itemClicked(QListWidgetItem*)"), self.pre_key_insert_completion) self.connect(self._editor.document(), SIGNAL("cursorPositionChanged(QTextCursor)"), self.update_metadata) def _select_next_row(self, move=1): new_row = self.completion_list.currentRow() + move if new_row < self.completion_list.count(): self.completion_list.setCurrentRow(new_row) else: self.completion_list.setCurrentRow(0) return True def _select_previous_row(self, move=1): new_row = self.completion_list.currentRow() - move if new_row >= 0: self.completion_list.setCurrentRow(new_row) else: self.completion_list.setCurrentRow(self.completion_list.count() - move) return True def update_metadata(self, cursor): if settings.CODE_COMPLETION: if self._editor.document().revision() != self._revision and \ cursor.block().blockNumber() != self._block: source = self._editor.get_text() source = source.encode(self._editor.encoding) self.cc.analyze_file(self._editor.ID, source, self._editor.indent, self._editor.useTabs) self._revision = self._editor.document().revision() self._block = cursor.block().blockNumber() def insert_completion(self, insert, type_=ord('a')): if insert != self._prefix: closing = '' if type_ in (ord('f'), ord('c')): closing = '()' extra = len(self._prefix) - len(insert) insertion = '%s%s' % (insert[extra:], closing) self._editor.textCursor().insertText(insertion) self.hide_completer() def _get_geometry(self): cr = self._editor.cursorRect() desktop_geometry = self.desktop.availableGeometry(self._editor) point = self._editor.mapToGlobal(cr.topLeft()) cr.moveTopLeft(point) #Check new position according desktop geometry width = (self.completion_list.sizeHintForColumn(0) + self.completion_list.verticalScrollBar().sizeHint().width() + 10) height = 200 orientation = (point.y() + height) < desktop_geometry.height() if orientation: cr.moveTop(cr.bottom()) cr.setWidth(width) cr.setHeight(height) if not orientation: cr.moveBottom(cr.top()) xpos = desktop_geometry.width() - (point.x() + width) if xpos < 0: cr.moveLeft(cr.left() + xpos) return cr def complete(self, results): self.add_list_items(results) self.completion_list.setCurrentRow(0) cr = self._get_geometry() self.setGeometry(cr) self.completion_list.updateGeometries() self.show() def add_list_items(self, proposals): self.completion_list.clear() for p in proposals: self.completion_list.addItem( QListWidgetItem(QIcon( self._icons.get(p[0], resources.IMAGES['attribute'])), p[1], type=ord(p[0]))) def set_completion_prefix(self, prefix, valid=True): self._prefix = prefix proposals = [] proposals += [('m', item) for item in self._completion_results.get('modules', []) if item.startswith(prefix)] proposals += [('c', item) for item in self._completion_results.get('classes', []) if item.startswith(prefix)] proposals += [ ('a', item) for item in self._completion_results.get('attributes', []) if item.startswith(prefix) ] proposals += [ ('f', item) for item in self._completion_results.get('functions', []) if item.startswith(prefix) ] if proposals and valid: self.complete(proposals) else: self.hide_completer() def _invalid_completion_position(self): result = False cursor = self._editor.textCursor() cursor.movePosition(QTextCursor.StartOfLine, QTextCursor.KeepAnchor) selection = cursor.selectedText()[:-1].split(' ') if len(selection) == 0 or selection[-1] == '' or \ selection[-1].isdigit(): result = True return result def fill_completer(self, force_completion=False): if not force_completion and (self._editor.cursor_inside_string() or self._editor.cursor_inside_comment() or self._invalid_completion_position()): return source = self._editor.get_text() source = source.encode(self._editor.encoding) offset = self._editor.textCursor().position() results = self.cc.get_completion(source, offset) self._completion_results = results if force_completion: cursor = self._editor.textCursor() cursor.movePosition(QTextCursor.StartOfWord, QTextCursor.KeepAnchor) prefix = cursor.selectedText() else: prefix = self._editor._text_under_cursor() self.set_completion_prefix(prefix) def hide_completer(self): self._prefix = '' self.hide() def pre_key_insert_completion(self): type_ = ord('a') current = self.completion_list.currentItem() insert = current.text() if not insert.endswith(')'): type_ = current.type() self.insert_completion(insert, type_) self.hide_completer() return True def process_pre_key_event(self, event): if not self.isVisible() or self._editor.lang != "python": return False skip = self._key_operations.get(event.key(), lambda: False)() self._key_operations.get(event.modifiers(), lambda: False)() if skip is None: skip = False return skip def process_post_key_event(self, event): if not settings.CODE_COMPLETION or self._editor.lang != "python": return if self.isVisible(): source = self._editor.get_text() source = source.encode(self._editor.encoding) offset = self._editor.textCursor().position() prefix, valid = self.cc.get_prefix(source, offset) self.set_completion_prefix(prefix, valid) self.completion_list.setCurrentRow(0) force_completion = (event.key() == Qt.Key_Space and event.modifiers() == Qt.ControlModifier) if event.key() == Qt.Key_Period or force_completion: self.fill_completer(force_completion)
class PopupCompleter(QFrame): def __init__(self): QFrame.__init__(self, None, Qt.FramelessWindowHint | Qt.ToolTip) vbox = QVBoxLayout(self) vbox.setContentsMargins(0, 0, 0, 0) vbox.setSpacing(0) self.listWidget = QListWidget() self.listWidget.setMinimumHeight(350) vbox.addWidget(self.listWidget) self.listWidget.currentItemChanged.connect(self._repaint_items) def _repaint_items(self, current, previous): if current is not None: widget = self.listWidget.itemWidget(current) if widget is not None: widget.set_selected() if previous is not None: widget = self.listWidget.itemWidget(previous) if widget is not None: widget.set_not_selected() def reload(self, model): """Reload the data of the Popup Completer, and restart the state.""" self.listWidget.clear() self.add_help() for item in model: self.listWidget.addItem(item[0]) self.listWidget.setItemWidget(item[0], item[1]) self.listWidget.setCurrentRow(8) def clear(self): """Remove all the items of the list (deleted), and reload the help.""" self.listWidget.clear() def refresh(self, model, has_text=True): """Refresh the list when the user search for some word.""" self.listWidget.clear() if not has_text: self.add_help() for item in model: self.listWidget.addItem(item[0]) self.listWidget.setItemWidget(item[0], item[1]) if model: self.listWidget.setCurrentItem(model[0][0]) else: self.add_no_found() def fetch_more(self, model): """Add more items to the list on user scroll.""" for item in model: self.listWidget.addItem(item[0]) self.listWidget.setItemWidget(item[0], item[1]) def add_no_found(self): """Load no results found message""" noFoundItem = self._create_help_item(resources.IMAGES['delete'], translations.TR_NO_RESULTS) self.listWidget.addItem(noFoundItem) def add_help(self): #Load help fileItem = self._create_help_item(resources.IMAGES['locate-file'], translations.TR_ONLY_FILES) self.listWidget.addItem(fileItem) classItem = self._create_help_item(resources.IMAGES['locate-class'], translations.TR_ONLY_CLASSES) self.listWidget.addItem(classItem) methodItem = self._create_help_item( resources.IMAGES['locate-function'], translations.TR_ONLY_METHODS) self.listWidget.addItem(methodItem) attributeItem = self._create_help_item( resources.IMAGES['locate-attributes'], translations.TR_ONLY_ATRIBUTES) self.listWidget.addItem(attributeItem) thisFileItem = self._create_help_item( resources.IMAGES['locate-on-this-file'], translations.TR_ONLY_CLASSES_METHODS) self.listWidget.addItem(thisFileItem) tabsItem = self._create_help_item(resources.IMAGES['locate-tab'], translations.TR_ONLY_CURRENT_TABS) self.listWidget.addItem(tabsItem) lineItem = self._create_help_item(resources.IMAGES['locate-line'], translations.TR_GO_TO_LINE) self.listWidget.addItem(lineItem) nonPythonItem = self._create_help_item( resources.IMAGES['locate-nonpython'], translations.TR_ONLY_NON_PYTHON) self.listWidget.addItem(nonPythonItem) def _create_help_item(self, image, text): Item = QListWidgetItem(QIcon(image), text) font = Item.font() font.setBold(True) Item.setSizeHint(QSize(20, 30)) Item.setBackground(QBrush(Qt.lightGray)) Item.setForeground(QBrush(Qt.black)) Item.setFont(font) return Item
class PopupCompleter(QFrame): def __init__(self): QFrame.__init__(self, None, Qt.FramelessWindowHint | Qt.ToolTip) vbox = QVBoxLayout(self) vbox.setContentsMargins(0, 0, 0, 0) vbox.setSpacing(0) self.listWidget = QListWidget() self.listWidget.setMinimumHeight(300) vbox.addWidget(self.listWidget) def reload(self, model): """Reload the data of the Popup Completer, and restart the state.""" self.listWidget.clear() self.add_help() for item in model: self.listWidget.addItem(item[0]) self.listWidget.setItemWidget(item[0], item[1]) self.listWidget.setCurrentRow(6) def clear(self): """Remove all the items of the list (deleted), and reload the help.""" self.listWidget.clear() def refresh(self, model): """Refresh the list when the user search for some word.""" self.listWidget.clear() for item in model: self.listWidget.addItem(item[0]) self.listWidget.setItemWidget(item[0], item[1]) if model: self.listWidget.setCurrentItem(model[0][0]) def fetch_more(self, model): """Add more items to the list on user scroll.""" for item in model: self.listWidget.addItem(item[0]) self.listWidget.setItemWidget(item[0], item[1]) def add_help(self): #Load help fileItem = QListWidgetItem(QIcon(resources.IMAGES['locate-file']), '@\t(Filter only by Files)') font = fileItem.font() font.setBold(True) fileItem.setSizeHint(QSize(20, 30)) fileItem.setBackground(QBrush(Qt.lightGray)) fileItem.setForeground(QBrush(Qt.black)) fileItem.setFont(font) self.listWidget.addItem(fileItem) classItem = QListWidgetItem(QIcon(resources.IMAGES['locate-class']), '<\t(Filter only by Classes)') self.listWidget.addItem(classItem) classItem.setSizeHint(QSize(20, 30)) classItem.setBackground(QBrush(Qt.lightGray)) classItem.setForeground(QBrush(Qt.black)) classItem.setFont(font) methodItem = QListWidgetItem( QIcon(resources.IMAGES['locate-function']), '>\t(Filter only by Methods)') self.listWidget.addItem(methodItem) methodItem.setSizeHint(QSize(20, 30)) methodItem.setBackground(QBrush(Qt.lightGray)) methodItem.setForeground(QBrush(Qt.black)) methodItem.setFont(font) attributeItem = QListWidgetItem( QIcon(resources.IMAGES['locate-attributes']), '-\t(Filter only by Attributes)') self.listWidget.addItem(attributeItem) attributeItem.setSizeHint(QSize(20, 30)) attributeItem.setBackground(QBrush(Qt.lightGray)) attributeItem.setForeground(QBrush(Qt.black)) attributeItem.setFont(font) thisFileItem = QListWidgetItem( QIcon(resources.IMAGES['locate-on-this-file']), '.\t(Filter only by Classes and Methods in this File)') font = thisFileItem.font() font.setBold(True) thisFileItem.setSizeHint(QSize(20, 30)) thisFileItem.setBackground(QBrush(Qt.lightGray)) thisFileItem.setForeground(QBrush(Qt.black)) thisFileItem.setFont(font) self.listWidget.addItem(thisFileItem) nonPythonItem = QListWidgetItem( QIcon(resources.IMAGES['locate-nonpython']), '!\t(Filter only by Non Python Files)') self.listWidget.addItem(nonPythonItem) nonPythonItem.setSizeHint(QSize(20, 30)) nonPythonItem.setBackground(QBrush(Qt.lightGray)) nonPythonItem.setForeground(QBrush(Qt.black)) nonPythonItem.setFont(font)
class PopupCompleter(QFrame): def __init__(self): QFrame.__init__(self, None, Qt.FramelessWindowHint | Qt.ToolTip) vbox = QVBoxLayout(self) vbox.setContentsMargins(0, 0, 0, 0) vbox.setSpacing(0) self.listWidget = QListWidget() self.listWidget.setMinimumHeight(300) vbox.addWidget(self.listWidget) def reload(self, model): """Reload the data of the Popup Completer, and restart the state.""" self.listWidget.clear() self.add_help() for item in model: self.listWidget.addItem(item[0]) self.listWidget.setItemWidget(item[0], item[1]) self.listWidget.setCurrentRow(6) def clear(self): """Remove all the items of the list (deleted), and reload the help.""" self.listWidget.clear() def refresh(self, model): """Refresh the list when the user search for some word.""" self.listWidget.clear() for item in model: self.listWidget.addItem(item[0]) self.listWidget.setItemWidget(item[0], item[1]) if model: self.listWidget.setCurrentItem(model[0][0]) def fetch_more(self, model): """Add more items to the list on user scroll.""" for item in model: self.listWidget.addItem(item[0]) self.listWidget.setItemWidget(item[0], item[1]) def add_help(self): #Load help fileItem = QListWidgetItem( QIcon(resources.IMAGES['locate-file']), '@\t(Filter only by Files)') font = fileItem.font() font.setBold(True) fileItem.setSizeHint(QSize(20, 30)) fileItem.setBackground(QBrush(Qt.lightGray)) fileItem.setForeground(QBrush(Qt.black)) fileItem.setFont(font) self.listWidget.addItem(fileItem) classItem = QListWidgetItem( QIcon(resources.IMAGES['locate-class']), '<\t(Filter only by Classes)') self.listWidget.addItem(classItem) classItem.setSizeHint(QSize(20, 30)) classItem.setBackground(QBrush(Qt.lightGray)) classItem.setForeground(QBrush(Qt.black)) classItem.setFont(font) methodItem = QListWidgetItem( QIcon(resources.IMAGES['locate-function']), '>\t(Filter only by Methods)') self.listWidget.addItem(methodItem) methodItem.setSizeHint(QSize(20, 30)) methodItem.setBackground(QBrush(Qt.lightGray)) methodItem.setForeground(QBrush(Qt.black)) methodItem.setFont(font) attributeItem = QListWidgetItem( QIcon(resources.IMAGES['locate-attributes']), '-\t(Filter only by Attributes)') self.listWidget.addItem(attributeItem) attributeItem.setSizeHint(QSize(20, 30)) attributeItem.setBackground(QBrush(Qt.lightGray)) attributeItem.setForeground(QBrush(Qt.black)) attributeItem.setFont(font) thisFileItem = QListWidgetItem( QIcon(resources.IMAGES['locate-on-this-file']), '.\t(Filter only by Classes and Methods in this File)') font = thisFileItem.font() font.setBold(True) thisFileItem.setSizeHint(QSize(20, 30)) thisFileItem.setBackground(QBrush(Qt.lightGray)) thisFileItem.setForeground(QBrush(Qt.black)) thisFileItem.setFont(font) self.listWidget.addItem(thisFileItem) nonPythonItem = QListWidgetItem( QIcon(resources.IMAGES['locate-nonpython']), '!\t(Filter only by Non Python Files)') self.listWidget.addItem(nonPythonItem) nonPythonItem.setSizeHint(QSize(20, 30)) nonPythonItem.setBackground(QBrush(Qt.lightGray)) nonPythonItem.setForeground(QBrush(Qt.black)) nonPythonItem.setFont(font)
class CodeCompletionWidget(QFrame): def __init__(self, editor): super(CodeCompletionWidget, self).__init__(None, Qt.FramelessWindowHint | Qt.ToolTip) self._editor = editor self.stack_layout = QStackedLayout(self) self.stack_layout.setContentsMargins(0, 0, 0, 0) self.stack_layout.setSpacing(0) self.completion_list = QListWidget() self.completion_list.setMinimumHeight(200) self.completion_list.setAlternatingRowColors(True) self._list_index = self.stack_layout.addWidget(self.completion_list) self._icons = { 'a': resources.IMAGES['attribute'], 'f': resources.IMAGES['function'], 'c': resources.IMAGES['class'], 'm': resources.IMAGES['module'] } self.cc = code_completion.CodeCompletion() self._completion_results = {} self._prefix = u'' self.setVisible(False) self.source = '' self._key_operations = { Qt.Key_Up: self._select_previous_row, Qt.Key_Down: self._select_next_row, Qt.Key_PageUp: (lambda: self._select_previous_row(6)), Qt.Key_PageDown: (lambda: self._select_next_row(6)), Qt.Key_Right: lambda: None, Qt.Key_Left: lambda: None, Qt.Key_Enter: self.pre_key_insert_completion, Qt.Key_Return: self.pre_key_insert_completion, Qt.Key_Tab: self.pre_key_insert_completion, Qt.Key_Space: self.hide_completer, Qt.Key_Escape: self.hide_completer, Qt.Key_Backtab: self.hide_completer, Qt.NoModifier: self.hide_completer, Qt.ShiftModifier: self.hide_completer, } desktop = QApplication.instance().desktop() self._desktop_geometry = desktop.availableGeometry() self.connect(self._editor.document(), SIGNAL("blockCountChanged(int)"), self.update_metadata) def _select_next_row(self, move=1): new_row = self.completion_list.currentRow() + move if new_row < self.completion_list.count(): self.completion_list.setCurrentRow(new_row) else: self.completion_list.setCurrentRow(0) return True def _select_previous_row(self, move=1): new_row = self.completion_list.currentRow() - move if new_row >= 0: self.completion_list.setCurrentRow(new_row) else: self.completion_list.setCurrentRow(self.completion_list.count() - move) return True def update_metadata(self): source = self._editor.get_text() source = source.encode(self._editor.encoding) self.cc.analyze_file('', source) def insert_completion(self, insert): if insert != self._prefix: extra = len(self._prefix) - len(insert) self._editor.textCursor().insertText(insert[extra:]) self.hide_completer() def _get_geometry(self): cr = self._editor.cursorRect() point = self._editor.mapToGlobal(cr.topLeft()) cr.moveTopLeft(point) #Check new position according desktop geometry width = (self.completion_list.sizeHintForColumn(0) + \ self.completion_list.verticalScrollBar().sizeHint().width() + 10) height = 200 orientation = (point.y() + height) < self._desktop_geometry.height() if orientation: cr.moveTop(cr.bottom()) cr.setWidth(width) cr.setHeight(height) if not orientation: cr.moveBottom(cr.top()) xpos = self._desktop_geometry.width() - (point.x() + width) if xpos < 0: cr.moveLeft(cr.left() + xpos) return cr def complete(self, results): self.add_list_items(results) self.completion_list.setCurrentRow(0) cr = self._get_geometry() self.setGeometry(cr) self.completion_list.updateGeometries() self.show() def add_list_items(self, proposals): self.completion_list.clear() for p in proposals: self.completion_list.addItem( QListWidgetItem( QIcon(self._icons.get(p[0], resources.IMAGES['attribute'])), p[1])) def set_completion_prefix(self, prefix, valid=True): self._prefix = prefix proposals = [] proposals += [('m', item) \ for item in self._completion_results.get('modules', []) \ if item.startswith(prefix)] proposals += [('c', item) \ for item in self._completion_results.get('classes', []) \ if item.startswith(prefix)] proposals += [('a', item) \ for item in self._completion_results.get('attributes', []) \ if item.startswith(prefix)] proposals += [('f', item) \ for item in self._completion_results.get('functions', []) \ if item.startswith(prefix)] if proposals and valid: self.complete(proposals) else: self.hide_completer() def fill_completer(self): source = self._editor.get_text() source = source.encode(self._editor.encoding) offset = self._editor.textCursor().position() results = self.cc.get_completion(source, offset) self._completion_results = results prefix = self._editor._text_under_cursor() self.set_completion_prefix(prefix) def hide_completer(self): self._prefix = '' self.hide() def pre_key_insert_completion(self): insert = unicode(self.completion_list.currentItem().text()) self.insert_completion(insert) self.hide_completer() return True def process_pre_key_event(self, event): if not self.isVisible() or self._editor.lang != "python": return False skip = self._key_operations.get(event.key(), lambda: False)() self._key_operations.get(event.modifiers(), lambda: False)() if skip is None: skip = False return skip def process_post_key_event(self, event): if not settings.CODE_COMPLETION or self._editor.lang != "python": return if self.isVisible(): source = self._editor.get_text() source = source.encode(self._editor.encoding) offset = self._editor.textCursor().position() prefix, valid = self.cc.get_prefix(source, offset) self.set_completion_prefix(prefix, valid) self.completion_list.setCurrentRow(0) if event.key() == Qt.Key_Period or (event.key() == Qt.Key_Space and \ event.modifiers() == Qt.ControlModifier): self.fill_completer()
class CodeCompletionWidget(QFrame): def __init__(self, editor): super(CodeCompletionWidget, self).__init__(None, Qt.FramelessWindowHint | Qt.ToolTip) self._editor = editor self.stack_layout = QStackedLayout(self) self.stack_layout.setContentsMargins(0, 0, 0, 0) self.stack_layout.setSpacing(0) self.completion_list = QListWidget() self.completion_list.setMinimumHeight(200) self.completion_list.setAlternatingRowColors(True) self._list_index = self.stack_layout.addWidget(self.completion_list) self._icons = { "a": resources.IMAGES["attribute"], "f": resources.IMAGES["function"], "c": resources.IMAGES["class"], } self.cc = code_completion.CodeCompletion() self._completion_results = [] self._prefix = u"" self.setVisible(False) self.source = "" self._key_operations = { Qt.Key_Up: self._select_previous_row, Qt.Key_Down: self._select_next_row, Qt.Key_PageUp: (lambda: self._select_previous_row(6)), Qt.Key_PageDown: (lambda: self._select_next_row(6)), Qt.Key_Right: lambda: None, Qt.Key_Left: lambda: None, Qt.Key_Enter: self.pre_key_insert_completion, Qt.Key_Return: self.pre_key_insert_completion, Qt.Key_Tab: self.pre_key_insert_completion, Qt.Key_Space: self.hide_completer, Qt.Key_Escape: self.hide_completer, Qt.Key_Backtab: self.hide_completer, Qt.NoModifier: self.hide_completer, Qt.ShiftModifier: self.hide_completer, } desktop = QApplication.instance().desktop() self._desktop_geometry = desktop.availableGeometry() self.connect(self._editor.document(), SIGNAL("blockCountChanged(int)"), self.update_metadata) def _select_next_row(self, move=1): new_row = self.completion_list.currentRow() + move if new_row < self.completion_list.count(): self.completion_list.setCurrentRow(new_row) else: self.completion_list.setCurrentRow(0) return True def _select_previous_row(self, move=1): new_row = self.completion_list.currentRow() - move if new_row >= 0: self.completion_list.setCurrentRow(new_row) else: self.completion_list.setCurrentRow(self.completion_list.count() - move) return True def update_metadata(self): source = self._editor.get_text() source = source.encode(self._editor.encoding) self.cc.analyze_file("", source) def insert_completion(self, insert): if insert != self._prefix: extra = len(self._prefix) - len(insert) self._editor.textCursor().insertText(insert[extra:]) self.hide_completer() def _get_geometry(self): cr = self._editor.cursorRect() point = self._editor.mapToGlobal(cr.topLeft()) cr.moveTopLeft(point) # Check new position according desktop geometry width = ( self.completion_list.sizeHintForColumn(0) + self.completion_list.verticalScrollBar().sizeHint().width() + 10 ) height = 200 orientation = (point.y() + height) < self._desktop_geometry.height() if orientation: cr.moveTop(cr.bottom()) cr.setWidth(width) cr.setHeight(height) if not orientation: cr.moveBottom(cr.top()) xpos = self._desktop_geometry.width() - (point.x() + width) if xpos < 0: cr.moveLeft(cr.left() + xpos) return cr def complete(self, results): self.add_list_items(results) self.completion_list.setCurrentRow(0) cr = self._get_geometry() self.setGeometry(cr) self.completion_list.updateGeometries() self.show() def add_list_items(self, proposals): self.completion_list.clear() for p in proposals: self.completion_list.addItem( QListWidgetItem(QIcon(self._icons.get(p[0], resources.IMAGES["attribute"])), p[1]) ) def set_completion_prefix(self, prefix): self._prefix = prefix proposals = [] proposals += [("c", item) for item in self.completion_results.get("classes", []) if item.startswith(prefix)] proposals += [("a", item) for item in self.completion_results.get("attributes", []) if item.startswith(prefix)] proposals += [("f", item) for item in self.completion_results.get("functions", []) if item.startswith(prefix)] if proposals: self.complete(proposals) else: self.hide_completer() def fill_completer(self): source = self._editor.get_text() source = source.encode(self._editor.encoding) offset = self._editor.textCursor().position() results = self.cc.get_completion(source, offset) self.completion_results = results prefix = self._editor._text_under_cursor() self.set_completion_prefix(prefix) def hide_completer(self): self._prefix = "" self.hide() def pre_key_insert_completion(self): insert = unicode(self.completion_list.currentItem().text()) self.insert_completion(insert) self.hide_completer() return True def process_pre_key_event(self, event): if not self.isVisible(): return False skip = self._key_operations.get(event.key(), lambda: False)() self._key_operations.get(event.modifiers(), lambda: False)() if skip is None: skip = False return skip def process_post_key_event(self, event): if not settings.CODE_COMPLETION or self._editor.lang != "python": return if self.isVisible(): source = self._editor.get_text() source = source.encode(self._editor.encoding) offset = self._editor.textCursor().position() prefix = self.cc.get_prefix(source, offset) self.set_completion_prefix(prefix) self.completion_list.setCurrentRow(0) if event.key() == Qt.Key_Period or (event.key() == Qt.Key_Space and event.modifiers() == Qt.ControlModifier): self.fill_completer()
class MainWindow(QMainWindow): """The main window widget for the program. """ def __init__(self, parent=None): super(MainWindow, self).__init__(parent) #### 1 CREATE AND INITIALIZE DATA STRUCTURES #### self.xLabel = None self.xSelection = DEFAULTX self.xSelection_old = None self.xArray = None self.yLabel = None self.ySelection = DEFAULTY self.ySelection_old = None self.yArray = None self.filename = None self.tdms_file_object = None self.channel_registry = {} # Y selector on Left self.ySelector = QListWidget() ySelectorLabel = QLabel("y axis channel") self.ySelector.setMaximumWidth(ySelectorLabel.sizeHint().width()) # File name and plot in the middle self.sourceFileName = QLabel("None") self.sourceFileName.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) sourceFileLabel = QLabel("current file") sourceFileLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) # Matplotlib canvas fig = Figure(dpi=100) self.canvas = FigureCanvas(fig) self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) mpl_toolbar = NavigationToolbar(self.canvas, self.canvas) self.axes = fig.add_subplot(111) # X selector on bottom self.xSelector = QListWidget() self.xSelector.addItem("Time") self.xSelector.setFlow(0) xSelectorLabel = QLabel("x axis channel") self.xSelector.setMaximumHeight(self.xSelector.sizeHintForColumn(0)) # Offset and parameter widgets on the right top self.offsetThing = OffsetWidget() self.attributesThing = AttributesWidget() # Save channel on right bottom self.save_chan_chkbx = QCheckBox() save_chan_label = QLabel("Save Channel") # Status bar at the bottom self.fileSizeLabel = QLabel("File Size: {f_size:0>7.3f} MB".format(f_size=0.0)) self.fileSizeLabel.setFixedWidth(self.fileSizeLabel.sizeHint().width()+10) self.fileSizeLabel.setFrameStyle(QFrame.Panel|QFrame.Sunken) self.yChanLength = QLabel("Y Channel Length: {y_len:0>7.0f}".format(y_len=0.0)) self.yChanLength.setFixedWidth(self.yChanLength.sizeHint().width()+10) self.yChanLength.setFrameStyle(QFrame.Panel|QFrame.Sunken) self.xChanLength = QLabel("X Channel Length: {x_len:0>7.0f}".format(x_len=0.0)) self.xChanLength.setFixedWidth(self.xChanLength.sizeHint().width()+10) self.xChanLength.setFrameStyle(QFrame.Panel|QFrame.Sunken) status = self.statusBar() status.setSizeGripEnabled(False) status.addPermanentWidget(self.fileSizeLabel) status.addPermanentWidget(self.yChanLength) status.addPermanentWidget(self.xChanLength) status.showMessage("Ready", 5000) #2 Create the central widget self.centralWidget = QWidget() # Left Side selectorLayout = QVBoxLayout() #selectorLayout.addWidget(xSelectorLabel) #selectorLayout.addWidget(self.xSelector) selectorLayout.addWidget(ySelectorLabel) selectorLayout.addWidget(self.ySelector) selectorLayout.addStretch() # Center centralLayout = QVBoxLayout() fileNameLayout = QHBoxLayout() xSelectorLayout = QHBoxLayout() fileNameLayout.addWidget(sourceFileLabel) fileNameLayout.addWidget(self.sourceFileName) xSelectorLayout.addWidget(xSelectorLabel) xSelectorLayout.addWidget(self.xSelector) centralLayout.addLayout(fileNameLayout) centralLayout.addWidget(self.canvas) centralLayout.addWidget(mpl_toolbar) centralLayout.addLayout(xSelectorLayout) # Right bottom save_chan_layout = QHBoxLayout() save_chan_layout.addWidget(self.save_chan_chkbx) save_chan_layout.addWidget(save_chan_label) # Right Side rightLayout = QVBoxLayout() rightLayout.addWidget(self.offsetThing) rightLayout.addWidget(self.attributesThing) rightLayout.addStretch() rightLayout.addLayout(save_chan_layout) layout = QHBoxLayout() layout.addLayout(selectorLayout) layout.addLayout(centralLayout) layout.addLayout(rightLayout) self.centralWidget.setLayout(layout) self.setCentralWidget(self.centralWidget) self.resize(self.sizeHint()) #3 Create and set up any dock windows #4 Create actions and insert them into menus and toolbars fileQuitAction = self.createAction("&Quit", self.close, "Ctrl+Q", "exit", "Close the application") fileOpenAction = self.createAction("&Open TDMS File", self.fileOpen, QKeySequence.Open, "fileopen", "Open an existing TDMS file") fileExportAction = self.createAction("&Export", self.exprtToHDF5, "Ctrl+E", tip="Export the TDMS data to HDF5") self.fileMenu = self.menuBar().addMenu("&File") self.fileMenuActions = (fileOpenAction, fileExportAction, fileQuitAction) #self.addActions(self.fileMenu, self.fileMenuActions) self.xSelector.itemSelectionChanged.connect(self.make_x_selection) self.ySelector.itemSelectionChanged.connect(self.make_y_selection) self.offsetThing.new_offset.connect(self.subtract_offset) self.fileMenu.triggered.connect(self.update_file_menu) self.save_chan_chkbx.stateChanged.connect(self.toggle_save) #5 Read in application's settings settings = QSettings() # Restore the geometry and state of the main window from last use #self.restoreGeometry(settings.value("MainWindow/Geometry")) #self.restoreState(settings.value("MainWindow/State")) self.setWindowTitle("TDMS to HDF5 Converter") self.recentFiles = settings.value("RecentFiles") if not self.recentFiles: self.recentFiles = [] self.update_file_menu() def update_ui(self): pass def initVariables(self): self.xLabel = None self.xSelection = DEFAULTX self.xSelection_old = None self.xArray = None self.yLabel = None self.ySelection = DEFAULTY self.ySelection_old = None self.yArray = None self.filename = None self.tdms_file_object = None self.channel_registry = {} def createAction(self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered()"): # Create the action action = QAction(text, self) # Give it its icon if icon is not None: action.setIcon(QIcon(":/{icon}.png".format(icon=icon))) # Give it its shortcut if shortcut is not None: action.setShortcut(shortcut) # Set up its help/tip text if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) # Connect it to a signal if slot is not None: self.connect(action, SIGNAL(signal), slot) # Make it checkable if checkable: action.setCheckable(True) return action def addActions(self, target, actions): for action in actions: if action is None: target.addSeparator() else: target.addAction(action) def update_file_menu(self): self.fileMenu.clear() self.addActions(self.fileMenu, self.fileMenuActions[:-1]) current = self.filename if self.filename is not None else None recentFiles = [] for fname in self.recentFiles: if fname != current and QFile.exists(fname): recentFiles.append(fname) if recentFiles: self.fileMenu.addSeparator() for i, fname in enumerate(recentFiles): action = QAction("&{num} {name}".format(num=i+1, name=QFileInfo(fname).fileName()), self) action.setData(fname) action.triggered.connect(lambda: self.loadFile(fname)) self.fileMenu.addAction(action) self.fileMenu.addSeparator() self.fileMenu.addAction(self.fileMenuActions[-1]) def fileOpen(self): # Process 1 self.initVariables() basedir = os.path.dirname(self.filename) if self.filename is not None \ else "~/Documents/PhD/root/raw-data/sio2al149/CryoMeasurement" formats = "TDMS files (*.tdms)" fname = QFileDialog.getOpenFileName(self, "Open a TDMS File", basedir, formats) # Process 1.1 Collect file name if fname and QFile.exists(fname): self.loadFile(fname) def loadFile(self, fname): # Process 1.2 Generate TDMS file object self.add_recent_file(fname) self.tdms_file_object = TdmsFile(fname) self.filename = fname # Process 1.3 Read data into local structure if self.tdms_file_object: # Process 1.3.0 Generate group list group_list = self.tdms_file_object.groups() # Processes 1.3.1 through 1.3.3 Sort TDMS data for group in group_list: self.sortTDMSGroupData(group) message = "Loaded {f_name}".format(f_name=os.path.basename(fname)) self.sourceFileName.setText(os.path.basename(fname)) # Process 2.1 Populate channel selection lists self.update_selectors() else: message = "Failed to load {f_name}".format(f_name=os.path. basename(fname)) self.statusBar().showMessage(message, 5000) fsize = os.path.getsize(self.filename) self.fileSizeLabel.setText("File Size: {file_size:>7.3f} MB".format(file_size=fsize/1E6)) #TODO self.updateStatus(message) # see Rapid GUI ch06.pyw def add_recent_file(self, fname): if fname is None: return if not fname in self.recentFiles: self.recentFiles.insert(0, fname) while len(self.recentFiles) > 9: self.recentFiles.pop() def sortTDMSGroupData(self, group): # Process 1.3 Sort Group data # Process 1.3.1 Get <Group> Channels group_props = self.tdms_file_object.object(group).properties # Process 1.3.2 Get <Group> Properties group_chans = self.tdms_file_object.group_channels(group) # Process 1.3.3 Create a new channel in the registry for each channel # in the group for chan in group_chans: chan_name = chan.path.split('/')[-1].strip("'") # Process 1.3.3.1 Generate new channel object and fill with data # Some of the TDMS channels were created, but never populated with # data. The following weeds those out. try: new_chan = Channel(chan_name, device=group, meas_array=chan.data) except TypeError: self.statusBar().showMessage("Channel {chan} in {dev} has no data" .format(chan=chan_name, dev=group), 5000) try: new_chan.set_start_time(chan.property("wf_start_time")) new_chan.set_delta_time(chan.property("wf_increment")) new_chan.set_location('raw/{c2_name}'.format(c2_name=chan_name)) if chan_name not in ['TCap', 'xMagnet']: new_chan.set_write() # Some of the channel-specific properties were actually # saved in the group object's properties list. # We retrieve those here. # Process 1.3.3.2 Resort the group properties of TDMS ADWin if group == "ADWin": for atr_name in ADWIN_DICT[chan_name]: try: new_chan.attributes[atr_name] = \ group_props[atr_name] except KeyError: #print('The key {a_name} was not found.' # .format(a_name=atr_name)) #print('The keys available are\n') #print(group_props) pass # Process 1.3.3.3 Add new channel to the registry self.channel_registry[chan_name] = new_chan #print('\tChannel name:\t{ch_name}'.format(ch_name=chan_name)) except (KeyError, UnboundLocalError): pass #print('Error: Was unable to load {c3_name}' # .format(c3_name=chan_name)) def update_selectors(self): # Clear the selectors self.xSelector.clear() self.ySelector.clear() # Add the names of the channels in the registry to both selectors for key in self.channel_registry.keys(): self.xSelector.addItem(key) self.ySelector.addItem(key) # Add the time "channel" to the x selector self.xSelector.addItem('Time') # Sort the lists (alphabetically) otherwise the order constantly changes self.xSelector.sortItems() self.ySelector.sortItems() # Set the current x selector default default_x_item = self.xSelector.findItems(DEFAULTX, Qt.MatchExactly) self.xSelector.setCurrentItem(default_x_item[0]) # Set the current y selector default try: default_y_item = self.ySelector.findItems(DEFAULTY, Qt.MatchExactly) self.ySelector.setCurrentItem(default_y_item[0]) except IndexError: self.ySelector.setCurrentRow(0) self.xSelector.setMinimumHeight(self.xSelector.sizeHintForRow(0)*3) self.ySelector.setMinimumWidth(self.ySelector.sizeHintForColumn(0)+10) def exprtToHDF5(self): # Process 5 Save to HDF5 fname = self.filename.split('.')[0] + '.hdf5' basedir = "/home/chris/Documents/PhD/root/data/sio2al149/cryo_measurement" if not os.path.exists(basedir): os.makedirs(basedir) formats = "TDMS files (*.hdf5 *.h5 *.he5 *.hdf)" dialog = QFileDialog() dialog.setFilter(formats) dialog.setDefaultSuffix("*.hdf5") dialog.selectFile(os.path.join(basedir, fname)) dialog.setDirectory(basedir) if dialog.exec_(): fname = dialog.selectedFiles() else: return # Process 5.1 Create HDF5 file object hdf5_file_object = h5py.File(fname[0]) # Process 5.2 Create channels at their locations for chan in self.channel_registry: chan_obj = self.channel_registry[chan] chan_name = chan #print(chan, self.channel_registry[chan].location, # self.channel_registry[chan].write_to_file) # Process 5.2.1 Write channel data if self.channel_registry[chan].write_to_file: dset = hdf5_file_object.create_dataset(chan_obj.location, data=chan_obj.data) # Process 5.2.2 Write channel attributes for attr_name in self.channel_registry[chan].attributes: attr_value = self.channel_registry[chan].attributes[attr_name] # Convert the datetime format to a string if type(attr_value) is datetime: attr_value = attr_value.isoformat() # There's currently a wierd bug when dealing with python3 # strings. # This gets around that if type(attr_value) is str: #attr_value = attr_value.encode('utf-8') #attr_value = np.string_(attr_value, dtype="S10") attr_value = np.string_(attr_value) dset.attrs.create(attr_name, attr_value) # Process 5.3 Write data to file hdf5_file_object.flush() hdf5_file_object.close() def make_x_selection(self): self.x_change = True # Get the name of the newly selected channel self.xSelection = self.xSelector.currentItem().text() # Get the axis label self.xLabel = self.gen_axis_label(self.xSelection) # If the xSelection is time, use the time data instead of measurement # data if self.xSelection == 'Time': try: self.xArray = self.channel_registry[self.ySelection].time except KeyError: self.xArray = np.array([]) else: self.xArray = self.channel_registry[self.xSelection].data if self.yLabel: self.plotData() self.xSelection_old = self.xSelector.currentItem() self.x_change = False self.xChanLength.setText("X Channel Length: {x_len:>7.0f}".format(x_len=len(self.xArray))) def make_y_selection(self, offset=0.0): self.y_change = True # Get the names of the selected channels from the selectors try: self.ySelection = self.ySelector.currentItem().text() except AttributeError: self.ySelection = DEFAULTY # Set save channel checkbox state self.save_chan_chkbx.setChecked(self.channel_registry[self.ySelection] .write_to_file) # Get the axis label self.yLabel = self.gen_axis_label(self.ySelection) # Generate the y-channel array to be plotted self.yArray = self.channel_registry[self.ySelection].data - offset # Update the attributes view self.attributesThing.clear_attributes() self.attributesThing.select_chan(self.channel_registry[self.ySelection]) if self.xSelection == 'Time': self.make_x_selection() else: self.plotData() self.ySelection_old = self.ySelector.currentItem() self.y_change = False self.yChanLength.setText("Y Channel Length: {y_len:>7.0f}".format(y_len=len(self.yArray))) def gen_axis_label(self, chan_name): # Generate the axis labels based on the selected channels # Cycle through the labes in the AXESLABELS dictionary for axlbl in AXESLABELS.keys(): # Cycle through the channel names in each label's dictionary entry for cn in AXESLABELS[axlbl]: # If a channel equals one of the selections, save the label if chan_name == cn: label = axlbl return label def plotData(self): # Clear the plot self.axes.cla() # Turn on the grid self.axes.grid(True) # Set the labels try: self.axes.set_xlabel(self.xLabel) except UnboundLocalError: self.statusBar().showMessage("Could not generate an axis label for {chan}" .format(chan=self.xSelection), 5000) try: self.axes.set_ylabel(self.yLabel) except UnboundLocalError: self.statusBar().showMessage("Could not generate an axis label for {chan}" .format(chan=self.ySelection), 5000) # Try plotting the data. There are still no checks in place to make sure # the arrays are of the same length. try: # Plot the data and label it self.axes.plot(self.xArray, self.yArray, label=self.ySelection) # Show the legend self.axes.legend(loc=0) # Draw everything self.canvas.draw() except ValueError: QMessageBox.warning(self, "Unequal Arrays", "{y_chan} and {x_chan} " .format(y_chan=self.ySelection, x_chan=self.xSelection) + \ "are not the same length!") if self.x_change: self.xSelector.setCurrentItem(self.xSelection_old) elif self.y_change: self.ySelector.setCurrentItem(self.ySelection_old) def subtract_offset(self): "Subtract the offset entered from the currently selected y channel." offset = self.offsetThing.offset_entry.value() self.make_y_selection(offset=offset) def toggle_save(self): self.channel_registry[self.ySelection].write_to_file = \ self.save_chan_chkbx.isChecked() def create_new_channel(self, ch_name): "Create a new channel in the registry." #print(ch_name) pass def closeEvent(self, event): """Reimplementation of the close even handler. We have to reimplement this because not all close actions, e.g. clicking the X button, call the close() method. We want to catch this so we can give the user the opportunity to save unsaved changes before the program exits. """ settings = QSettings() #settings.setValue("MainWindow/Geometry", QVariant( # self.saveGeometry())) #settings.setValue("MainWindow/State", QVariant( # self.saveState())) if self.recentFiles: recentFiles = self.recentFiles else: recentFiles = [] settings.setValue("RecentFiles", recentFiles)
class PopupCompleter(QFrame): def __init__(self): QFrame.__init__(self, None, Qt.FramelessWindowHint | Qt.ToolTip) vbox = QVBoxLayout(self) vbox.setContentsMargins(0, 0, 0, 0) vbox.setSpacing(0) self.listWidget = QListWidget() self.listWidget.setMinimumHeight(350) vbox.addWidget(self.listWidget) self.listWidget.currentItemChanged.connect(self._repaint_items) def _repaint_items(self, current, previous): if current is not None: widget = self.listWidget.itemWidget(current) if widget is not None: widget.set_selected() if previous is not None: widget = self.listWidget.itemWidget(previous) if widget is not None: widget.set_not_selected() def reload(self, model): """Reload the data of the Popup Completer, and restart the state.""" self.listWidget.clear() self.add_help() for item in model: self.listWidget.addItem(item[0]) self.listWidget.setItemWidget(item[0], item[1]) self.listWidget.setCurrentRow(8) def clear(self): """Remove all the items of the list (deleted), and reload the help.""" self.listWidget.clear() def refresh(self, model, has_text=True): """Refresh the list when the user search for some word.""" self.listWidget.clear() if not has_text: self.add_help() for item in model: self.listWidget.addItem(item[0]) self.listWidget.setItemWidget(item[0], item[1]) if model: self.listWidget.setCurrentItem(model[0][0]) else: self.add_no_found() def fetch_more(self, model): """Add more items to the list on user scroll.""" for item in model: self.listWidget.addItem(item[0]) self.listWidget.setItemWidget(item[0], item[1]) def add_no_found(self): #Load no results found message noFoundItem = QListWidgetItem( QIcon(resources.IMAGES['delete']), 'No results were found!') font = noFoundItem.font() font.setBold(True) noFoundItem.setSizeHint(QSize(20, 30)) noFoundItem.setBackground(QBrush(Qt.lightGray)) noFoundItem.setForeground(QBrush(Qt.black)) noFoundItem.setFont(font) self.listWidget.addItem(noFoundItem) def add_help(self): #Load help fileItem = QListWidgetItem( QIcon(resources.IMAGES['locate-file']), '@\t(Filter only by Files)') font = fileItem.font() font.setBold(True) fileItem.setSizeHint(QSize(20, 30)) fileItem.setBackground(QBrush(Qt.lightGray)) fileItem.setForeground(QBrush(Qt.black)) fileItem.setFont(font) self.listWidget.addItem(fileItem) classItem = QListWidgetItem( QIcon(resources.IMAGES['locate-class']), '<\t(Filter only by Classes)') self.listWidget.addItem(classItem) classItem.setSizeHint(QSize(20, 30)) classItem.setBackground(QBrush(Qt.lightGray)) classItem.setForeground(QBrush(Qt.black)) classItem.setFont(font) methodItem = QListWidgetItem( QIcon(resources.IMAGES['locate-function']), '>\t(Filter only by Methods)') self.listWidget.addItem(methodItem) methodItem.setSizeHint(QSize(20, 30)) methodItem.setBackground(QBrush(Qt.lightGray)) methodItem.setForeground(QBrush(Qt.black)) methodItem.setFont(font) attributeItem = QListWidgetItem( QIcon(resources.IMAGES['locate-attributes']), '-\t(Filter only by Attributes)') self.listWidget.addItem(attributeItem) attributeItem.setSizeHint(QSize(20, 30)) attributeItem.setBackground(QBrush(Qt.lightGray)) attributeItem.setForeground(QBrush(Qt.black)) attributeItem.setFont(font) thisFileItem = QListWidgetItem( QIcon(resources.IMAGES['locate-on-this-file']), '.\t(Filter only by Classes and Methods in this File)') font = thisFileItem.font() font.setBold(True) thisFileItem.setSizeHint(QSize(20, 30)) thisFileItem.setBackground(QBrush(Qt.lightGray)) thisFileItem.setForeground(QBrush(Qt.black)) thisFileItem.setFont(font) self.listWidget.addItem(thisFileItem) tabsItem = QListWidgetItem( QIcon(resources.IMAGES['locate-tab']), '/\t(Filter only by the current Tabs)') font = tabsItem.font() font.setBold(True) tabsItem.setSizeHint(QSize(20, 30)) tabsItem.setBackground(QBrush(Qt.lightGray)) tabsItem.setForeground(QBrush(Qt.black)) tabsItem.setFont(font) self.listWidget.addItem(tabsItem) lineItem = QListWidgetItem( QIcon(resources.IMAGES['locate-line']), ':\t(Go to Line)') font = lineItem.font() font.setBold(True) lineItem.setSizeHint(QSize(20, 30)) lineItem.setBackground(QBrush(Qt.lightGray)) lineItem.setForeground(QBrush(Qt.black)) lineItem.setFont(font) self.listWidget.addItem(lineItem) nonPythonItem = QListWidgetItem( QIcon(resources.IMAGES['locate-nonpython']), '!\t(Filter only by Non Python Files)') self.listWidget.addItem(nonPythonItem) nonPythonItem.setSizeHint(QSize(20, 30)) nonPythonItem.setBackground(QBrush(Qt.lightGray)) nonPythonItem.setForeground(QBrush(Qt.black)) nonPythonItem.setFont(font)
class KeywordList(HelpedWidget): """Shows a list of keywords. The data structure expected and sent to the getter and setter is an array of values.""" def __init__(self, model, list_label="", help_link=""): HelpedWidget.__init__(self, list_label, help_link) assert isinstance(model, ListModelMixin) self.model = model self.keyword_list = [] self.list = QListWidget(self) self.list.setMinimumHeight(100) self.list.setMaximumHeight(150) self.default_selection_mode = self.list.selectionMode() self.addWidget(self.list) self.addRemoveWidget = AddRemoveWidget(self.addItem, self.removeItem) self.addWidget(self.addRemoveWidget) self.title = "New keyword" self.description = "Enter name of keyword:" self.model.observable().attach(ListModelMixin.LIST_CHANGED_EVENT, self.modelChanged) self.modelChanged() def setSelectable(self, selectable): if selectable: self.list.setSelectionMode(self.default_selection_mode) else: self.list.setSelectionMode(QAbstractItemView.NoSelection) def setPopupLabels(self, title, description): """Change the labels of the default popup.""" self.title = title self.description = description def newKeywordPopup(self, keyword_list): """ Pops up a message box asking for a new keyword. Override this and return a string to customize the input dialog - Empty string equals canceled. The provided list are the already defined keywords """ new_keyword, ok = QInputDialog.getText(self, self.tr(self.title), self.tr(self.description), QLineEdit.Normal) if ok: return str(new_keyword).strip() else: return "" def addItem(self): """Called by the add button to insert a new keyword""" new_keyword = self.newKeywordPopup(self.keyword_list) if not new_keyword == "": self.model.addItem(new_keyword) def removeItem(self): """Called by the remove button to remove a selected keyword""" if not self.list.currentItem() is None: row = self.list.currentRow() try: self.model.removeItem(self.keyword_list[row]) except NotImplementedError: message = "Support for removal of items has not been implemented!" QMessageBox.information(self, "Not implemented!", message) def modelChanged(self): """Retrieves data from the model and inserts it into the list""" keywords = self.model.getList() self.list.clear() self.keyword_list = keywords for keyword in keywords: self.list.addItem(keyword)
class KeywordList(HelpedWidget): """Shows a list of keywords. The data structure expected and sent to the getter and setter is an array of values.""" def __init__(self, model, list_label="", help_link=""): HelpedWidget.__init__(self, list_label, help_link) assert isinstance(model, ListModelMixin) self.model = model self.keyword_list = [] self.list = QListWidget(self) self.list.setMinimumHeight(100) self.list.setMaximumHeight(150) self.default_selection_mode = self.list.selectionMode() self.addWidget(self.list) self.addRemoveWidget = AddRemoveWidget(self.addItem, self.removeItem) self.addWidget(self.addRemoveWidget) self.title = "New keyword" self.description = "Enter name of keyword:" self.model.observable().attach(ListModelMixin.LIST_CHANGED_EVENT, self.modelChanged) self.modelChanged() def setSelectable(self, selectable): if selectable: self.list.setSelectionMode(self.default_selection_mode) else: self.list.setSelectionMode(QAbstractItemView.NoSelection) def setPopupLabels(self, title, description): """Change the labels of the default popup.""" self.title = title self.description = description def newKeywordPopup(self, keyword_list): """ Pops up a message box asking for a new keyword. Override this and return a string to customize the input dialog - Empty string equals canceled. The provided list are the already defined keywords """ new_keyword, ok = QInputDialog.getText(self, self.tr(self.title), self.tr(self.description), QLineEdit.Normal) if ok: return str(new_keyword).strip() else: return "" def addItem(self): """Called by the add button to insert a new keyword""" new_keyword = self.newKeywordPopup(self.keyword_list) if not new_keyword == "": self.model.addItem(new_keyword) def removeItem(self): """Called by the remove button to remove a selected keyword""" if not self.list.currentItem() is None: row = self.list.currentRow() try: self.model.removeItem(self.keyword_list[row]) except NotImplementedError: message = "Support for removal of items has not been implemented!" QMessageBox.information(self, "Not implemented!", message) def modelChanged(self): """Retrieves data from the model and inserts it into the list""" keywords = self.model.getList() self.list.clear() self.keyword_list = keywords for keyword in keywords: self.list.addItem(keyword) def cleanup(self): self.model.observable().detach(ListModelMixin.LIST_CHANGED_EVENT, self.modelChanged)
class LayerImportBrowser(QDialog): class VectorPage(QWidget): def __init__(self, parent=None, filters="", encodings=[]): QWidget.__init__(self, parent) self.filters = filters self.layerLineEdit = QLineEdit() self.browseToolButton = QToolButton() self.browseToolButton.setAutoRaise(True) self.browseToolButton.setIcon(QIcon(":document-open")) layerLabel = QLabel("&Dataset:") layerLabel.setBuddy(self.layerLineEdit) self.encodingComboBox = QComboBox() self.encodingComboBox.addItems(encodings) encodingLabel = QLabel("&Encoding:") encodingLabel.setBuddy(self.encodingComboBox) hbox = QHBoxLayout() hbox.addWidget(layerLabel) hbox.addWidget(self.layerLineEdit) hbox.addWidget(self.browseToolButton) vbox = QVBoxLayout() vbox.addLayout(hbox) hbox = QHBoxLayout() hbox.addWidget(encodingLabel) hbox.addWidget(self.encodingComboBox) vbox.addLayout(hbox) self.setLayout(vbox) self.encodingComboBox.setCurrentIndex(self.encodingComboBox.findText("System")) self.connect(self.browseToolButton, SIGNAL("clicked()"), self.browseToFile) self.connect(self.encodingComboBox, SIGNAL("currentIndexChanged(QString)"), self.changeEncoding) def browseToFile(self): dialog = QFileDialog(self, "manageR - Open Vector File", unicode(robjects.r.getwd()[0]), self.filters) if not dialog.exec_() == QDialog.Accepted: return files = dialog.selectedFiles() file = files.first().trimmed() self.layerLineEdit.setText(file) self.emit(SIGNAL("filePathChanged(QString)"), file) def changeEncoding(self, text): self.emit(SIGNAL("encodingChanged(QString)"), text) class RasterPage(QWidget): def __init__(self, parent=None, filters=""): QWidget.__init__(self, parent) self.parent = parent self.filters = filters self.layerLineEdit = QLineEdit() self.browseToolButton = QToolButton() self.browseToolButton.setAutoRaise(True) self.browseToolButton.setIcon(QIcon(":document-open")) layerLabel = QLabel("&Dataset:") layerLabel.setBuddy(self.layerLineEdit) hbox = QHBoxLayout() hbox.addWidget(layerLabel) hbox.addWidget(self.layerLineEdit) hbox.addWidget(self.browseToolButton) vbox = QVBoxLayout() vbox.addLayout(hbox) self.setLayout(vbox) self.connect(self.browseToolButton, SIGNAL("clicked()"), self.browseToFile) def browseToFile(self): dialog = QFileDialog(self, "manageR - Open Raster File", unicode(robjects.r.getwd()[0]), self.filters) if not dialog.exec_() == QDialog.Accepted: return files = dialog.selectedFiles() file = files.first().trimmed() self.layerLineEdit.setText(file) self.emit(SIGNAL("filePathChanged(QString)"), file) def __init__(self, parent=None, vectors="", rasters="", encodings=[]): QDialog.__init__(self, parent) self.contentsWidget = QListWidget() self.setWindowIcon(QIcon(":icon")) self.contentsWidget.setViewMode(QListView.IconMode) self.contentsWidget.setIconSize(QSize(76, 66)) self.contentsWidget.setMovement(QListView.Static) self.contentsWidget.setMaximumWidth(106) self.contentsWidget.setMinimumWidth(106) self.contentsWidget.setMinimumHeight(220) self.contentsWidget.setSpacing(12) self.__filePath = "" self.__encoding = "System" self.__type = 0 self.pagesWidget = QStackedWidget() vectorPage = self.VectorPage(self, vectors, encodings) self.pagesWidget.addWidget(vectorPage) rasterPage = self.RasterPage(self, rasters) self.pagesWidget.addWidget(rasterPage) buttons = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel, Qt.Horizontal, self) self.connect(buttons, SIGNAL("accepted()"), self.accept) self.connect(buttons, SIGNAL("rejected()"), self.reject) self.connect(vectorPage, SIGNAL("filePathChanged(QString)"), self.setFilePath) self.connect(vectorPage, SIGNAL("encodingChanged(QString)"), self.setEncoding) self.connect(rasterPage, SIGNAL("filePathChanged(QString)"), self.setFilePath) self.createIcons() self.contentsWidget.setCurrentRow(0) horizontalLayout = QHBoxLayout() horizontalLayout.addWidget(self.contentsWidget) horizontalLayout.addWidget(self.pagesWidget, 1) mainLayout = QVBoxLayout() mainLayout.addLayout(horizontalLayout) mainLayout.addStretch(1) mainLayout.addSpacing(12) mainLayout.addWidget(buttons) self.setLayout(mainLayout) self.setWindowTitle("manageR - Import Layer") def createIcons(self): vectorButton = QListWidgetItem(self.contentsWidget) vectorButton.setIcon(QIcon(":custom-vector.svg")) vectorButton.setText("Vector Layer") vectorButton.setTextAlignment(Qt.AlignHCenter) vectorButton.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) rasterButton = QListWidgetItem(self.contentsWidget) rasterButton.setIcon(QIcon(":custom-raster.svg")) rasterButton.setText("Raster Layer") rasterButton.setTextAlignment(Qt.AlignHCenter) rasterButton.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.connect(self.contentsWidget, SIGNAL("currentItemChanged(QListWidgetItem*, QListWidgetItem*)"), self.changePage) def changePage(self, current, previous): if not current: current = previous self.pagesWidget.setCurrentIndex(self.contentsWidget.row(current)) def filePath(self): return self.__filePath def setFilePath(self, filePath): self.__filePath = filePath def encoding(self): return self.__encoding def setEncoding(self, encoding): self.__encoding = encoding def layerType(self): return self.__type def setLayerType(self, type): self.__type = type def accept(self): self.__type = self.pagesWidget.currentIndex() QDialog.accept(self)