class OperationsOverviewWidget(QWidget): def __init__(self,parent=None): super(OperationsOverviewWidget,self).__init__(parent) self.operation_prototype = [] self.operation_prototype.append( OperationDefinitionPrototype('operation_definition_id',_('Op.'),operation_definition_cache.all_on_order_part(), editable=False)) self.operation_prototype.append( TextAreaPrototype('description',_('Description'),nullable=True,editable=False)) self.operation_prototype.append( FloatNumberPrototype('value',_('Value'),nullable=True,editable=False)) self.operation_prototype.append( DurationPrototype('planned_hours',_('Planned time'),nullable=True,editable=False)) # operation_prototype.append( DurationPrototype('t_reel',_('Used time'),nullable=False,editable=False)) self.operation_prototype.append( DurationPrototype('done_hours',_('Imputations'),editable=False)) # operation_prototype.append( TextLinePrototype('note',_('Note'),editable=True,nullable=True,hidden=True)) self.model = PrototypedModelView(self.operation_prototype,self) self.view = PrototypedQuickView(self.operation_prototype,self) self.view.setModel(self.model) self.view.verticalHeader().hide() self.view.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents) # Description column wide enough self.view.horizontalHeader().setResizeMode(1,QHeaderView.Stretch) self.view.setWordWrap(True) self.view.setSelectionBehavior(QAbstractItemView.SelectRows) self.view.setSelectionMode(QAbstractItemView.ExtendedSelection) # self.controller_operation = PrototypeController(self, # self.operation_prototype, # ProxyTableView(None,self.operation_prototype)) # self.controller_operation.view.verticalHeader().hide() # # self.controller_operation.setModel(TrackingProxyModel(None,operation_prototype)) # self.controller_operation.setModel(TrackingProxyModel(self,self.operation_prototype)) # self.controller_operation.view.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents) # Description column wide enough # self.controller_operation.view.horizontalHeader().setResizeMode(1,QHeaderView.Stretch) # self.controller_operation.view.setSelectionBehavior(QAbstractItemView.SelectRows) layout = QHBoxLayout() layout.setContentsMargins(0,0,0,0) layout.addWidget(self.view) self.setLayout(layout) self.copy_operations_action = QAction(_("Copy operations"),self.view) self.copy_operations_action.triggered.connect( self.copy_operations_slot) self.copy_operations_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_C)) self.copy_operations_action.setShortcutContext(Qt.WidgetWithChildrenShortcut) self.view.addAction(self.copy_operations_action) def fill_order_part(self, order_part_id): """ Fill with order part's data. Doesn't keep any reference to the order part. """ if order_part_id: mainlog.debug("fill_order_part : triggered !") operations = dao.operation_dao.find_by_order_part_id_frozen(order_part_id) mainlog.debug("fill_order_part : build model !") self.model.buildModelFromObjects(operations) mainlog.debug("fill_order_part : build model complete !") self.view.verticalHeader().setResizeMode(QHeaderView.ResizeToContents) else: self.model.clear() ndx = self.model.index(0,0) mainlog.debug("fill_order_part : setCurrentIndex !") self.view.setCurrentIndex(ndx) mainlog.debug("fill_order_part : setCurrentIndex done!") @Slot() def copy_operations_slot(self): mainlog.debug("copy_operations_slot") view = self.view model = self.model # Collect the rows indices rows = set() for ndx in view.selectedIndexes(): if ndx.row() >= 0: rows.add(ndx.row()) # There are no guarantee on the selectedIndexes order rows = sorted(list(rows)) # Copy for elsewhere in Horse if len(rows): operations = [] for row_ndx in rows: operation = model.object_at(row_ndx) mainlog.debug(operation) operations.append(operation) copy_paste_manager.copy_operations(operations) else: # If nothing to copy then we leave the copy/paste clipboard # as it is. So one could paste again what he copied before. pass
class DeliverySlipPanel(HorsePanel): delivery_slip_changed = Signal() def close_panel(self): self.filter_widget.remember_current_selection( configuration) def _selected_slip(self): cur_ndx = self.search_results_view.currentIndex() if cur_ndx.row() >= 0: return cur_ndx.model().object_at(cur_ndx.row()) return None def reprint(self): cur_ndx = self.search_results_view.currentIndex() slip_id = cur_ndx.model().index(cur_ndx.row(),0).data() if dao.delivery_slip_part_dao.id_exists(slip_id): print_delivery_slip(dao,slip_id) else: makeErrorBox(_("The delivery slip {} doesn't exist").format(slip_id)).exec_() def desactivate(self): slip_id = self._selected_slip().delivery_slip_id mainlog.debug("Desactivate slip {}".format(slip_id)) dao.delivery_slip_part_dao.deactivate(slip_id) self.refresh(slip_id) self.delivery_slip_changed.emit() def activate(self): slip_id = self._selected_slip().delivery_slip_id dao.delivery_slip_part_dao.activate(slip_id) self.refresh(slip_id) self.delivery_slip_changed.emit() def delete(self): slip_id = self._selected_slip().delivery_slip_id dao.delivery_slip_part_dao.delete_last(slip_id) self.refresh(slip_id) self.delivery_slip_changed.emit() @Slot() def show_actions(self): button = self.action_menu.parent() p = button.mapToGlobal(QPoint(0,button.height())) self.action_menu.exec_(p) @Slot() def _toggle_edit_filters(self): self.filter_widget.setVisible( not self.filter_widget.isVisible()) def __init__(self,parent): super(DeliverySlipPanel,self).__init__(parent) title = _("Delivery slips") self.slip_data = None self.set_panel_title(_("Delivery slip overview")) self.reprint_delivery_slip = QAction(_("Reprint delivery slip"),self) # , parent self.reprint_delivery_slip.triggered.connect( self.reprint) # self.reprint_delivery_slip.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_V)) self.reprint_delivery_slip.setShortcutContext(Qt.WidgetWithChildrenShortcut) # self.controller_operation.view.addAction(self.reprint_delivery_slip) self.desactivate_delivery_slip = QAction(_("Desactivate delivery slip"),self) # , parent self.desactivate_delivery_slip.triggered.connect( self.desactivate) self.desactivate_delivery_slip.setShortcutContext(Qt.WidgetWithChildrenShortcut) self.activate_delivery_slip = QAction(_("Activate delivery slip"),self) # , parent self.activate_delivery_slip.triggered.connect( self.activate) self.activate_delivery_slip.setShortcutContext(Qt.WidgetWithChildrenShortcut) self.delete_delivery_slip = QAction(_("Delete delivery slip"),self) # , parent self.delete_delivery_slip.triggered.connect( self.delete) self.delete_delivery_slip.setShortcutContext(Qt.WidgetWithChildrenShortcut) filter_family = FilterQuery.DELIVERY_SLIPS_FAMILY self.filter_widget = PersistentFilter( filter_family, suggestion_finder) self.filter_widget.apply_filter.connect(self.apply_filter_slot) self.filter_widget.hide() navigation = NavBar( self, [ (self.filter_widget.get_filters_combo(), None), (_("Edit filter"),self._toggle_edit_filters), (_("Action"),self.show_actions) ] ) self.title_widget = TitleWidget(title, self, navigation) # navigation) self.action_menu = QMenu(navigation.buttons[0]) list_actions = [ (self.reprint_delivery_slip,None), (self.activate_delivery_slip,None), (self.desactivate_delivery_slip,None), # (self.delete_delivery_slip,None) ] populate_menu(self.action_menu, self, list_actions, context=Qt.WidgetWithChildrenShortcut) # self.setWindowTitle(title) top_layout = QVBoxLayout(self) # self.filter_line_edit = QLineEdit() # self.filter_line_edit = QueryLineEdit(suggestion_finder) initialize_customer_cache() # FIXME Not the place to do that # filter_family = 'delivery_slips' # self.filter_name = FiltersCombo(self, filter_family) # filter_widget = PersistentFilter(filter_family, self.filter_name) # filter_widget.apply_filter.connect(self.apply_filter_slot) self.proto = [] self.proto.append( IntegerNumberPrototype('delivery_slip_id',_("Slip Nr"), editable=False)) self.proto.append( DatePrototype('creation',_('Date'), editable=False)) self.proto.append( TextLinePrototype('fullname',_('Customer'), editable=False)) self.proto.append( TextLinePrototype('user_label',_('Order'), editable=False)) self.search_results_model = DeliverySlipPanelModel(self.proto, self) self.search_results_view = PrototypedQuickView(self.proto, self) self.search_results_view.setModel(self.search_results_model) self.search_results_view.verticalHeader().hide() self.search_results_view.horizontalHeader().setResizeMode(1, QHeaderView.ResizeToContents) self.search_results_view.horizontalHeader().setResizeMode(2, QHeaderView.Stretch) self.search_results_view.horizontalHeader().setSortIndicatorShown(True) self.search_results_view.horizontalHeader().setSortIndicator(0,Qt.AscendingOrder) self.search_results_view.horizontalHeader().sectionClicked.connect(self._section_clicked) self.search_results_view.setSelectionBehavior(QAbstractItemView.SelectRows) self.search_results_view.setSelectionMode(QAbstractItemView.SingleSelection) self.search_results_view.selectionModel().currentRowChanged.connect(self.row_selected) self.slip_part_view = DeliverySlipViewWidget(self) hlayout_results = QHBoxLayout() # w = SubFrame(_("Delivery slips"),self.search_results_view,None) hlayout_results.addWidget(self.search_results_view) w = SubFrame(_("Detail"),self.slip_part_view,None) hlayout_results.addWidget(w) top_layout.addWidget(self.title_widget) top_layout.addWidget(self.filter_widget) top_layout.addLayout(hlayout_results) top_layout.setStretch(2,100) self.setLayout(top_layout) self.filter_widget.load_last_filter( configuration) def refresh(self,slip_id): filter_string = self.filter_line_edit.text() self.apply_filter_slot(filter_string) if slip_id: ndx = self.search_results_model.find_index( lambda s:s.delivery_slip_id == slip_id) r = 0 m = self.search_results_model if ndx: r = ndx.row() s = QItemSelection(m.index(r,0), m.index(r, m.columnCount()-1)) self.search_results_view.selectionModel().select(s, QItemSelectionModel.Select) @Slot(int) def _section_clicked(self,logical_ndx): self.refresh_action() @Slot(str) def apply_filter_slot(self, filter_string): if filter_string: try: self.slip_data = dao.delivery_slip_part_dao.load_slip_parts_on_filter(filter_string) except DataException as de: if de.code == DataException.CRITERIA_IS_EMPTY: showErrorBox(_("Error in the filter !"),_("The filter can't be empty"),object_name="filter_is_empty") elif de.code == DataException.CRITERIA_IS_TOO_SHORT: showErrorBox(_("Error in the filter !"),_("The filter is too short"),object_name="filter_is_too_short") elif de.code == DataException.CRITERIA_IS_TOO_LONG: showErrorBox(_("Error in the filter !"),_("The filter is too long"),object_name="filter_is_too_long") return else: self.slip_data = dao.delivery_slip_part_dao.find_recent2(1000) self.refresh_action() def refresh_action(self): if self.slip_data == None: self.slip_data = dao.delivery_slip_part_dao.find_recent2(1000) data = self.slip_data headers = self.search_results_view.horizontalHeader() section_sorted = headers.sortIndicatorSection() sort_criteria = self._get_sort_criteria( section_sorted) sort_order = None if sort_criteria: sort_order = headers.sortIndicatorOrder() data = sorted(data, key=cmp_to_key(sort_criteria), reverse = sort_order == Qt.DescendingOrder) self.search_results_model.buildModelFromObjects(data) if sort_criteria: # Changing the model removes the sort order (which makes sense because # changing the model may alter the order of rows) headers.setSortIndicator(section_sorted,sort_order) self.search_results_view.setFocus(Qt.OtherFocusReason) @Slot(QModelIndex,QModelIndex) def row_selected(self,cur_ndx,prev_ndx): if cur_ndx.model(): slip = cur_ndx.model().object_at( cur_ndx.row()) if slip: slip_id = slip.delivery_slip_id self.slip_part_view.set_delivery_slip_parts(dao.delivery_slip_part_dao.load_slip_parts_frozen(slip_id)) self.activate_delivery_slip.setEnabled( not slip.active) self.desactivate_delivery_slip.setEnabled( slip.active) self.delete_delivery_slip.setEnabled( cur_ndx.row() == 0) return self.slip_part_view.set_delivery_slip_parts(None) SECTION_SLIP_ID = 0 SECTION_CREATION_DATE = 1 SECTION_CUSTOMER = 2 SECTION_ORDER_LABEL = 3 def _get_sort_criteria(self,section_sorted): sort_criteria = None # True if the parts of the order stay grouped # together in the table order_stay_together = True if section_sorted == self.SECTION_CUSTOMER: # Customer sort_criteria = lambda a,b: cmp(a.fullname, b.fullname) or \ cmp(a.delivery_slip_id,b.delivery_slip_id) elif section_sorted == self.SECTION_CREATION_DATE: sort_criteria = lambda a,b: cmp(a.creation or date(2100,1,1), b.creation or date(2100,1,1)) elif section_sorted == self.SECTION_SLIP_ID: sort_criteria = lambda a,b: cmp(a.delivery_slip_id, b.delivery_slip_id) elif section_sorted == self.SECTION_ORDER_LABEL: sort_criteria = lambda a,b: cmp(a.user_label, b.user_label) else: sort_criteria = None if sort_criteria is not None: self.current_sort_criteria = sort_criteria else: sort_criteria = self.current_sort_criteria return sort_criteria
class SupplyOrderOverview(HorsePanel): def close_panel(self): self.filter_widget.remember_current_selection(configuration) def _selected_supply_order_part(self): cur_ndx = self.search_results_view.currentIndex() if cur_ndx.row() >= 0: return cur_ndx.model().object_at(cur_ndx.row()) return None @Slot() def show_actions(self): button = self.action_menu.parent() p = button.mapToGlobal(QPoint(0, button.height())) self.action_menu.exec_(p) SECTION_REFERENCE = 0 SECTION_SUPPLIER = 1 SECTION_DEADLINE = 2 SECTION_DESCRIPTION = 3 SECTION_CREATION_DATE = 6 def _make_sort_criteria(self, section_sorted, sort_order): sort_criteria = None if section_sorted == self.SECTION_REFERENCE: if sort_order == Qt.AscendingOrder: def ordering_key(p): return p.accounting_label * 1000 + p.position sort_criteria = lambda a, b: cmp(ordering_key(a), ordering_key(b)) else: def ordering_key(p): return p.accounting_label * 1000 + 999 - p.position sort_criteria = lambda a, b: cmp(ordering_key(a), ordering_key(b)) elif section_sorted == self.SECTION_SUPPLIER: order_correction = +1 if sort_order == Qt.DescendingOrder: order_correction = -1 sort_criteria = lambda a,b: cmp(a.supplier_fullname, b.supplier_fullname) or \ cmp(a.accounting_label,b.accounting_label) or order_correction * cmp(a.position,b.position) elif section_sorted == self.SECTION_DEADLINE: # Deadline sort_criteria = lambda a, b: cmp( a.expected_delivery_date or date(2100, 1, 1), b. expected_delivery_date or date(2100, 1, 1)) return sort_criteria def _fill_model(self, parts_data=None): """ Refills the list of parts data with given parts data. If no parts data are given, then the last data set is reused. This thake into account the currently selected sort indicator and, if any, the currently selected filter. """ if parts_data is not None: self.parts_data = parts_data else: parts_data = self.parts_data view = self.search_results_view model = self.search_results_model headers = view.horizontalHeader() sort_order = headers.sortIndicatorOrder() section_sorted = headers.sortIndicatorSection() sort_criteria = self._make_sort_criteria(section_sorted, sort_order) if sort_criteria: sort_order = headers.sortIndicatorOrder() if sys.version[0] == '3': parts_data = sorted(parts_data, key=cmp_to_key(sort_criteria), reverse=sort_order == Qt.DescendingOrder) else: parts_data = sorted(parts_data, sort_criteria, reverse=sort_order == Qt.DescendingOrder) model.buildModelFromObjects(parts_data) if sort_criteria: # Changing the model removes the sort order (which makes sense because # changing the model may alter the order of rows) # => I have to reset it headers.setSortIndicator(section_sorted, sort_order) if len(parts_data) == 0: # Must do this because when the model is empty # the slection is not updated, so no signal # is sent self._fill_order_part_detail(None) else: view.selectionModel().reset() view.selectionModel().select( view.model().index(0, 0), QItemSelectionModel.Select | QItemSelectionModel.Rows) view.horizontalHeader().setResizeMode(self.SECTION_DESCRIPTION, QHeaderView.Stretch) @Slot() def refresh_action(self): mainlog.debug("refresh_action") self._apply_filter(self.filter_widget.current_filter()) @Slot(int) def section_clicked(self, logical_ndx): self._fill_model() @Slot(str) def _apply_filter(self, filter_text): mainlog.debug(u"_apply_filter : {}".format(filter_text)) parts = [] len_check = False if " " in filter_text.strip(): # More than one word in the filter => I assume it's the full # fledged filtering check = check_parse(filter_text) if check == True: parts = supply_order_service.find_parts_expression_filter( filter_text) len_check = True else: showErrorBox(_("Error in the filter !"), check, object_name="filter_is_wrong") elif filter_text: parts = supply_order_service.find_parts_filtered(filter_text) len_check = True else: parts = supply_order_service.find_recent_parts() len_check = False if len_check and len(parts) >= supply_order_service.MAX_RESULTS: showWarningBox( _("Too many results"), _("The query you've given brought back too many results. Only a part of them is displayed. Consider refining your query" )) self._fill_model(parts) self.search_results_view.setFocus(Qt.OtherFocusReason) def _make_supply_order_detail_view(self): # There's a self.proto somewhere, don't mess with it :-) # proto = [] # proto.append( TextLinePrototype('description',_('Description'), editable=True,nullable=False)) # proto.append( FloatNumberPrototype('quantity',_('Quantity'), editable=True,nullable=False)) # proto.append( FloatNumberPrototype('unit_price',_('Unit price'), editable=True,nullable=False)) # self.detail_model = PrototypedModelView(proto, self) # self.detail_view = PrototypedQuickView(proto, self) # self.detail_view.setModel(self.detail_model) # self.detail_view.verticalHeader().hide() self.detail_description = QTextEdit() self.detail_description.setTextInteractionFlags( Qt.TextBrowserInteraction) self.delivery_date_widget = QLabel() self.creation_date_widget = QLabel() self.supplier_reference_widget = QLabel() hlayout = QHBoxLayout() hlayout.addWidget(QLabel(_("Delivery date"))) hlayout.addWidget(self.delivery_date_widget) hlayout.addStretch() hlayout3 = QHBoxLayout() hlayout3.addWidget(QLabel(_("Creation date"))) hlayout3.addWidget(self.creation_date_widget) hlayout3.addStretch() hlayout2 = QHBoxLayout() hlayout2.addWidget(QLabel(_("Supplier's reference"))) hlayout2.addWidget(self.supplier_reference_widget) hlayout2.addStretch() layout = QVBoxLayout() layout.addLayout(hlayout) layout.addLayout(hlayout3) layout.addLayout(hlayout2) layout.addWidget(self.detail_description) layout.addStretch() # layout.addWidget(self.detail_view) # layout.setStretch(0,1) # layout.setStretch(1,3) return layout @Slot() def _toggle_edit_filters(self): self.filter_widget.setVisible(not self.filter_widget.isVisible()) def __init__(self, parent): super(SupplyOrderOverview, self).__init__(parent) initialize_supplier_cache() self.set_panel_title(_("Supply Orders")) # navigation = NavBar( self, # [ (_("Action"),self.show_actions) ] ) # self.action_menu = QMenu(navigation.buttons[0]) title = _("Supply orders") # self.setWindowTitle(title) filter_family = FilterQuery.SUPPLIER_ORDER_SLIPS_FAMILY self.filter_widget = PersistentFilter(filter_family) self.filter_widget.apply_filter.connect(self._apply_filter) self.filter_widget.hide() self.proto = [] self.proto.append( TextLinePrototype('human_identifier', _("Part Nr"), editable=False)) self.proto.append( TextLinePrototype('supplier_fullname', _('Supplier'), editable=False)) self.proto.append( DatePrototype('expected_delivery_date', _('Deadline'), editable=True, nullable=False)) self.proto.append( TextLinePrototype('description', _('Description'), editable=True, nullable=False)) self.proto.append( FloatNumberPrototype('quantity', _('Quantity'), editable=True, nullable=False)) self.proto.append( FloatNumberPrototype('unit_price', _('Unit price'), editable=True, nullable=False)) self.proto.append( DatePrototype('creation_date', _('Creation date'), editable=False, nullable=False)) # self.proto.append( DatePrototype('creation_date',_('Creation'), editable=False)) # self.proto.append( DatePrototype('expected_delivery_date',_('Expected\ndelivery'), editable=False)) # self.proto.append( TextLinePrototype('supplier_fullname',_('Supplier'), editable=False)) self.search_results_model = PrototypedModelView(self.proto, self) self.search_results_view = PrototypedQuickView(self.proto, self) self.search_results_view.setModel(self.search_results_model) self.search_results_view.horizontalHeader().setSortIndicatorShown(True) self.search_results_view.verticalHeader().hide() self.search_results_view.verticalHeader().setResizeMode( QHeaderView.ResizeToContents) self.search_results_view.doubleClicked.connect( self._supply_order_double_clicked) self.search_results_view.activated.connect( self._supply_order_double_clicked) self.search_results_view.horizontalHeader().sectionClicked.connect( self.section_clicked) top_layout = QVBoxLayout(self) navigation = NavBar(self, [(self.filter_widget.get_filters_combo(), None), (_("Edit filter"), self._toggle_edit_filters)]) self.title_widget = TitleWidget(title, self, navigation) # navigation) hlayout_results = QHBoxLayout() # w = SubFrame(_("Supply order parts"),self.search_results_view,None) hlayout_results.addWidget(self.search_results_view) w = SubFrame(_("Supply order detail"), self._make_supply_order_detail_view(), None) hlayout_results.addWidget(w) hlayout_results.setStretch(0, 2) hlayout_results.setStretch(0, 1) top_layout.addWidget(self.title_widget) top_layout.addWidget(self.filter_widget) top_layout.addLayout(hlayout_results) top_layout.setStretch(3, 100) self.setLayout(top_layout) self.search_results_view.setSelectionBehavior( QAbstractItemView.SelectRows) self.search_results_view.setSelectionMode( QAbstractItemView.SingleSelection) # self.search_results_view.activated.connect(self.row_activated) self.search_results_view.selectionModel().currentRowChanged.connect( self.row_selected) # self.detail_view.doubleClicked.connect(self._supply_order_double_clicked) # pub.subscribe(self.refresh_panel, 'supply_order.changed') # pub.subscribe(self.refresh_panel, 'supply_order.deleted') # self.filter_widget.select_default_filter() self.filter_widget.load_last_filter(configuration) supply_order_selected = Signal(object) @Slot(QModelIndex) def _supply_order_double_clicked(self, cur_ndx): mainlog.debug("_supply_order_double_clicked") supply_order = cur_ndx.model().object_at(cur_ndx.row()) if supply_order: self.supply_order_selected.emit(supply_order) def _fill_order_part_detail(self, supply_order_part): if supply_order_part: supply_order_part_id = supply_order_part.supply_order_id supply_order, parts = supply_order_service.find_by_id( supply_order_part.supply_order_id) self.detail_description.setText(supply_order.description) self.delivery_date_widget.setText( date_to_s(supply_order.expected_delivery_date) or "-") self.supplier_reference_widget.setText( supply_order.supplier_reference or "-") self.creation_date_widget.setText( date_to_s(supply_order.creation_date) or "-") else: self.detail_description.setText("-") self.delivery_date_widget.setText("-") self.supplier_reference_widget.setText("-") self.creation_date_widget.setText("-") @Slot(QModelIndex, QModelIndex) def row_selected(self, cur_ndx, prev_ndx): if cur_ndx.model(): supply_order_part = cur_ndx.model().object_at(cur_ndx.row()) self._fill_order_part_detail(supply_order_part)