Exemple #1
0
    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')
Exemple #2
0
    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)
Exemple #3
0
    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)
Exemple #4
0
    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())
Exemple #5
0
    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)
Exemple #6
0
    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()
        )
Exemple #7
0
    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()
        )
Exemple #8
0
    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()
        )