Changeset 72651df in sasview


Ignore:
Timestamp:
Nov 23, 2018 7:23:04 AM (3 weeks ago)
Author:
Piotr Rozyczko <piotr.rozyczko@…>
Branches:
ESS_GUI, ESS_GUI_Invariant, ESS_GUI_batch_fitting, ESS_GUI_ordering
Children:
9817207
Parents:
f2e199e
Message:

Implemented drag and drop on items in the Tab List widget. SASVIEW-568

Location:
src/sas/qtgui/Perspectives/Fitting
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • src/sas/qtgui/Perspectives/Fitting/ConstraintWidget.py

    r21e71f1 r72651df  
    1919from sas.qtgui.Perspectives.Fitting.Constraint import Constraint 
    2020 
     21class DnDTableWidget(QtWidgets.QTableWidget): 
     22    def __init__(self, *args, **kwargs): 
     23        super().__init__(*args, **kwargs) 
     24 
     25        self.setDragEnabled(True) 
     26        self.setAcceptDrops(True) 
     27        self.viewport().setAcceptDrops(True) 
     28        self.setDragDropOverwriteMode(False) 
     29        self.setDropIndicatorShown(True) 
     30 
     31        self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) 
     32        self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) 
     33        self.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove) 
     34 
     35        self._is_dragged = True 
     36 
     37    def isDragged(self): 
     38        """ 
     39        Return the drag status 
     40        """ 
     41        return self._is_dragged 
     42 
     43    def dragEnterEvent(self, event): 
     44        """ 
     45        Called automatically on a drag in the TableWidget 
     46        """ 
     47        self._is_dragged = True 
     48        event.accept() 
     49 
     50    def dragLeaveEvent(self, event): 
     51        """ 
     52        Called automatically on a drag stop 
     53        """ 
     54        self._is_dragged = False 
     55        event.accept() 
     56 
     57    def dropEvent(self, event: QtGui.QDropEvent): 
     58        if not event.isAccepted() and event.source() == self: 
     59            drop_row = self.drop_on(event) 
     60            rows = sorted(set(item.row() for item in self.selectedItems())) 
     61            rows_to_move = [[QtWidgets.QTableWidgetItem(self.item(row_index, column_index)) for column_index in range(self.columnCount())] 
     62                            for row_index in rows] 
     63            for row_index in reversed(rows): 
     64                self.removeRow(row_index) 
     65                if row_index < drop_row: 
     66                    drop_row -= 1 
     67 
     68            for row_index, data in enumerate(rows_to_move): 
     69                row_index += drop_row 
     70                self.insertRow(row_index) 
     71                for column_index, column_data in enumerate(data): 
     72                    self.setItem(row_index, column_index, column_data) 
     73            event.accept() 
     74            for row_index in range(len(rows_to_move)): 
     75                self.item(drop_row + row_index, 0).setSelected(True) 
     76                self.item(drop_row + row_index, 1).setSelected(True) 
     77        super().dropEvent(event) 
     78        # Reset the drag flag. Must be done after the drop even got accepted! 
     79        self._is_dragged = False 
     80 
     81    def drop_on(self, event): 
     82        index = self.indexAt(event.pos()) 
     83        if not index.isValid(): 
     84            return self.rowCount() 
     85 
     86        return index.row() + 1 if self.is_below(event.pos(), index) else index.row() 
     87 
     88    def is_below(self, pos, index): 
     89        rect = self.visualRect(index) 
     90        margin = 2 
     91        if pos.y() - rect.top() < margin: 
     92            return False 
     93        elif rect.bottom() - pos.y() < margin: 
     94            return True 
     95 
     96        return rect.contains(pos, True) and not \ 
     97            (int(self.model().flags(index)) & QtCore.Qt.ItemIsDropEnabled) and \ 
     98            pos.y() >= rect.center().y() 
     99 
     100 
    21101class ConstraintWidget(QtWidgets.QWidget, Ui_ConstraintWidgetUI): 
    22102    """ 
     
    29109    def __init__(self, parent=None): 
    30110        super(ConstraintWidget, self).__init__() 
     111 
    31112        self.parent = parent 
    32113        self.setupUi(self) 
     
    36117        self.page_id = 301 
    37118        self.tab_id = self.page_id 
     119        # fitpage order in the widget 
     120        self._row_order = [] 
     121 
     122        # Set the table widget into layout 
     123        self.tblTabList = DnDTableWidget(self) 
     124        self.tblLayout.addWidget(self.tblTabList) 
    38125 
    39126        # Are we chain fitting? 
     
    261348        Respond to check/uncheck and to modify the model moniker actions 
    262349        """ 
     350        # If this "Edit" is just a response from moving rows around, 
     351        # update the tab order and leave 
     352        if self.tblTabList.isDragged(): 
     353            self._row_order = [] 
     354            for i in range(self.tblTabList.rowCount()): 
     355                self._row_order.append(self.tblTabList.item(i,0).data(0)) 
     356            return 
     357 
    263358        item = self.tblTabList.item(row, column) 
    264359        if column == 0: 
     
    281376            self.tblTabList.blockSignals(False) 
    282377            self.cmdFit.setEnabled(False) 
     378            if new_moniker == "": 
     379                msg = "Please use a non-empty name." 
     380            else: 
     381                msg = "Please use a unique name." 
     382            self.parent.communicate.statusBarUpdateSignal.emit(msg) 
     383            item.setToolTip(msg) 
    283384            return 
    284385        self.tblTabList.blockSignals(True) 
     
    286387        self.tblTabList.blockSignals(False) 
    287388        self.cmdFit.setEnabled(True) 
     389        item.setToolTip("") 
     390        msg = "Fitpage name changed to {}.".format(new_moniker) 
     391        self.parent.communicate.statusBarUpdateSignal.emit(msg) 
     392 
    288393        if not self.current_cell: 
    289394            return 
     
    682787 
    683788        tabs = [tab for tab in ObjectLibrary.listObjects() if self.isTabImportable(tab)] 
     789        if not self._row_order: 
     790            # Initialize tab order list 
     791            self._row_order = tabs 
     792        else: 
     793            tabs = self.orderedSublist(self._row_order, tabs) 
     794            self._row_order = tabs 
     795 
    684796        for tab in tabs: 
    685797            self.updateFitLine(tab) 
     
    687799            # We have at least 1 fit page, allow fitting 
    688800            self.cmdFit.setEnabled(True) 
     801 
     802    def orderedSublist(self, order_list, target_list): 
     803        """ 
     804        Orders the target_list such that any elements 
     805        present in order_list show up first and in the order 
     806        from order_list. 
     807        """ 
     808        tmp_list = [] 
     809        # 1. get the non-matching elements 
     810        nonmatching = list(set(target_list) - set(order_list)) 
     811        # 2: start with matching tabs, in the correct order 
     812        for elem in order_list: 
     813            if elem in target_list: 
     814                tmp_list.append(elem) 
     815        # 3. add the remaning tabs in any order 
     816        ordered_list = tmp_list + nonmatching 
     817        return ordered_list 
    689818 
    690819    def validateMoniker(self, new_moniker=None): 
  • src/sas/qtgui/Perspectives/Fitting/UI/ConstraintWidgetUI.ui

    recc5d043 r72651df  
    1414   <string>Constrained and Simultaneous Fit</string> 
    1515  </property> 
    16   <layout class="QGridLayout" name="gridLayout_2"> 
     16  <layout class="QGridLayout" name="gridLayout_3"> 
    1717   <item row="0" column="0"> 
    1818    <widget class="QGroupBox" name="groupBox"> 
     
    2020      <string>Source choice for simultaneous fitting</string> 
    2121     </property> 
    22      <layout class="QVBoxLayout" name="verticalLayout"> 
    23       <item> 
     22     <layout class="QGridLayout" name="gridLayout_2"> 
     23      <item row="0" column="0"> 
    2424       <layout class="QHBoxLayout" name="horizontalLayout_2"> 
    2525        <item> 
     
    6262       </layout> 
    6363      </item> 
    64       <item> 
    65        <widget class="QTableWidget" name="tblTabList"> 
    66         <property name="sizePolicy"> 
    67          <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> 
    68           <horstretch>0</horstretch> 
    69           <verstretch>0</verstretch> 
    70          </sizepolicy> 
    71         </property> 
    72         <property name="contextMenuPolicy"> 
    73          <enum>Qt::ActionsContextMenu</enum> 
    74         </property> 
    75         <property name="alternatingRowColors"> 
    76          <bool>true</bool> 
    77         </property> 
    78         <property name="selectionBehavior"> 
    79          <enum>QAbstractItemView::SelectRows</enum> 
    80         </property> 
    81        </widget> 
     64      <item row="1" column="0"> 
     65       <layout class="QHBoxLayout" name="tblLayout"/> 
    8266      </item> 
    8367     </layout> 
Note: See TracChangeset for help on using the changeset viewer.