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;
}
Beispiel #4
0
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 );
    }
}
Beispiel #5
0
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 );
    }
}
Beispiel #6
0
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 );
    }
}
Beispiel #7
0
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();
    }
}
Beispiel #8
0
     } 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" );
Beispiel #9
0
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 );
}