def populateTree(self, projects): """populates tree with user projects """ logger.debug('TaskTreeModel.populateTree() is started') self.setColumnCount(4) self.setHorizontalHeaderLabels( ['Name', 'Type', 'Resources', 'Dependencies']) for project in projects: project_item = TaskItem(0, 4, task=project) project_item.parent = None project_item.setColumnCount(4) # Set Font my_font = project_item.font() my_font.setBold(True) project_item.setFont(my_font) # color with task status from anima import defaults project_item.setData( QtGui.QColor( *defaults.status_colors_by_id.get(project.status_id)), QtCore.Qt.BackgroundRole) # use black text project_item.setForeground(QtGui.QBrush(QtGui.QColor(0, 0, 0))) self.appendRow(project_item) logger.debug('TaskTreeModel.populateTree() is finished')
def setup_ui(self): """create the UI widgets """ self.vertical_layout = QtWidgets.QVBoxLayout(self) self.setLayout(self.vertical_layout) # the widget should consist of a QGraphic self.thumbnail_graphics_view = QtWidgets.QGraphicsView(self) # set size policy size_policy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) size_policy.setHorizontalStretch(0) size_policy.setVerticalStretch(0) size_policy.setHeightForWidth( self.thumbnail_graphics_view.sizePolicy().hasHeightForWidth()) self.thumbnail_graphics_view.setSizePolicy(size_policy) # set size default_size = QtCore.QSize(*self.default_thumbnail_size) self.thumbnail_graphics_view.setMinimumSize(default_size) self.thumbnail_graphics_view.setMaximumSize(default_size) self.thumbnail_graphics_view.setAutoFillBackground(False) self.thumbnail_graphics_view.setVerticalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOff) self.thumbnail_graphics_view.setHorizontalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOff) brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) brush.setStyle(QtCore.Qt.SolidPattern) self.thumbnail_graphics_view.setBackgroundBrush(brush) self.thumbnail_graphics_view.setInteractive(False) self.thumbnail_graphics_view.setRenderHints( QtGui.QPainter.Antialiasing | QtGui.QPainter.HighQualityAntialiasing | QtGui.QPainter.SmoothPixmapTransform | QtGui.QPainter.TextAntialiasing) self.vertical_layout.addWidget(self.thumbnail_graphics_view) self.upload_thumbnail_button = QtWidgets.QPushButton(self) self.upload_thumbnail_button.setText("Upload...") self.upload_thumbnail_button.setGeometry( self.thumbnail_graphics_view.geometry()) self.upload_thumbnail_button.setVisible(True) self.vertical_layout.addWidget(self.upload_thumbnail_button) # create signals # QtCore.QObject.connect( # self.thumbnail_graphics_view, # QtCore.SIGNAL("clicked()"), # self.thumbnail_graphics_view_clicked # ) QtCore.QObject.connect(self.upload_thumbnail_button, QtCore.SIGNAL("clicked()"), self.upload_thumbnail_button_clicked)
def setup_ui(self): """create the UI widgets """ self.vertical_layout = QtWidgets.QVBoxLayout(self) from anima.ui.lib import QtCore, QtGui # the widget should consist of a QGraphic self.thumbnail_graphics_view = QtWidgets.QGraphicsView(self) # set size policy size_policy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed ) size_policy.setHorizontalStretch(0) size_policy.setVerticalStretch(0) size_policy.setHeightForWidth( self.thumbnail_graphics_view.sizePolicy().hasHeightForWidth()) self.thumbnail_graphics_view.setSizePolicy(size_policy) # set size default_size = QtCore.QSize( self.default_thumbnail_size, self.default_thumbnail_size ) self.thumbnail_graphics_view.setMinimumSize(default_size) self.thumbnail_graphics_view.setMaximumSize(default_size) self.thumbnail_graphics_view.setAutoFillBackground(False) self.thumbnail_graphics_view.setVerticalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOff ) self.thumbnail_graphics_view.setHorizontalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOff ) brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) brush.setStyle(QtCore.Qt.SolidPattern) self.thumbnail_graphics_view.setBackgroundBrush(brush) self.thumbnail_graphics_view.setInteractive(False) self.thumbnail_graphics_view.setRenderHints( QtGui.QPainter.Antialiasing | QtGui.QPainter.HighQualityAntialiasing | QtGui.QPainter.SmoothPixmapTransform | QtGui.QPainter.TextAntialiasing ) self.vertical_layout.addWidget(self.thumbnail_graphics_view)
def fetchMore(self): logger.debug('TaskItem.fetchMore() is started for item: %s' % self.text()) if self.canFetchMore(): from sqlalchemy.orm import aliased from sqlalchemy.dialects.postgresql import array_agg from stalker import Task, User from stalker.models.task import Task_Resources from stalker.db.session import DBSession inner_tasks = aliased(Task) subquery = DBSession.query(Task.id) \ .filter(Task.id == inner_tasks.parent_id) query = DBSession.query( Task.id, Task.name, Task.entity_type, Task.status_id, subquery.exists().label('has_children'), array_agg(User.name).label('resources') ) \ .outerjoin(Task_Resources, Task.__table__.c.id == Task_Resources.c.task_id) \ .outerjoin(User, Task_Resources.c.resource_id == User.id) \ .group_by( Task.id, Task.name, Task.entity_type, Task.status_id, subquery.exists().label('has_children') ) if self.task.entity_type != 'Project': # query child tasks query = query.filter(Task.parent_id == self.task.id) else: # query only root tasks query = query.filter(Task.project_id == self.task.id)\ .filter(Task.parent_id==None) tasks = query.order_by(Task.name).all() # # model = self.model() # This will cause a SEGFAULT # # TODO: update it later on # start = time.time() from anima import defaults task_items = [] for task in tasks: task_item = TaskItem(0, 4, task=task) task_item.parent = self # color with task status task_item.setData( QtGui.QColor( *defaults.status_colors_by_id[task.status_id]), QtCore.Qt.BackgroundRole) # use black text task_item.setForeground(QtGui.QBrush(QtGui.QColor(0, 0, 0))) task_items.append(task_item) if task_items: # self.appendRows(task_items) for task_item in task_items: # TODO: Create a custom QStandardItem for each data type in different columns entity_type_item = QtGui.QStandardItem() entity_type_item.setData(task_item.task.entity_type, QtCore.Qt.DisplayRole) resources_item = QtGui.QStandardItem() if task_item.task.resources != [None]: resources_item.setData( ', '.join(map(str, task_item.task.resources)), QtCore.Qt.DisplayRole) self.appendRow( [task_item, entity_type_item, resources_item]) self.fetched_all = True logger.debug('TaskItem.fetchMore() is finished for item: %s' % self.text())
def fill_calendar_with_time_logs(self): """fill the calendar with daily time log info """ resource_id = self.get_current_resource_id() # do not update if the calendar is showing the same user if self.calendar_widget.resource_id == resource_id or resource_id == -1: return tool_tip_text_format = u'{start:%H:%M} - {end:%H:%M} | {task_name}' # import time # start = time.time() # get all the TimeLogs grouped daily sql = """-- TOP DOWN SEARCH -- select "TimeLogs".start::date as date, array_agg(task_rec_data.full_path) as task_name, array_agg("TimeLogs".start) as start, array_agg("TimeLogs".end) as end, sum(extract(epoch from ("TimeLogs".end - "TimeLogs".start))) from "TimeLogs" join ( with recursive recursive_task(id, parent_id, path_names) as ( select task.id, task.project_id, -- task.project_id::text as path, ("Projects".code || '') as path_names from "Tasks" as task join "Projects" on task.project_id = "Projects".id where task.parent_id is NULL union all select task.id, task.parent_id, -- (parent.path || '|' || task.parent_id:: text) as path, (parent.path_names || ' | ' || "Parent_SimpleEntities".name) as path_names from "Tasks" as task inner join recursive_task as parent on task.parent_id = parent.id inner join "SimpleEntities" as "Parent_SimpleEntities" on parent.id = "Parent_SimpleEntities".id ) select recursive_task.id, "SimpleEntities".name || ' (' || recursive_task.path_names || ')' as full_path from recursive_task join "SimpleEntities" on recursive_task.id = "SimpleEntities".id ) as task_rec_data on "TimeLogs".task_id = task_rec_data.id -- getting all the data is as fast as getting one, so get all the TimeLogs of this user where "TimeLogs".resource_id = :resource_id group by cast("TimeLogs".start as date) order by cast("TimeLogs".start as date) """ from sqlalchemy import text from stalker.db.session import DBSession result = DBSession.connection().execute( text(sql), resource_id=resource_id ).fetchall() # end = time.time() # print('getting data from sql: %0.3f sec' % (end - start)) from anima.utils import utc_to_local time_shifter = utc_to_local import stalker # TODO: Remove this in a later version from distutils.version import LooseVersion if LooseVersion(stalker.__version__) >= LooseVersion('0.2.18'): def time_shifter(x): return x for r in result: calendar_day = r[0] year = calendar_day.year month = calendar_day.month day = calendar_day.day daily_logged_seconds = r[4] daily_logged_hours = daily_logged_seconds // 3600 daily_logged_minutes = \ (daily_logged_seconds - daily_logged_hours * 3600) // 60 tool_tip_text_data = [ u'Total: %i h %i min logged' % (daily_logged_hours, daily_logged_minutes) if daily_logged_hours else u'Total: %i min logged' % daily_logged_minutes ] for task_name, start, end in sorted( zip(r[1], r[2], r[3]), key=lambda x: x[1]): time_log_tool_tip_text = tool_tip_text_format.format( start=time_shifter(start), end=time_shifter(end), task_name=task_name ) tool_tip_text_data.append(time_log_tool_tip_text) merged_tool_tip = u'\n'.join(tool_tip_text_data) date_format = QtGui.QTextCharFormat() bg_brush = QtGui.QBrush() bg_brush.setColor( QtGui.QColor(0, 255.0 / 86400.0 * daily_logged_seconds, 0) ) date_format.setBackground(bg_brush) date_format.setToolTip(merged_tool_tip) date = QtCore.QDate(year, month, day) self.calendar_widget.setDateTextFormat(date, date_format)
def fetchMore(self): logger.debug( 'TaskItem.fetchMore() is started for item: %s' % self.text() ) if self.canFetchMore(): tasks = [] if isinstance(self.task, Task): tasks = self.task.children elif isinstance(self.task, Project): tasks = self.task.root_tasks # model = self.model() # This will cause a SEGFAULT if self.user_tasks_only: user_tasks_and_parents = [] # need to filter tasks which do not belong to user for task in tasks: for user_task in self.user.tasks: if task in user_task.parents or \ task is user_task or \ task in self.user.projects: user_tasks_and_parents.append(task) break tasks = user_tasks_and_parents tasks = sorted(tasks, key=lambda x: x.name) for task in tasks: task_item = TaskItem(0, 3) task_item.parent = self task_item.task = task task_item.user = self.user task_item.user_tasks_only = self.user_tasks_only # set the font # name_item = QtGui.QStandardItem(task.name) # entity_type_item = QtGui.QStandardItem(task.entity_type) # task_item.setItem(0, 0, name_item) # task_item.setItem(0, 1, entity_type_item) task_item.setText(task.name) make_bold = False if isinstance(task, Task): if task.is_container: make_bold = True elif isinstance(task, Project): make_bold = True if make_bold: my_font = task_item.font() my_font.setBold(True) task_item.setFont(my_font) # color with task status task_item.setData( QtGui.QColor( *status_colors[task_item.task.status.code.lower()] ), QtCore.Qt.BackgroundRole ) # use black text task_item.setForeground( QtGui.QBrush(QtGui.QColor(0, 0, 0)) ) self.appendRow(task_item) self.fetched_all = True logger.debug( 'TaskItem.fetchMore() is finished for item: %s' % self.text() )
def fetchMore(self): logger.debug( 'TaskItem.fetchMore() is started for item: %s' % self.text() ) if self.canFetchMore(): from sqlalchemy import alias from stalker import Task from stalker.db.session import DBSession inner_tasks = alias(Task.__table__) subquery = DBSession.query(Task.id)\ .filter(Task.id == inner_tasks.c.parent_id) query = DBSession.query( Task.id, Task.name, Task.entity_type, Task.status_id, subquery.exists().label('has_children') ) if self.task.entity_type != 'Project': # query child tasks query = query.filter(Task.parent_id == self.task.id) else: # query only root tasks query = query.filter(Task.project_id == self.task.id)\ .filter(Task.parent_id==None) tasks = query.order_by(Task.name).all() # # model = self.model() # This will cause a SEGFAULT # # TODO: update it later on # start = time.time() from anima import defaults task_items = [] for task in tasks: task_item = TaskItem(0, 3, entity=task) task_item.parent = self # color with task status task_item.setData( QtGui.QColor( *defaults.status_colors_by_id[task.status_id] ), QtCore.Qt.BackgroundRole ) # use black text task_item.setForeground( QtGui.QBrush(QtGui.QColor(0, 0, 0)) ) task_items.append(task_item) if task_items: self.appendRows(task_items) self.fetched_all = True logger.debug( 'TaskItem.fetchMore() is finished for item: %s' % self.text() )
def fetchMore(self): logger.debug( 'TaskItem.fetchMore() is started for item: %s' % self.text() ) if self.canFetchMore(): tasks = [] if self.task_name is None: self.task_name, self.task_entity_type = \ db.DBSession \ .query(SimpleEntity.name, SimpleEntity.entity_type) \ .filter(SimpleEntity.id == self.task_id) \ .first() if self.task_children_data is None: if self.task_entity_type in self.task_entity_types: self.task_children_data = db.DBSession \ .query(Task.id, Task.name, Task.entity_type, Task.status_id) \ .filter(Task.parent_id == self.task_id) \ .order_by(Task.name) \ .all() elif self.task_entity_type == 'Project': self.task_children_data = db.DBSession\ .query(Task.id, Task.name, Task.entity_type, Task.status_id) \ .filter(Task.parent_id == None) \ .filter(Task.project_id == self.task_id) \ .order_by(Task.name) \ .all() tasks = self.task_children_data # # model = self.model() # This will cause a SEGFAULT # # TODO: update it later on # if self.user_tasks_only: # user_tasks_and_parents = [] # # need to filter tasks which do not belong to user # for task in tasks: # for user_task in self.user.tasks: # if task in user_task.parents or \ # task is user_task or \ # task in self.user.projects: # user_tasks_and_parents.append(task) # break # # tasks = user_tasks_and_parents # # tasks = sorted(tasks, key=lambda x: x.name) # start = time.time() task_items = [] for task in tasks: task_item = TaskItem(0, 3) task_item.parent = self task_item.task_id = task[0] task_item.user_id = self.user_id task_item.user_tasks_only = self.user_tasks_only # set the font # name_item = QtGui.QStandardItem(task.name) # entity_type_item = QtGui.QStandardItem(task.entity_type) # task_item.setItem(0, 0, name_item) # task_item.setItem(0, 1, entity_type_item) task_item.setText(task[1]) # make_bold = False # if task_item.canFetchMore(): # make_bold = True # if task[2] in self.task_entity_types: # children_count = \ # db.DBSession.query(Task.id)\ # .filter(Task.parent_id == task[0])\ # .count() # if children_count: # make_bold = True # elif task[2] == 'Project': # make_bold = True # if make_bold: # my_font = task_item.font() # my_font.setBold(True) # task_item.setFont(my_font) # color with task status task_item.setData( QtGui.QColor( *status_colors_by_id[task[3]] ), QtCore.Qt.BackgroundRole ) # use black text task_item.setForeground( QtGui.QBrush(QtGui.QColor(0, 0, 0)) ) task_items.append(task_item) if task_items: self.appendRows(task_items) self.fetched_all = True logger.debug( 'TaskItem.fetchMore() is finished for item: %s' % self.text() )