class PostViewWidget(HorsePanel): def __init__(self, parent, order_overview_widget, find_order_slot): global configuration super(PostViewWidget, self).__init__(parent) self.set_panel_title(_("Post overview")) self.bold_font = QFont(self.font()) self.bold_font.setBold(True) self.nb_cols = 8 # Number of columns in the operation definition table self.order_overview_widget = order_overview_widget self.button = QPushButton(_("Refresh"), self) self.button.clicked.connect(self.refresh_action) self.sort_by_deadline_button = QRadioButton(_("By deadline"), self) self.sort_by_deadline_button.toggled.connect(self.sort_by_deadline) self.sort_by_size_button = QRadioButton(_("By hours left to do"), self) self.sort_by_size_button.toggled.connect(self.sort_by_size) # hlayout = QHBoxLayout() # hlayout.setObjectName("halyout") # hlayout.setContentsMargins(0,0,0,0) # hlayout.addWidget(self.sort_by_deadline_button) # hlayout.addWidget(self.sort_by_size_button) # hlayout.addWidget(self.button) # hlayout.addStretch() self.navbar = NavBar(self, [(self.sort_by_deadline_button, None), (self.sort_by_size_button, None), (self.button, None), (_("Find"), find_order_slot)]) self.navbar.buttons[3].setObjectName("specialMenuButton") self.vlayout = QVBoxLayout(self) self.vlayout.setObjectName("Vlayout") self.vlayout.addWidget( TitleWidget(_("Posts Overview"), self, self.navbar)) self._table_model = QStandardItemModel(1, self.nb_cols, self) self.table_view = QTableView(None) self.table_view.setModel(self._table_model) self.table_view.selectionModel().currentChanged.connect( self.operation_selected) self.table_view.verticalHeader().hide() self.table_view.horizontalHeader().hide() self.table_view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table_view.setSelectionBehavior(QAbstractItemView.SelectRows) # This forces Qt to expand layout once I fill data in # FIXME dirty but I really don't get why setting # the mini width to something smaller (that happens at # startup, on first refresh) doesn't work self.table_view.setMinimumWidth(1) self.table_view.setMaximumWidth(1) self.post_view_scene = PostViewScene(self, order_overview_widget) self.post_view_scene_view = QGraphicsView(self) self.post_view_scene_view.setScene(self.post_view_scene) self.post_view_scene_view.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.splitter = QSplitter(Qt.Horizontal) self.splitter.addWidget( SubFrame(_("Posts"), self.table_view, self.splitter)) self.splitter.addWidget( SubFrame(_("Workload"), self.post_view_scene_view, self.splitter)) # self.splitter.setStretchFactor(0,1) self.splitter.setStretchFactor(1, 1) self.vlayout.addWidget(self.splitter) # hlayout = QHBoxLayout() # hlayout.addWidget(SubFrame(_("Posts"),self.table_view,self)) # hlayout.addWidget(SubFrame(_("Workload"),self.post_view_scene_view,self)) # hlayout.setStretch(1,1) # self.vlayout.addLayout(hlayout) self.vlayout.setStretch(0, 0) self.vlayout.setStretch(1, 1) self.setLayout(self.vlayout) self.timer = QTimer(self) self.timer.timeout.connect(self.slidePostsScene) self.current_view_y = 0 def _data_load(self): global dao all_operations = dao.operation_dao.load_all_operations_ready_for_production( ) operation_definitions = dao.operation_definition_dao.all_direct_frozen( ) return operation_definitions, all_operations def _reset_operation_definitions(self, operations): self._table_model.setColumnCount(1) self._table_model.setRowCount(len(operations)) # BUG This should be refreshed on reload() too row = col = 0 first_active = None for opdef in operations: if opdef.operation_definition_id in self.post_view_scene.drawn_operations_data: # currently total planned time t = self.post_view_scene.drawn_operations_data[ opdef.operation_definition_id] ndx = self._table_model.index(row, col) if not first_active: first_active = ndx self._table_model.setData( ndx, u"{} {}".format(opdef.description, t), Qt.DisplayRole) # self._table_model.setData(ndx,self.bold_font,Qt.FontRole) self._table_model.setData(self._table_model.index(row, col), opdef.operation_definition_id, Qt.UserRole) row += 1 else: pass # self._table_model.setData(self._table_model.index(row,col),opdef.description,Qt.DisplayRole) # = col + 1 # if col == self.nb_cols: # col = 0 # row += 1 self._table_model.setRowCount(row) # self.table_view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) # self.vlayout.setStretch(0,0) # self.vlayout.setStretch(1,10) # self.vlayout.setStretch(2,10000) # height = 0 # for c in range(self.table_view.model().rowCount()): # height += self.table_view.rowHeight(c) + 1 # +1 for cell border # self.table_view.setMinimumHeight(height) # self.table_view.setMaximumHeight(height) for i in range(self.nb_cols): self.table_view.resizeColumnToContents(i) self.table_view.setMaximumWidth(self.table_view.columnWidth(0)) self.table_view.setMinimumWidth(self.table_view.columnWidth(0)) self.table_view.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Preferred) self.table_view.update() self.splitter.update() return first_active def slide_to_operation(self, opdef_id): if opdef_id in self.post_view_scene.posts_offsets: self.slide_target_opdef_id = opdef_id # mainlog.debug("Target y = {}".format(self.post_view_scene.posts_offsets[self.slide_target_opdef])) self.timer.start(20) @Slot() def slidePostsScene(self): if self.slide_target_opdef_id is None: return # self.post_view_scene_view self.post_view_scene.set_cursor_on( self.slide_target_opdef_id ) # This done here also aviod some screen trashing v = self.post_view_scene_view.verticalScrollBar().value() # mainlog.debug( "slidePostsScene : {}".format(v)) r = self.post_view_scene.posts_offsets[self.slide_target_opdef_id] target_y = r.y() + r.height() / 2 delta = (target_y - self.current_view_y) * 0.4 self.current_view_y = self.current_view_y + delta self.post_view_scene_view.centerOn(0, self.current_view_y) # mainlog.debug( "slidePostsScene : {} / {}".format(target_y, self.current_view_y)) if self.post_view_scene_view.verticalScrollBar().value() == v: # Close enough => stop moving # FIXME not correct because we must stop when the view stops moving, not when the goal we set for centerOn is reached self.timer.stop() @Slot(QModelIndex, QModelIndex) def operation_selected(self, ndx_cur, ndx_old): if ndx_cur.isValid(): opdef = self._table_model.data(ndx_cur, Qt.UserRole) if opdef: self.slide_to_operation( self._table_model.data(ndx_cur, Qt.UserRole)) @Slot() def refresh_action(self): # FIXME reload operations as well operation_definitions, all_operations = self._data_load() # mainlog.debug("reload") if self.sort_by_deadline_button.isChecked(): self.post_view_scene.reload(self, operation_definitions, all_operations, 1) elif self.sort_by_size_button.isChecked(): self.post_view_scene.reload(self, operation_definitions, all_operations, 2) else: self.post_view_scene.reload(self, operation_definitions, all_operations, 0) # mainlog.debug("reset") first_active = self._reset_operation_definitions(operation_definitions) # self.table_view.selectionModel().currentChanged.connect(self.operation_selected) if first_active: self.table_view.setCurrentIndex(first_active) # mainlog.debug("done reset") @Slot(bool) def sort_by_deadline(self, checked): if checked: self.refresh_action() @Slot(bool) def sort_by_size(self, checked): if checked: self.refresh_action() order_part_double_clicked = Signal(int) # Callback that will be called by HooverBar def set_on_order_part(self, order_part_id): self.order_part_double_clicked.emit(order_part_id)
class WorldViewer(QWidget): def __init__(self, charname='', currentzone='', parent=None): super(WorldViewer, self).__init__(parent) self.setWindowTitle("World Viewer") if not DEBUG: self.setWindowState(Qt.WindowMaximized) self.move(0,0) self.grabKeyboard() self.keyspressed = set() self.currentzone = currentzone self.charname = charname self.scene = QGraphicsScene() self.view = QGraphicsView(self.scene) self.view.scale(5, 5) self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # pb = QPushButton("Push!") # stylesheet = ''' # QPushButton { # border: 2px solid #8f8f91; # border-radius: 6px; # background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, # stop: 0 #f6f7fa, stop: 1 #dadbde); # min-width: 80px; # } # # QPushButton:pressed { # background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, # stop: 0 #dadbde, stop: 1 #f6f7fa); # } # # QPushButton:flat { # border: none; /* no border for a flat push button */ # } # QPushButton:default { # border-color: navy; /* make the default button prominent */ # } # ''' # pb.setStyleSheet(stylesheet) # self.scene.addWidget(pb) layout = QVBoxLayout() for w in (self.view, ): layout.addWidget(w) self.setLayout(layout) self.loading = self.scene.addText("Loading...") self.loading.setHtml("<h1>Loading...</h1>") self.last_update = datetime.datetime.now() self.world_objects = {} self.world_object_widgets = {} self._update_objects(client.get_all_objects(self.currentzone)) print self.world_objects # Set character status to online. client.set_status(self.currentzone, self.charname) self.loading.hide() # Set a repeating callback on a timer to get object updates self.obj_update_timer = QTimer(self) self.connect(self.obj_update_timer, SIGNAL("timeout()"), self.update_objects) self.obj_update_timer.start(CLIENT_UPDATE_FREQ) # Set a repeating callback on a timer to send movement packets. self.movement_timer = QTimer(self) self.connect(self.movement_timer, SIGNAL("timeout()"), self.send_movement) self.movement_timer.start(CLIENT_UPDATE_FREQ) def sizeHint(self): desktop = QApplication.instance().desktop() geom = desktop.availableGeometry() return QSize(geom.width()/2, geom.height()/2) def keyPressEvent(self, event): '''Qt's key handling is wierd. If a key gets "stuck", just press and release it again.''' # Ignore autorepeat events. if event.isAutoRepeat(): event.ignore() return # Add all other events to our set of pressed keys. self.keyspressed.add(event.key()) event.accept() def keyReleaseEvent(self, event): # Ignore autorepeat events. if event.isAutoRepeat(): event.ignore() return # Remove all other events from our set of pressed keys. self.keyspressed.discard(event.key()) event.accept() def send_movement(self): '''Send movement calls to the zone/movement server.''' x = 0 y = 0 def _in_set(x, *args): for a in args: if int(a) in x: return True return False if _in_set(self.keyspressed, Qt.Key_Left, Qt.Key_A): x -= 1 if _in_set(self.keyspressed, Qt.Key_Right, Qt.Key_D): x += 1 if _in_set(self.keyspressed, Qt.Key_Up, Qt.Key_W): y -= 1 if _in_set(self.keyspressed, Qt.Key_Down, Qt.Key_S): y += 1 client.send_movement(self.currentzone, self.charname, x, y, 0) def _update_objects(self, objectslist): if len(objectslist) != 0: print "Updated %d objects." % len(objectslist) for obj in objectslist: # Filter out any hidden objects if "hidden" in obj.get('states'): continue obj_id = obj['_id']['$oid'] self.world_objects.update({obj_id: obj}) if obj_id not in self.world_object_widgets: # Create a new widget, add it to the view and to world_object_widgets objwidget = WorldObject(obj) self.world_object_widgets.update({obj_id: objwidget}) self.scene.addItem(objwidget) else: objwidget = self.world_object_widgets[obj_id] objwidget.setOffset(obj['loc']['x'], obj['loc']['y']) # Update our view if the name is the same as our character. if obj['name'] == self.charname: self.view.centerOn(objwidget) self.view.ensureVisible(objwidget) def update_objects(self): '''Gets an upated list of objects from the zone and stores them locally.''' new_objects = client.get_objects_since(self.last_update, self.currentzone) self._update_objects(new_objects) self.last_update = datetime.datetime.now()
class WorldViewer(QWidget): def __init__(self, charname='', currentzone='', parent=None): super(WorldViewer, self).__init__(parent) self.setWindowTitle("World Viewer") if not DEBUG: self.setWindowState(Qt.WindowMaximized) self.move(0, 0) self.grabKeyboard() self.keyspressed = set() self.currentzone = currentzone self.charname = charname self.scene = QGraphicsScene() self.view = QGraphicsView(self.scene) self.view.scale(5, 5) self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # pb = QPushButton("Push!") # stylesheet = ''' # QPushButton { # border: 2px solid #8f8f91; # border-radius: 6px; # background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, # stop: 0 #f6f7fa, stop: 1 #dadbde); # min-width: 80px; # } # # QPushButton:pressed { # background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, # stop: 0 #dadbde, stop: 1 #f6f7fa); # } # # QPushButton:flat { # border: none; /* no border for a flat push button */ # } # QPushButton:default { # border-color: navy; /* make the default button prominent */ # } # ''' # pb.setStyleSheet(stylesheet) # self.scene.addWidget(pb) layout = QVBoxLayout() for w in (self.view, ): layout.addWidget(w) self.setLayout(layout) self.loading = self.scene.addText("Loading...") self.loading.setHtml("<h1>Loading...</h1>") self.last_update = datetime.datetime.now() self.world_objects = {} self.world_object_widgets = {} self._update_objects(client.get_all_objects(self.currentzone)) print self.world_objects # Set character status to online. client.set_status(self.currentzone, self.charname) self.loading.hide() # Set a repeating callback on a timer to get object updates self.obj_update_timer = QTimer(self) self.connect(self.obj_update_timer, SIGNAL("timeout()"), self.update_objects) self.obj_update_timer.start(CLIENT_UPDATE_FREQ) # Set a repeating callback on a timer to send movement packets. self.movement_timer = QTimer(self) self.connect(self.movement_timer, SIGNAL("timeout()"), self.send_movement) self.movement_timer.start(CLIENT_UPDATE_FREQ) def sizeHint(self): desktop = QApplication.instance().desktop() geom = desktop.availableGeometry() return QSize(geom.width() / 2, geom.height() / 2) def keyPressEvent(self, event): '''Qt's key handling is wierd. If a key gets "stuck", just press and release it again.''' # Ignore autorepeat events. if event.isAutoRepeat(): event.ignore() return # Add all other events to our set of pressed keys. self.keyspressed.add(event.key()) event.accept() def keyReleaseEvent(self, event): # Ignore autorepeat events. if event.isAutoRepeat(): event.ignore() return # Remove all other events from our set of pressed keys. self.keyspressed.discard(event.key()) event.accept() def send_movement(self): '''Send movement calls to the zone/movement server.''' x = 0 y = 0 def _in_set(x, *args): for a in args: if int(a) in x: return True return False if _in_set(self.keyspressed, Qt.Key_Left, Qt.Key_A): x -= 1 if _in_set(self.keyspressed, Qt.Key_Right, Qt.Key_D): x += 1 if _in_set(self.keyspressed, Qt.Key_Up, Qt.Key_W): y -= 1 if _in_set(self.keyspressed, Qt.Key_Down, Qt.Key_S): y += 1 client.send_movement(self.currentzone, self.charname, x, y, 0) def _update_objects(self, objectslist): if len(objectslist) != 0: print "Updated %d objects." % len(objectslist) for obj in objectslist: # Filter out any hidden objects if "hidden" in obj.get('states'): continue obj_id = obj['_id']['$oid'] self.world_objects.update({obj_id: obj}) if obj_id not in self.world_object_widgets: # Create a new widget, add it to the view and to world_object_widgets objwidget = WorldObject(obj) self.world_object_widgets.update({obj_id: objwidget}) self.scene.addItem(objwidget) else: objwidget = self.world_object_widgets[obj_id] objwidget.setOffset(obj['loc']['x'], obj['loc']['y']) # Update our view if the name is the same as our character. if obj['name'] == self.charname: self.view.centerOn(objwidget) self.view.ensureVisible(objwidget) def update_objects(self): '''Gets an upated list of objects from the zone and stores them locally.''' new_objects = client.get_objects_since(self.last_update, self.currentzone) self._update_objects(new_objects) self.last_update = datetime.datetime.now()