diff --git a/src/plugins/filters/planner/import/plannerimport.cpp b/src/plugins/filters/planner/import/plannerimport.cpp index 548fb868..3c236ca3 100644 --- a/src/plugins/filters/planner/import/plannerimport.cpp +++ b/src/plugins/filters/planner/import/plannerimport.cpp @@ -1,552 +1,552 @@ /* This file is part of the KDE project * Copyright (C) 2019 Dag Andersen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ // clazy:excludeall=qstring-arg #include "plannerimport.h" -#include +#include "kptproject.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KPlato; #define PLANNERIMPORT_LOG "calligra.plan.filter.planner.import" #define debugPlannerImport qCDebug(QLoggingCategory(PLANNERIMPORT_LOG))<();) PlannerImport::PlannerImport(QObject* parent, const QVariantList &) : KoFilter(parent) { } KoFilter::ConversionStatus PlannerImport::convert(const QByteArray& from, const QByteArray& to) { debugPlannerImport << from << to; if ((from != "application/x-planner") || (to != "application/x-vnd.kde.plan")) { return KoFilter::NotImplemented; } QFile in(m_chain->inputFile()); if (!in.open(QIODevice::ReadOnly)) { errorPlannerImport << "Unable to open input file!"; in.close(); return KoFilter::FileNotFound; } QDomDocument inDoc; if (!inDoc.setContent(&in)) { errorPlannerImport << "Invalid format in input file!"; in.close(); return KoFilter::InvalidFormat; } - MainDocument *part = 0; + KoDocument *part = 0; bool batch = false; if (m_chain->manager()) { batch = m_chain->manager()->getBatchMode(); } if (batch) { //TODO debugPlannerImport << "batch"; } else { //debugPlannerImport<<"online"; - part = qobject_cast(m_chain->outputDocument()); + part = m_chain->outputDocument(); } - if (part == 0) { + if (part == 0 || part->project() == 0) { errorPlannerImport << "Cannot open document"; return KoFilter::InternalError; } if (!loadPlanner(inDoc, part)) { return KoFilter::ParsingError; } return KoFilter::OK; } DateTime toDateTime(const QString &dts) { // NOTE: time ends in Z, so should be UTC, but it seems it is in local time anyway. // Atm, just ignore timezone const QString format = QString("yyyyMMddThhmmssZ"); return DateTime(QDateTime::fromString(dts, format)); } // bool loadProject(const QDomElement &el, Project &project) { ScheduleManager *sm = project.createScheduleManager("Planner"); project.addScheduleManager(sm); sm->createSchedules(); sm->setAllowOverbooking(true); sm->expected()->setScheduled(true); project.setCurrentSchedule(sm->scheduleId()); project.setName(el.attribute("name")); project.setLeader(el.attribute("manager")); DateTime dt = toDateTime(el.attribute("project-start")); if (dt.isValid()) { project.setConstraintStartTime(dt); project.setStartTime(dt); } if (el.hasAttribute("calendar")) { Calendar *c = new Calendar(); c->setId(el.attribute("calendar")); project.addCalendar(c); project.setDefaultCalendar(c); debugPlannerImport<<"Added default calendar:"< // // // // // // // // // // // // interval start="0900" end="1700"/> // /overridden-day-type> // /overridden-day-types> // days/> // /calendar> // calendar id="2" name="Standard"> // default-week mon="0" tue="0" wed="0" thu="0" fri="0" sat="1" sun="1"/> // overridden-day-types> // overridden-day-type id="0"> // interval start="0800" end="1200"/> // interval start="1300" end="1700"/> // /overridden-day-type> // /overridden-day-types> // days/> // calendar id="3" name="Min kalender"> // // overridden-day-types> // overridden-day-type id="3"> // interval start="0800" end="1600"/> // /overridden-day-type> // /overridden-day-types> // days> // day date="20190506" type="day-type" id="3"/> // /days> // /calendar> // /calendar> // CalendarDay::State toDayState(int type) { QList state = QList() << CalendarDay::Working << CalendarDay::NonWorking; if (type < state.count()) { return state.value(type); } return CalendarDay::Undefined; } bool loadWeek(const QDomElement &el, Calendar *calendar) { debugPlannerImport<name(); QList defaultWeek = QList() << 2 << 2 << 2 << 2 << 2 << 2 << 2; QDomElement wel; forEachChildElementWithTag(wel, el, "default-week") { defaultWeek[0] = wel.attribute("mon", "2").toInt(); defaultWeek[1] = wel.attribute("tue", "2").toInt(); defaultWeek[2] = wel.attribute("wed", "2").toInt(); defaultWeek[3] = wel.attribute("thu", "2").toInt(); defaultWeek[4] = wel.attribute("fri", "2").toInt(); defaultWeek[5] = wel.attribute("sat", "2").toInt(); defaultWeek[6] = wel.attribute("sun", "2").toInt(); } debugPlannerImport<weekday(i+1); day->setState(toDayState(defaultWeek.at(i))); } forEachChildElementWithTag(wel, el, "overridden-day-types") { QDomElement oel; forEachChildElementWithTag(oel, wel, "overridden-day-type") { if (oel.hasAttribute("id")) { int id = oel.attribute("id").toInt(); if (!defaultWeek.contains(id)) { continue; } for (int i = 0; i < defaultWeek.count(); ++i) { if (defaultWeek.at(i) != id) { continue; } CalendarDay *day = calendar->weekday(i+1); day->setState(CalendarDay::Working); QDomElement iel; forEachChildElementWithTag(iel, oel, "interval") { QTime start = QTime::fromString(iel.attribute("start"), "hhmm"); QTime end = QTime::fromString(iel.attribute("end"), "hhmm"); day->addInterval(TimeInterval(start, start.msecsTo(end))); debugPlannerImport<<"Overridden:"<"<addInterval(TimeInterval(start, start.msecsTo(end))); } calendar->addDay(day); } return true; } bool loadCalendars(const QDomElement &el, Project &project, Calendar *parent = 0) { QDomElement cel; forEachChildElementWithTag(cel, el, "calendar") { QString id = cel.attribute("id"); Calendar *calendar = project.findCalendar(id); if (!calendar) { calendar = new Calendar(); calendar->setId(cel.attribute("id")); project.addCalendar(calendar, parent); debugPlannerImport<<"Loading new calendar"<id(); } else debugPlannerImport<<"Loading default calendar"<id(); calendar->setName(cel.attribute("name")); loadWeek(cel, calendar); loadDays(cel, calendar); loadCalendars(cel, project, calendar); } return true; } // // // bool loadResourceGroups(const QDomElement &el, Project &project) { QDomNodeList lst = el.elementsByTagName("group"); QDomElement gel; forEachElementInList(gel, lst) { ResourceGroup *g = new ResourceGroup(); g->setId(gel.attribute("id")); g->setName(gel.attribute("name")); project.addResourceGroup(g); } return true; } // // // Resource::Type toResourceType(const QString &type) { QMap types; types["0"] = Resource::Type_Material; types["1"] = Resource::Type_Work; return types.contains(type) ? types[type] : Resource::Type_Work; } bool loadResources(const QDomElement &el, Project &project) { QDomNodeList lst = el.elementsByTagName("resource"); QDomElement rel; forEachElementInList(rel, lst) { Resource *r = new Resource(); r->setId(rel.attribute("id")); r->setName(rel.attribute("name")); r->setInitials(rel.attribute("short-name")); r->setEmail(rel.attribute("email")); r->setType(toResourceType(rel.attribute("type"))); int units = rel.attribute("units", "0").toInt(); if (units == 0) { // atm. planner saves 0 but assumes 100% units = 100; } r->setUnits(units); r->setNormalRate(rel.attribute("std-rate").toDouble()); r->setCalendar(project.findCalendar(rel.attribute("calendar"))); QString gid = rel.attribute("group"); ResourceGroup *g = project.group(gid); if (!g) { // add a default g = new ResourceGroup(); g->setId(gid); // FIXME handle: gid *should* be empty if group was not found g->setName(i18n("Resources")); project.addResourceGroup(g); } project.addResource(g, r); } return true; } Estimate::Type toEstimateType(const QString type) { Estimate::Type res = Estimate::Type_Effort; if (type == "fixed-work") { res = Estimate::Type_Effort; } else if (type == "fixed-duration") { res = Estimate::Type_Duration; } return res; } Node::ConstraintType toConstraintType(const QString &type) { Node::ConstraintType res = Node::ASAP; if (type == "must-start-on") { res = Node::MustStartOn; } else if (type == "start-no-earlier-than") { res = Node::StartNotEarlier; } return res; } bool loadConstraint(const QDomElement &el, Task *t) { QDomElement cel; forEachChildElementWithTag(cel, el, "constraint") { t->setConstraint(toConstraintType(cel.attribute("type"))); t->setConstraintStartTime(toDateTime(cel.attribute("time"))); } return true; } // bool loadTasks(const QDomElement &el, Project &project, Node *parent = 0) { QDomElement cel; forEachChildElementWithTag(cel, el, "task") { Task *t = project.createTask(); t->setId(cel.attribute("id", t->id())); t->setName(cel.attribute("name")); t->setDescription(cel.attribute("note")); loadConstraint(cel, t); t->estimate()->setType(toEstimateType(cel.attribute("scheduling"))); t->estimate()->setExpectedEstimate(Duration(cel.attribute("work", "0").toDouble(), Duration::Unit_s).toDouble()); project.addSubTask(t, parent); long sid = project.scheduleManagers().first()->scheduleId(); NodeSchedule *sch = new NodeSchedule(); sch->setId(sid); sch->setNode(t); t->addSchedule(sch); sch->setParent(t->parentNode()->currentSchedule()); t->setCurrentSchedule(sid); const QString format = QString("yyyyMMddThhmmssZ"); QDateTime start = QDateTime::fromString(cel.attribute("work-start"), format); QDateTime end = QDateTime::fromString(cel.attribute("end"), format); t->setStartTime(DateTime(start)); t->setEndTime(DateTime(end)); sch->setScheduled(true); debugPlannerImport<<"Loaded:"< types; types["FS"] = Relation::FinishStart; types["FF"] = Relation::FinishFinish; types["SS"] = Relation::StartStart; types["SF"] = Relation::FinishStart; // not supported, use default return types.value(type); } // // // bool loadDependencies(const QDomElement &el, Project &project) { QDomElement cel; forEachChildElementWithTag(cel, el, "task") { QString succid = cel.attribute("id"); Node *child = project.findNode(succid); if (!child) { warnPlannerImport<<"Task"< bool loadAllocations(const QDomElement &el, Project &project) { QDomNodeList lst = el.elementsByTagName("allocation"); QDomElement pel; forEachElementInList(pel, lst) { Task *t = dynamic_cast(project.findNode(pel.attribute("task-id"))); Resource *r = project.findResource(pel.attribute("resource-id")); if (!t || !r) { warnPlannerImport<<"Could not find task/resource:"<resourceGroupRequest(r->parentGroup()); if (!gr) { gr = new ResourceGroupRequest(r->parentGroup()); t->addRequest(gr); } ResourceRequest *rr = new ResourceRequest(r); rr->setUnits(pel.attribute("units").toInt()); gr->addResourceRequest(rr); // do assignments Calendar *calendar = r->calendar(); if (!calendar) { warnPlannerImport<<"No resource calendar:"<currentSchedule(); Schedule *rs = r->schedule(ts->id()); if (!rs) { rs = r->createSchedule(t->name(), t->type(), ts->id()); } r->setCurrentSchedulePtr(rs); AppointmentIntervalList apps = calendar->workIntervals(t->startTime(), t->endTime(), rr->units()); foreach (const AppointmentInterval &a, apps.map()) { r->addAppointment(ts, a.startTime(), a.endTime(), a.load()); } rs->setScheduled(true); debugPlannerImport<<"Assignments:"<appointmentIntervals().intervals(); } return true; } -bool PlannerImport::loadPlanner(const QDomDocument &in, MainDocument *doc) const +bool PlannerImport::loadPlanner(const QDomDocument &in, KoDocument *doc) const { QDomElement pel = in.documentElement(); if (pel.tagName() != "project") { errorPlannerImport << "Missing project element"; return false; } - Project &project = doc->getProject(); + Project &project = *doc->project(); if (!loadProject(pel, project)) { return false; } QDomElement el = pel.elementsByTagName("calendars").item(0).toElement(); if (el.isNull()) { debugPlannerImport << "No calendars element"; } loadCalendars(el, project); el = pel.elementsByTagName("resource-groups").item(0).toElement(); if (el.isNull()) { debugPlannerImport << "No resource-groups element"; } loadResourceGroups(el, project); el = pel.elementsByTagName("resources").item(0).toElement(); if (el.isNull()) { debugPlannerImport << "No resources element"; } loadResources(el, project); el = pel.elementsByTagName("tasks").item(0).toElement(); if (el.isNull()) { debugPlannerImport << "No tasks element"; } else { loadTasks(el, project); loadDependencies(el, project); } loadAllocations(pel, project); foreach(const Node *n, project.allNodes()) { if (n->endTime() > project.endTime()) { project.setEndTime(n->endTime()); } } return true; } #include "plannerimport.moc" diff --git a/src/plugins/filters/planner/import/plannerimport.h b/src/plugins/filters/planner/import/plannerimport.h index 143db702..491ec56e 100644 --- a/src/plugins/filters/planner/import/plannerimport.h +++ b/src/plugins/filters/planner/import/plannerimport.h @@ -1,49 +1,47 @@ /* This file is part of the KDE project * Copyright (C) 2019 Dag Andersen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef PLANNERIMPORT_H #define PLANNERIMPORT_H #include #include #include class QByteArray; class QDomDocument; -namespace KPlato { - class MainDocument; -} +class KoDocument; class PlannerImport : public KoFilter { Q_OBJECT public: PlannerImport(QObject* parent, const QVariantList &); virtual ~PlannerImport() {} virtual KoFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to); - bool loadPlanner(const QDomDocument &in, KPlato::MainDocument *doc) const; + bool loadPlanner(const QDomDocument &in, KoDocument *doc) const; }; #endif // PLANNERIMPORT_H