コード例 #1
0
 def rebuildMonth( self ):
     """
     Rebuilds the month for this scene.
     """
     # make sure we start at 0 for sunday vs. 7 for sunday
     day_map     = dict([(i+1, i+1) for i in range(7)])
     day_map[7]  = 0
     
     today   = QDate.currentDate()
     curr    = self.currentDate()
     first   = QDate(curr.year(), curr.month(), 1)
     last    = QDate(curr.year(), curr.month(), curr.daysInMonth())
     first   = first.addDays(-day_map[first.dayOfWeek()])
     last    = last.addDays(6-day_map[last.dayOfWeek()])
     
     cols    = 7
     rows    = (first.daysTo(last) + 1) / cols
     
     hlines  = []
     vlines  = []
     
     padx    = 6
     pady    = 6
     header  = 24
     
     w       = self.width() - (2 * padx)
     h       = self.height() - (2 * pady)
     
     dw      = (w / cols) - 1
     dh      = ((h - header) / rows) - 1
     
     x0      = padx
     y0      = pady + header
     
     x       = x0
     y       = y0
     
     for row in range(rows + 1):
         hlines.append(QLine(x0, y, w, y))
         y += dh
     
     for col in range(cols + 1):
         vlines.append(QLine(x, y0, x, h))
         x += dw
     
     self._buildData['grid'] = hlines + vlines
     
     # draw the date fields
     date = first
     row  = 0
     col  = 0
     
     # draw the headers
     x = x0
     y = pady
     
     regular_text = []
     mid_text     = []
     self._buildData['regular_text'] = regular_text
     self._buildData['mid_text']     = mid_text
     
     for day in ('Sun', 'Mon','Tue','Wed','Thu','Fri','Sat'):
         regular_text.append((x + 5,
                              y,
                              dw,
                              y0,
                              Qt.AlignLeft | Qt.AlignVCenter,
                              day))
         x += dw
     
     for i in range(first.daysTo(last) + 1):
         top    = (y0 + (row * dh))
         left   = (x0 + (col * dw))
         rect   = QRectF(left - 1, top, dw, dh)
         
         # mark the current date on the calendar
         if ( date == curr ):
             self._buildData['curr_date'] = rect
         
         # mark today's date on the calendar
         elif ( date == today ):
             self._buildData['today'] = rect
         
         # determine how to draw the calendar
         format = 'd'
         if ( date.day() == 1 ):
             format = 'MMM d'
         
         # determine the color to draw the text
         if ( date.month() == curr.month() ):
             text = regular_text
         else:
             text = mid_text
         
         # draw the text
         text.append((left + 2,
                      top + 2,
                      dw - 4,
                      dh - 4,
                      Qt.AlignTop | Qt.AlignLeft,
                      date.toString(format)))
         
         # update the limits
         if ( not i ):
             self._minimumDate = date
         self._maximumDate = date
         
         self._dateGrid[date.toJulianDay()] = ((row, col), rect)
         if ( col == (cols - 1) ):
             row += 1
             col = 0
         else:
             col += 1
             
         date = date.addDays(1)
コード例 #2
0
class XGanttWidgetItem(XTreeWidgetItem):
    """ 
    Defines the main widget item class that contains information for both the
    tree and view widget items.
    """

    ItemStyle = enum('Normal', 'Group', 'Milestone')

    def __init__(self, ganttWidget):
        super(XGanttWidgetItem, self).__init__()

        # set default properties
        self.setFixedHeight(ganttWidget.cellHeight())
        for i in range(1, 20):
            self.setTextAlignment(i, Qt.AlignCenter)

        # define custom properties
        self._blockedAdjustments = {}
        self._viewItem = self.createViewItem()
        self._dateStart = QDate.currentDate()
        self._dateEnd = QDate.currentDate()
        self._allDay = True
        self._timeStart = QTime(0, 0, 0)
        self._timeEnd = QTime(23, 59, 59)
        self._name = "NONE"
        self._properties = {}
        self._itemStyle = XGanttWidgetItem.ItemStyle.Normal
        self._useGroupStyleWithChildren = True
        self._dependencies = {}
        self._reverseDependencies = {}
        self._dbEntry = None
        self._workdays = 0
        self._ganttWidget = ganttWidget
        #self._calculateWeekdays         = 0
        #self._dbDepartmentAssignment    = ''

        self.setPrivelages()

#    def __del__( self ):
#        self.removeFromScene()

    def addChild(self, item):
        """
        Adds a new child item to this item.
        
        :param      item | <XGanttWidgetItem>
        """
        super(XGanttWidgetItem, self).addChild(item)

        item.sync()

    def addDependency(self, item):
        """
        Creates a dependency for this item to the next item.  This item will
        be treated as the source, the other as the target.
        
        :param      item | <QGanttWidgetItem>
        """
        if item in self._dependencies:
            return

        viewItem = XGanttDepItem(self, item)

        self._dependencies[item] = viewItem
        item._reverseDependencies[self] = viewItem

        self.syncDependencies()

    def adjustmentsBlocked(self, key):
        """
        Returns whether or not hierarchy adjustments are being blocked.
        
        :param      key | <str>
        
        :return     <bool>
        """
        return self._blockedAdjustments.get(str(key), False)

    def adjustChildren(self, days):
        """
        Shifts the children for this item by the inputed number of days.
        
        :param      days | <int>
        """
        if (self.adjustmentsBlocked('children')):
            return

        if (self.itemStyle() != self.ItemStyle.Group):
            return

        if (not days):
            return

        for c in range(self.childCount()):
            child = self.child(c)
            child.blockAdjustments('range', True)
            child.setDateStart(child.dateStart().addDays(days))
            child.blockAdjustments('range', False)

    def adjustRange(self, recursive=True):
        """
        Adjust the start and end ranges for this item based on the limits from
        its children.  This method will only apply to group items.
        
        :param      recursive | <bool>
        """
        if (self.adjustmentsBlocked('range')):
            return

        if (self.itemStyle() == self.ItemStyle.Group):
            dateStart = self.dateStart()
            dateEnd = self.dateEnd()
            first = True

            for c in range(self.childCount()):
                child = self.child(c)

                if (first):
                    dateStart = child.dateStart()
                    dateEnd = child.dateEnd()
                    first = False
                else:
                    dateStart = min(child.dateStart(), dateStart)
                    dateEnd = max(child.dateEnd(), dateEnd)

            self._dateStart = dateStart
            self._dateEnd = dateEnd

            self.sync()

        if (self.parent() and recursive):
            self.parent().adjustRange(True)

    def blockAdjustments(self, key, state):
        """
        Blocks the inputed adjustments for the given key type.
        
        :param      key     | <str>
                    state   | <bool>
        """
        self._blockedAdjustments[str(key)] = state

    def clearDependencies(self):
        """
        Clears out all the dependencies from the scene.
        """
        gantt = self.ganttWidget()
        if (not gantt):
            return

        scene = gantt.viewWidget().scene()

        for target, viewItem in self._dependencies.items():
            target._reverseDependencies.pop(self)
            scene.removeItem(viewItem)

        self._dependencies.clear()

    def createViewItem(self):
        """
        Returns a new XGanttViewItem to use with this item.
        
        :return     <XGanttViewItem>
        """
        return XGanttViewItem(self)

    def RefreshFromDB(self):
        if self._dbEntry is not None:
            startDate = self._dbEntry._startdate
            endDate = self._dbEntry._enddate
            self.setDateStart(
                QDate(startDate.year, startDate.month, startDate.day), True)
            self.setDateEnd(QDate(endDate.year, endDate.month, endDate.day),
                            True)
            self.setName(self._dbEntry._name)
            self.sync()

    def dataUpdated(self, startdate, enddate):
        """
        Sets the database entry to updated for save.
        """
        #if (sharedDB.freezeDBUpdates == 0):
        if self._dbEntry is not None:
            self._dbEntry._updated = 1
            #sharedDB.changesToBeSaved = 1
            self._dbEntry._startdate = startdate.toPyDate()
            self._dbEntry._enddate = enddate.toPyDate()
            sharedDB.myAvailabilityManager.CalculateBooking()
            #if self._dbEntry._type == "phaseassignment":
#self._dbEntry.updateAvailability()
        return 1

    def dateEnd(self):
        """
        Return the end date for this gantt item.
        
        :return     <QDate>
        """
        if type(self._dateEnd) is datetime.date:
            self._dateEnd = QDate(self._dateEnd.year, self._dateEnd.month,
                                  self._dateEnd.day)

        return self._dateEnd

    def dateStart(self):
        """
        Return the start date for this gantt item.
        
        :return     <QDate>
        """

        if type(self._dateStart) is datetime.date:
            self._dateStart = QDate(self._dateStart.year,
                                    self._dateStart.month, self._dateStart.day)

        return self._dateStart

    def dateTimeEnd(self):
        """
        Returns a merging of data from the date end with the time end.
        
        :return     <QDateTime>
        """
        return QDateTime(self.dateEnd(), self.timeEnd())

    def dateTimeStart(self):
        """
        Returns a merging of data from the date end with the date start.
        
        :return     <QDateTime>
        """
        return QDateTime(self.dateStart(), self.timeStart())

    def dependencies(self):
        """
        Returns a list of all the dependencies linked with this item.
        
        :return     [<XGanttWidgetItem>, ..]
        """
        return self._dependencies.keys()

    def duration(self):
        """
        Returns the number of days this gantt item represents.
        
        :return     <int>
        """
        return 1 + self.dateStart().daysTo(self.dateEnd())

    def ganttWidget(self):
        """
        Returns the gantt widget that this item is linked to.
        
        :return     <XGanttWidget> || None
        """
        tree = self.treeWidget()
        if (not tree):
            return None

        #from projexui.widgets.xganttwidget import XGanttWidget
        return projexui.ancestor(tree,
                                 projexui.widgets.xganttwidget.XGanttWidget)

    def insertChild(self, index, item):
        """
        Inserts a new item in the given index.
        
        :param      index | <int>
                    item  | <XGanttWidgetItem>
        """
        super(XGanttWidgetItem, self).insertChild(index, item)
        item.sync()

    def isAllDay(self):
        """
        Returns whether or not this item reflects an all day event.
        
        :return     <bool>
        """
        return self._allDay

    def itemStyle(self):
        """
        Returns the item style information for this item.
        
        :return     <XGanttWidgetItem.ItemStyle>
        """
        if (self.useGroupStyleWithChildren() and self.childCount()):
            return XGanttWidgetItem.ItemStyle.Group

        return self._itemStyle

    def name(self):
        """
        Returns the name for this gantt widget item.
        
        :return     <str>
        """
        return self._name

    def property(self, key, default=None):
        """
        Returns the custom data that is stored on this object.
        
        :param      key     | <str>
                    default | <variant>
        
        :return     <variant>
        """
        if key == 'Name':
            return self.name()
        elif key == 'Start':
            return self.dateStart()
        elif key == 'End':
            return self.dateEnd()
        elif key == 'Calendar Days':
            return self.duration()
        elif key == 'Work Days':
            return self.weekdays()
        elif key == 'Time Start':
            return self.timeStart()
        elif key == 'Time End':
            return self.timeEnd()
        elif key == 'All Day':
            return self.isAllDay()
        else:
            return self._properties.get(str(key), default)

    def removeFromScene(self):
        """
        Removes this item from the view scene.
        """
        gantt = self.ganttWidget()
        if not gantt:
            return

        scene = gantt.viewWidget().scene()

        scene.removeItem(self.viewItem())
        for target, viewItem in self._dependencies.items():
            target._reverseDependencies.pop(self)
            scene.removeItem(viewItem)

    def setAllDay(self, state):
        """
        Sets whether or not this item is an all day event.
        
        :param      state | <bool>
        """
        self._allDay = state

    def setDateEnd(self, date, ignoreDuration=False):
        """
        Sets the date start value for this item.
        
        :param      dateStart | <QDate>
        """
        date = QDate(date)

        delta = self._dateEnd.daysTo(date)
        if (not delta):
            return

        if (self.itemStyle() != self.ItemStyle.Group):
            self._dateEnd = date
        else:
            duration = self.duration()
            if ignoreDuration is False:
                self._dateStart = date.addDays(-duration)
            self._dateEnd = date

        self.adjustChildren(delta)
        self.adjustRange()

        # sync the tree
        self.sync()

    def setDateStart(self, date, ignoreDuration=False):
        """
        Sets the date start value for this item.
        
        :param      dateStart | <QDate>
        """

        delta = self._dateStart.daysTo(date)
        if (not delta):
            return

        duration = self.duration()
        self._dateStart = date

        if ignoreDuration is False:
            self.setWorkdayDuration(self._workdays)

        #if type(date) is QDate:
        #    date.addDays(duration - 1)
        #else:
        #    date += timedelta(days=(duration - 1))
        #self._dateEnd   = date

        self.adjustChildren(delta)
        self.adjustRange()

        # udpate the tree widget
        self.sync()

    def projectChanged(self):
        #set project name
        if self._dbEntry is not None:
            self.setHidden(self._dbEntry._hidden)
            self.setName(self._dbEntry._name)

    def setDuration(self, duration):
        """
        Sets the duration for this item to the inputed duration.
        
        :param      duration | <int>
        """
        if duration < 1:
            return False

        self.setDateEnd(self.dateStart().addDays(duration - 1))

        self.dataUpdated(self.dateStart(), self.dateEnd())

        return True

    def setItemStyle(self, itemStyle):
        """
        Sets the item style that will be used for this widget.  If you are
        trying to set a style on an item that has children, make sure to turn 
        off the useGroupStyleWithChildren option, or it will always display as
        a group.
        
        :param      itemStyle | <XGanttWidgetItem.ItemStyle>
        """
        self._itemStyle = itemStyle

        # initialize the group icon for group style
        if itemStyle == XGanttWidgetItem.ItemStyle.Group and \
           self.icon(0).isNull():
            ico = projexui.resources.find('img/folder_close.png')
            expand_ico = projexui.resources.find('img/folder_open.png')
            self.setIcon(0, QIcon(ico))
            self.setExpandedIcon(0, QIcon(expand_ico))

    def setName(self, name):
        """
        Sets the name of this widget item to the inputed name.
        
        :param      name | <str>
        """
        self._name = name

        tree = self.treeWidget()
        if tree:
            col = tree.column('Name')
            if col != -1:
                self.setData(col, Qt.EditRole, qt.wrapVariant(name))

        self.sync()

    def setProperty(self, key, value):
        """
        Sets the custom property for this item's key to the inputed value.  If
        the widget has a column that matches the inputed key, then the value 
        will be added to the tree widget as well.
        
        :param      key     | <str>
                    value   | <variant>
        """
        if key == 'Name':
            if self._dbEntry._type == "project":
                self.setName(value)
                self._dbEntry.setProperty(propertyname=key, value=value)
            #self.sync()
        elif key == 'Start':
            if self.dateStart() != value:
                self.setDateStart(value)
                self.dataUpdated(self.dateStart(), self.dateEnd())
        elif key == 'End':
            if self.dateEnd() != value:
                self.setDateEnd(value)
                self.dataUpdated(self.dateStart(), self.dateEnd())
        elif key == 'Calendar Days':
            if self.duration() != value:
                self.setDuration(value)
        elif key == 'Time Start':
            self.setTimeStart(value)
        elif key == 'Time End':
            self.setTimeEnd(value)
        elif key == 'All Day':
            self.setAllDay(value)
        elif key == 'Work Days':
            if self.weekdays() != value:
                self.setWorkdayDuration(value)
        else:
            self._properties[str(key)] = value

            tree = self.treeWidget()
            if tree:
                col = tree.column(key)
                if col != -1:
                    self.setData(col, Qt.EditRole, qt.wrapVariant(value))

    def setTimeEnd(self, time):
        """
        Sets the ending time that this item will use.  To properly use a timed
        item, you need to also set this item's all day property to False.
        
        :sa         setAllDay
        
        :param      time | <QTime>
        """
        self._timeEnd = time
        self.sync()

    def setTimeStart(self, time):
        """
        Sets the starting time that this item will use.  To properly use a timed
        item, you need to also set this item's all day property to False.
        
        :sa         setAllDay
        
        :param      time | <QTime>
        """
        self._timeStart = time
        self.sync()

    def setUseGroupStyleWithChildren(self, state):
        """
        Sets whether or not this item should display as group style when 
        it has children.  This will override whatever is set in the style
        property for the item.
        
        :return     <bool>
        """
        self._useGroupStyleWithChildren = state

    def setPrivelages(self):
        #iterate through fields and adjust edit flag
        #print ("Privelages: "+str(sharedDB.currentUser._idPrivileges))
        if sharedDB.currentUser._idPrivileges > 1:
            self.setFlags(self.flags() ^ Qt.ItemIsEditable)
        #else:
        #flags =  Qt.ItemIsEditable
        #flags |= Qt.ItemIsSelectable
        #flags |= Qt.ItemIsFocusable
        #self.setFlags( flags )

    def setWorkdayDuration(self, duration):
        """
        Sets the duration for this item to the inputed duration.
        
        :param      duration | <int>
        """
        if duration < 1:
            return False

        x = 0
        dateEnd = self.dateStart()
        while x < duration:
            #print dateEnd.dayOfWeek()
            if dateEnd.dayOfWeek() < 6:
                x += 1
            dateEnd = dateEnd.addDays(1)

        self.setDateEnd(dateEnd.addDays(-1))
        self.dataUpdated(self.dateStart(), self.dateEnd())
        self.sync()
        return True

    def sync(self, recursive=False):
        """
        Syncs the information from this item to the tree and view.
        """
        self.syncTree()
        self.syncView()

        if (recursive):
            for c in range(self.childCount()):
                self.child(c).sync(recursive=True)

    def syncDependencies(self, recursive=False):
        """
        Syncs the dependencies for this item to the view.
        
        :param      recurisve | <bool>
        """
        scene = self.viewItem().scene()
        if (not scene):
            return

        visible = self.viewItem().isVisible()
        depViewItems = self._dependencies.values()
        depViewItems += self._reverseDependencies.values()

        for depViewItem in depViewItems:
            if (not depViewItem.scene()):
                scene.addItem(depViewItem)

            depViewItem.rebuild()
            depViewItem.setVisible(visible)

        if (recursive):
            for c in range(self.childCount()):
                self.child(c).syncDependencies(recursive=True)

    def syncTree(self, recursive=False, blockSignals=True):
        """
        Syncs the information from this item to the tree.
        """
        tree = self.treeWidget()

        # sync the tree information
        if not tree:
            return

        if blockSignals:
            tree.blockSignals(True)

        date_format = self.ganttWidget().dateFormat()
        for c, col in enumerate(tree.columns()):
            value = self.property(col, '')
            #if (col == "Work Days" or col == "Calendar Days"):
            self.setData(c, Qt.EditRole, qt.wrapVariant(value))

        if recursive:
            for i in range(self.childCount()):
                self.child(i).syncTree(recursive=True, blockSignals=False)

        if blockSignals:
            tree.blockSignals(False)

    def syncView(self, recursive=False):
        """
        Syncs the information from this item to the view.
        """

        # update the view widget
        item = self.viewItem()
        gantt = self.ganttWidget()

        if (not gantt):
            return

        tree = self.treeWidget()
        viewItem = self.viewItem()

        #sets name of viewitem
        viewItem.setText(self._name)

        if (not viewItem.scene()):
            scene = gantt.viewWidget().scene()
            scene.addItem(viewItem)

        if (self.isHidden() or not tree):
            viewItem.hide()
            return

        viewItem.show()
        tree_rect = tree.visualItemRect(self)

        # check to see if this item is hidden
        if (tree_rect.height() == 0):
            viewItem.hide()

        cell_w = gantt.cellWidth()
        view_x = gantt.viewWidget().scene().dateXPos(self.dateStart())
        tree_y = tree_rect.y()
        tree_y += tree.header().height()
        #add scrollbar value
        # ganttWidget.scroll.uiGanttTREE.verticalScrollBar()
        tree_y += self._ganttWidget.uiGanttTREE.verticalScrollBar().value()
        view_w = self.duration() * cell_w
        tree_h = tree_rect.height()

        # determine the % off from the start and end based on this items time
        if (not self.isAllDay()):
            full_day = 24 * 60 * 60  # full days worth of seconds

            # determine the start offset
            start = self.timeStart()
            start_day = (start.hour() * 60 * 60)
            start_day += (start.minute() * 60)
            start_day += (start.second())

            offset_start = (start_day / float(full_day)) * cell_w

            # determine the end offset
            end = self.timeEnd()
            end_day = (end.hour() * 60 * 60)
            end_day += (start.minute() * 60)
            end_day += (start.second() + 1)  # forces at least 1 second

            offset_end = ((full_day - end_day) / float(full_day)) * cell_w

            # update the xpos and widths
            view_x += offset_start
            view_w -= (offset_start + offset_end)

        item.setSyncing(True)
        item.setPos(view_x, tree_y)

        #if ()
        if self.isExpanded():
            viewHeight = self.visibleChildrenCount() + 1
        else:
            viewHeight = 1
        item.setRect(0, 0, view_w, tree_h * viewHeight)
        item.setSyncing(False)

        self.syncDependencies()

        if (recursive):
            for i in range(self.childCount()):
                self.child(i).syncView(recursive=True)

    def takeChild(self, index):
        """
        Removes the child at the given index from this item.
        
        :param      index | <int>
        """
        item = super(XGanttWidgetItem, self).takeChild(index)

        if item:
            item.removeFromScene()

        return item

    def takeDependency(self, item):
        """
        Removes the dependency between the this item and the inputed target.
        
        :param      item | <XGanttWidgetItem>
        """
        if (not item in self._dependencies):
            return

        item._reverseDependencies.pop(self)
        viewItem = self._dependencies.pop(item)

        scene = viewItem.scene()
        if (scene):
            scene.removeItem(viewItem)

    def timeEnd(self):
        """
        Returns the ending time that will be used for this item.  If it is an
        all day event, then the time returned will be 23:59:59.
        
        :return     <QTime>
        """
        if (self.isAllDay()):
            return QTime(23, 59, 59)
        return self._timeEnd

    def timeStart(self):
        """
        Returns the starting time that will be used for this item.  If it is
        an all day event, then the time returned will be 0:0:0
        
        :return     <QTime>
        """
        if (self.isAllDay()):
            return QTime(0, 0, 0)

        return self._timeStart

    def useGroupStyleWithChildren(self):
        """
        Returns whether or not this item should display as group style when 
        it has children.  This will override whatever is set in the style
        property for the item.
        
        :return     <bool>
        """
        return self._useGroupStyleWithChildren

    def viewChanged(self, dateStart, dateEnd):
        """
        Called when the view item is changed by the user.
        
        :param      dateStart | <QDate>
                    dateEnd   | <QDate>
        """

        if self._dateStart != dateStart or self._dateEnd != dateEnd:

            delta = self._dateStart.daysTo(dateStart)
            self._dateStart = dateStart

            #print self.property("Work Days")
            #print self._workdays
            #if !justWeekdays
            if self._dbEntry is not None:
                if self._dbEntry._type == "project":
                    self._dateEnd = dateEnd
                else:
                    self.setWorkdayDuration(self._workdays)
            else:
                self.setWorkdayDuration(self._workdays)

            self.adjustChildren(delta)
            self.adjustRange()

            self.syncDependencies()
            self.syncTree()

            self.dataUpdated(self.dateStart(), self.dateEnd())

    def viewItem(self):
        """
        Returns the view item that is linked with this item.
        
        :return     <XGanttViewItem>
        """
        if type(self._viewItem).__name__ == 'weakref':
            return self._viewItem()
        return self._viewItem

    def visibleChildrenCount(self):
        count = 0
        for i in range(self.childCount()):
            if not self.child(i).isHidden():
                count += 1
        return count

    def weekdays(self):
        """
        Returns the number of weekdays this item has.
        
        :return     <int>
        """
        #if self._calculateWeekdays:
        if self.itemStyle() == self.ItemStyle.Group:
            out = 0
            for i in range(self.childCount()):
                out += self.child(i).weekdays()
            return out
        else:

            dstart = self.dateStart().toPyDate()
            dend = self.dateEnd().toPyDate()
            self._workdays = projex.dates.weekdays(dstart, dend)
            return self._workdays
コード例 #3
0
class XGanttWidgetItem(XTreeWidgetItem):
    """ 
    Defines the main widget item class that contains information for both the
    tree and view widget items.
    """
    
    ItemStyle = enum('Normal', 'Group', 'Milestone')
    
    def __init__( self, ganttWidget ):
        super(XGanttWidgetItem, self).__init__()
        
        # set default properties
        self.setFixedHeight(ganttWidget.cellHeight())
        for i in range(1, 20):
            self.setTextAlignment(i, Qt.AlignCenter)
        
        # define custom properties
        self._blockedAdjustments        = {}
        self._viewItem                  = self.createViewItem()
        self._dateStart                 = QDate.currentDate()
        self._dateEnd                   = QDate.currentDate()
        self._allDay                    = True
        self._timeStart                 = QTime(0, 0, 0)
        self._timeEnd                   = QTime(23, 59, 59)
        self._name                      = "NONE"
        self._properties                = {}
        self._itemStyle                 = XGanttWidgetItem.ItemStyle.Normal
        self._useGroupStyleWithChildren = True
        self._dependencies              = {}
        self._reverseDependencies       = {}
        self._dbEntry                   = None
        self._workdays                  = 0
        self._ganttWidget               = ganttWidget
        #self._calculateWeekdays         = 0
        #self._dbDepartmentAssignment    = ''
    
        self.setPrivelages()
        
#    def __del__( self ):
#        self.removeFromScene()
    
    def addChild( self, item ):
        """
        Adds a new child item to this item.
        
        :param      item | <XGanttWidgetItem>
        """
        super(XGanttWidgetItem, self).addChild(item)
        
        item.sync()
    
    def addDependency( self, item ):
        """
        Creates a dependency for this item to the next item.  This item will
        be treated as the source, the other as the target.
        
        :param      item | <QGanttWidgetItem>
        """
        if item in self._dependencies:
            return
        
        viewItem = XGanttDepItem(self, item)
        
        self._dependencies[item]        = viewItem
        item._reverseDependencies[self] = viewItem
        
        self.syncDependencies()
    
    def adjustmentsBlocked( self, key ):
        """
        Returns whether or not hierarchy adjustments are being blocked.
        
        :param      key | <str>
        
        :return     <bool>
        """
        return self._blockedAdjustments.get(str(key), False)
    
    def adjustChildren( self, days ):
        """
        Shifts the children for this item by the inputed number of days.
        
        :param      days | <int>
        """
        if ( self.adjustmentsBlocked('children') ):
            return
            
        if ( self.itemStyle() != self.ItemStyle.Group ):
            return
        
        if ( not days ):
            return
        
        for c in range(self.childCount()):
            child = self.child(c)
            child.blockAdjustments('range', True)
            child.setDateStart(child.dateStart().addDays(days))
            child.blockAdjustments('range', False)
    
    def adjustRange( self, recursive = True ):
        """
        Adjust the start and end ranges for this item based on the limits from
        its children.  This method will only apply to group items.
        
        :param      recursive | <bool>
        """
        if ( self.adjustmentsBlocked('range') ):
            return
        
        if ( self.itemStyle() == self.ItemStyle.Group ):
            dateStart = self.dateStart()
            dateEnd   = self.dateEnd()
            first     = True
            
            for c in range(self.childCount()):
                child       = self.child(c)
                
                if ( first ):
                    dateStart = child.dateStart()
                    dateEnd   = child.dateEnd()
                    first     = False
                else:
                    dateStart   = min(child.dateStart(), dateStart)
                    dateEnd     = max(child.dateEnd(), dateEnd)
            
            self._dateStart = dateStart
            self._dateEnd   = dateEnd
            
            self.sync()
        
        if ( self.parent() and recursive ):
            self.parent().adjustRange(True)
    
    def blockAdjustments( self, key, state ):
        """
        Blocks the inputed adjustments for the given key type.
        
        :param      key     | <str>
                    state   | <bool>
        """
        self._blockedAdjustments[str(key)] = state
    
    def clearDependencies( self ):
        """
        Clears out all the dependencies from the scene.
        """
        gantt = self.ganttWidget()
        if ( not gantt ):
            return
        
        scene = gantt.viewWidget().scene()
        
        for target, viewItem in self._dependencies.items():
            target._reverseDependencies.pop(self)
            scene.removeItem(viewItem)
        
        self._dependencies.clear()
    
    def createViewItem( self ):
        """
        Returns a new XGanttViewItem to use with this item.
        
        :return     <XGanttViewItem>
        """
        return XGanttViewItem(self)
    
    def GetDatesFromDBEntry(self):
        if self._dbEntry is not None:
            startDate = self._dbEntry._startdate
            endDate = self._dbEntry._enddate
            self.setDateStart(QDate(startDate.year,startDate.month,startDate.day),True)
	    self.setDateEnd(QDate(endDate.year,endDate.month,endDate.day),True)
        
    
    def dataUpdated(self,startdate,enddate):
        """
        Sets the database entry to updated for save.
        """
        #if (sharedDB.freezeDBUpdates == 0):
        if self._dbEntry is not None:
	    self._dbEntry._updated = 1
	    #sharedDB.changesToBeSaved = 1
	    self._dbEntry._startdate = startdate.toPyDate()
	    self._dbEntry._enddate = enddate.toPyDate()
            sharedDB.myAvailabilityManager.CalculateBooking()
	    #if self._dbEntry._type == "phaseassignment":
		#self._dbEntry.updateAvailability()
        return 1
    
    def dateEnd( self ):
        """
        Return the end date for this gantt item.
        
        :return     <QDate>
        """
        if type(self._dateEnd) is datetime.date:
            self._dateEnd = QDate(self._dateEnd.year,self._dateEnd.month,self._dateEnd.day)
        
        return self._dateEnd
    
    def dateStart( self ):
        """
        Return the start date for this gantt item.
        
        :return     <QDate>
        """
        
        if type(self._dateStart) is datetime.date:
            self._dateStart = QDate(self._dateStart.year,self._dateStart.month,self._dateStart.day)
        
        return self._dateStart
    
    def dateTimeEnd( self ):
        """
        Returns a merging of data from the date end with the time end.
        
        :return     <QDateTime>
        """
        return QDateTime(self.dateEnd(), self.timeEnd())
    
    def dateTimeStart( self ):
        """
        Returns a merging of data from the date end with the date start.
        
        :return     <QDateTime>
        """
        return QDateTime(self.dateStart(), self.timeStart())
    
    def dependencies( self ):
        """
        Returns a list of all the dependencies linked with this item.
        
        :return     [<XGanttWidgetItem>, ..]
        """
        return self._dependencies.keys()
    
    def duration( self ):
        """
        Returns the number of days this gantt item represents.
        
        :return     <int>
        """
        return 1 + self.dateStart().daysTo(self.dateEnd())
    
    def ganttWidget( self ):
        """
        Returns the gantt widget that this item is linked to.
        
        :return     <XGanttWidget> || None
        """
        tree = self.treeWidget()
        if ( not tree ):
            return None
        
        #from projexui.widgets.xganttwidget import XGanttWidget
        return projexui.ancestor(tree, projexui.widgets.xganttwidget.XGanttWidget)
    
    def insertChild( self, index, item ):
        """
        Inserts a new item in the given index.
        
        :param      index | <int>
                    item  | <XGanttWidgetItem>
        """
        super(XGanttWidgetItem, self).insertChild(index, item)
        item.sync()
    
    def isAllDay( self ):
        """
        Returns whether or not this item reflects an all day event.
        
        :return     <bool>
        """
        return self._allDay
    
    def itemStyle( self ):
        """
        Returns the item style information for this item.
        
        :return     <XGanttWidgetItem.ItemStyle>
        """
        if ( self.useGroupStyleWithChildren() and self.childCount() ):
            return XGanttWidgetItem.ItemStyle.Group
        
        return self._itemStyle
    
    def name( self ):
        """
        Returns the name for this gantt widget item.
        
        :return     <str>
        """
        return self._name
    
    def property( self, key, default = None ):
        """
        Returns the custom data that is stored on this object.
        
        :param      key     | <str>
                    default | <variant>
        
        :return     <variant>
        """
        if key == 'Name':
            return self.name()
        elif key == 'Start':
            return self.dateStart()
        elif key == 'End':
            return self.dateEnd()
        elif key == 'Calendar Days':
            return self.duration()
        elif key == 'Work Days':
            return self.weekdays()
        elif key == 'Time Start':
            return self.timeStart()
        elif key == 'Time End':
            return self.timeEnd()
        elif key == 'All Day':
            return self.isAllDay()
        else:
            return self._properties.get(str(key), default)
    
    def removeFromScene( self ):
        """
        Removes this item from the view scene.
        """
        gantt = self.ganttWidget()
        if not gantt:
            return
        
        scene = gantt.viewWidget().scene()
        
        scene.removeItem(self.viewItem())
        for target, viewItem in self._dependencies.items():
            target._reverseDependencies.pop(self)
            scene.removeItem(viewItem)
    
    def setAllDay( self, state ):
        """
        Sets whether or not this item is an all day event.
        
        :param      state | <bool>
        """
        self._allDay = state
    
    def setDateEnd( self, date, ignoreDuration = False ):
        """
        Sets the date start value for this item.
        
        :param      dateStart | <QDate>
        """
        date = QDate(date)
        
        delta = self._dateEnd.daysTo(date)
        if ( not delta ):
            return
        
        if ( self.itemStyle() != self.ItemStyle.Group ):
            self._dateEnd = date
        else:
            duration        = self.duration()
            if ignoreDuration is False:
                self._dateStart = date.addDays(-duration)
            self._dateEnd   = date
            
        self.adjustChildren(delta)
        self.adjustRange()
        
        # sync the tree
        self.sync()
        
    def setDateStart( self, date, ignoreDuration = False):
        """
        Sets the date start value for this item.
        
        :param      dateStart | <QDate>
        """
        
        delta           = self._dateStart.daysTo(date)
        if ( not delta ):
            return
        
        duration        = self.duration()
        self._dateStart = date
        
        if ignoreDuration is False:
            self.setWorkdayDuration(self._workdays)
        
        #if type(date) is QDate:
        #    date.addDays(duration - 1)
        #else:
        #    date += timedelta(days=(duration - 1))
        #self._dateEnd   = date
        
        self.adjustChildren(delta)
        self.adjustRange()
        
        # udpate the tree widget
        self.sync()
    
    def projectChanged(self):
        #set project name
        if self._dbEntry is not None:
	    self.setHidden(self._dbEntry._hidden)	
	    self.setName(self._dbEntry._name)        
    
    def setDuration( self, duration ):
        """
        Sets the duration for this item to the inputed duration.
        
        :param      duration | <int>
        """
        if duration < 1:
            return False
        
        self.setDateEnd(self.dateStart().addDays(duration - 1))
        
        self.dataUpdated(self.dateStart(),self.dateEnd())
        
        return True
    
    def setItemStyle( self, itemStyle ):
        """
        Sets the item style that will be used for this widget.  If you are
        trying to set a style on an item that has children, make sure to turn 
        off the useGroupStyleWithChildren option, or it will always display as
        a group.
        
        :param      itemStyle | <XGanttWidgetItem.ItemStyle>
        """
        self._itemStyle = itemStyle
        
        # initialize the group icon for group style
        if itemStyle == XGanttWidgetItem.ItemStyle.Group and \
           self.icon(0).isNull():
            ico = projexui.resources.find('img/folder_close.png')
            expand_ico = projexui.resources.find('img/folder_open.png')
            self.setIcon(0, QIcon(ico))
            self.setExpandedIcon(0, QIcon(expand_ico))
    
    def setName( self, name ):
        """
        Sets the name of this widget item to the inputed name.
        
        :param      name | <str>
        """
        self._name = name
        
        tree = self.treeWidget()
        if tree:
            col = tree.column('Name')
            if col != -1:
                self.setData(col, Qt.EditRole, qt.wrapVariant(name))
        
        self.sync()
    
    def setProperty( self, key, value ):
        """
        Sets the custom property for this item's key to the inputed value.  If
        the widget has a column that matches the inputed key, then the value 
        will be added to the tree widget as well.
        
        :param      key     | <str>
                    value   | <variant>
        """
        if key == 'Name':
            if self._dbEntry._type == "project":
		self.setName(value)            
		self._dbEntry.setProperty(propertyname = key, value = value)
            #self.sync()
        elif key == 'Start':
            if self.dateStart() != value:
		self.setDateStart(value)
		self.dataUpdated(self.dateStart(),self.dateEnd())
        elif key == 'End':
            if self.dateEnd() != value:
		self.setDateEnd(value)
		self.dataUpdated(self.dateStart(),self.dateEnd())
        elif key == 'Calendar Days':
            if self.duration() != value:
		self.setDuration(value)
        elif key == 'Time Start':
            self.setTimeStart(value)
        elif key == 'Time End':
            self.setTimeEnd(value)
        elif key == 'All Day':
            self.setAllDay(value)
        elif key == 'Work Days':
            if self.weekdays() != value:
		self.setWorkdayDuration(value)
        else:
            self._properties[str(key)] = value
            
            tree = self.treeWidget()
            if tree:
                col = tree.column(key)
                if col != -1:
                    self.setData(col, Qt.EditRole, qt.wrapVariant(value))
    
    def setTimeEnd( self, time ):
        """
        Sets the ending time that this item will use.  To properly use a timed
        item, you need to also set this item's all day property to False.
        
        :sa         setAllDay
        
        :param      time | <QTime>
        """
        self._timeEnd = time
        self.sync()
    
    def setTimeStart( self, time ):
        """
        Sets the starting time that this item will use.  To properly use a timed
        item, you need to also set this item's all day property to False.
        
        :sa         setAllDay
        
        :param      time | <QTime>
        """
        self._timeStart = time
        self.sync()
    
    def setUseGroupStyleWithChildren( self, state ):
        """
        Sets whether or not this item should display as group style when 
        it has children.  This will override whatever is set in the style
        property for the item.
        
        :return     <bool>
        """
        self._useGroupStyleWithChildren = state

    def setPrivelages (self):
        #iterate through fields and adjust edit flag
        #print ("Privelages: "+str(sharedDB.currentUser._idPrivileges))
        if sharedDB.currentUser._idPrivileges > 1:
            self.setFlags( self.flags() ^ Qt.ItemIsEditable )
        #else:
            #flags =  Qt.ItemIsEditable
            #flags |= Qt.ItemIsSelectable 
            #flags |= Qt.ItemIsFocusable
            #self.setFlags( flags )
    
    def setWorkdayDuration( self, duration ):
        
        """
        Sets the duration for this item to the inputed duration.
        
        :param      duration | <int>
        """
        if duration < 1:
            return False
        
        x = 0
        dateEnd = self.dateStart()
        while x < duration:
            #print dateEnd.dayOfWeek()
            if dateEnd.dayOfWeek()<6:
                x+=1
            dateEnd = dateEnd.addDays(1)
        
        
        self.setDateEnd(dateEnd.addDays(-1))
        self.dataUpdated(self.dateStart(),self.dateEnd())
        self.sync()
        return True
    
    def sync( self, recursive = False ):
        """
        Syncs the information from this item to the tree and view.
        """
        self.syncTree()
        self.syncView()
        
        if ( recursive ):
            for c in range(self.childCount()):
                self.child(c).sync(recursive = True)
    
    def syncDependencies( self, recursive = False ):
        """
        Syncs the dependencies for this item to the view.
        
        :param      recurisve | <bool>
        """
        scene = self.viewItem().scene()
        if ( not scene ):
            return
        
        visible       = self.viewItem().isVisible()
        depViewItems  = self._dependencies.values() 
        depViewItems += self._reverseDependencies.values()
        
        for depViewItem in depViewItems:
            if ( not depViewItem.scene() ):
                scene.addItem(depViewItem)
            
            depViewItem.rebuild()
            depViewItem.setVisible(visible)
        
        if ( recursive ):
            for c in range(self.childCount()):
                self.child(c).syncDependencies(recursive = True)
        
    def syncTree(self, recursive=False, blockSignals=True):
        """
        Syncs the information from this item to the tree.
        """
        tree = self.treeWidget()
        
        # sync the tree information
        if not tree:
            return
        
        if blockSignals:
            tree.blockSignals(True)

        date_format = self.ganttWidget().dateFormat()
        for c, col in enumerate(tree.columns()):
            value = self.property(col, '')
            #if (col == "Work Days" or col == "Calendar Days"):
            self.setData(c, Qt.EditRole, qt.wrapVariant(value))
        
        if recursive:
            for i in range(self.childCount()):
                self.child(i).syncTree(recursive=True, blockSignals=False)
        
        if blockSignals:
            tree.blockSignals(False)
    
    def syncView( self, recursive = False ):
        """
        Syncs the information from this item to the view.
        """
        
        # update the view widget
        item    = self.viewItem()
        gantt   = self.ganttWidget()
        
        if ( not gantt ):
            return
        
        tree        = self.treeWidget()
        viewItem    = self.viewItem()
        
        #sets name of viewitem
        viewItem.setText(self._name)
        
        if ( not viewItem.scene() ):
            scene = gantt.viewWidget().scene()
            scene.addItem(viewItem)
        
        if ( self.isHidden() or not tree ):
            viewItem.hide()
            return
        
        viewItem.show()
        tree_rect   = tree.visualItemRect(self)
        
        # check to see if this item is hidden
        if ( tree_rect.height() == 0 ):
            viewItem.hide()
        
        cell_w  = gantt.cellWidth()
        view_x  = gantt.viewWidget().scene().dateXPos(self.dateStart())
        tree_y  = tree_rect.y()
        tree_y += tree.header().height()
        #add scrollbar value
        # ganttWidget.scroll.uiGanttTREE.verticalScrollBar()
        tree_y += self._ganttWidget.uiGanttTREE.verticalScrollBar().value()
        view_w  = self.duration() * cell_w 
        tree_h  = tree_rect.height()
        
        # determine the % off from the start and end based on this items time
        if ( not self.isAllDay() ):
            full_day   = 24 * 60 * 60 # full days worth of seconds
            
            # determine the start offset
            start      = self.timeStart()
            start_day  = (start.hour() * 60 * 60) 
            start_day += (start.minute() * 60) 
            start_day += (start.second())
            
            offset_start = (start_day / float(full_day)) * cell_w
            
            # determine the end offset
            end         = self.timeEnd()
            end_day     = (end.hour() * 60 * 60)
            end_day    += (start.minute() * 60)
            end_day    += (start.second() + 1) # forces at least 1 second
            
            offset_end = ((full_day - end_day) / float(full_day)) * cell_w
            
            # update the xpos and widths
            view_x += offset_start
            view_w -= (offset_start + offset_end)
       
        item.setSyncing(True)
        item.setPos(view_x, tree_y)
        
        #if ()
        if self.isExpanded():
            viewHeight = self.visibleChildrenCount()+1
        else:
            viewHeight = 1
        item.setRect(0, 0, view_w, tree_h*viewHeight)
        item.setSyncing(False)
        
        self.syncDependencies()
        
        if ( recursive ):
            for i in range(self.childCount()):
                self.child(i).syncView(recursive = True)
    
    def takeChild( self, index ):
        """
        Removes the child at the given index from this item.
        
        :param      index | <int>
        """
        item = super(XGanttWidgetItem, self).takeChild(index)
        
        if item:
            item.removeFromScene()
            
        return item
        
    def takeDependency( self, item ):
        """
        Removes the dependency between the this item and the inputed target.
        
        :param      item | <XGanttWidgetItem>
        """
        if ( not item in self._dependencies ):
            return
        
        item._reverseDependencies.pop(self)
        viewItem = self._dependencies.pop(item)
        
        scene    = viewItem.scene()
        if ( scene ):
            scene.removeItem(viewItem)
    
    def timeEnd( self ):
        """
        Returns the ending time that will be used for this item.  If it is an
        all day event, then the time returned will be 23:59:59.
        
        :return     <QTime>
        """
        if ( self.isAllDay() ):
            return QTime(23, 59, 59)
        return self._timeEnd
    
    def timeStart( self ):
        """
        Returns the starting time that will be used for this item.  If it is
        an all day event, then the time returned will be 0:0:0
        
        :return     <QTime>
        """
        if ( self.isAllDay() ):
            return QTime(0, 0, 0)
        
        return self._timeStart
    
    def useGroupStyleWithChildren( self ):
        """
        Returns whether or not this item should display as group style when 
        it has children.  This will override whatever is set in the style
        property for the item.
        
        :return     <bool>
        """
        return self._useGroupStyleWithChildren
    
    def viewChanged( self, dateStart, dateEnd ):
        """
        Called when the view item is changed by the user.
        
        :param      dateStart | <QDate>
                    dateEnd   | <QDate>
        """
        
        if self._dateStart!=dateStart or self._dateEnd!=dateEnd:
        
            delta           = self._dateStart.daysTo(dateStart)
            self._dateStart = dateStart

            #print self.property("Work Days")
            #print self._workdays
            #if !justWeekdays
            if self._dbEntry is not None:
		if self._dbEntry._type == "project":
		    self._dateEnd   = dateEnd
		else:
		    self.setWorkdayDuration(self._workdays)
            else:
		    self.setWorkdayDuration(self._workdays)
            
            
            self.adjustChildren(delta)
            self.adjustRange()
            
            self.syncDependencies()
            self.syncTree()
    
            self.dataUpdated(self.dateStart(),self.dateEnd())
    
    def viewItem( self ):
        """
        Returns the view item that is linked with this item.
        
        :return     <XGanttViewItem>
        """
        if type(self._viewItem).__name__ == 'weakref':
            return self._viewItem()
        return self._viewItem
    
    def visibleChildrenCount(self):
        count = 0
        for i in range(self.childCount()):
            if not self.child(i).isHidden():
                count +=1
        return count
    
    def weekdays(self):
        """
        Returns the number of weekdays this item has.
        
        :return     <int>
        """
        #if self._calculateWeekdays:
        if self.itemStyle() == self.ItemStyle.Group:
            out = 0
            for i in range(self.childCount()):
                out += self.child(i).weekdays()
            return out
        else:
            
            dstart = self.dateStart().toPyDate()
            dend   = self.dateEnd().toPyDate()
            self._workdays = projex.dates.weekdays(dstart, dend)
            return self._workdays
            #self._calculateWeekdays = 0
コード例 #4
0
    def rebuildMonth(self):
        """
        Rebuilds the month for this scene.
        """
        # make sure we start at 0 for sunday vs. 7 for sunday
        day_map = dict([(i + 1, i + 1) for i in range(7)])
        day_map[7] = 0

        today = QDate.currentDate()
        curr = self.currentDate()
        first = QDate(curr.year(), curr.month(), 1)
        last = QDate(curr.year(), curr.month(), curr.daysInMonth())
        first = first.addDays(-day_map[first.dayOfWeek()])
        last = last.addDays(6 - day_map[last.dayOfWeek()])

        cols = 7
        rows = (first.daysTo(last) + 1) / cols

        hlines = []
        vlines = []

        padx = 6
        pady = 6
        header = 24

        w = self.width() - (2 * padx)
        h = self.height() - (2 * pady)

        dw = (w / cols) - 1
        dh = ((h - header) / rows) - 1

        x0 = padx
        y0 = pady + header

        x = x0
        y = y0

        for row in range(rows + 1):
            hlines.append(QLine(x0, y, w, y))
            y += dh

        for col in range(cols + 1):
            vlines.append(QLine(x, y0, x, h))
            x += dw

        self._buildData['grid'] = hlines + vlines

        # draw the date fields
        date = first
        row = 0
        col = 0

        # draw the headers
        x = x0
        y = pady

        regular_text = []
        mid_text = []
        self._buildData['regular_text'] = regular_text
        self._buildData['mid_text'] = mid_text

        for day in ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'):
            regular_text.append(
                (x + 5, y, dw, y0, Qt.AlignLeft | Qt.AlignVCenter, day))
            x += dw

        for i in range(first.daysTo(last) + 1):
            top = (y0 + (row * dh))
            left = (x0 + (col * dw))
            rect = QRectF(left - 1, top, dw, dh)

            # mark the current date on the calendar
            if (date == curr):
                self._buildData['curr_date'] = rect

            # mark today's date on the calendar
            elif (date == today):
                self._buildData['today'] = rect

            # determine how to draw the calendar
            format = 'd'
            if (date.day() == 1):
                format = 'MMM d'

            # determine the color to draw the text
            if (date.month() == curr.month()):
                text = regular_text
            else:
                text = mid_text

            # draw the text
            text.append(
                (left + 2, top + 2, dw - 4, dh - 4, Qt.AlignTop | Qt.AlignLeft,
                 date.toString(format)))

            # update the limits
            if (not i):
                self._minimumDate = date
            self._maximumDate = date

            self._dateGrid[date.toJulianDay()] = ((row, col), rect)
            if (col == (cols - 1)):
                row += 1
                col = 0
            else:
                col += 1

            date = date.addDays(1)