void IdleCorrectionDialog::updateDuration() { const auto secs = m_start.secsTo( QDateTime::currentDateTime() ); m_ui->idleLabel->setText( tr("Charm detected that the computer became idle for %1 hours, while an event was in progress.") .arg( hoursAndMinutes( secs ) ) ); }
void EventEditorDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const { const Event& event = m_model->eventForIndex( index ); Q_ASSERT( event.isValid() ); const TaskTreeItem& item = DATAMODEL->taskTreeItem( event.taskId() ); if ( event.isValid() ) { bool locked = DATAMODEL->isEventActive( event.id() ); QString dateAndDuration; QTextStream dateStream( &dateAndDuration ); QDate date = event.startDateTime().date(); QTime time = event.startDateTime().time(); QTime endTime = event.endDateTime().time(); dateStream << date.toString( Qt::SystemLocaleDate ) << " " << time.toString( "h:mm" ) << " - " << endTime.toString( "h:mm" ) << " (" << hoursAndMinutes( event.duration() ) << ") Week " << date.weekNumber(); QString taskName; QTextStream taskStream( &taskName ); // print leading zeroes for the TaskId const int taskIdLength = CONFIGURATION.taskPaddingLength; taskStream << QString( "%1" ).arg( item.task().id(), taskIdLength, 10, QChar( '0' ) ) << " " << DATAMODEL->smartTaskName( item.task() ); paint( painter, option, taskName, dateAndDuration, logDuration( event.duration() ), locked ? EventState_Locked : EventState_Default ); } }
QSize EventEditorDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const { // to have the size hint recalculated, simply set m_cachedSizeHint // to an invalid value (m_cachedSizeHint = QSize();) if ( ! m_cachedSizeHint.isValid() ) { // make up event settings and calculate the space they need: QPixmap pixmap( 2000, 800 ); // temp QPainter painter( &pixmap ); QStyleOptionViewItem fakeOption ( option ); fakeOption.rect.setSize( pixmap.size() ); const QString task ( tr( "KDAB/Programming" ) ); QString dateAndDuration; QTextStream stream( &dateAndDuration ); QDate date = QDate::currentDate(); QTime time = QTime::currentTime(); stream << date.toString( Qt::SystemLocaleDate ) << " " << time.toString( Qt::SystemLocaleDate ) << " " << hoursAndMinutes( 3654 ); m_cachedSizeHint = paint( &painter, fakeOption, task, dateAndDuration, 42, EventState_Locked ).size(); } return m_cachedSizeHint; }
void EventView::slotDeleteEvent() { const TaskTreeItem& taskTreeItem = MODEL.charmDataModel()->taskTreeItem( m_event.taskId() ); const QString name = MODEL.charmDataModel()->fullTaskName( taskTreeItem.task() ); const QDate startDate = m_event.startDateTime().date(); const QTime startTime = m_event.startDateTime().time(); const QDate endDate = m_event.endDateTime().date(); const QTime endTime = m_event.endDateTime().time(); const bool sameDates = ( startDate == endDate ); QString message; if ( sameDates ) message = tr( "<html><b>%1</b>%2: %3 - %4 (Duration: %5)</html>" ) .arg( name ) .arg( QLocale::system().toString( startDate, QLocale::ShortFormat ) ).arg( QLocale::system().toString( startTime, QLocale::ShortFormat ) ) .arg( QLocale::system().toString( endTime, QLocale::ShortFormat ) ).arg( hoursAndMinutes( m_event.duration() ) ); else message = tr( "<html><b>%1</b><table><tr><td>Starting:</td><td>%2 at %3</td></tr>" "<tr><td>Ending:</td><td>%4 at %5</td></tr><tr><td>Duration:</td><td>%6.</td></tr></html>" ) .arg( name ) .arg( QLocale::system().toString( startDate, QLocale::ShortFormat ) ).arg( QLocale::system().toString( startTime, QLocale::ShortFormat ) ) .arg( QLocale::system().toString( endDate, QLocale::ShortFormat ) ).arg( QLocale::system().toString( endTime, QLocale::ShortFormat ) ) .arg( hoursAndMinutes( m_event.duration() ) ); if ( MessageBox::question( this, tr( "Delete Event?" ), message, tr( "Delete" ), tr("Cancel") ) == QMessageBox::Yes ) { auto command = new CommandDeleteEvent( m_event, this ); command->prepare(); stageCommand( command ); } }
void EventView::slotUpdateTotal() { // what matching signal does the proxy emit? int seconds = m_model->totalDuration(); if ( seconds == 0 ) { m_labelTotal->clear(); } else { QString total; QTextStream stream( &total ); stream << "(" << hoursAndMinutes( seconds ) << " total)"; m_labelTotal->setText( total ); } }
void EventView::slotDeleteEvent() { const TaskTreeItem& taskTreeItem = MODEL.charmDataModel()->taskTreeItem( m_event.taskId() ); const QString name = MODEL.charmDataModel()->fullTaskName( taskTreeItem.task() ); const QDate date = m_event.startDateTime().date(); const QTime time = m_event.startDateTime().time(); const QString dateAndDuration = date.toString( Qt::SystemLocaleDate ) + ' ' + time.toString( Qt::SystemLocaleDate ) + ' ' + hoursAndMinutes( m_event.duration() ); const QString eventDescription = name + ' ' + dateAndDuration; if ( MessageBox::question( this, tr( "Delete Event?" ), tr( "<html>Do you really want to delete the event <b>%1</b>?" ).arg(eventDescription), tr( "Delete" ), tr("Cancel") ) == QMessageBox::Yes ) { CommandDeleteEvent* command = new CommandDeleteEvent( m_event, this ); command->prepare(); stageCommand( command ); } }
QVariant TaskModelAdapter::data( const QModelIndex& index, int role ) const { if ( ! index.isValid() ) return QVariant(); const TaskTreeItem* item = itemFor( index ); const TaskId id = item->task().id(); const Event& activeEvent = m_dataModel->activeEventFor( id ); const bool isActive = activeEvent.isValid(); const QApplication* application = static_cast<QApplication*>( QApplication::instance() ); Q_ASSERT( application ); // we assume this code is executed in a GUI app // handle roles that are treated all the same, everywhere: switch( role ) { // problem: foreground role is never queried for case Qt::ForegroundRole: if( item->task().isCurrentlyValid() ) { return application->palette().color( QPalette::Active, QPalette::Text ); } else { return application->palette().color( QPalette::Disabled, QPalette::Text ); } break; case Qt::BackgroundRole: if( item->task().isCurrentlyValid() ) { return QVariant(); } else { QColor color( "crimson" ); color.setAlphaF( 0.25 ); return color; } break; case Qt::DisplayRole: return DATAMODEL->taskIdAndNameString( item->task().id() ); case Qt::DecorationRole: if ( isActive ) { return Data::activePixmap(); } else { return QVariant(); } break; case Qt::CheckStateRole: if ( item->task().subscribed() ) { return Qt::Checked; } else { return Qt::Unchecked; } break; case TasksViewRole_Name: // now unused return item->task().name(); case TasksViewRole_RunningTime: return hoursAndMinutes( activeEvent.duration() ); case TasksViewRole_TaskId: return id; case Qt::EditRole: // we edit the comment case TasksViewRole_Comment: return activeEvent.comment(); case TasksViewRole_Filter: return DATAMODEL->taskIdAndFullNameString( item->task().id() ); default: return QVariant(); } }
} else { field.text = m_shortDayNames[ column - 1 ]; } field.background = (Day % 2) ? m_paintAttributes.headerBrush : m_paintAttributes.headerEvenDayBrush; } else if ( row == TotalsRow ) { field.background = m_paintAttributes.totalsRowBrush; if ( column == TaskColumn ) { // field.text = tr( "Total" ); } else if ( column == TotalsColumn ) { int total = 0; Q_FOREACH( const WeeklySummary& s, m_summaries ) { total += std::accumulate( s.durations.begin(), s.durations.end(), 0 ); } field.text = hoursAndMinutes( total ); } else { int total = 0; Q_FOREACH( const WeeklySummary& s, m_summaries ) { total += s.durations[Day]; } field.text = hoursAndMinutes( total ); field.background = (Day % 2) ? m_paintAttributes.totalsRowBrush : m_paintAttributes.totalsRowEvenDayBrush; } } else if ( row == TrackingRow ) { // we only return one value, the paint method will treat this // column as a special case field.background = m_paintAttributes.taskBrushOdd; // field.text = tr( " 00:45 2345 KDAB/HR/Project Time Bookkeeping" );
void ActivityReport::slotUpdate() { const QString DateFormat( "yyyy/MM/dd" ); const QString TimeFormat( "HH:mm" ); const QString DateTimeFormat( "yyyy/MM/dd HH:mm" ); // retrieve matching events: EventIdList matchingEvents = DATAMODEL->eventsThatStartInTimeFrame( m_start, m_end ); matchingEvents = eventIdsSortedByStartTime( matchingEvents ); if ( m_rootTask != 0 ) { matchingEvents = filteredBySubtree( matchingEvents, m_rootTask ); } // filter unproductive events: if ( m_rootExcludeTask != 0 ) { matchingEvents = filteredBySubtree( matchingEvents, m_rootExcludeTask, true ); } // calculate total: int totalSeconds = 0; Q_FOREACH( EventId id, matchingEvents ) { const Event& event = DATAMODEL->eventForId( id ); Q_ASSERT( event.isValid() ); totalSeconds += event.duration(); } QTextDocument* report = new QTextDocument( this ); QDomDocument doc = createReportTemplate(); QDomElement root = doc.documentElement(); QDomElement body = root.firstChildElement( "body" ); // create the caption: { QDomElement headline = doc.createElement( "h1" ); QDomText text = doc.createTextNode( tr( "Activity Report" ) ); headline.appendChild( text ); body.appendChild( headline ); } { QDomElement headline = doc.createElement( "h3" ); QString content = tr( "Report for %1, from %2 to %3" ) .arg( CONFIGURATION.user.name() ) .arg( m_start.toString( Qt::TextDate ) ) .arg( m_end.toString( Qt::TextDate ) ); QDomText text = doc.createTextNode( content ); headline.appendChild( text ); body.appendChild( headline ); { QDomElement paragraph = doc.createElement( "h4" ); QString totalsText = tr( "Total: %1" ).arg( hoursAndMinutes( totalSeconds ) ); QDomText totalsElement = doc.createTextNode( totalsText ); paragraph.appendChild( totalsElement ); body.appendChild( paragraph ); } if ( m_rootTask != 0 ) { QDomElement paragraph = doc.createElement( "p" ); const Task& task = DATAMODEL->getTask( m_rootTask ); QString rootTaskText = tr( "Activity under task %1" ).arg( DATAMODEL->fullTaskName( task ) ); QDomText rootText = doc.createTextNode( rootTaskText ); paragraph.appendChild( rootText ); body.appendChild( paragraph ); } QDomElement paragraph = doc.createElement( "br" ); body.appendChild( paragraph ); } { const QString Headlines[] = { tr( "Date and Time, Task, Description" ) }; const int NumberOfColumns = sizeof Headlines / sizeof Headlines[0]; // now for a table QDomElement table = doc.createElement( "table" ); table.setAttribute( "width", "100%" ); table.setAttribute( "align", "left" ); table.setAttribute( "cellpadding", "3" ); table.setAttribute( "cellspacing", "0" ); body.appendChild( table ); // table header QDomElement tableHead = doc.createElement( "thead" ); table.appendChild( tableHead ); QDomElement headerRow = doc.createElement( "tr" ); headerRow.setAttribute( "class", "header_row" ); tableHead.appendChild( headerRow ); // column headers for ( int i = 0; i < NumberOfColumns; ++i ) { QDomElement header = doc.createElement( "th" ); QDomText text = doc.createTextNode( Headlines[i] ); header.appendChild( text ); headerRow.appendChild( header ); } QDomElement tableBody = doc.createElement( "tbody" ); table.appendChild( tableBody ); // rows Q_FOREACH( EventId id, matchingEvents ) { const Event& event = DATAMODEL->eventForId( id ); Q_ASSERT( event.isValid() ); const TaskTreeItem& item = DATAMODEL->taskTreeItem( event.taskId() ); const Task& task = item.task(); Q_ASSERT( task.isValid() ); const QString row1Texts[] = { tr( "%1 %2-%3 (%4) -- [%5] %6" ) .arg( event.startDateTime().date().toString( Qt::SystemLocaleShortDate ).trimmed() ) .arg( event.startDateTime().time().toString( Qt::SystemLocaleShortDate ).trimmed() ) .arg( event.endDateTime().time().toString( Qt::SystemLocaleShortDate ).trimmed() ) .arg( hoursAndMinutes( event.duration() ) ) .arg( QString().setNum( task.id() ).trimmed(), Configuration::instance().taskPaddingLength, '0' ) .arg( task.name().trimmed() ) }; QDomElement row1 = doc.createElement( "tr" ); row1.setAttribute( "class", "event_attributes_row" ); QDomElement row2 = doc.createElement( "tr" ); for ( int index = 0; index < NumberOfColumns; ++index ) { QDomElement cell = doc.createElement( "td" ); cell.setAttribute( "class", "event_attributes" ); QDomText text = doc.createTextNode( row1Texts[index] ); cell.appendChild( text ); row1.appendChild( cell ); } QDomElement cell2 = doc.createElement( "td" ); cell2.setAttribute( "class", "event_description" ); cell2.setAttribute( "align", "left" ); QDomElement preElement = doc.createElement( "pre" ); QDomText preText = doc.createTextNode( event.comment() ); preElement.appendChild( preText ); cell2.appendChild( preElement ); row2.appendChild( cell2 ); tableBody.appendChild( row1 ); tableBody.appendChild( row2 ); } } // NOTE: seems like the style sheet has to be set before the html // code is pushed into the QTextDocument QFile stylesheet( ":/Charm/report_stylesheet.sty" ); if ( stylesheet.open( QIODevice::ReadOnly | QIODevice::Text ) ) { QString style = stylesheet.readAll(); if ( !style.isEmpty() ) { report->setDefaultStyleSheet( style ); } else { qDebug() << "WeeklyTimeSheet::create: default style sheet is empty, too bad"; } } else { qDebug() << "WeeklyTimeSheet::create: cannot load report style sheet: " << stylesheet.errorString(); } report->setHtml( doc.toString() ); setDocument( report ); }