File indexing completed on 2024-11-17 04:49:33
0001 /* 0002 * Copyright (C) 2003, 2004 by Mark Bucciarelli <mark@hubcapconsutling.com> 0003 * Copyright (C) 2019 Alexander Potashev <aspotashev@gmail.com> 0004 * 0005 * This program is free software; you can redistribute it and/or modify 0006 * it under the terms of the GNU General Public License as published by 0007 * the Free Software Foundation; either version 2 of the License, or 0008 * (at your option) any later version. 0009 * 0010 * This program is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 * GNU General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU General Public License along 0016 * with this program; if not, write to the 0017 * Free Software Foundation, Inc. 0018 * 51 Franklin Street, Fifth Floor 0019 * Boston, MA 02110-1301 USA. 0020 * 0021 */ 0022 0023 #include "csvhistory.h" 0024 0025 #include "ktimetrackerutility.h" 0026 #include "ktt_debug.h" 0027 #include "model/projectmodel.h" 0028 #include "model/task.h" 0029 #include "model/tasksmodel.h" 0030 0031 static int64_t todaySeconds(const QDate &date, const KCalendarCore::Event::Ptr &event) 0032 { 0033 if (!event) { 0034 return 0; 0035 } 0036 0037 qCDebug(KTT_LOG) << "found an event for task, event=" << event->uid(); 0038 QDateTime startTime = event->dtStart(); 0039 QDateTime endTime = event->dtEnd(); 0040 QDateTime NextMidNight = startTime; 0041 NextMidNight.setTime(QTime(0, 0)); 0042 NextMidNight = NextMidNight.addDays(1); 0043 // LastMidNight := mdate.setTime(0:00) as it would read in a decent 0044 // programming language 0045 QDateTime LastMidNight = QDateTime::currentDateTime(); 0046 LastMidNight.setDate(date); 0047 LastMidNight.setTime(QTime(0, 0)); 0048 int64_t secsstartTillMidNight = startTime.secsTo(NextMidNight); 0049 int64_t secondsToAdd = 0; // seconds that need to be added to the actual cell 0050 0051 if (startTime.date() == date && event->dtEnd().date() == date) { 0052 // all the event occurred today 0053 secondsToAdd = startTime.secsTo(endTime); 0054 } 0055 0056 if (startTime.date() == date && endTime.date() > date) { 0057 // the event started today, but ended later 0058 secondsToAdd = secsstartTillMidNight; 0059 } 0060 0061 if (startTime.date() < date && endTime.date() == date) { 0062 // the event started before today and ended today 0063 secondsToAdd = LastMidNight.secsTo(event->dtEnd()); 0064 } 0065 0066 if (startTime.date() < date && endTime.date() > date) { 0067 // the event started before today and ended after 0068 secondsToAdd = 86400; 0069 } 0070 0071 return secondsToAdd; 0072 } 0073 0074 QString exportCSVHistoryToString(ProjectModel *projectModel, const ReportCriteria &rc) 0075 { 0076 const QDate &from = rc.from; 0077 const QDate &to = rc.to; 0078 QString delim = rc.delimiter; 0079 const QString cr = QStringLiteral("\n"); 0080 const int64_t intervalLength = from.daysTo(to) + 1; 0081 QMap<QString, QVector<int64_t>> secsForUid; 0082 QMap<QString, QString> uidForName; 0083 0084 QString retval; 0085 0086 // Step 1: Prepare two hashmaps: 0087 // * "uid -> seconds each day": used while traversing events, as uid is their id 0088 // "seconds each day" are stored in a vector 0089 // * "name -> uid", ordered by name: used when creating the csv file at the end 0090 auto tasks = projectModel->tasksModel()->getAllTasks(); 0091 qCDebug(KTT_LOG) << "Tasks count: " << tasks.size(); 0092 for (Task *task : tasks) { 0093 qCDebug(KTT_LOG) << ", Task Name: " << task->name() << ", UID: " << task->uid(); 0094 // uid -> seconds each day 0095 // * Init each element to zero 0096 QVector<int64_t> vector(intervalLength, 0); 0097 secsForUid[task->uid()] = vector; 0098 0099 // name -> uid 0100 // * Create task fullname concatenating each parent's name 0101 QString fullName; 0102 Task *parentTask; 0103 parentTask = task; 0104 fullName += parentTask->name(); 0105 parentTask = parentTask->parentTask(); 0106 while (parentTask) { 0107 fullName = parentTask->name() + QStringLiteral("->") + fullName; 0108 qCDebug(KTT_LOG) << "Fullname(inside): " << fullName; 0109 parentTask = parentTask->parentTask(); 0110 qCDebug(KTT_LOG) << "Parent task: " << parentTask; 0111 } 0112 0113 uidForName[fullName] = task->uid(); 0114 0115 qCDebug(KTT_LOG) << "Fullname(end): " << fullName; 0116 } 0117 0118 qCDebug(KTT_LOG) << "secsForUid" << secsForUid; 0119 qCDebug(KTT_LOG) << "uidForName" << uidForName; 0120 0121 std::unique_ptr<FileCalendar> calendar = projectModel->asCalendar(QUrl()); 0122 0123 // Step 2: For each date, get the events and calculate the seconds 0124 // Store the seconds using secsForUid hashmap, so we don't need to translate 0125 // uids We rely on rawEventsForDate to get the events 0126 qCDebug(KTT_LOG) << "Let's iterate for each date: "; 0127 int dayCount = 0; 0128 for (QDate mdate = from; mdate.daysTo(to) >= 0; mdate = mdate.addDays(1)) { 0129 if (dayCount++ > 365 * 100) { 0130 return QStringLiteral("too many days to process"); 0131 } 0132 0133 qCDebug(KTT_LOG) << mdate.toString(); 0134 for (const auto &event : calendar->rawEventsForDate(mdate)) { 0135 qCDebug(KTT_LOG) << "Summary: " << event->summary() << ", Related to uid: " << event->relatedTo(); 0136 qCDebug(KTT_LOG) << "Today's seconds: " << todaySeconds(mdate, event); 0137 secsForUid[event->relatedTo()][from.daysTo(mdate)] += todaySeconds(mdate, event); 0138 } 0139 } 0140 0141 // Step 3: For each task, generate the matching row for the CSV file 0142 // We use the two hashmaps to have direct access using the task name 0143 0144 // First CSV file line 0145 // FIXME: localize strings and date formats 0146 retval.append(QStringLiteral("\"Task name\"")); 0147 for (int i = 0; i < intervalLength; ++i) { 0148 retval.append(delim); 0149 retval.append(from.addDays(i).toString()); 0150 } 0151 retval.append(cr); 0152 0153 // Rest of the CSV file 0154 QMapIterator<QString, QString> nameUid(uidForName); 0155 double time; 0156 while (nameUid.hasNext()) { 0157 nameUid.next(); 0158 retval.append(rc.quote + nameUid.key() + rc.quote); 0159 qCDebug(KTT_LOG) << nameUid.key() << ": " << nameUid.value() << Qt::endl; 0160 0161 for (int day = 0; day < intervalLength; day++) { 0162 qCDebug(KTT_LOG) << "Secs for day " << day << ":" << secsForUid[nameUid.value()][day]; 0163 retval.append(delim); 0164 time = secsForUid[nameUid.value()][day] / 60.0; 0165 retval.append(formatTime(time, rc.decimalMinutes)); 0166 } 0167 0168 retval.append(cr); 0169 } 0170 0171 qDebug() << "Retval is \n" << retval; 0172 return retval; 0173 }