def effort_time_changed(self, q_time): """runs when the effort has been changed """ if self.updating_timings: return self.updating_timings = True # q_time should be a multiple of the TIMING_RESOLUTION q_time = self.round_to_timing_resolution(q_time) self.effort_time_edit.setTime(q_time) # q_time can not be smaller thane TIMING_RESOLUTION from anima import TIMING_RESOLUTION start_of_today = QtCore.QTime(0, 0) secs_since_start_of_day = start_of_today.secsTo(q_time) if secs_since_start_of_day < TIMING_RESOLUTION * 60: # clip to TIMING_RESOLUTION q_time = QtCore.QTime(0, 0) q_time = q_time.addSecs(TIMING_RESOLUTION * 60) self.effort_time_edit.setTime(q_time) start_time = self.start_time_edit.time() end_time = start_time.addSecs(start_of_today.secsTo(q_time)) self.end_time_edit.setTime(end_time) self.updating_timings = False self.update_percentage() self.update_info_text()
def start_time_changed(self, q_time): """validates the start time """ if self.updating_timings: return self.updating_timings = True # q_time should be a multiple of the TIMING_RESOLUTION q_time = self.round_to_timing_resolution(q_time) self.start_time_edit.setTime(q_time) end_time = self.end_time_edit.time() if q_time >= end_time: from anima import TIMING_RESOLUTION logger.debug("updating end_time with set_time") self.end_time_edit.setTime(q_time.addSecs(TIMING_RESOLUTION * 60)) logger.debug("updated end_time with set_time") start_time = self.start_time_edit.time() end_time = self.end_time_edit.time() secs = start_time.secsTo(end_time) logger.debug("secs: %s" % secs) new_time = QtCore.QTime(0, 0) new_time = new_time.addSecs(secs) logger.debug("new_time: %s" % new_time) logger.debug("updating end_time with set_time") self.effort_time_edit.setTime(new_time) logger.debug("updated end_time with set_time") self.updating_timings = False self.update_percentage() self.update_info_text()
def stepBy(self, step): """Custom stepBy function :param step: :return: """ if self.currentSectionIndex() == 1: if step < 0: # auto update the hour section to the next hour minute = self.time().minute() if minute == 0: # increment the hour section by one self.setTime( QtCore.QTime(self.time().hour() - 1, 60 - self.resolution)) else: self.setTime( QtCore.QTime(self.time().hour(), minute - self.resolution)) else: # auto update the hour section to the next hour minute = self.time().minute() if minute == (60 - self.resolution): # increment the hour section by one self.setTime(QtCore.QTime(self.time().hour() + 1, 0)) else: self.setTime( QtCore.QTime(self.time().hour(), minute + self.resolution)) else: if step < 0: if self.time().hour() != 0: super(TimeEdit, self).stepBy(step) else: if self.time().hour() != 23: super(TimeEdit, self).stepBy(step)
def round_to_timing_resolution(cls, q_time): """rounds to the TIMING_RESOLUTION :param q_time: :return: """ logger.debug("q_time(RAW) : %s" % q_time) from anima import TIMING_RESOLUTION start_of_today = QtCore.QTime(0, 0) secs = start_of_today.secsTo(q_time) logger.debug('secs : %s' % secs) logger.debug("TIMING_RESOLUTION: %s" % TIMING_RESOLUTION) rounded_secs = (secs // (TIMING_RESOLUTION * 60)) * TIMING_RESOLUTION * 60 logger.debug("rounded_secs: %s" % rounded_secs) rounded_q_time = start_of_today.addSecs(rounded_secs) logger.debug("q_time(Rounded): %s" % rounded_q_time) return rounded_q_time
def end_time_changed(self, q_time): """validates the end time """ if self.updating_timings: return self.updating_timings = True logger.debug("end_time_changed event is triggered!") # q_time should be a multiple of the TIMING_RESOLUTION q_time = self.round_to_timing_resolution(q_time) self.end_time_edit.setTime(q_time) start_time = self.start_time_edit.time() if q_time <= start_time: from anima import TIMING_RESOLUTION if q_time.hour() == 0 and q_time.minute() == 0: start_time = q_time end_time = q_time.addSecs(TIMING_RESOLUTION * 60) self.end_time_edit.setTime(end_time) else: start_time = q_time.addSecs(-TIMING_RESOLUTION * 60) self.start_time_edit.setTime(start_time) start_time = self.start_time_edit.time() end_time = self.end_time_edit.time() secs = start_time.secsTo(end_time) logger.debug("secs: %s" % secs) new_time = QtCore.QTime(0, 0) new_time = new_time.addSecs(secs) logger.debug("new_time: %s" % new_time) self.effort_time_edit.setTime(new_time) self.updating_timings = False self.update_percentage() self.update_info_text()
def _set_defaults(self): """sets the defaults for the ui """ logger.debug("started setting up interface defaults") # Set Default Value for time current_time = QtCore.QTime.currentTime() # round the minutes to the resolution minute = current_time.minute() hour = current_time.hour() minute = int(minute / float(timing_resolution)) * timing_resolution current_time = QtCore.QTime(hour, minute) self.start_time_edit.setTime(current_time) self.end_time_edit.setTime(current_time.addSecs(timing_resolution * 60)) self.calendar_widget.resource_id = -1 # enter revision types revision_types = [ 'Yetistiremedim', 'Ajans', 'Yonetmen', 'Ic Revizyon', ] self.revision_type_combo_box.addItems(revision_types) if not self.logged_in_user: self.logged_in_user = self.get_logged_in_user() # fill the tasks comboBox from stalker import Status, Task status_wfd = Status.query.filter(Status.code == 'WFD').first() status_cmpl = Status.query.filter(Status.code == 'CMPL').first() status_prev = Status.query.filter(Status.code == 'PREV').first() if not self.timelog: # dialog is in create TimeLog mode # if a task has been given just feed that task to the comboBox if self.task: all_tasks = [self.task] else: # no Task is given nor updating a TimeLog # show all the suitable tasks of the logged_in_user all_tasks = Task.query \ .filter(Task.resources.contains(self.logged_in_user)) \ .filter(Task.status != status_wfd) \ .filter(Task.status != status_cmpl) \ .filter(Task.status != status_prev) \ .all() # sort the task labels all_tasks = sorted( all_tasks, key=lambda task: '%s | %s' % ( task.project.name.lower(), ' | '.join(map(lambda x: x.name.lower(), task.parents)) ) ) else: # dialog is working in update TimeLog mode all_tasks = [self.timelog.task] self.tasks_combo_box.setSizeAdjustPolicy( QtWidgets.QComboBox.AdjustToContentsOnFirstShow ) self.tasks_combo_box.setFixedWidth(360) self.tasks_combo_box.clear() self.tasks_combo_box.addTasks(all_tasks) self.tasks_combo_box.setSizePolicy( QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Minimum ) # if a time log is given set the fields from the given time log if self.timelog: # first update Task try: self.tasks_combo_box.setCurrentTask(self.timelog.task) except IndexError as e: return # set the resource # and disable the tasks_combo_box and resource_combo_box self.tasks_combo_box.setEnabled(False) self.resource_combo_box.setEnabled(False) # set the start and end time from anima.utils import utc_to_local start_date = utc_to_local(self.timelog.start) end_date = utc_to_local(self.timelog.end) # set the date self.calendar_widget.setSelectedDate( QtCore.QDate(start_date.year, start_date.month, start_date.day) ) # first reset the start and end time values self.start_time_edit.setTime(QtCore.QTime(0, 0)) self.end_time_edit.setTime(QtCore.QTime(23, 50)) # now set the timelog time self.start_time_edit.setTime( QtCore.QTime( start_date.hour, start_date.minute ) ) self.end_time_edit.setTime( QtCore.QTime( end_date.hour, end_date.minute ) ) self.fill_calendar_with_time_logs() # also trigger an update to the side info bar self.calendar_widget_selection_changed()
def __init__(self, parent=None, task=None, timelog=None): logger.debug("initializing the interface") # store the logged in user self.logged_in_user = None self.no_time_left = False self.extended_hours = None self.extended_minutes = None self.timelog = timelog self.timelog_created = False self.task = task super(MainDialog, self).__init__(parent) self.setupUi(self) # customize the ui elements from anima.ui.widgets import TaskComboBox self.tasks_comboBox = TaskComboBox(self) self.tasks_comboBox.setObjectName("tasks_comboBox") self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.tasks_comboBox) # self.start_timeEdit.deleteLater() from anima.ui.widgets import TimeEdit self.start_timeEdit = TimeEdit(self, resolution=timing_resolution) self.start_timeEdit.setCurrentSection( QtWidgets.QDateTimeEdit.MinuteSection) self.start_timeEdit.setCalendarPopup(True) self.start_timeEdit.setObjectName("start_timeEdit") self.start_timeEdit.setWrapping(True) self.formLayout.insertRow(4, self.label, self.start_timeEdit) self.start_timeEdit.setDisplayFormat("HH:mm") # self.end_timeEdit.deleteLater() self.end_timeEdit = TimeEdit(self, resolution=timing_resolution) self.end_timeEdit.setCurrentSection( QtWidgets.QDateTimeEdit.MinuteSection) self.end_timeEdit.setCalendarPopup(True) self.end_timeEdit.setObjectName("end_timeEdit") self.end_timeEdit.setWrapping(True) self.formLayout.insertRow(5, self.label_2, self.end_timeEdit) self.end_timeEdit.setDisplayFormat("HH:mm") current_time = QtCore.QTime.currentTime() # round the minutes to the resolution minute = current_time.minute() hour = current_time.hour() minute = int(minute / float(timing_resolution)) * timing_resolution current_time = QtCore.QTime(hour, minute) self.start_timeEdit.setTime(current_time) self.end_timeEdit.setTime(current_time.addSecs(timing_resolution * 60)) self.calendarWidget.resource_id = -1 # setup signals self._setup_signals() # setup defaults self._set_defaults() # center window self.center_window()
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)) # TODO: Remove this in a later version from anima.utils import utc_to_local time_shifter = utc_to_local from distutils.version import LooseVersion import stalker if LooseVersion(stalker.__version__) >= LooseVersion('0.2.18'): def time_shifter(x): return x last_end_date = None 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) # store the last_end_date last_end_date = end 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) # set the start time in the UI to the last_end_date's time value # so the UI will automatically be set to the start of the next # available slot import pytz import datetime from anima.utils import local_to_utc utc_now = local_to_utc(datetime.datetime.now()) utc_now = utc_now.replace(tzinfo=pytz.utc) start_of_today = datetime.datetime(utc_now.year, utc_now.month, utc_now.day, tzinfo=utc_now.tzinfo) if last_end_date and last_end_date > start_of_today: from anima import TIMING_RESOLUTION last_end_time = QtCore.QTime(last_end_date.hour, last_end_date.minute) self.start_time_edit.setTime(last_end_time) self.end_time_edit.setTime(last_end_time.addSecs(TIMING_RESOLUTION * 60))