Example #1
0
    def __init__(self,
                 specialized_device,
                 display_mode,
                 write_mode,
                 parent=None):
        """Construct a device specific widget.
        * specialized_device should be a DeviceBase subclass tailored to the specific device.
        * display_mode and write_mode are the display and write modes to use with the device.
        """
        super(DeviceWidgetBase, self).__init__(parent)
        self.log = util.make_logging_source_adapter(__name__, self)
        self.device = specialized_device
        self._display_mode = display_mode
        self._write_mode = write_mode
        self.make_settings = None

        self.device.hardware_set.connect(self._on_device_hardware_set)
        self._on_device_hardware_set(self.device, None, self.device.hw)

        self.notes_widget = gui_util.DeviceNotesWidget(specialized_device)

        self.hide_notes_button = QtWidgets.QPushButton(
            clicked=self._toggle_hide_notes)
        self.set_notes_visible(False)

        self.tab_widget = QtWidgets.QTabWidget()
        self.tab_widget.setCornerWidget(self.hide_notes_button,
                                        Qt.TopRightCorner)

        layout = QtWidgets.QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self.notes_widget)
        layout.addWidget(self.tab_widget)
        layout.setStretch(1, 1)
Example #2
0
    def __init__(self, orientation=Qt.Horizontal, parent=None):
        super(SimpleToolBar, self).__init__(parent)
        self.orientation = orientation
        if orientation == Qt.Horizontal:
            self.setLayout(QtWidgets.QHBoxLayout())
        else:
            self.setLayout(QtWidgets.QVBoxLayout())

        self.layout().setSpacing(2)
        self.layout().setContentsMargins(0, 0, 0, 0)
        self.layout().addStretch(1)
Example #3
0
    def get_toolbar(self):
        tb = QtWidgets.QToolBar()

        for a in self.actions():
            tb.addAction(a)

        return tb
Example #4
0
def make_title_label(title):
    title_font = QtGui.QFont()
    title_font.setBold(True)
    label = QtWidgets.QLabel(title)
    label.setFont(title_font)
    label.setAlignment(Qt.AlignCenter)
    return label
Example #5
0
def make_spinbox(min_value=None,
                 max_value=None,
                 value=None,
                 limits=None,
                 prefix=None,
                 suffix=None,
                 single_step=None,
                 parent=None):
    ret = QtWidgets.QSpinBox(parent)
    if min_value is not None:
        ret.setMinimum(min_value)
    if max_value is not None:
        ret.setMaximum(max_value)
    if limits is not None:
        ret.setMinimum(limits[0])
        ret.setMaximum(limits[1])
    if prefix is not None:
        ret.setPrefix(prefix)
    if suffix is not None:
        ret.setSuffix(suffix)
    if single_step is not None:
        ret.setSingleStep(single_step)
    if value is not None:
        ret.setValue(value)

    return ret
Example #6
0
    def __init__(self, gui_app, parent=None):
        super(TutorialWidget, self).__init__(parent)
        self.gui_app = gui_app

        #self.setStyleSheet('background: lightyellow;')

        self.text_doc = QtGui.QTextDocument(self)

        f = QtCore.QFile(":/quickstart.html")
        if f.open(QtCore.QIODevice.ReadOnly):
            s = QtCore.QTextStream(f)
            html = s.readAll()
        else:
            html = "quickstart.html not found!"

        self.text_doc.setHtml(html)

        self.text_browser = TutorialTextBrowser(openLinks=False)
        self.text_browser.setDocument(self.text_doc)
        self.text_browser.href_hover.connect(self._on_href_hover)

        layout = QtWidgets.QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self.text_browser)

        self.flasher = UIFlasher(widget=self)
Example #7
0
    def paint(self, painter, option, index):
        node = index.internalPointer()

        option = QtWidgets.QStyleOptionViewItem(option)
        self.initStyleOption(option, index)

        if (option.state & QtWidgets.QStyle.State_Selected
                and isinstance(node, (ctm.DeviceNode, htm.DeviceNode))
                and self.director.linked_mode):

            device = node.ref
            color = None

            if device.idc_conflict or device.address_conflict:
                color = QtGui.QColor('darkRed')

            elif device.has_hw and device.has_cfg:
                if device.hw.is_connected():
                    if device.config_applied is True:
                        color = QtGui.QColor('darkGreen')
                    elif device.config_applied is False:
                        color = QtGui.QColor('darkOrange')
                    # else config_applied should be None meaning "unknown"

            if color is not None:
                option.palette.setColor(QtGui.QPalette.Highlight, color)

        super(MCTreeItemDelegate, self).paint(painter, option, index)
Example #8
0
    def __init__(self,
                 serial_ports_usb,
                 serial_ports_serial,
                 urls_in_use=list(),
                 url=None,
                 do_connect_default=True,
                 autoconnect_default=True,
                 title="Add MRC",
                 parent=None):
        super(AddMRCDialog, self).__init__(parent)
        self.urls_in_use = urls_in_use
        self.ui = util.loadUi(":/ui/connect_dialog.ui")
        layout = QtWidgets.QHBoxLayout(self)
        layout.addWidget(self.ui)

        self.setWindowTitle(title)
        self.ui.buttonBox.button(
            QtWidgets.QDialogButtonBox.Ok).setEnabled(False)

        self.ui.accepted.connect(self.accept)
        self.ui.rejected.connect(self.reject)

        for combo in (self.ui.combo_serial_port_usb,
                      self.ui.combo_serial_port_serial):
            combo.setValidator(
                QtGui.QRegExpValidator(QtCore.QRegExp('.+'), None))

        self.ui.le_tcp_host.setValidator(
            QtGui.QRegExpValidator(QtCore.QRegExp('.+'), None))
        self.ui.le_mesycontrol_host.setValidator(
            QtGui.QRegExpValidator(QtCore.QRegExp('.+'), None))
        self.ui.le_tcp_host.setText('localhost')
        self.ui.le_mesycontrol_host.setText('localhost')
        self.ui.cb_connect.setChecked(do_connect_default)
        self.ui.cb_autoconnect.setChecked(autoconnect_default)

        for port in serial_ports_usb:
            self.ui.combo_serial_port_usb.addItem(port)

        for port in serial_ports_serial:
            self.ui.combo_serial_port_serial.addItem(port)

        for le in self.ui.findChildren(QtWidgets.QLineEdit):
            le.textChanged.connect(self._validate_inputs)

        for combo in self.ui.findChildren(QtWidgets.QComboBox):
            combo.currentIndexChanged.connect(self._validate_inputs)
            combo.editTextChanged.connect(self._validate_inputs)

        for spin in self.ui.findChildren(QtWidgets.QSpinBox):
            spin.valueChanged.connect(self._validate_inputs)

        self.ui.stacked_widget.currentChanged.connect(self._validate_inputs)
        self._validate_inputs()

        self._result = None

        if url is not None:
            self._set_url(url)
Example #9
0
    def _create_actions(self):
        a = QtWidgets.QAction(QtGui.QIcon.fromTheme("edit-copy"),
                              "&Copy",
                              self,
                              triggered=self._copy_action)

        a.setShortcut(QtGui.QKeySequence.Copy)
        a.setEnabled(False)
        self._actions['copy'] = a

        a = QtWidgets.QAction(QtGui.QIcon.fromTheme("edit-paste"),
                              "&Paste",
                              self,
                              triggered=self._paste_action)
        a.setShortcut(QtGui.QKeySequence.Paste)
        a.setEnabled(False)
        self._actions['paste'] = a
Example #10
0
    def contextMenuEvent(self, event):
        menu = QtWidgets.QMenu()

        for a in self._actions.values():
            if a.isEnabled():
                menu.addAction(a)

        if not menu.isEmpty():
            menu.exec_(self.mapToGlobal(event.pos()))
Example #11
0
    def addAction(self, action):
        super(FixedWidthVerticalToolBar, self).addAction(action)
        b = QtWidgets.QToolButton()
        b.setDefaultAction(action)

        self.layout().takeAt(self.layout().count() - 1)
        self.layout().addWidget(b, 0, Qt.AlignHCenter)
        self.layout().addStretch(1)
        self.setFixedWidth(self.sizeHint().width())
Example #12
0
def make_apply_common_button_layout(input_spinbox, tooltip, on_clicked):

    # Wrapper to invoke the clicked handler without the boolean arg that's
    # passed from QPushButton.clicked().
    def _on_clicked():
        on_clicked()

    button = QtWidgets.QPushButton(clicked=_on_clicked)
    button.setIcon(QtGui.QIcon(":/arrow-bottom.png"))
    button.setMaximumHeight(input_spinbox.sizeHint().height())
    button.setMaximumWidth(16)
    button.setToolTip(tooltip)

    layout = QtWidgets.QHBoxLayout()
    layout.addWidget(input_spinbox)
    layout.addWidget(button)
    layout.setContentsMargins(0, 0, 0, 0)
    layout.setSpacing(1)

    return (layout, button)
Example #13
0
    def __init__(self, context, parent=None):
        super(MainWindow, self).__init__(parent)
        self.log = util.make_logging_source_adapter(__name__, self)
        self.context = context
        self.mdiArea = MCMdiArea()
        self.toolbar = self.addToolBar("toolbar")
        self.toolbar.setObjectName("toolbar")
        self.setWindowTitle("mesycontrol")
        self.setWindowIcon(make_icon(":/window-icon.png"))

        self.mdiArea.setLayout(QtWidgets.QGridLayout())
        self.setCentralWidget(self.mdiArea)

        self.status_bar = QtWidgets.QStatusBar()
        self.setStatusBar(self.status_bar)

        self.actionQuickstart = QtWidgets.QAction("Quickstart")
        self.actionQuickstart.setShortcut("F1")

        self.menu_file = QtWidgets.QMenu("&File")
        self.menu_window = QtWidgets.QMenu("&Window")
        self.menu_help = QtWidgets.QMenu("&Help")

        self.menu_help.addAction(self.actionQuickstart)
        self.menu_help.addSeparator()
        self.menu_help.addAction("&About", self.on_actionAbout_triggered)
        self.menu_help.addAction("About &Qt", self.on_actionAbout_Qt_triggered)

        self.menu_bar = self.menuBar()
        self.menu_bar.addMenu(self.menu_file)
        self.menu_bar.addMenu(self.menu_help)

        # Treeview
        self.treeview = MCTreeView(app_registry=context.app_registry,
                                   device_registry=context.device_registry)

        dw_tree = QtWidgets.QDockWidget("Device tree", self)
        dw_tree.setObjectName("dw_treeview")
        dw_tree.setWidget(self.treeview)
        dw_tree.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable
                            | QtWidgets.QDockWidget.DockWidgetFloatable)
        self.addDockWidget(Qt.BottomDockWidgetArea, dw_tree)

        # Log view
        self.logview = log_view.LogView(parent=self)
        dw_logview = QtWidgets.QDockWidget("Application Log", self)
        dw_logview.setObjectName("dw_logview")
        dw_logview.setWidget(self.logview)
        dw_logview.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable
                               | QtWidgets.QDockWidget.DockWidgetFloatable)
        self.addDockWidget(Qt.BottomDockWidgetArea, dw_logview)
Example #14
0
    def __init__(self, device, parent=None):
        super(DeviceNotesWidget, self).__init__(parent)

        self.device = device

        device.read_mode_changed.connect(self._on_device_read_mode_changed)
        device.write_mode_changed.connect(self._on_device_write_mode_changed)
        device.extension_changed.connect(self._on_device_extension_changed)

        self.text_edit = NotesTextEdit()
        self.text_edit.setReadOnly(True)
        self.text_edit.modificationChanged.connect(
                self._on_text_edit_modification_changed)

        fm = self.text_edit.fontMetrics()
        rh = fm.lineSpacing() + DeviceNotesWidget.ADD_PIXELS_PER_ROW
        self.text_edit.setFixedHeight(DeviceNotesWidget.DISPLAY_ROWS * rh)

        layout = QtWidgets.QHBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        layout.addWidget(self.text_edit)

        self.edit_button = QtWidgets.QPushButton(util.make_icon(":/edit.png"), str(),
                clicked=self._on_edit_button_clicked)
        self.edit_button.setToolTip("Edit Device Notes")
        self.edit_button.setStatusTip(self.edit_button.toolTip())

        button_layout = QtWidgets.QVBoxLayout()
        button_layout.setContentsMargins(0, 0, 0, 0)
        button_layout.addWidget(self.edit_button, 0, Qt.AlignHCenter)
        button_layout.addStretch(1)

        layout.addLayout(button_layout)

        self._populate()
Example #15
0
    def __init__(self, title=str(), parent=None):
        super(SubProgressDialog, self).__init__(parent)
        self.log = util.make_logging_source_adapter(__name__, self)
        self.ui = util.loadUi(":/ui/subprogress_widget.ui")
        self.setWindowTitle(title)
        self.setWindowIcon(util.make_icon(":/window-icon.png"))

        l = QtWidgets.QHBoxLayout(self)
        l.setContentsMargins(0, 0, 0, 0)
        l.setSpacing(0)
        l.addWidget(self.ui)
        self.resize(300, 100)

        self.ui.cancel_button.clicked.connect(self.cancel)
        self._reset()
Example #16
0
        def wrapper(*args, **kwargs):

            f = func(*args, **kwargs)

            if f.done():
                return

            fo = FutureObserver(the_future=f)
            pd = QtWidgets.QProgressDialog()

            if not cancelable:
                pd.setCancelButton(None)

            fo.progress_range_changed.connect(pd.setRange)
            fo.progress_changed.connect(pd.setValue)
            fo.progress_text_changed.connect(pd.setLabelText)
            fo.done.connect(pd.close)

            pd.exec_()
Example #17
0
    def createEditor(self, parent, options, idx):
        if not self._is_device_rc(idx):
            return super(MCTreeItemDelegate,
                         self).createEditor(parent, options, idx)

        combo = QtWidgets.QComboBox(parent)
        combo = AutoPopupComboBox(parent)
        combo.addItem("RC on", True)
        combo.addItem("RC off", False)

        # Hack to make the combobox commit immediately after the user selects
        # an item.
        def on_combo_activated(index):
            self.commitData.emit(combo)
            self.closeEditor.emit(combo,
                                  QtWidgets.QAbstractItemDelegate.NoHint)

        combo.activated.connect(on_combo_activated)

        return combo
Example #18
0
 def __init__(self, parent=None):
     super(FixedWidthVerticalToolBar, self).__init__(parent)
     self.setLayout(QtWidgets.QVBoxLayout())
     self.layout().setContentsMargins(0, 0, 0, 0)
     self.layout().addStretch(1)
Example #19
0
def vline(parent=None):
    ret = QtWidgets.QFrame(parent)
    ret.setFrameShape(QtWidgets.QFrame.VLine)
    ret.setFrameShadow(QtWidgets.QFrame.Sunken)
    return ret
Example #20
0
    def on_actionAbout_triggered(self):
        try:
            from . import mc_version
            version = mc_version.version
        except ImportError:
            version = "devel version"

        d = QtWidgets.QDialog(self)
        d.setWindowTitle("About mesycontrol")

        license = QtWidgets.QTextBrowser(parent=d)
        license.setWindowFlags(Qt.Window)
        license.setWindowTitle("mesycontrol license")
        license.setText("")

        try:
            f = QtCore.QFile(":/gpl-notice.txt")
            if not f.open(QtCore.QIODevice.ReadOnly | QtCore.QIODevice.Text):
                return
            license.setPlainText(str(f.readAll(), 'utf-8'))
        finally:
            f.close()

        l = QtWidgets.QVBoxLayout(d)

        logo = QtWidgets.QLabel()
        logo.setPixmap(
            QtGui.QPixmap(":/mesytec-logo.png").scaledToWidth(
                300, Qt.SmoothTransformation))
        l.addWidget(logo)

        t = "mesycontrol - %s" % version
        label = QtWidgets.QLabel(t)
        font = label.font()
        font.setPointSize(15)
        font.setBold(True)
        label.setFont(font)
        l.addWidget(label)

        l.addWidget(QtWidgets.QLabel("Remote control for mesytec devices."))
        l.addWidget(QtWidgets.QLabel("© 2014-2022 mesytec GmbH & Co. KG"))

        t = '<a href="mailto:[email protected]">[email protected]</a> - <a href="http://www.mesytec.com">www.mesytec.com</a>'
        label = QtWidgets.QLabel(t)
        label.setOpenExternalLinks(True)
        l.addWidget(label)

        t = 'Running on Python %s using PySide2 %s with Qt %s.' % (
            platform.python_version(), PySide2.__version__,
            PySide2.QtCore.__version__)
        l.addWidget(QtWidgets.QLabel(t))

        l.addSpacing(20)

        bl = QtWidgets.QHBoxLayout()

        def license_button_clicked():
            sz = license.size()
            sz = sz.expandedTo(QtCore.QSize(500, 300))
            license.resize(sz)
            license.show()
            license.raise_()

        b = QtWidgets.QPushButton("&License", clicked=license_button_clicked)
        bl.addWidget(b)

        b = QtWidgets.QPushButton("&Close", clicked=d.close)
        b.setAutoDefault(True)
        b.setDefault(True)
        bl.addWidget(b)

        l.addLayout(bl)

        for item in (l.itemAt(i) for i in range(l.count())):
            item.setAlignment(Qt.AlignHCenter)

            w = item.widget()

            if isinstance(w, QtWidgets.QLabel):
                w.setTextInteractionFlags(Qt.TextBrowserInteraction)

        d.exec_()
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import random
import sys

from mesycontrol.qt import Qt
from mesycontrol.qt import QtCore
from mesycontrol.qt import QtGui
from mesycontrol.qt import QtWidgets
from mesycontrol.qt import PySide2

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)

    centerWidget = QtWidgets.QWidget()
    centerLayout = QtWidgets.QVBoxLayout(centerWidget)

    for i in range(10):
        letterCount = random.randint(0, 10)
        buttonText = f"Button {i}" + "z" * letterCount
        button = QtWidgets.QToolButton()
        button.setText(buttonText)
        button.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
                             QtWidgets.QSizePolicy.Fixed)
        centerLayout.addWidget(button)

    centerLayout.addStretch(1)
    centerWidget.setFixedWidth(centerWidget.sizeHint().width())

    leftTree = QtWidgets.QTreeView()
Example #22
0
    def __init__(self,
                 bus=None,
                 available_addresses=bm.ALL_DEVICE_ADDRESSES,
                 known_idcs=list(),
                 allow_custom_idcs=True,
                 title="Add Device",
                 selected_bus=None,
                 selected_address=None,
                 selected_idc=None,
                 assigned_name=None,
                 parent=None):
        """
        Dialog constructor.

        If `bus' is given the dialog will use it as the selected bus and won't
        allow the user to change the bus.

        `available_addresses` should be a list of (bus, address) pairs. These
        address pairs will be available for the user to choose from.

        `known_idcs` should be a list of (idc, name) pairs.

        If `allow_custom_idcs` is True the user may enter a custom IDC,
        otherwise only IDCs from `known_idcs` are selectable.

        If `known_idcs' is empty and `allow_custom_idcs' is False this method
        will raise an exception.

        If `selected_bus` and `selected_address` is not None the corresponding
        item will be preselected in the GUI.

        If `selected_idc` is not None the device type will be set using the given IDC
        and will not be modifyable.
        """

        if len(known_idcs) == 0 and not allow_custom_idcs:
            raise RuntimeError("No devices to choose from")

        if len(available_addresses) == 0 or (
                bus is not None and util.ilen_destructive(
                    filter(lambda x: x[0] == bus, available_addresses)) == 0):
            raise RuntimeError("No addresses available")

        super(AddDeviceDialog, self).__init__(parent)

        self.log = util.make_logging_source_adapter(__name__, self)

        self.setWindowTitle(title)
        self._result = None
        self.allow_custom_idcs = allow_custom_idcs

        self.bus_combo = QtWidgets.QComboBox()
        self.bus_combo.addItems([str(i) for i in bm.BUS_RANGE])

        self.address_combos = [QtWidgets.QComboBox() for i in bm.BUS_RANGE]

        for b, a in sorted(available_addresses):
            self.address_combos[b].addItem("%X" % a, a)

        self.address_combo_stack = QtWidgets.QStackedWidget()

        for combo in self.address_combos:
            self.address_combo_stack.addWidget(combo)

        self.bus_combo.activated.connect(
            self.address_combo_stack.setCurrentIndex)

        self.idc_combo = EatReturnCombo()
        for idc, name in sorted(known_idcs, key=lambda x: x[1]):
            self.idc_combo.addItem("%s (%d)" % (name, idc), idc)

        if self.idc_combo.findData(idc) < 0:
            self.idc_combo.addItem(str(idc), idc)

        if selected_idc is not None:
            self.log.debug("selected_idc=%d, idx=%d", selected_idc,
                           self.idc_combo.findData(selected_idc))

            self.idc_combo.setCurrentIndex(
                self.idc_combo.findData(selected_idc))
            self.idc_combo.setEnabled(False)

        if bus is not None:
            self.bus_combo.setCurrentIndex(bus)
            self.address_combo_stack.setCurrentIndex(bus)

        self.name_input = QtWidgets.QLineEdit()

        if assigned_name is not None:
            self.name_input.setText(assigned_name)

        self.button_box = QtWidgets.QDialogButtonBox(
            QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel)

        if allow_custom_idcs:
            self.idc_combo.setEditable(True)
            self.idc_combo.setValidator(QtGui.QIntValidator(1, 99))

            ok_button = self.button_box.button(QtWidgets.QDialogButtonBox.Ok)
            ok_button.setEnabled(len(known_idcs))

            def combo_index_changed():
                ok_button.setEnabled(True)

            def combo_le_text_edited():
                ok_button.setEnabled(
                    self.idc_combo.lineEdit().hasAcceptableInput())

            self.idc_combo.currentIndexChanged.connect(combo_index_changed)
            self.idc_combo.lineEdit().textEdited.connect(combo_le_text_edited)

        if selected_bus is not None:
            assert selected_bus in bm.BUS_RANGE
            self.bus_combo.setCurrentIndex(selected_bus)
            self.address_combo_stack.setCurrentIndex(selected_bus)

            if selected_address is not None:
                assert selected_address in bm.DEV_RANGE
                combo = self.address_combo_stack.currentWidget()
                combo.setCurrentIndex(combo.findText("%X" % selected_address))

        def accept():
            bus = self.bus_combo.currentIndex()
            address = int(self.address_combos[bus].itemData(
                self.address_combos[bus].currentIndex()))

            if self.allow_custom_idcs and self.idc_combo.lineEdit(
            ).hasAcceptableInput():
                idc = int(self.idc_combo.lineEdit().text())
            else:
                idx = self.idc_combo.currentIndex()
                idc = int(self.idc_combo.itemData(idx))

            name = self.name_input.text()

            self._result = AddDeviceDialog.Result(bus, address, idc, name)

            super(AddDeviceDialog, self).accept()

        self.button_box.accepted.connect(accept)
        self.button_box.rejected.connect(self.reject)

        layout = QtWidgets.QFormLayout(self)
        layout.addRow("Bus", self.bus_combo)
        layout.addRow("Address", self.address_combo_stack)
        layout.addRow("IDC", self.idc_combo)
        layout.addRow("Name", self.name_input)
        layout.addRow(self.button_box)
Example #23
0
        layout = QtWidgets.QFormLayout(self)
        layout.addRow("Bus", self.bus_combo)
        layout.addRow("Address", self.address_combo_stack)
        layout.addRow("IDC", self.idc_combo)
        layout.addRow("Name", self.name_input)
        layout.addRow(self.button_box)

    def result(self):
        return self._result


if __name__ == "__main__":
    from functools import partial
    import sys

    a = QtWidgets.QApplication(sys.argv)

    dialogs = list()
    d = AddDeviceDialog()
    dialogs.append(d)

    d = AddDeviceDialog(bus=1)
    dialogs.append(d)

    d = AddDeviceDialog(available_addresses=[(0, 1), (1, 1), (0, 15), (1, 13)])
    dialogs.append(d)

    d = AddDeviceDialog(bus=1,
                        available_addresses=[(0, 1), (1, 1), (0, 15), (1, 13)])
    dialogs.append(d)
Example #24
0
 def get_toolbar(self):
     if self._toolbar is None:
         self._toolbar = tb = QtWidgets.QToolBar()
         for a in self._actions.values():
             tb.addAction(a)
     return self._toolbar
Example #25
0
    def __init__(self,
                 device,
                 display_mode=util.COMBINED,
                 write_mode=util.COMBINED,
                 parent=None):

        super(DeviceTableWidget, self).__init__(parent)

        self.log = util.make_logging_source_adapter(__name__, self)
        settings = util.loadUi(":/ui/device_tableview_settings.ui")

        self.log.debug("display_mode=%d, write_mode=%d", display_mode,
                       write_mode)

        model = DeviceTableModel(device,
                                 display_mode=display_mode,
                                 write_mode=write_mode)
        self.view = DeviceTableView(model=model)
        sort_model = self.view.sort_model

        self.view.display_mode_changed.connect(self.display_mode_changed)
        self.view.write_mode_changed.connect(self.write_mode_changed)

        menu = QtWidgets.QMenu('Filter options', self)
        action = menu.addAction("Hide unknown")
        action.setCheckable(True)
        action.setChecked(sort_model.filter_unknown)
        action.triggered.connect(sort_model.set_filter_unknown)

        action = menu.addAction("Hide read-only")
        action.setCheckable(True)
        action.setChecked(sort_model.filter_readonly)
        action.triggered.connect(sort_model.set_filter_readonly)

        action = menu.addAction("Hide volatile")
        action.setCheckable(True)
        action.setChecked(sort_model.filter_volatile)
        action.triggered.connect(sort_model.set_filter_volatile)

        action = menu.addAction("Hide static")
        action.setCheckable(True)
        action.setChecked(sort_model.filter_static)
        action.triggered.connect(sort_model.set_filter_static)

        menu.addSeparator()

        action = menu.addAction("Ignore param ranges on edit")
        action.setCheckable(True)
        action.triggered.connect(model.set_editing_ignore_parameter_ranges)

        action = menu.addAction("Hexadecimal values")
        action.setCheckable(True)
        action.triggered.connect(model.set_display_hex_values)

        menu.addSeparator()

        action = menu.addAction("Resize table cells")
        action.triggered.connect(self.view.resizeColumnsToContents)
        action.triggered.connect(self.view.resizeRowsToContents)

        settings.pb_settings.setMenu(menu)

        settings.le_filter.textChanged.connect(sort_model.setFilterWildcard)

        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(settings)
        layout.addWidget(self.view)
        self.setLayout(layout)
Example #26
0
factory.append_predicate_binding(
        RadioButtonGroupParameterBinding.predicate, RadioButtonGroupParameterBinding)

factory.append_classinfo_binding(
        QtWidgets.QLCDNumber, LCDNumberParameterBinding)

factory.append_classinfo_binding(
        QtWidgets.QSlider, SliderParameterBinding)

factory.append_predicate_binding(
        lambda target: target is None, TargetlessParameterBinding)

if __name__ == "__main__":
    import mock

    app = QtWidgets.QApplication([])

    device = mock.MagicMock()
    profile = mock.MagicMock()
    display_mode = util.CONFIG
    write_mode = util.COMBINED
    target = QtWidgets.QSpinBox()

    d = dict(device=device)

    binding = factory.make_binding(device=device, profile=profile, display_mode=display_mode,
            write_mode=write_mode, target=target)

    target2 = util.DelayedDoubleSpinBox()
    binding2 = factory.make_binding(device=device, profile=profile, display_mode=display_mode,
            write_mode=write_mode, unit_name="the_unit_name", target=target2)
Example #27
0
    def __init__(self,
                 app_registry,
                 device_registry,
                 linked_mode_on=False,
                 parent=None):
        super(MCTreeView, self).__init__(parent)
        self.log = util.make_logging_source_adapter(__name__, self)

        self._director = MCTreeDirector(app_registry=app_registry,
                                        device_registry=device_registry,
                                        linked_mode_on=linked_mode_on)

        self.cfg_model = self._director.cfg_model
        self.hw_model = self._director.hw_model

        self.cfg_view = ConfigTreeView()
        self.cfg_view.setObjectName('config_tree_view')
        self.cfg_view.setModel(self.cfg_model)
        self.cfg_model.rowsInserted.connect(self.cfg_view.expandAll)

        def on_cfg_rows_removed(parentIndex, start, end):
            self.log.debug(
                f"on_cfg_rows_removed parentIndex={parentIndex} start={start} end={end}"
            )
            self.cfg_view.rowsRemoved(parentIndex, start, end)
            self.cfg_view.resizeColumnToContents(0)

        self.cfg_model.rowsRemoved.connect(on_cfg_rows_removed)

        def resize_cfg_cols():
            self.cfg_view.resizeColumnToContents(0)

        self.cfg_model.rowsInserted.connect(resize_cfg_cols)

        self.cfg_view.customContextMenuRequested.connect(
            self._cfg_context_menu)
        self.cfg_view.expanded.connect(self._cfg_expanded)
        self.cfg_view.collapsed.connect(self._cfg_collapsed)
        self.cfg_view.setItemDelegate(MCTreeItemDelegate(self._director))

        self.cfg_view.selectionModel().selectionChanged.connect(
            self._cfg_selection_changed)
        self.cfg_view.doubleClicked.connect(self._cfg_view_double_clicked)
        self.cfg_view.clicked.connect(self._cfg_view_clicked)

        self.hw_view = HardwareTreeView()
        self.hw_view.setObjectName('hardware_tree_view')
        self.hw_view.setModel(self.hw_model)
        self.hw_model.rowsInserted.connect(self.hw_view.expandAll)

        def on_hw_rows_removed(parentIndex, start, end):
            self.log.debug(
                f"on_hw_rows_removed parentIndex={parentIndex} start={start} end={end}"
            )
            self.hw_view.rowsRemoved(parentIndex, start, end)
            self.hw_view.resizeColumnToContents(0)

        self.hw_model.rowsRemoved.connect(on_hw_rows_removed)

        def resize_hw_cols():
            self.hw_view.resizeColumnToContents(0)

        self.hw_model.rowsInserted.connect(resize_hw_cols)

        self.hw_view.customContextMenuRequested.connect(self._hw_context_menu)
        self.hw_view.expanded.connect(self._hw_expanded)
        self.hw_view.collapsed.connect(self._hw_collapsed)
        self.hw_view.setItemDelegate(MCTreeItemDelegate(self._director))
        self.hw_view.setFirstColumnSpanned(0, QtCore.QModelIndex(), True)

        self.hw_view.selectionModel().selectionChanged.connect(
            self._hw_selection_changed)
        self.hw_view.doubleClicked.connect(self._hw_view_double_clicked)
        self.hw_view.clicked.connect(self._hw_view_clicked)

        self.cfg_view.expandAll()
        self.hw_view.expandAll()

        self.splitter_toolbar = util.SimpleToolBar(Qt.Vertical)
        self.cfg_toolbar = util.SimpleToolBar(Qt.Horizontal)
        self.cfg_toolbar.layout().setContentsMargins(0, 0, 0, 0)
        self.hw_toolbar = util.SimpleToolBar(Qt.Horizontal)
        self.hw_toolbar.layout().setContentsMargins(0, 0, 0, 0)

        cfg_widget = QtWidgets.QGroupBox("Config")
        cfg_layout = QtWidgets.QVBoxLayout(cfg_widget)
        cfg_layout.setContentsMargins(2, 2, 2, 2)
        cfg_layout.addWidget(self.cfg_toolbar)
        cfg_layout.addWidget(self.cfg_view)
        cfg_layout.setStretch(1, 1)

        hw_widget = QtWidgets.QGroupBox("Hardware")
        hw_layout = QtWidgets.QVBoxLayout(hw_widget)
        hw_layout.setContentsMargins(2, 2, 2, 2)
        hw_layout.addWidget(self.hw_toolbar)
        hw_layout.addWidget(self.hw_view)
        hw_layout.setStretch(1, 1)

        center_widget = QtWidgets.QGroupBox("Actions")
        center_layout = QtWidgets.QVBoxLayout(center_widget)
        center_layout.setContentsMargins(2, 2, 2, 2)
        center_layout.addWidget(self.splitter_toolbar)
        self.center_widget = center_widget

        self.splitter = splitter = DoubleClickSplitter()
        splitter.setChildrenCollapsible(False)
        splitter.addWidget(hw_widget)
        splitter.addWidget(center_widget)
        splitter.addWidget(cfg_widget)

        def on_handle_double_clicked():
            # make hw and cfg views the same size which will result in the
            # splitter buttons being centered
            sizes = splitter.sizes()
            size = (sizes[0] + sizes[2]) / 2
            sizes[0], sizes[2] = size, size
            splitter.setSizes(sizes)

        splitter.handle(1).doubleClicked.connect(on_handle_double_clicked)
        splitter.handle(2).doubleClicked.connect(on_handle_double_clicked)

        layout = QtWidgets.QGridLayout(self)
        layout.addWidget(splitter, 0, 0)

        self._ignore_next_selection = False
Example #28
0
 def addAction(self, action) -> QtWidgets.QToolButton:
     super(SimpleToolBar, self).addAction(action)
     b = QtWidgets.QToolButton()
     b.setDefaultAction(action)
     self.addWidget(b)
     return b
Example #29
0
            finally:
                self.setTextColor(self._original_text_color)

    def contextMenuEvent(self, event):
        pos  = event.globalPos()
        menu = self.createStandardContextMenu(pos)
        menu.addAction("Clear").triggered.connect(self.clear)
        menu.exec_(pos)

if __name__ == "__main__":
    logging.basicConfig(level=logging.DEBUG,
            format='[%(asctime)-15s] [%(name)s.%(levelname)s] %(message)s')
    qapp = QtGui.QApplication(sys.argv)

    log_view = LogView()
    log_view.resize(400, 400)
    log_view.show()

    qt_logger = util.QtLogEmitter()
    qt_logger.log_record.connect(log_view.handle_log_record)
    logging.getLogger().addHandler(qt_logger.get_handler())

    logger = logging.getLogger(__name__)
    def on_button_clicked():
        logging.getLogger("testlogger").debug("Hello World!")

    button = QtWidgets.QPushButton("Log!", clicked=on_button_clicked)
    button.show()

    sys.exit(qapp.exec_())
Example #30
0
def mesycontrol_gui_main():
    faulthandler.enable()

    if not is_windows:
        parser = argparse.ArgumentParser(
            description='mesycontrol GUI command line arguments')
        parser.add_argument('--logging-config', metavar='FILE')
        parser.add_argument('--setup', metavar='FILE')
        opts = parser.parse_args()
    else:
        opts = None

    # Logging setup
    if opts is not None and opts.logging_config is not None:
        logging.config.fileConfig(opts.logging_config)
    else:
        logging.basicConfig(
            level=logging.DEBUG,
            format='[%(asctime)-15s] [%(name)s.%(levelname)-8s] %(message)s')

        if colorlog and (not is_windows or colorama):
            fmt = '%(bg_blue)s[%(asctime)-15s]%(reset)s '
            fmt += '[%(green)s%(name)s%(reset)s.%(log_color)s%(levelname)-8s%(reset)s] %(message)s'
            fmt = colorlog.ColoredFormatter(fmt)
            hdlr = logging.getLogger().handlers[0]
            hdlr.setFormatter(fmt)

        # Lower the log level for certain loggers.
        for ln in (
                "basic_tree_model",
                "future",
                "mc_treeview",
                #"tcp_client.MCTCPClient",
                "hardware_controller.Controller",
                "PyQt4.uic"):
            logging.getLogger(ln).setLevel(logging.INFO)

        fn = QtCore.QStandardPaths.writableLocation(
            QtCore.QStandardPaths.DocumentsLocation)
        fn = os.path.join(str(fn), "mesycontrol.log")

        try:
            fh = logging.FileHandler(fn, "w")
            fh.setFormatter(
                logging.Formatter(
                    fmt=
                    '[%(asctime)-15s] [%(name)s.%(levelname)-8s] %(message)s'))
            logging.getLogger().addHandler(fh)
        except IOError:
            pass

    logging.info("Starting up...")

    logging.info("Running on Python version %s", sys.version)

    # Signal handling
    signal.signum_to_name = dict((getattr(signal, n), n) for n in dir(signal)
                                 if n.startswith('SIG') and '_' not in n)

    class SignalHandler(object):
        def __init__(self):
            self._called = False
            self._app = None

        def set_app(self, app):
            self._app = weakref.ref(app)

        def get_app(self):
            return self._app() if self._app is not None else None

        def __call__(self, signum, frame):

            if not self._called and self.get_app() is not None:
                logging.info("Received signal %s. Quitting...",
                             signal.signum_to_name.get(signum, "%d" % signum))

                self._called = True
                self.get_app().quit()
            else:
                logging.info("Received signal %s. Forcing quit...",
                             signal.signum_to_name.get(signum, "%d" % signum))

                QtWidgets.QApplication.quit()

    sigint_handler = SignalHandler()
    signal.signal(signal.SIGINT, sigint_handler)

    # Create an exception hook registry and register the original handler with
    # it.
    sys.excepthook = util.ExceptionHookRegistry()
    sys.excepthook.register_handler(sys.__excepthook__)

    # Qt setup
    QtCore.QLocale.setDefault(QtCore.QLocale.c())
    QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_ShareOpenGLContexts, True)
    app = QtWidgets.QApplication(sys.argv)
    app.setStyle(QtWidgets.QStyleFactory.create("Windows"))
    app.setAttribute(Qt.AA_DontShowIconsInMenus, False)

    # Let the interpreter run every 500 ms to be able to react to signals
    # arriving from the OS.
    timer = QtCore.QTimer()
    timer.timeout.connect(lambda: None)
    timer.start(500)

    # Confine garbage collection to the main thread to avoid crashes.
    garbage_collector = util.GarbageCollector()

    # Path setup
    main_file = sys.executable if getattr(sys, 'frozen', False) else __file__
    bin_dir = os.path.abspath(os.path.dirname(main_file))

    # Update the environments path to easily find the mesycontrol_server binary.
    os.environ['PATH'] = bin_dir + os.pathsep + os.environ['PATH']

    logging.debug("main_file=%s, bin_dir=%s", main_file, bin_dir)

    # Application setup
    context = app_context.Context(main_file, auto_load_device_modules=False)
    setup_file = None
    settings = context.make_qsettings()

    if opts is not None and opts.setup is not None:
        setup_file = opts.setup
    elif bool(
            settings.value('Options/open_last_setup_at_start', True,
                           type=bool)):
        setup_file = settings.value('Files/last_setup_file', str())

    with app_context.use(context):
        mainwindow = gui_mainwindow.MainWindow(context)
        gui_application = gui.GUIApplication(context, mainwindow)
        sigint_handler.set_app(gui_application)
        mainwindow.show()
        mainwindow.restore_settings()

        if setup_file:
            try:
                context.open_setup(setup_file)
            except Exception as e:
                settings.remove('Files/last_setup_file')
                QtWidgets.QMessageBox.critical(
                    mainwindow, "Error",
                    "Opening setup file %s failed:\n%s" % (setup_file, e))

        def on_qapp_about_to_quit():
            logging.debug(
                "received signal QApplication.aboutToQuit(), calling Context.shutdown()"
            )
            # Call shutdown() here while the eventloop (app.exec_()) is still running.
            context.shutdown()

        app.aboutToQuit.connect(on_qapp_about_to_quit)

        ret = app.exec_()
        logging.debug("app.exec_() returned %d", ret)

    del mainwindow
    del garbage_collector

    sys.exit(ret)