diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index dd629d4f..0506c9fb 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,253 +1,259 @@
set(PLAN_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/interfaces)
set(PLANPLUGIN_INCLUDES
${CMAKE_CURRENT_SOURCE_DIR}/libs/plugin
)
set(PLANKUNDO2_INCLUDES
${CMAKE_CURRENT_SOURCE_DIR}/libs/kundo2
${CMAKE_CURRENT_BINARY_DIR}/libs/kundo2
)
set(PLANSTORE_INCLUDES
${CMAKE_CURRENT_SOURCE_DIR}/libs/store
${CMAKE_CURRENT_BINARY_DIR}/libs/store
)
set(PLANODF_INCLUDES
${CMAKE_CURRENT_SOURCE_DIR}/libs/odf
${CMAKE_CURRENT_BINARY_DIR}/libs/odf
${PLANSTORE_INCLUDES}
)
set(PLANWIDGETS_INCLUDES
${CMAKE_CURRENT_SOURCE_DIR}/libs/widgetutils
${CMAKE_CURRENT_BINARY_DIR}/libs/widgetutils
${CMAKE_CURRENT_SOURCE_DIR}/libs/widgets
${CMAKE_CURRENT_BINARY_DIR}/libs/widgets
)
set(PLANMAIN_INCLUDES
${PLANWIDGETS_INCLUDES}
${PLANODF_INCLUDES}
${PLANKUNDO2_INCLUDES}
${CMAKE_CURRENT_SOURCE_DIR}/libs/main
${CMAKE_CURRENT_BINARY_DIR}/libs/main
)
set(PLANKERNEL_INCLUDES
${CMAKE_CURRENT_SOURCE_DIR}/libs/kernel
${CMAKE_CURRENT_BINARY_DIR}/libs/kernel
)
set(PLANMODELS_INCLUDES
${CMAKE_CURRENT_SOURCE_DIR}/libs/models
${CMAKE_CURRENT_BINARY_DIR}/libs/models
)
set(PLANUI_INCLUDES
${CMAKE_CURRENT_SOURCE_DIR}/libs/ui
${CMAKE_CURRENT_BINARY_DIR}/libs/ui
)
set(PLAN_INCLUDES
${CMAKE_CURRENT_BINARY_DIR}
${PLANKERNEL_INCLUDES}
${PLANMODELS_INCLUDES}
${PLANUI_INCLUDES}
${PLANMAIN_INCLUDES}
)
# For odf
set(RNG_SOURCE_DIR ${PROJECT_SOURCE_DIR}/devtools/scripts)
if(KF5Holidays_FOUND)
add_definitions(-DHAVE_KHOLIDAYS)
endif()
if (KF5AkonadiContact_FOUND)
# disable for now: there is a bug
# it only works if you use kde contacts (of course) but many use other stuff, so gets dissapointed
add_definitions(-DPLAN_KDEPIMLIBS_FOUND)
message(WARNING "AkonadiContacs available, but function is disabled due to Bug 311940")
endif ()
if (PLANCHARTDEBUG)
add_definitions(-DPLAN_CHART_DEBUG)
endif ()
#add_subdirectory(interfaces)
add_subdirectory(servicetypes)
add_subdirectory( templates )
add_subdirectory( pics )
add_subdirectory( toolbar )
add_subdirectory( plugins )
add_subdirectory( libs )
if(BUILD_TESTING)
add_subdirectory( tests )
endif()
add_subdirectory( workpackage )
include_directories(${PLAN_INCLUDES})
add_definitions(-DTRANSLATION_DOMAIN=\"calligraplan\")
########### KPlato private library ###############
set(planprivate_LIB_SRCS
+ welcome/WelcomeView.cpp
+
kptviewlistdocker.cpp
kptviewlist.cpp
kptviewlistdialog.cpp
kptschedulesdocker.cpp
kptconfig.cpp
config/ConfigWorkVacationPanel.cpp
config/ConfigProjectPanel.cpp
config/kpttaskdefaultpanel.cpp
config/kptworkpackageconfigpanel.cpp
config/kptcolorsconfigpanel.cpp
config/ConfigDocumentationPanel.cpp
config/ConfigTaskModulesPanel.cpp
+ config/ConfigProjectTemplatesPanel.cpp
config/ConfigDialog.cpp
kptcontext.cpp
kptfactory.cpp
kptpart.cpp
kptmaindocument.cpp
kptview.cpp
# KPtViewAdaptor.cpp
kptprintingcontrolprivate.cpp
kptschedulerpluginloader.cpp
kptbuiltinschedulerplugin.cpp
kptconfigskeleton.cpp
kptinsertfiledlg.cpp
kptloadsharedprojectsdialog.cpp
about/aboutpage.cpp
KPlatoXmlLoader.cpp
)
ki18n_wrap_ui(planprivate_LIB_SRCS
+ welcome/WelcomeView.ui
+
kptviewlistaddview.ui
kptviewlisteditview.ui
kptviewlisteditcategory.ui
config/ConfigWorkVacationPanel.ui
config/ConfigProjectPanel.ui
config/kptconfigtaskpanelbase.ui
config/kptworkpackageconfigpanel.ui
config/kptcolorsconfigpanel.ui
config/ConfigDocumentationPanel.ui
config/ConfigTaskModulesPanel.ui
+ config/ConfigProjectTemplatesPanel.ui
kptinsertfilepanel.ui
)
kconfig_add_kcfg_files(plansettings_SRCS calligraplansettings.kcfgc)
add_library(planprivate SHARED ${planprivate_LIB_SRCS} ${plansettings_SRCS} )
generate_export_header(planprivate BASE_NAME plan)
target_link_libraries(planprivate
PUBLIC
plankernel
planmodels
planui
planmain
PRIVATE
planplugin
KF5::IconThemes
#KF5::KHtml
)
if(KF5AkonadiContact_FOUND)
target_link_libraries(planprivate PRIVATE KF5::AkonadiContact)
endif()
set_target_properties(planprivate PROPERTIES VERSION ${GENERIC_PLAN_LIB_VERSION} SOVERSION ${GENERIC_PLAN_LIB_SOVERSION} )
install(TARGETS planprivate ${INSTALL_TARGETS_DEFAULT_ARGS})
########### KPlato part ###############
set(planpart_PART_SRCS kptfactoryinit.cpp )
add_library(calligraplanpart MODULE ${planpart_PART_SRCS})
#calligraplan_part_desktop_to_json(calligraplanpart planpart.desktop)
if(${KF5_VERSION} VERSION_LESS "5.16.0")
kcoreaddons_desktop_to_json(calligraplanpart planpart.desktop)
else()
kcoreaddons_desktop_to_json(calligraplanpart planpart.desktop
# SERVICE_TYPES ${PLAN_SOURCE_DIR}/servicetypes/calligraplan_part.desktop
)
endif()
target_link_libraries(calligraplanpart PUBLIC KF5::Parts KF5::CoreAddons PRIVATE planprivate)
install(TARGETS calligraplanpart DESTINATION ${PLUGIN_INSTALL_DIR}/calligraplan/parts)
########### KPlato executable ###############
set(calligraplan_KDEINIT_SRCS main.cpp )
file(GLOB ICONS_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/pics/*-apps-calligraplan.png")
ecm_add_app_icon(kdeinit_app_ICONS_SRCS ICONS ${ICONS_SRCS})
if(WIN32)
set(_resourcefile "${CMAKE_CURRENT_BINARY_DIR}/kdeinit_app_ICONS_SRCS.rc")
endif()
kf5_add_kdeinit_executable( calligraplan ${calligraplan_KDEINIT_SRCS})
if (APPLE)
set_target_properties(calligraplan PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.template)
set_target_properties(calligraplan PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER "org.calligra.plan")
set_target_properties(calligraplan PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Plan")
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/calligraplan_KDEINIT_SRCS.icns DESTINATION ${BUNDLE_INSTALL_DIR}/calligraplan.app/Contents/Resources)
endif ()
target_link_libraries(kdeinit_calligraplan planmain)
install(TARGETS kdeinit_calligraplan ${INSTALL_TARGETS_DEFAULT_ARGS})
target_link_libraries(calligraplan kdeinit_calligraplan planmain)
install(TARGETS calligraplan ${INSTALL_TARGETS_DEFAULT_ARGS})
########### install files ###############
install( FILES calligraplan.rc calligraplan_readonly.rc DESTINATION ${KXMLGUI_INSTALL_DIR}/calligraplan)
install( PROGRAMS org.kde.calligraplan.desktop DESTINATION ${XDG_APPS_INSTALL_DIR})
install( FILES calligraplanrc DESTINATION ${CONFIG_INSTALL_DIR})
install(FILES calligraplansettings.kcfg DESTINATION ${KCFG_INSTALL_DIR})
install(FILES org.kde.calligraplan.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR})
# TODO: with the new embedded JSON data for plugins there is no schema ATM to define extended properties
# plan_viewplugin.desktop
install(FILES
about/top-left-plan.png
about/main.html
about/intro.html
about/tips.html
about/tutorial.html
about/plan.css
DESTINATION ${DATA_INSTALL_DIR}/calligraplan/about
)
configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h )
#add_custom_target(apidox doc/api/gendocs.pl WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
diff --git a/src/calligraplansettings.kcfg b/src/calligraplansettings.kcfg
index be952402..ff202967 100644
--- a/src/calligraplansettings.kcfg
+++ b/src/calligraplansettings.kcfg
@@ -1,381 +1,387 @@
1760
176
40
8
true
NoneExists
true
InWeekCalendar
Default
true
08:00
16:00
true
08:00
16:00
true
08:00
16:00
true
08:00
16:00
true
08:00
16:00
false
08:00
16:00
false
08:00
16:00
false
AsSoonAsPossible
CurrentdateTime
CurrentdateTime
Effort
Hour
8.0
-75
100
Linear
false
#0000ff
#0000ff
#0000ff
#0000ff
#0000ff
#00ff00
#ff0000
#A0A0A0
#ffff00
#0000ff
#ff0000
#A0A0A0
#ffff00
EnumUnit::Minute
EnumUnit::Month
https://userbase.kde.org/Plan
https://userbase.kde.org/Plan/Manual
true
+
+
+
+
+
+
diff --git a/src/config/ConfigDialog.cpp b/src/config/ConfigDialog.cpp
index cc3a188e..cd4a7cb5 100644
--- a/src/config/ConfigDialog.cpp
+++ b/src/config/ConfigDialog.cpp
@@ -1,81 +1,90 @@
/* 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.
*/
#include "ConfigDialog.h"
#include "ConfigProjectPanel.h"
#include "ConfigWorkVacationPanel.h"
#include "kpttaskdefaultpanel.h"
#include "kptworkpackageconfigpanel.h"
#include "kptcolorsconfigpanel.h"
#include "ConfigDocumentationPanel.h"
#include "ConfigTaskModulesPanel.h"
+#include "ConfigProjectTemplatesPanel.h"
#include
#include
#include
#include
#include
#include
#include
#include
using namespace KPlato;
ConfigDialog::ConfigDialog(QWidget *parent, const QString& name, KConfigSkeleton *config )
: KConfigDialog( parent, name, config )
{
m_pages << addPage(new ConfigProjectPanel(), i18n("Project Defaults"), koIconName("calligraplan") );
m_pages << addPage(new ConfigWorkVacationPanel(), i18n("Work & Vacation"), koIconName("view-calendar") );
m_pages << addPage(new TaskDefaultPanel(), i18n("Task Defaults"), koIconName("view-task") );
m_pages << addPage(new ColorsConfigPanel(), i18n("Task Colors"), koIconName("fill-color") );
ConfigTaskModulesPanel *page = new ConfigTaskModulesPanel();
m_pages << addPage(page, i18n("Task Modules"), koIconName("calligraplanwork") );
connect(page, &ConfigTaskModulesPanel::settingsChanged, this, &ConfigDialog::updateButtons);
connect(this, &ConfigDialog::updateWidgetsSettings, page, &ConfigTaskModulesPanel::updateSettings);
connect(this, &ConfigDialog::updateWidgetsData, page, &ConfigTaskModulesPanel::updateWidgets);
m_pages << addPage(new WorkPackageConfigPanel(), i18n("Work Package"), koIconName("calligraplanwork") );
m_pages << addPage(new ConfigDocumentationPanel(), i18n("Documentation"), koIconName("documents") );
+
+ ConfigProjectTemplatesPanel *p = new ConfigProjectTemplatesPanel();
+ m_pages << addPage(p, i18n("Project Templates"), koIconName("calligraplan"));
+ connect(p, &ConfigProjectTemplatesPanel::settingsChanged, this, &ConfigDialog::updateButtons);
+ connect(this, &ConfigDialog::updateWidgetsSettings, p, &ConfigProjectTemplatesPanel::updateSettings);
+ connect(this, &ConfigDialog::updateWidgetsData, p, &ConfigProjectTemplatesPanel::updateWidgets);
}
void ConfigDialog::updateSettings()
{
emit updateWidgetsSettings();
new Help(KPlatoSettings::contextPath(), KPlatoSettings::contextLanguage());
+
+ KPlatoSettings::self()->save();
}
void ConfigDialog::updateWidgets()
{
emit updateWidgetsData();
}
bool ConfigDialog::hasChanged()
{
QWidget *w = currentPage()->widget()->findChild("ConfigWidget");
return w ? w->property("hasChanged").toBool() : false;
}
void ConfigDialog::showHelp()
{
Help::invoke("Configure_Plan");
}
diff --git a/src/config/ConfigProjectTemplatesPanel.cpp b/src/config/ConfigProjectTemplatesPanel.cpp
new file mode 100644
index 00000000..12e18309
--- /dev/null
+++ b/src/config/ConfigProjectTemplatesPanel.cpp
@@ -0,0 +1,76 @@
+/* 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 "ConfigProjectTemplatesPanel.h"
+
+#include "calligraplansettings.h"
+
+#include
+#include
+
+using namespace KPlato;
+
+ConfigProjectTemplatesPanel::ConfigProjectTemplatesPanel(QWidget *parent)
+{
+ setObjectName("ConfigWidget");
+ ui.setupUi(this);
+ model.setStringList(KPlatoSettings::projectTemplatePaths());
+ ui.projectTemplatesView->setModel(&model);
+
+ connect(ui.insertTemplatePath, &QToolButton::clicked, this, &ConfigProjectTemplatesPanel::slotInsertClicked);
+ connect(ui.removeTemplatePath, &QToolButton::clicked, this, &ConfigProjectTemplatesPanel::slotRemoveClicked);
+
+ connect(&model, &QStringListModel::dataChanged, this, &ConfigProjectTemplatesPanel::settingsChanged);
+}
+
+bool ConfigProjectTemplatesPanel::hasChanged() const
+{
+ bool changed = KPlatoSettings::projectTemplatePaths() != model.stringList();
+ return changed;
+}
+
+void ConfigProjectTemplatesPanel::updateSettings()
+{
+ KPlatoSettings::setProjectTemplatePaths(model.stringList());
+}
+
+void ConfigProjectTemplatesPanel::updateWidgets()
+{
+ model.setStringList(KPlatoSettings::projectTemplatePaths());
+}
+
+void ConfigProjectTemplatesPanel::slotInsertClicked()
+{
+ QString dirName = QFileDialog::getExistingDirectory(this, i18n("Project Templates Path"));
+ if (!dirName.isEmpty()) {
+ model.setStringList(model.stringList() << dirName);
+ }
+ emit settingsChanged();
+}
+
+void ConfigProjectTemplatesPanel::slotRemoveClicked()
+{
+ QList lst = ui.projectTemplatesView->selectionModel()->selectedRows();
+ for (const QModelIndex &idx : lst) {
+ model.removeRow(idx.row(), idx.parent());
+ }
+ emit settingsChanged();
+}
+
diff --git a/src/config/ConfigProjectTemplatesPanel.h b/src/config/ConfigProjectTemplatesPanel.h
new file mode 100644
index 00000000..737071a3
--- /dev/null
+++ b/src/config/ConfigProjectTemplatesPanel.h
@@ -0,0 +1,61 @@
+/* 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 CONFIGPROJECTTEMPLATESPANEL_H
+#define CONFIGPROJECTTEMPLATESPANEL_H
+
+#include "plan_export.h"
+
+#include "ui_ConfigProjectTemplatesPanel.h"
+
+#include
+#include
+
+namespace KPlato
+{
+
+
+class PLAN_EXPORT ConfigProjectTemplatesPanel : public QWidget
+{
+ Q_OBJECT
+ Q_PROPERTY(bool hasChanged READ hasChanged)
+
+public:
+ explicit ConfigProjectTemplatesPanel( QWidget *parent=nullptr );
+
+ QStringListModel model;
+ Ui::ConfigProjectTemplatesPanel ui;
+
+ bool hasChanged() const;
+
+public Q_SLOTS:
+ void updateSettings();
+ void updateWidgets();
+
+Q_SIGNALS:
+ void settingsChanged();
+
+private Q_SLOTS:
+ void slotInsertClicked();
+ void slotRemoveClicked();
+};
+
+} //KPlato namespace
+
+#endif
diff --git a/src/config/ConfigProjectTemplatesPanel.ui b/src/config/ConfigProjectTemplatesPanel.ui
new file mode 100644
index 00000000..6cb29ff8
--- /dev/null
+++ b/src/config/ConfigProjectTemplatesPanel.ui
@@ -0,0 +1,66 @@
+
+
+ KPlato::ConfigProjectTemplatesPanel
+
+
+
+ 0
+ 0
+ 400
+ 300
+
+
+
+ -
+
+
+ Insert
+
+
+
+ libs/uilibs/ui
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 181
+
+
+
+
+ -
+
+
+ Remove
+
+
+
+ libs/uilibs/ui
+
+
+
+ -
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+
+
+
+
+
+
diff --git a/src/kptconfig.cpp b/src/kptconfig.cpp
index 7aeba5de..9d118ebf 100644
--- a/src/kptconfig.cpp
+++ b/src/kptconfig.cpp
@@ -1,362 +1,367 @@
/* This file is part of the KDE project
Copyright (C) 2004, 2007 Dag Andersen
Copyright (C) 2011, 2012 Dag Andersen
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 "kptconfig.h"
#include "calligraplansettings.h"
#include "kptconfigskeleton.h"
#include "kptfactory.h"
#include "kptproject.h"
#include "kptdebug.h"
#include
namespace KPlato
{
Config::Config()
: ConfigBase()
{
debugPlan<<"Leader:"<save();
}
bool Config::isWorkingday(int day) const
{
switch (day) {
case Qt::Monday: return KPlatoSettings::monday(); break;
case Qt::Tuesday: return KPlatoSettings::tuesday(); break;
case Qt::Wednesday: return KPlatoSettings::wednesday(); break;
case Qt::Thursday: return KPlatoSettings::thursday(); break;
case Qt::Friday: return KPlatoSettings::friday(); break;
case Qt::Saturday: return KPlatoSettings::saturday(); break;
case Qt::Sunday: return KPlatoSettings::sunday(); break;
default: break;
};
return false;
}
QTime Config::dayStartTime(int day) const
{
switch (day) {
case Qt::Monday: return QTime::fromString(KPlatoSettings::mondayStart()); break;
case Qt::Tuesday: return QTime::fromString(KPlatoSettings::tuesdayStart()); break;
case Qt::Wednesday: return QTime::fromString(KPlatoSettings::wednesdayStart()); break;
case Qt::Thursday: return QTime::fromString(KPlatoSettings::thursdayStart()); break;
case Qt::Friday: return QTime::fromString(KPlatoSettings::fridayStart()); break;
case Qt::Saturday: return QTime::fromString(KPlatoSettings::saturdayStart()); break;
case Qt::Sunday: return QTime::fromString(KPlatoSettings::sundayStart()); break;
default: break;
};
return QTime();
}
int Config::dayLength(int day) const
{
QTime start = dayStartTime(day);
QTime end;
int value = 0;
switch (day) {
case Qt::Monday:
end = QTime::fromString(KPlatoSettings::mondayEnd());
break;
case Qt::Tuesday:
end = QTime::fromString(KPlatoSettings::tuesdayEnd());
break;
case Qt::Wednesday:
end = QTime::fromString(KPlatoSettings::wednesdayEnd());
break;
case Qt::Thursday:
end = QTime::fromString(KPlatoSettings::thursdayEnd());
break;
case Qt::Friday:
end = QTime::fromString(KPlatoSettings::fridayEnd());
break;
case Qt::Saturday:
end = QTime::fromString(KPlatoSettings::saturdayEnd());
break;
case Qt::Sunday:
end = QTime::fromString(KPlatoSettings::sundayEnd());
break;
default: break;
};
value = start.msecsTo(end);
if (value < 0) {
value = (24*60*60*1000) + value;
} else if (value == 0 && start == QTime(0, 0)) {
value = 24*60*60*1000;
}
return value;
}
void Config::setDefaultValues( Project &project ) const
{
project.setLeader( KPlatoSettings::manager() );
project.setUseSharedResources( KPlatoSettings::useSharedResources() );
project.setSharedResourcesFile( KPlatoSettings::sharedResourcesFile() );
project.setSharedProjectsUrl( QUrl(KPlatoSettings::sharedProjectsPlace()) );
project.setDescription( KPlatoSettings::projectDescription() );
StandardWorktime *v = project.standardWorktime();
Q_ASSERT(v);
if (v) {
v->setYear(KPlatoSettings::hoursPrYear());
v->setMonth(KPlatoSettings::hoursPrMonth());
v->setWeek(KPlatoSettings::hoursPrWeek());
v->setDay(KPlatoSettings::hoursPrDay());
}
Project::WorkPackageInfo wpi;
wpi.checkForWorkPackages = KPlatoSettings::checkForWorkPackages();
wpi.retrieveUrl = KPlatoSettings::retrieveUrl();
wpi.deleteAfterRetrieval = KPlatoSettings::deleteFile();
wpi.archiveAfterRetrieval = !KPlatoSettings::deleteFile();
wpi.archiveUrl = KPlatoSettings::saveUrl();
#if 0 // not used atm
wpi.publishUrl = KPlatoSettings::publishUrl();
#endif
project.setWorkPackageInfo(wpi);
project.setUseLocalTaskModules(useLocalTaskModules());
QList urls;
for (const QString &s : taskModulePaths()) {
urls << QUrl::fromUserInput(s);
}
project.setTaskModules(urls);
}
void Config::setDefaultValues( Task &task )
{
task.setLeader( KPlatoSettings::leader() );
task.setDescription( KPlatoSettings::description() );
task.setConstraint( (Node::ConstraintType) KPlatoSettings::constraintType() );
// avoid problems with start <= end & end >= start
task.setConstraintStartTime( DateTime() );
task.setConstraintEndTime( DateTime() );
switch ( KPlatoSettings::startTimeUsage() ) {
case KPlatoSettings::EnumStartTimeUsage::CurrentdateTime:
task.setConstraintStartTime( DateTime( QDateTime::currentDateTime() ) );
break;
case KPlatoSettings::EnumStartTimeUsage::CurrentDate:
task.setConstraintStartTime( DateTime( QDate::currentDate(), KPlatoSettings::constraintStartTime().time() ) );
break;
case KPlatoSettings::EnumStartTimeUsage::SpecifiedDateTime: //fall through
default:
task.setConstraintStartTime( DateTime( KPlatoSettings::constraintStartTime() ) );
break;
}
switch ( KPlatoSettings::endTimeUsage() ) {
case KPlatoSettings::EnumEndTimeUsage::CurrentdateTime:
task.setConstraintEndTime( DateTime( QDateTime::currentDateTime() ) );
break;
case KPlatoSettings::EnumEndTimeUsage::CurrentDate:
task.setConstraintEndTime( DateTime( QDate::currentDate(), KPlatoSettings::constraintEndTime().time() ) );
break;
case KPlatoSettings::EnumEndTimeUsage::SpecifiedDateTime: //fall through
default:
task.setConstraintEndTime( DateTime( KPlatoSettings::constraintEndTime() ) );
break;
}
task.estimate()->setType( (Estimate::Type) KPlatoSettings::estimateType() );
task.estimate()->setUnit( (Duration::Unit) KPlatoSettings::unit() );
task.estimate()->setExpectedEstimate( KPlatoSettings::expectedEstimate() );
task.estimate()->setPessimisticRatio( KPlatoSettings::pessimisticRatio() );
task.estimate()->setOptimisticRatio( KPlatoSettings::optimisticRatio() );
}
int Config::minimumDurationUnit() const
{
return KPlatoSettings::minimumDurationUnit();
}
int Config::maximumDurationUnit() const
{
return KPlatoSettings::maximumDurationUnit();
}
QBrush Config::summaryTaskDefaultColor() const
{
QColor c = KPlatoSettings::summaryTaskDefaultColor();
if ( KPlatoSettings::colorGradientType() == KPlatoSettings::EnumColorGradientType::Linear ) {
return gradientBrush( c );
}
return c;
}
bool Config::summaryTaskLevelColorsEnabled() const
{
return KPlatoSettings::summaryTaskLevelColorsEnabled();
}
QBrush Config::summaryTaskLevelColor_1() const
{
QColor c = KPlatoSettings::summaryTaskLevelColor_1();
if ( KPlatoSettings::colorGradientType() == KPlatoSettings::EnumColorGradientType::Linear ) {
return gradientBrush( c );
}
return c;
}
QBrush Config::summaryTaskLevelColor_2() const
{
QColor c = KPlatoSettings::summaryTaskLevelColor_2();
if ( KPlatoSettings::colorGradientType() == KPlatoSettings::EnumColorGradientType::Linear ) {
return gradientBrush( c );
}
return c;
}
QBrush Config::summaryTaskLevelColor_3() const
{
QColor c = KPlatoSettings::summaryTaskLevelColor_3();
if ( KPlatoSettings::colorGradientType() == KPlatoSettings::EnumColorGradientType::Linear ) {
return gradientBrush( c );
}
return c;
}
QBrush Config::summaryTaskLevelColor_4() const
{
QColor c = KPlatoSettings::summaryTaskLevelColor_4();
if ( KPlatoSettings::colorGradientType() == KPlatoSettings::EnumColorGradientType::Linear ) {
return gradientBrush( c );
}
return c;
}
QBrush Config::taskNormalColor() const
{
QColor c = KPlatoSettings::taskNormalColor();
if ( KPlatoSettings::colorGradientType() == KPlatoSettings::EnumColorGradientType::Linear ) {
return gradientBrush( c );
}
return c;
}
QBrush Config::taskErrorColor() const
{
QColor c = KPlatoSettings::taskErrorColor();
if ( KPlatoSettings::colorGradientType() == KPlatoSettings::EnumColorGradientType::Linear ) {
return gradientBrush( c );
}
return c;
}
QBrush Config::taskCriticalColor() const
{
QColor c = KPlatoSettings::taskCriticalColor();
if ( KPlatoSettings::colorGradientType() == KPlatoSettings::EnumColorGradientType::Linear ) {
return gradientBrush( c );
}
return c;
}
QBrush Config::taskFinishedColor() const
{
QColor c = KPlatoSettings::taskFinishedColor();
if ( KPlatoSettings::colorGradientType() == KPlatoSettings::EnumColorGradientType::Linear ) {
return gradientBrush( c );
}
return c;
}
QBrush Config::milestoneNormalColor() const
{
QColor c = KPlatoSettings::milestoneNormalColor();
if ( KPlatoSettings::colorGradientType() == KPlatoSettings::EnumColorGradientType::Linear ) {
return gradientBrush( c );
}
return c;
}
QBrush Config::milestoneErrorColor() const
{
QColor c = KPlatoSettings::milestoneErrorColor();
if ( KPlatoSettings::colorGradientType() == KPlatoSettings::EnumColorGradientType::Linear ) {
return gradientBrush( c );
}
return c;
}
QBrush Config::milestoneCriticalColor() const
{
QColor c = KPlatoSettings::milestoneCriticalColor();
if ( KPlatoSettings::colorGradientType() == KPlatoSettings::EnumColorGradientType::Linear ) {
return gradientBrush( c );
}
return c;
}
QBrush Config::milestoneFinishedColor() const
{
QColor c = KPlatoSettings::milestoneFinishedColor();
if ( KPlatoSettings::colorGradientType() == KPlatoSettings::EnumColorGradientType::Linear ) {
return gradientBrush( c );
}
return c;
}
QString Config::documentationPath() const
{
return KPlatoSettings::documentationPath();
}
QString Config::contextPath() const
{
return KPlatoSettings::contextPath();
}
QString Config::contextLanguage() const
{
return KPlatoSettings::contextLanguage();
}
bool Config::useLocalTaskModules() const
{
return KPlatoSettings::useLocalTaskModules();
}
QStringList Config::taskModulePaths() const
{
return KPlatoSettings::taskModulePaths();
}
+QStringList Config::projectTemplatePaths() const
+{
+ return KPlatoSettings::projectTemplatePaths();
+}
+
} //KPlato namespace
diff --git a/src/kptconfig.h b/src/kptconfig.h
index 6422b446..14f8c729 100644
--- a/src/kptconfig.h
+++ b/src/kptconfig.h
@@ -1,78 +1,80 @@
/* This file is part of the KDE project
Copyright (C) 2004, 2007 Dag Andersen
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 KPTCONFIG_H
#define KPTCONFIG_H
#include "kptconfigbase.h"
namespace KPlato
{
class Config : public ConfigBase
{
Q_OBJECT
public:
Config();
~Config() override;
void readConfig();
void saveSettings();
bool isWorkingday(int day) const;
QTime dayStartTime(int day) const;
int dayLength(int day) const;
void setDefaultValues( Project &project ) const override;
void setDefaultValues( Task &task ) override;
int minimumDurationUnit() const override;
int maximumDurationUnit() const override;
bool summaryTaskLevelColorsEnabled() const override;
QBrush summaryTaskDefaultColor() const override;
QBrush summaryTaskLevelColor_1() const override;
QBrush summaryTaskLevelColor_2() const override;
QBrush summaryTaskLevelColor_3() const override;
QBrush summaryTaskLevelColor_4() const override;
QBrush taskNormalColor() const override;
QBrush taskErrorColor() const override;
QBrush taskCriticalColor() const override;
QBrush taskFinishedColor() const override;
QBrush milestoneNormalColor() const override;
QBrush milestoneErrorColor() const override;
QBrush milestoneCriticalColor() const override;
QBrush milestoneFinishedColor() const override;
QString documentationPath() const override;
QString contextPath() const override;
QString contextLanguage() const override;
bool useLocalTaskModules() const override;
QStringList taskModulePaths() const override;
+
+ QStringList projectTemplatePaths() const override;
};
} //KPlato namespace
#endif // CONFIG_H
diff --git a/src/kptmaindocument.cpp b/src/kptmaindocument.cpp
index 49453b44..11ad1ff2 100644
--- a/src/kptmaindocument.cpp
+++ b/src/kptmaindocument.cpp
@@ -1,1619 +1,1625 @@
/* This file is part of the KDE project
* Copyright (C) 1998, 1999, 2000 Torben Weis
* Copyright (C) 2004, 2010, 2012 Dag Andersen
* Copyright (C) 2006 Raphael Langerhorst
* Copyright (C) 2007 Thorsten Zachmann
* 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 "kptmaindocument.h"
#include "kptpart.h"
#include "kptview.h"
#include "kptfactory.h"
#include "kptproject.h"
#include "kptlocale.h"
#include "kptresource.h"
#include "kptcontext.h"
#include "kptschedulerpluginloader.h"
#include "kptschedulerplugin.h"
#include "kptbuiltinschedulerplugin.h"
#include "kptschedule.h"
#include "kptcommand.h"
#include "calligraplansettings.h"
#include "kpttask.h"
#include "KPlatoXmlLoader.h"
#include "XmlSaveContext.h"
#include "kptpackage.h"
#include "kptdebug.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef HAVE_KHOLIDAYS
#include
#endif
namespace KPlato
{
MainDocument::MainDocument(KoPart *part)
: KoDocument(part),
m_project( 0 ),
m_context( 0 ), m_xmlLoader(),
m_loadingTemplate( false ),
m_loadingSharedResourcesTemplate( false ),
m_viewlistModified( false ),
m_checkingForWorkPackages( false ),
m_loadingSharedProject(false),
m_skipSharedProjects(false),
m_isTaskModule(false),
m_calculationCommand(nullptr),
m_currentCalculationManager(nullptr),
m_nextCalculationManager(nullptr),
m_taskModulesWatch(nullptr)
{
Q_ASSERT(part);
setAlwaysAllowSaving(true);
m_config.setReadWrite( isReadWrite() );
loadSchedulerPlugins();
setProject( new Project( m_config ) ); // after config & plugins are loaded
m_project->setId( m_project->uniqueNodeId() );
m_project->registerNodeId( m_project ); // register myself
connect(this, &MainDocument::insertSharedProject, this, &MainDocument::slotInsertSharedProject);
}
MainDocument::~MainDocument()
{
qDeleteAll( m_schedulerPlugins );
if ( m_project ) {
m_project->deref(); // deletes if last user
}
qDeleteAll( m_mergedPackages );
delete m_context;
delete m_calculationCommand;
}
+void MainDocument::initEmpty()
+{
+ KoDocument::initEmpty();
+ setProject(new Project(m_config));
+}
+
void MainDocument::slotNodeChanged(Node *node, int property)
{
switch (property) {
case Node::TypeProperty:
case Node::ResourceRequestProperty:
case Node::ConstraintTypeProperty:
case Node::StartConstraintProperty:
case Node::EndConstraintProperty:
case Node::PriorityProperty:
case Node::EstimateProperty:
case Node::EstimateRiskProperty:
setCalculationNeeded();
break;
case Node::EstimateOptimisticProperty:
case Node::EstimatePessimisticProperty:
if (node->estimate()->risktype() != Estimate::Risk_None) {
setCalculationNeeded();
}
break;
default:
break;
}
}
void MainDocument::slotScheduleManagerChanged(ScheduleManager *sm, int property)
{
if (sm->schedulingMode() == ScheduleManager::AutoMode) {
switch (property) {
case ScheduleManager::DirectionProperty:
case ScheduleManager::OverbookProperty:
case ScheduleManager::DistributionProperty:
case ScheduleManager::SchedulingModeProperty:
case ScheduleManager::GranularityProperty:
setCalculationNeeded();
break;
default:
break;
}
}
}
void MainDocument::setCalculationNeeded()
{
for (ScheduleManager *sm : m_project->allScheduleManagers()) {
if (sm->isBaselined()) {
continue;
}
if (sm->schedulingMode() == ScheduleManager::AutoMode) {
m_nextCalculationManager = sm;
break;
}
}
if (!m_currentCalculationManager) {
m_currentCalculationManager = m_nextCalculationManager;
m_nextCalculationManager = nullptr;
QTimer::singleShot(0, this, &MainDocument::slotStartCalculation);
}
}
void MainDocument::slotStartCalculation()
{
if (m_currentCalculationManager) {
m_calculationCommand = new CalculateScheduleCmd(*m_project, m_currentCalculationManager);
m_calculationCommand->redo();
}
}
void MainDocument::slotCalculationFinished(Project *p, ScheduleManager *sm)
{
if (sm != m_currentCalculationManager) {
return;
}
delete m_calculationCommand;
m_calculationCommand = nullptr;
m_currentCalculationManager = m_nextCalculationManager;
m_nextCalculationManager = nullptr;
if (m_currentCalculationManager) {
QTimer::singleShot(0, this, &MainDocument::slotStartCalculation);
}
}
void MainDocument::setReadWrite( bool rw )
{
m_config.setReadWrite( rw );
KoDocument::setReadWrite( rw );
}
void MainDocument::loadSchedulerPlugins()
{
// Add built-in scheduler
addSchedulerPlugin( "Built-in", new BuiltinSchedulerPlugin( this ) );
// Add all real scheduler plugins
SchedulerPluginLoader *loader = new SchedulerPluginLoader(this);
connect(loader, &SchedulerPluginLoader::pluginLoaded, this, &MainDocument::addSchedulerPlugin);
loader->loadAllPlugins();
}
void MainDocument::addSchedulerPlugin( const QString &key, SchedulerPlugin *plugin)
{
debugPlan<setConfig( m_config );
}
void MainDocument::setProject( Project *project )
{
if ( m_project ) {
delete m_project;
}
m_project = project;
if ( m_project ) {
connect( m_project, &Project::projectChanged, this, &MainDocument::changed );
// m_project->setConfig( config() );
m_project->setSchedulerPlugins( m_schedulerPlugins );
// For auto scheduling
delete m_calculationCommand;
m_calculationCommand = nullptr;
m_currentCalculationManager = nullptr;
m_nextCalculationManager = nullptr;
connect(m_project, &Project::nodeAdded, this, &MainDocument::setCalculationNeeded);
connect(m_project, &Project::nodeRemoved, this, &MainDocument::setCalculationNeeded);
connect(m_project, &Project::relationAdded, this, &MainDocument::setCalculationNeeded);
connect(m_project, &Project::relationRemoved, this, &MainDocument::setCalculationNeeded);
connect(m_project, &Project::calendarChanged, this, &MainDocument::setCalculationNeeded);
connect(m_project, &Project::defaultCalendarChanged, this, &MainDocument::setCalculationNeeded);
connect(m_project, &Project::calendarAdded, this, &MainDocument::setCalculationNeeded);
connect(m_project, &Project::calendarRemoved, this, &MainDocument::setCalculationNeeded);
connect(m_project, &Project::scheduleManagerChanged, this, &MainDocument::slotScheduleManagerChanged);
connect(m_project, &Project::nodeChanged, this, &MainDocument::slotNodeChanged);
connect(m_project, &Project::sigCalculationFinished, this, &MainDocument::slotCalculationFinished);
}
m_aboutPage.setProject( project );
QString dir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
if (!dir.isEmpty()) {
dir += "/taskmodules";
m_project->setLocalTaskModulesPath(QUrl::fromLocalFile(dir));
}
setTaskModulesWatch();
connect(project, &Project::taskModulesChanged, this, &MainDocument::setTaskModulesWatch);
emit changed();
}
void MainDocument::setTaskModulesWatch()
{
delete m_taskModulesWatch;
m_taskModulesWatch = new KDirWatch(this);
for (const QUrl &url : m_project->taskModules()) {
m_taskModulesWatch->addDir(url.toLocalFile());
}
connect(m_taskModulesWatch, &KDirWatch::dirty, this, &MainDocument::taskModuleDirChanged);
}
void MainDocument::taskModuleDirChanged()
{
// HACK to trigger update FIXME
m_project->setUseLocalTaskModules(m_project->useLocalTaskModules());
}
bool MainDocument::loadOdf( KoOdfReadStore &odfStore )
{
warnPlan<< "OpenDocument not supported, let's try native xml format";
return loadXML( odfStore.contentDoc(), 0 ); // We have only one format, so try to load that!
}
bool MainDocument::loadXML( const KoXmlDocument &document, KoStore* )
{
QPointer updater;
if (progressUpdater()) {
updater = progressUpdater()->startSubtask(1, "Plan::Part::loadXML");
updater->setProgress(0);
m_xmlLoader.setUpdater( updater );
}
QString value;
KoXmlElement plan = document.documentElement();
// Check if this is the right app
value = plan.attribute( "mime", QString() );
if ( value.isEmpty() ) {
errorPlan << "No mime type specified!";
setErrorMessage( i18n( "Invalid document. No mimetype specified." ) );
return false;
}
if ( value == "application/x-vnd.kde.kplato" ) {
if (updater) {
updater->setProgress(5);
}
m_xmlLoader.setMimetype( value );
QString message;
Project *newProject = new Project(m_config, false);
KPlatoXmlLoader loader( m_xmlLoader, newProject );
bool ok = loader.load( plan );
if ( ok ) {
setProject( newProject );
setModified( false );
debugPlan<schedules();
// Cleanup after possible bug:
// There should *not* be any deleted schedules (or with parent == 0)
foreach ( Node *n, newProject->nodeDict()) {
foreach ( Schedule *s, n->schedules()) {
if ( s->isDeleted() ) { // true also if parent == 0
errorPlan<name()<takeSchedule( s );
delete s;
}
}
}
} else {
setErrorMessage( loader.errorMessage() );
delete newProject;
}
if (updater) {
updater->setProgress(100); // the rest is only processing, not loading
}
emit changed();
return ok;
}
if ( value != "application/x-vnd.kde.plan" ) {
errorPlan << "Unknown mime type " << value;
setErrorMessage( i18n( "Invalid document. Expected mimetype application/x-vnd.kde.plan, got %1", value ) );
return false;
}
QString syntaxVersion = plan.attribute( "version", PLAN_FILE_SYNTAX_VERSION );
m_xmlLoader.setVersion( syntaxVersion );
if ( syntaxVersion > PLAN_FILE_SYNTAX_VERSION ) {
KMessageBox::ButtonCode ret = KMessageBox::warningContinueCancel(
0, i18n( "This document was created with a newer version of Plan (syntax version: %1)\n"
"Opening it in this version of Plan will lose some information.", syntaxVersion ),
i18n( "File-Format Mismatch" ), KGuiItem( i18n( "Continue" ) ) );
if ( ret == KMessageBox::Cancel ) {
setErrorMessage( "USER_CANCELED" );
return false;
}
}
if (updater) updater->setProgress(5);
/*
#ifdef KOXML_USE_QDOM
int numNodes = plan.childNodes().count();
#else
int numNodes = plan.childNodesCount();
#endif
*/
#if 0
This test does not work any longer. KoXml adds a couple of elements not present in the file!!
if ( numNodes > 2 ) {
//TODO: Make a proper bitching about this
debugPlan <<"*** Error ***";
debugPlan <<" Children count should be maximum 2, but is" << numNodes;
return false;
}
#endif
m_xmlLoader.startLoad();
KoXmlNode n = plan.firstChild();
for ( ; ! n.isNull(); n = n.nextSibling() ) {
if ( ! n.isElement() ) {
continue;
}
KoXmlElement e = n.toElement();
if ( e.tagName() == "project" ) {
Project *newProject = new Project(m_config, true);
m_xmlLoader.setProject( newProject );
if ( newProject->load( e, m_xmlLoader ) ) {
if ( newProject->id().isEmpty() ) {
newProject->setId( newProject->uniqueNodeId() );
newProject->registerNodeId( newProject );
}
// The load went fine. Throw out the old project
setProject( newProject );
// Cleanup after possible bug:
// There should *not* be any deleted schedules (or with parent == 0)
foreach ( Node *n, newProject->nodeDict()) {
foreach ( Schedule *s, n->schedules()) {
if ( s->isDeleted() ) { // true also if parent == 0
errorPlan<name()<takeSchedule( s );
delete s;
}
}
}
} else {
delete newProject;
m_xmlLoader.addMsg( XMLLoaderObject::Errors, "Loading of project failed" );
//TODO add some ui here
}
}
}
m_xmlLoader.stopLoad();
if (updater) updater->setProgress(100); // the rest is only processing, not loading
setModified( false );
emit changed();
return true;
}
QDomDocument MainDocument::saveXML()
{
debugPlan;
// Save the project
XmlSaveContext context(m_project);
context.save();
return context.document;
}
QDomDocument MainDocument::saveWorkPackageXML( const Node *node, long id, Resource *resource )
{
debugPlanWp<name() );
wp.setAttribute( "owner-id", resource->id() );
}
wp.setAttribute( "time-tag", QDateTime::currentDateTime().toString( Qt::ISODate ) );
wp.setAttribute("save-url", m_project->workPackageInfo().retrieveUrl.toString(QUrl::None));
wp.setAttribute("load-url", m_project->workPackageInfo().publishUrl.toString(QUrl::None));
debugPlanWp<<"publish:"<workPackageInfo().publishUrl.toString(QUrl::None);
debugPlanWp<<"retrieve:"<workPackageInfo().retrieveUrl.toString(QUrl::None);
doc.appendChild( wp );
// Save the project
m_project->saveWorkPackageXML( doc, node, id );
return document;
}
bool MainDocument::saveWorkPackageToStream( QIODevice *dev, const Node *node, long id, Resource *resource )
{
QDomDocument doc = saveWorkPackageXML( node, id, resource );
// Save to buffer
QByteArray s = doc.toByteArray(); // utf8 already
dev->open( QIODevice::WriteOnly );
int nwritten = dev->write( s.data(), s.size() );
if ( nwritten != (int)s.size() ) {
warnPlanWp<<"wrote:"<m_specialOutputFlag == SaveEncrypted ) {
backend = KoStore::Encrypted;
debugPlan <<"Saving using encrypted backend.";
}*/
#endif
QByteArray mimeType = "application/x-vnd.kde.plan.work";
debugPlanWp <<"MimeType=" << mimeType;
KoStore *store = KoStore::createStore( file, KoStore::Write, mimeType, backend );
/* if ( d->m_specialOutputFlag == SaveEncrypted && !d->m_password.isNull( ) ) {
store->setPassword( d->m_password );
}*/
if ( store->bad() ) {
setErrorMessage( i18n( "Could not create the workpackage file for saving: %1", file ) ); // more details needed?
delete store;
return false;
}
// Tell KoStore not to touch the file names
if ( ! store->open( "root" ) ) {
setErrorMessage( i18n( "Not able to write '%1'. Partition full?", QString( "maindoc.xml") ) );
delete store;
return false;
}
KoStoreDevice dev( store );
if ( !saveWorkPackageToStream( &dev, node, id, resource ) || !store->close() ) {
errorPlanWp <<"saveToStream failed";
delete store;
return false;
}
node->documents().saveToStore( store );
debugPlanWp <<"Saving done of url:" << file;
if ( !store->finalize() ) {
delete store;
return false;
}
// Success
delete store;
return true;
}
bool MainDocument::saveWorkPackageUrl( const QUrl &_url, const Node *node, long id, Resource *resource )
{
debugPlanWp<<_url;
QApplication::setOverrideCursor( Qt::WaitCursor );
emit statusBarMessage( i18n("Saving...") );
bool ret = false;
ret = saveWorkPackageFormat( _url.path(), node, id, resource ); // kzip don't handle file://
QApplication::restoreOverrideCursor();
emit clearStatusBarMessage();
return ret;
}
bool MainDocument::loadWorkPackage( Project &project, const QUrl &url )
{
debugPlanWp<bad() ) {
// d->lastErrorMessage = i18n( "Not a valid Calligra file: %1", file );
errorPlanWp<<"bad store"<open( "root" ) ) { // "old" file format (maindoc.xml)
// i18n( "File does not have a maindoc.xml: %1", file );
errorPlanWp<<"No root"<device(), &errorMsg, &errorLine, &errorColumn );
if ( ! ok ) {
errorPlanWp << "Parsing error in " << url.url() << "! Aborting!" << endl
<< " In line: " << errorLine << ", column: " << errorColumn << endl
<< " Error message: " << errorMsg;
//d->lastErrorMessage = i18n( "Parsing error in %1 at line %2, column %3\nError message: %4",filename ,errorLine, errorColumn , QCoreApplication::translate("QXml", errorMsg.toUtf8(), 0, QCoreApplication::UnicodeUTF8));
} else {
package = loadWorkPackageXML( project, store->device(), doc, url );
if ( package ) {
package->url = url;
m_workpackages.insert( package->timeTag, package );
if (!m_mergedPackages.contains(package->timeTag)) {
m_mergedPackages[package->timeTag] = package->project; // register this for next time
}
} else {
ok = false;
}
}
store->close();
//###
if ( ok && package && package->settings.documents ) {
ok = extractFiles( store, package );
}
delete store;
if ( ! ok ) {
// QApplication::restoreOverrideCursor();
return false;
}
return true;
}
Package *MainDocument::loadWorkPackageXML( Project &project, QIODevice *, const KoXmlDocument &document, const QUrl &url )
{
QString value;
bool ok = true;
Project *proj = 0;
Package *package = 0;
KoXmlElement plan = document.documentElement();
// Check if this is the right app
value = plan.attribute( "mime", QString() );
if ( value.isEmpty() ) {
errorPlanWp<timeTag = QDateTime::fromString( loader.timeTag(), Qt::ISODate );
} else if ( value != "application/x-vnd.kde.plan.work" ) {
errorPlanWp << "Unknown mime type " << value;
setErrorMessage( i18n( "Invalid document. Expected mimetype application/x-vnd.kde.plan.work, got %1", value ) );
return 0;
} else {
if (plan.attribute("editor") != QStringLiteral("PlanWork")) {
warnPlanWp<<"Skipped work package file not generated with PlanWork:"< PLANWORK_FILE_SYNTAX_VERSION ) {
KMessageBox::ButtonCode ret = KMessageBox::warningContinueCancel(
0, i18n( "This document was created with a newer version of PlanWork (syntax version: %1)\n"
"Opening it in this version of PlanWork will lose some information.", syntaxVersion ),
i18n( "File-Format Mismatch" ), KGuiItem( i18n( "Continue" ) ) );
if ( ret == KMessageBox::Cancel ) {
setErrorMessage( "USER_CANCELED" );
return 0;
}
}
m_xmlLoader.setVersion( plan.attribute( "plan-version", PLAN_FILE_SYNTAX_VERSION ) );
m_xmlLoader.startLoad();
proj = new Project();
package = new Package();
package->project = proj;
KoXmlNode n = plan.firstChild();
for ( ; ! n.isNull(); n = n.nextSibling() ) {
if ( ! n.isElement() ) {
continue;
}
KoXmlElement e = n.toElement();
if ( e.tagName() == "project" ) {
m_xmlLoader.setProject( proj );
ok = proj->load( e, m_xmlLoader );
if ( ! ok ) {
m_xmlLoader.addMsg( XMLLoaderObject::Errors, "Loading of work package failed" );
warnPlanWp<<"Skip workpackage:"<<"Loading project failed";
//TODO add some ui here
}
} else if ( e.tagName() == "workpackage" ) {
package->timeTag = QDateTime::fromString( e.attribute( "time-tag" ), Qt::ISODate );
package->ownerId = e.attribute( "owner-id" );
package->ownerName = e.attribute( "owner" );
debugPlan<<"workpackage:"<timeTag<ownerId<ownerName;
KoXmlElement elem;
forEachElement( elem, e ) {
if ( elem.tagName() != "settings" ) {
continue;
}
package->settings.usedEffort = (bool)elem.attribute( "used-effort" ).toInt();
package->settings.progress = (bool)elem.attribute( "progress" ).toInt();
package->settings.documents = (bool)elem.attribute( "documents" ).toInt();
}
}
}
if ( proj->numChildren() > 0 ) {
package->task = static_cast( proj->childNode( 0 ) );
package->toTask = qobject_cast( m_project->findNode( package->task->id() ) );
WorkPackage &wp = package->task->workPackage();
if ( wp.ownerId().isEmpty() ) {
wp.setOwnerId( package->ownerId );
wp.setOwnerName( package->ownerName );
}
if (wp.ownerId() != package->ownerId) {
warnPlanWp<<"Current owner:"<ownerName;
}
debugPlanWp<<"Task set:"<task->name();
}
m_xmlLoader.stopLoad();
}
if (ok && proj->id() != project.id()) {
debugPlanWp<<"Skip workpackage:"<<"Not the correct project";
ok = false;
}
if (ok && (package->task == nullptr)) {
warnPlanWp<<"Skip workpackage:"<<"No task in workpackage file";
ok = false;
}
if (ok && (package->toTask == nullptr)) {
warnPlanWp<<"Skip workpackage:"<<"Cannot find task:"<task->id()<task->name();
ok = false;
}
if (ok && !package->timeTag.isValid()) {
warnPlanWp<<"Work package is not time tagged:"<task->name()<url;
ok = false;
}
if (ok && m_mergedPackages.contains(package->timeTag)) {
debugPlanWp<<"Skip workpackage:"<<"already merged:"<task->name()<url;
ok = false; // already merged
}
if (!ok) {
delete proj;
delete package;
return nullptr;
}
return package;
}
bool MainDocument::extractFiles( KoStore *store, Package *package )
{
if ( package->task == 0 ) {
errorPlan<<"No task!";
return false;
}
foreach ( Document *doc, package->task->documents().documents() ) {
if ( ! doc->isValid() || doc->type() != Document::Type_Product || doc->sendAs() != Document::SendAs_Copy ) {
continue;
}
if ( ! extractFile( store, package, doc ) ) {
return false;
}
}
return true;
}
bool MainDocument::extractFile( KoStore *store, Package *package, const Document *doc )
{
QTemporaryFile tmpfile;
if ( ! tmpfile.open() ) {
errorPlan<<"Failed to open temporary file";
return false;
}
if ( ! store->extractFile( doc->url().fileName(), tmpfile.fileName() ) ) {
errorPlan<<"Failed to extract file:"<url().fileName()<<"to:"<documents.insert( tmpfile.fileName(), doc->url() );
tmpfile.setAutoRemove( false );
debugPlan<<"extracted:"<url().fileName()<<"->"<(sender());
if (m_project && m_project->workPackageInfo().checkForWorkPackages) {
checkForWorkPackages( true );
}
if (timer && timer->interval() != 10000) {
timer->stop();
timer->setInterval(10000);
timer->start();
}
}
void MainDocument::checkForWorkPackages( bool keep )
{
if (m_checkingForWorkPackages || m_project == nullptr || m_project->numChildren() == 0 || m_project->workPackageInfo().retrieveUrl.isEmpty()) {
return;
}
if ( ! keep ) {
qDeleteAll( m_mergedPackages );
m_mergedPackages.clear();
}
QDir dir( m_project->workPackageInfo().retrieveUrl.path(), "*.planwork" );
m_infoList = dir.entryInfoList( QDir::Files | QDir::Readable, QDir::Time );
checkForWorkPackage();
return;
}
void MainDocument::checkForWorkPackage()
{
if ( ! m_infoList.isEmpty() ) {
m_checkingForWorkPackages = true;
QUrl url = QUrl::fromLocalFile( m_infoList.takeLast().absoluteFilePath() );
if (!m_skipUrls.contains(url) && !loadWorkPackage(*m_project, url)) {
m_skipUrls << url;
debugPlanWp<<"skip url:"<toTask<url;
if (m_workpackages.value(package->timeTag) == package) {
m_workpackages.remove(package->timeTag);
}
QFile file( package->url.path() );
if ( ! file.exists() ) {
warnPlanWp<<"File does not exist:"<toTask<url;
return;
}
Project::WorkPackageInfo wpi = m_project->workPackageInfo();
debugPlanWp<<"retrieve:"<url.adjusted(QUrl::RemoveFilename);
if (wpi.archiveAfterRetrieval && wpi.archiveUrl.isValid()) {
QDir dir(wpi.archiveUrl.path());
if ( ! dir.exists() ) {
if ( ! dir.mkpath( dir.path() ) ) {
//TODO message
warnPlanWp<<"Failed to create archive directory:"<generateUniqueIds();
m_project->setConstraintStartTime( QDateTime(QDate::currentDate(), QTime(0, 0, 0), Qt::LocalTime) );
m_project->setConstraintEndTime( m_project->constraintStartTime().addYears( 2 ) );
m_project->locale()->setCurrencyLocale(QLocale::AnyLanguage, QLocale::AnyCountry);
m_project->locale()->setCurrencySymbol(QString());
} else if ( isImporting() ) {
// NOTE: I don't think this is a good idea.
// Let the filter generate ids for non-plan files.
// If the user wants to create a new project from an old one,
// he should use Tools -> Insert Project File
//m_project->generateUniqueNodeIds();
}
if (m_loadingSharedResourcesTemplate && m_project->calendarCount() > 0) {
Calendar *c = m_project->calendarAt(0);
c->setTimeZone(QTimeZone::systemTimeZone());
}
if (m_project->useSharedResources() && !m_project->sharedResourcesFile().isEmpty() && !m_skipSharedProjects) {
QUrl url = QUrl::fromLocalFile(m_project->sharedResourcesFile());
if (url.isValid()) {
insertResourcesFile(url, m_project->loadProjectsAtStartup() ? m_project->sharedProjectsUrl() : QUrl());
}
}
if ( store == 0 ) {
// can happen if loading a template
debugPlan<<"No store";
return true; // continue anyway
}
delete m_context;
m_context = new Context();
KoXmlDocument doc;
if ( loadAndParse( store, "context.xml", doc ) ) {
store->close();
m_context->load( doc );
} else warnPlan<<"No context";
return true;
}
// TODO:
// Due to splitting of KoDocument into a document and a part,
// we simulate the old behaviour by registering all views in the document.
// Find a better solution!
void MainDocument::registerView( View* view )
{
if ( view && ! m_views.contains( view ) ) {
m_views << QPointer( view );
}
}
bool MainDocument::completeSaving( KoStore *store )
{
foreach ( View *view, m_views ) {
if ( view ) {
if ( store->open( "context.xml" ) ) {
if ( m_context == 0 ) m_context = new Context();
QDomDocument doc = m_context->save( view );
KoStoreDevice dev( store );
QByteArray s = doc.toByteArray(); // this is already Utf8!
(void)dev.write( s.data(), s.size() );
(void)store->close();
m_viewlistModified = false;
emit viewlistModified( false );
}
break;
}
}
return true;
}
bool MainDocument::loadAndParse(KoStore *store, const QString &filename, KoXmlDocument &doc)
{
//debugPlan << "oldLoadAndParse: Trying to open " << filename;
if (!store->open(filename))
{
warnPlan << "Entry " << filename << " not found!";
// d->lastErrorMessage = i18n( "Could not find %1",filename );
return false;
}
// Error variables for QDomDocument::setContent
QString errorMsg;
int errorLine, errorColumn;
bool ok = doc.setContent( store->device(), &errorMsg, &errorLine, &errorColumn );
if ( !ok )
{
errorPlan << "Parsing error in " << filename << "! Aborting!" << endl
<< " In line: " << errorLine << ", column: " << errorColumn << endl
<< " Error message: " << errorMsg;
/* d->lastErrorMessage = i18n( "Parsing error in %1 at line %2, column %3\nError message: %4"
,filename ,errorLine, errorColumn ,
QCoreApplication::translate("QXml", errorMsg.toUtf8(), 0,
QCoreApplication::UnicodeUTF8));*/
store->close();
return false;
}
debugPlan << "File " << filename << " loaded and parsed";
return true;
}
void MainDocument::insertFile( const QUrl &url, Node *parent, Node *after )
{
Part *part = new Part( this );
MainDocument *doc = new MainDocument( part );
part->setDocument( doc );
doc->disconnect(); // doc shall not handle feedback from openUrl()
doc->setAutoSave( 0 ); //disable
doc->m_insertFileInfo.url = url;
doc->m_insertFileInfo.parent = parent;
doc->m_insertFileInfo.after = after;
connect(doc, &KoDocument::completed, this, &MainDocument::insertFileCompleted);
connect(doc, &KoDocument::canceled, this, &MainDocument::insertFileCancelled);
doc->openUrl( url );
}
void MainDocument::insertFileCompleted()
{
debugPlan<( sender() );
if ( doc ) {
Project &p = doc->getProject();
insertProject( p, doc->m_insertFileInfo.parent, doc->m_insertFileInfo.after );
doc->documentPart()->deleteLater(); // also deletes document
} else {
KMessageBox::error( 0, i18n("Internal error, failed to insert file.") );
}
}
void MainDocument::insertResourcesFile(const QUrl &url, const QUrl &projects)
{
insertSharedProjects(projects); // prepare for insertion after shared resources
m_sharedProjectsFiles.removeAll(url); // resource file is not a project
Part *part = new Part( this );
MainDocument *doc = new MainDocument( part );
doc->m_skipSharedProjects = true; // should not have shared projects, but...
part->setDocument( doc );
doc->disconnect(); // doc shall not handle feedback from openUrl()
doc->setAutoSave( 0 ); //disable
doc->setCheckAutoSaveFile(false);
connect(doc, &KoDocument::completed, this, &MainDocument::insertResourcesFileCompleted);
connect(doc, &KoDocument::canceled, this, &MainDocument::insertFileCancelled);
doc->openUrl( url );
}
void MainDocument::insertResourcesFileCompleted()
{
debugPlanShared<( sender() );
if (doc) {
Project &p = doc->getProject();
mergeResources(p);
m_project->setSharedResourcesLoaded(true);
doc->documentPart()->deleteLater(); // also deletes document
slotInsertSharedProject(); // insert shared bookings
} else {
KMessageBox::error( 0, i18n("Internal error, failed to insert file.") );
}
}
void MainDocument::insertFileCancelled( const QString &error )
{
debugPlan<( sender() );
if ( doc ) {
doc->documentPart()->deleteLater(); // also deletes document
}
}
void MainDocument::clearResourceAssignments()
{
foreach (Resource *r, m_project->resourceList()) {
r->clearExternalAppointments();
}
}
void MainDocument::loadResourceAssignments(QUrl url)
{
insertSharedProjects(url);
slotInsertSharedProject();
}
void MainDocument::insertSharedProjects(const QList &urls)
{
clearResourceAssignments();
m_sharedProjectsFiles = urls;
slotInsertSharedProject();
}
void MainDocument::insertSharedProjects(const QUrl &url)
{
m_sharedProjectsFiles.clear();
QFileInfo fi(url.path());
if (!fi.exists()) {
return;
}
if (fi.isFile()) {
m_sharedProjectsFiles = QList() << url;
debugPlan<<"Get all projects in file:"<m_skipSharedProjects = true; // never load recursively
part->setDocument( doc );
doc->disconnect(); // doc shall not handle feedback from openUrl()
doc->setAutoSave( 0 ); //disable
doc->setCheckAutoSaveFile(false);
doc->m_loadingSharedProject = true;
connect(doc, &KoDocument::completed, this, &MainDocument::insertSharedProjectCompleted);
connect(doc, &KoDocument::canceled, this, &MainDocument::insertSharedProjectCancelled);
doc->openUrl(m_sharedProjectsFiles.takeFirst());
}
void MainDocument::insertSharedProjectCompleted()
{
debugPlanShared<( sender() );
if (doc) {
Project &p = doc->getProject();
debugPlanShared<id()<<"Loaded project:"<id() && p.isScheduled(ANYSCHEDULED)) {
// FIXME: improve!
// find a suitable schedule
ScheduleManager *sm = 0;
foreach(ScheduleManager *m, p.allScheduleManagers()) {
if (m->isBaselined()) {
sm = m;
break;
}
if (m->isScheduled()) {
sm = m; // take the last one, more likely to be subschedule
}
}
if (sm) {
foreach(Resource *r, p.resourceList()) {
Resource *res = m_project->resource(r->id());
if (res && res->isShared()) {
Appointment *app = new Appointment();
app->setAuxcilliaryInfo(p.name());
foreach(const Appointment *a, r->appointments(sm->scheduleId())) {
*app += *a;
}
if (app->isEmpty()) {
delete app;
} else {
res->addExternalAppointment(p.id(), app);
debugPlanShared<name()<<"added:"<auxcilliaryInfo()<documentPart()->deleteLater(); // also deletes document
emit insertSharedProject(); // do next file
} else {
KMessageBox::error( 0, i18n("Internal error, failed to insert file.") );
}
}
void MainDocument::insertSharedProjectCancelled( const QString &error )
{
debugPlanShared<( sender() );
if ( doc ) {
doc->documentPart()->deleteLater(); // also deletes document
}
}
bool MainDocument::insertProject( Project &project, Node *parent, Node *after )
{
debugPlan<<&project;
// make sure node ids in new project is unique also in old project
QList existingIds = m_project->nodeDict().keys();
foreach ( Node *n, project.allNodes() ) {
QString oldid = n->id();
n->setId( project.uniqueNodeId( existingIds ) );
project.removeId( oldid ); // remove old id
project.registerNodeId( n ); // register new id
}
MacroCommand *m = new InsertProjectCmd( project, parent==0?m_project:parent, after, kundo2_i18n( "Insert project" ) );
if ( m->isEmpty() ) {
delete m;
} else {
addCommand( m );
}
return true;
}
// check if calendar 'c' has children that will not be removed (normally 'Local' calendars)
bool canRemoveCalendar(const Calendar *c, const QList &lst)
{
for (Calendar *cc : c->calendars()) {
if (!lst.contains(cc)) {
return false;
}
if (!canRemoveCalendar(cc, lst)) {
return false;
}
}
return true;
}
// sort parent calendars before children
QList sortedRemoveCalendars(Project &shared, const QList &lst) {
QList result;
for (Calendar *c : lst) {
if (c->isShared() && !shared.calendar(c->id())) {
result << c;
}
result += sortedRemoveCalendars(shared, c->calendars());
}
return result;
}
bool MainDocument::mergeResources(Project &project)
{
debugPlanShared<<&project;
// Just in case, remove stuff not related to resources
foreach(Node *n, project.childNodeIterator()) {
debugPlanShared<<"Project not empty, delete node:"<name();
NodeDeleteCmd cmd(n);
cmd.execute();
}
foreach(ScheduleManager *m, project.scheduleManagers()) {
debugPlanShared<<"Project not empty, delete schedule:"<name();
DeleteScheduleManagerCmd cmd(project, m);
cmd.execute();
}
foreach(Account *a, project.accounts().accountList()) {
debugPlanShared<<"Project not empty, delete account:"<name();
RemoveAccountCmd cmd(project, a);
cmd.execute();
}
// Mark all resources / groups as shared
foreach(ResourceGroup *g, project.resourceGroups()) {
g->setShared(true);
}
foreach(Resource *r, project.resourceList()) {
r->setShared(true);
}
// Mark all calendars shared
foreach(Calendar *c, project.allCalendars()) {
c->setShared(true);
}
// check if any shared stuff has been removed
QList removedGroups;
QList removedResources;
QList removedCalendars;
QStringList removed;
foreach(ResourceGroup *g, m_project->resourceGroups()) {
if (g->isShared() && !project.findResourceGroup(g->id())) {
removedGroups << g;
removed << i18n("Group: %1", g->name());
}
}
foreach(Resource *r, m_project->resourceList()) {
if (r->isShared() && !project.findResource(r->id())) {
removedResources << r;
removed << i18n("Resource: %1", r->name());
}
}
removedCalendars = sortedRemoveCalendars(project, m_project->calendars());
for (Calendar *c : qAsConst(removedCalendars)) {
removed << i18n("Calendar: %1", c->name());
}
if (!removed.isEmpty()) {
KMessageBox::ButtonCode result = KMessageBox::warningYesNoCancelList(
0,
i18n("Shared resources has been removed from the shared resources file."
"\nSelect how they shall be treated in this project."),
removed,
xi18nc("@title:window", "Shared resources"),
KStandardGuiItem::remove(),
KGuiItem(i18n("Convert")),
KGuiItem(i18n("Keep"))
);
switch (result) {
case KMessageBox::Yes: // Remove
for (Resource *r : qAsConst(removedResources)) {
RemoveResourceCmd cmd(r->parentGroup(), r);
cmd.redo();
}
for (ResourceGroup *g : qAsConst(removedGroups)) {
if (g->resources().isEmpty()) {
RemoveResourceGroupCmd cmd(m_project, g);
cmd.redo();
} else {
// we may have put local resource(s) in this group
// so we need to keep it
g->setShared(false);
m_project->removeResourceGroupId(g->id());
g->setId(m_project->uniqueResourceGroupId());
m_project->insertResourceGroupId(g->id(), g);
}
}
for (Calendar *c : qAsConst(removedCalendars)) {
CalendarRemoveCmd cmd(m_project, c);
cmd.redo();
}
break;
case KMessageBox::No: // Convert
for (Resource *r : qAsConst(removedResources)) {
r->setShared(false);
m_project->removeResourceId(r->id());
r->setId(m_project->uniqueResourceId());
m_project->insertResourceId(r->id(), r);
}
for (ResourceGroup *g : qAsConst(removedGroups)) {
g->setShared(false);
m_project->removeResourceGroupId(g->id());
g->setId(m_project->uniqueResourceGroupId());
m_project->insertResourceGroupId(g->id(), g);
}
for (Calendar *c : qAsConst(removedCalendars)) {
c->setShared(false);
m_project->removeCalendarId(c->id());
c->setId(m_project->uniqueCalendarId());
m_project->insertCalendarId(c->id(), c);
}
break;
case KMessageBox::Cancel: // Keep
break;
default:
break;
}
}
// update values of already existing objects
QStringList l1;
foreach(ResourceGroup *g, project.resourceGroups()) {
l1 << g->id();
}
QStringList l2;
foreach(ResourceGroup *g, m_project->resourceGroups()) {
l2 << g->id();
}
debugPlanShared< removegroups;
foreach(ResourceGroup *g, project.resourceGroups()) {
ResourceGroup *group = m_project->findResourceGroup(g->id());
if (group) {
if (!group->isShared()) {
// User has probably created shared resources from this project,
// so the resources exists but are local ones.
// Convert to shared and do not load the group from shared.
removegroups << g;
group->setShared(true);
debugPlanShared<<"Set group to shared:"<id();
}
group->setName(g->name());
group->setType(g->type());
debugPlanShared<<"Updated group:"<id();
}
}
QList removeresources;
foreach(Resource *r, project.resourceList()) {
Resource *resource = m_project->findResource(r->id());
if (resource) {
if (!resource->isShared()) {
// User has probably created shared resources from this project,
// so the resources exists but are local ones.
// Convert to shared and do not load the resource from shared.
removeresources << r;
resource->setShared(true);
debugPlanShared<<"Set resource to shared:"<id();
}
resource->setName(r->name());
resource->setInitials(r->initials());
resource->setEmail(r->email());
resource->setType(r->type());
resource->setAutoAllocate(r->autoAllocate());
resource->setAvailableFrom(r->availableFrom());
resource->setAvailableUntil(r->availableUntil());
resource->setUnits(r->units());
resource->setNormalRate(r->normalRate());
resource->setOvertimeRate(r->overtimeRate());
QString id = r->calendar(true) ? r->calendar(true)->id() : QString();
resource->setCalendar(m_project->findCalendar(id));
id = r->account() ? r->account()->name() : QString();
resource->setAccount(m_project->accounts().findAccount(id));
resource->setRequiredIds(r->requiredIds());
resource->setTeamMemberIds(r->teamMemberIds());
debugPlanShared<<"Updated resource:"<id();
}
}
QList removecalendars;
foreach(Calendar *c, project.allCalendars()) {
Calendar *calendar = m_project->findCalendar(c->id());
if (calendar) {
if (!calendar->isShared()) {
// User has probably created shared resources from this project,
// so the calendar exists but are local ones.
// Convert to shared and do not load the resource from shared.
removecalendars << c;
calendar->setShared(true);
debugPlanShared<<"Set calendar to shared:"<id();
}
*calendar = *c;
debugPlanShared<<"Updated calendar:"<id();
}
}
debugPlanShared<<"Remove:"<childCount() == 0) {
removecalendars.removeAt(i);
debugPlanShared<<"Delete calendar:"<id();
CalendarRemoveCmd cmd(&project, c);
cmd.execute();
}
}
}
for (Resource *r : qAsConst(removeresources)) {
debugPlanShared<<"Delete resource:"<id();
RemoveResourceCmd cmd(r->parentGroup(), r);
cmd.execute();
}
for (ResourceGroup *g : qAsConst(removegroups)) {
debugPlanShared<<"Delete group:"<id();
RemoveResourceGroupCmd cmd(&project, g);
cmd.execute();
}
// insert new objects
Q_ASSERT(project.childNodeIterator().isEmpty());
InsertProjectCmd cmd(project, m_project, 0);
cmd.execute();
return true;
}
void MainDocument::insertViewListItem( View */*view*/, const ViewListItem *item, const ViewListItem *parent, int index )
{
// FIXME callers should take care that they now get a signal even if originating from themselves
emit viewListItemAdded(item, parent, index);
setModified( true );
m_viewlistModified = true;
}
void MainDocument::removeViewListItem( View */*view*/, const ViewListItem *item )
{
// FIXME callers should take care that they now get a signal even if originating from themselves
emit viewListItemRemoved(item);
setModified( true );
m_viewlistModified = true;
}
void MainDocument::setModified( bool mod )
{
debugPlan<name().isEmpty()) {
setUrl(QUrl(m_project->name() + ".plan"));
}
if (m_project->scheduleManagers().isEmpty()) {
ScheduleManager *sm = m_project->createScheduleManager();
sm->setAllowOverbooking(false);
sm->setSchedulingMode(ScheduleManager::AutoMode);
}
Calendar *week = nullptr;
if (KPlatoSettings::generateWeek()) {
bool always = KPlatoSettings::generateWeekChoice() == KPlatoSettings::EnumGenerateWeekChoice::Always;
bool ifnone = KPlatoSettings::generateWeekChoice() == KPlatoSettings::EnumGenerateWeekChoice::NoneExists;
if (always || (ifnone && m_project->calendarCount() == 0)) {
// create a calendar
week = new Calendar(i18nc("Base calendar name", "Base"));
m_project->addCalendar(week);
CalendarDay vd(CalendarDay::NonWorking);
for (int i = Qt::Monday; i <= Qt::Sunday; ++i) {
if (m_config.isWorkingday(i)) {
CalendarDay wd(CalendarDay::Working);
TimeInterval ti(m_config.dayStartTime(i), m_config.dayLength(i));
wd.addInterval(ti);
week->setWeekday(i, wd);
} else {
week->setWeekday(i, vd);
}
}
}
}
#ifdef HAVE_KHOLIDAYS
if (KPlatoSettings::generateHolidays()) {
bool inweek = week != 0 && KPlatoSettings::generateHolidaysChoice() == KPlatoSettings::EnumGenerateHolidaysChoice::InWeekCalendar;
bool subcalendar = week != 0 && KPlatoSettings::generateHolidaysChoice() == KPlatoSettings::EnumGenerateHolidaysChoice::AsSubCalendar;
bool separate = week == 0 || KPlatoSettings::generateHolidaysChoice() == KPlatoSettings::EnumGenerateHolidaysChoice::AsSeparateCalendar;
Calendar *holiday = nullptr;
if (inweek) {
holiday = week;
week->setDefault(true);
debugPlan<<"in week";
} else if (subcalendar) {
holiday = new Calendar(i18n("Holidays"));
m_project->addCalendar(holiday, week);
holiday->setDefault(true);
debugPlan<<"subcalendar";
} else if (separate) {
holiday = new Calendar(i18n("Holidays"));
m_project->addCalendar(holiday);
holiday->setDefault(true);
debugPlan<<"separate";
} else {
Q_ASSERT(false); // something wrong
}
debugPlan<setHolidayRegion(KPlatoSettings::region());
}
#else
week->setDefault(true);
#endif
}
// creates a "new" project from current project (new ids etc)
void MainDocument::createNewProject()
{
setEmpty();
clearUndoHistory();
setModified( false );
resetURL();
KoDocumentInfo *info = documentInfo();
info->resetMetaData();
info->setProperty( "title", "" );
setTitleModified();
m_project->generateUniqueNodeIds();
Duration dur = m_project->constraintEndTime() - m_project->constraintStartTime();
m_project->setConstraintStartTime( QDateTime(QDate::currentDate(), QTime(0, 0, 0), Qt::LocalTime) );
m_project->setConstraintEndTime( m_project->constraintStartTime() + dur );
while ( m_project->numScheduleManagers() > 0 ) {
foreach ( ScheduleManager *sm, m_project->allScheduleManagers() ) {
if ( sm->childCount() > 0 ) {
continue;
}
if ( sm->expected() ) {
sm->expected()->setDeleted( true );
sm->setExpected( 0 );
}
m_project->takeScheduleManager( sm );
delete sm;
}
}
foreach ( Schedule *s, m_project->schedules() ) {
m_project->takeSchedule( s );
delete s;
}
foreach ( Node *n, m_project->allNodes() ) {
foreach ( Schedule *s, n->schedules() ) {
n->takeSchedule( s );
delete s;
}
}
foreach ( Resource *r, m_project->resourceList() ) {
foreach ( Schedule *s, r->schedules() ) {
r->takeSchedule( s );
delete s;
}
}
}
void MainDocument::setIsTaskModule(bool value)
{
m_isTaskModule = value;
}
bool MainDocument::isTaskModule() const
{
return m_isTaskModule;
}
} //KPlato namespace
diff --git a/src/kptmaindocument.h b/src/kptmaindocument.h
index f10c5f84..d14d5603 100644
--- a/src/kptmaindocument.h
+++ b/src/kptmaindocument.h
@@ -1,276 +1,277 @@
/* This file is part of the KDE project
* Copyright (C) 1998, 1999, 2000 Torben Weis
* Copyright (C) 2004 - 2010 Dag Andersen
* Copyright (C) 2006 Raphael Langerhorst
* Copyright (C) 2007 Thorsten Zachmann
* 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 KPTMAINDOCUMENT_H
#define KPTMAINDOCUMENT_H
#include "plan_export.h"
#include "kptpackage.h"
#include "kpttask.h"
#include "kptconfig.h"
#include "kptwbsdefinition.h"
#include "kptxmlloaderobject.h"
#include "about/aboutpage.h"
#include "KoDocument.h"
#include
#include
#define PLAN_MIME_TYPE "application/x-vnd.kde.plan"
class KDirWatch;
/// The main namespace.
namespace KPlato
{
class DocumentChild;
class Project;
class Context;
class SchedulerPlugin;
class ViewListItem;
class View;
class Package;
class PLAN_EXPORT MainDocument : public KoDocument
{
Q_OBJECT
public:
explicit MainDocument(KoPart *part);
~MainDocument() override;
+ void initEmpty() override;
/// reimplemented from KoDocument
QByteArray nativeFormatMimeType() const override { return PLAN_MIME_TYPE; }
/// reimplemented from KoDocument
QByteArray nativeOasisMimeType() const override { return ""; }
/// reimplemented from KoDocument
QStringList extraNativeMimeTypes() const override
{
return QStringList() << PLAN_MIME_TYPE;
}
void setReadWrite( bool rw ) override;
void configChanged();
void paintContent( QPainter& painter, const QRect& rect) override;
void setProject( Project *project );
Project *project() const override { return m_project; }
Project &getProject() { return *m_project; }
const Project &getProject() const { return * m_project; }
QString projectName() const override { return m_project->name(); }
/**
* Return the set of SupportedSpecialFormats that the kplato wants to
* offer in the "Save" file dialog.
* Note: SaveEncrypted is not supported.
*/
int supportedSpecialFormats() const override { return SaveAsDirectoryStore; }
// The load and save functions. Look in the file kplato.dtd for info
bool loadXML( const KoXmlDocument &document, KoStore *store ) override;
QDomDocument saveXML() override;
/// Save a workpackage file containing @p node with schedule identity @p id, owned by @p resource
QDomDocument saveWorkPackageXML( const Node *node, long id, Resource *resource = 0 );
bool saveOdf( SavingContext &/*documentContext */) override { return false; }
bool loadOdf( KoOdfReadStore & odfStore ) override;
Config &config() { return m_config; }
Context *context() const { return m_context; }
WBSDefinition &wbsDefinition() { return m_project->wbsDefinition(); }
const XMLLoaderObject &xmlLoader() const { return m_xmlLoader; }
DocumentChild *createChild( KoDocument *doc, const QRect &geometry = QRect() );
bool saveWorkPackageToStream( QIODevice * dev, const Node *node, long id, Resource *resource = 0 );
bool saveWorkPackageFormat( const QString &file, const Node *node, long id, Resource *resource = 0 );
bool saveWorkPackageUrl( const QUrl & _url, const Node *node, long id, Resource *resource = 0 );
/// Load the workpackage from @p url into @p project. Return true if successful, else false.
bool loadWorkPackage( Project &project, const QUrl &url );
Package *loadWorkPackageXML( Project& project, QIODevice*, const KoXmlDocument& document, const QUrl& url );
QMap workPackages() const { return m_workpackages; }
void clearWorkPackages() {
qDeleteAll(m_workpackages);
m_workpackages.clear();
m_checkingForWorkPackages = false;
}
void insertFile( const QUrl &url, Node *parent, Node *after = 0 );
bool insertProject( Project &project, Node *parent, Node *after );
bool mergeResources(Project &project);
KPlatoAboutPage &aboutPage() { return m_aboutPage; }
bool extractFiles( KoStore *store, Package *package );
bool extractFile( KoStore *store, Package *package, const Document *doc );
void registerView( View *view );
/// Create a new project from this project
/// Generates new project id and task ids
/// Keeps resource- and calendar ids
void createNewProject();
bool isTaskModule() const;
using KoDocument::setModified;
public Q_SLOTS:
void setModified( bool mod ) override;
/// Inserts an item into all other views than @p view
void insertViewListItem(KPlato::View *view, const KPlato::ViewListItem *item, const KPlato::ViewListItem *parent, int index);
/// Removes the view list item from all other views than @p view
void removeViewListItem(KPlato::View *view, const KPlato::ViewListItem *item);
/// View selector has been modified
void slotViewlistModified();
/// Check for workpackages
/// If @p keep is true, packages that has been refused will not be checked for again
void checkForWorkPackages(bool keep);
/// Remove @p package
void terminateWorkPackage( const KPlato::Package *package );
void setLoadingTemplate( bool );
void setLoadingSharedResourcesTemplate( bool );
void insertResourcesFile(const QUrl &url, const QUrl &projects = QUrl());
void slotProjectCreated();
/// Prepare for insertion of resource assignments of shared resources from the project(s) in @p urls
void insertSharedProjects(const QList &urls);
/// Prepare for insertion of resource assignments of shared resources from the project(s) in @p url
void insertSharedProjects(const QUrl &url);
/// Clear resource assignments of shared resources
void clearResourceAssignments();
/// Load resource assignments of shared resources from the project(s) in @p url
void loadResourceAssignments(QUrl url);
void setIsTaskModule(bool value);
void autoCheckForWorkPackages();
Q_SIGNALS:
void changed();
void workPackageLoaded();
void viewlistModified( bool );
void viewListItemAdded(const KPlato::ViewListItem *item, const KPlato::ViewListItem *parent, int index);
void viewListItemRemoved(const KPlato::ViewListItem *item);
void insertSharedProject();
protected:
/// Load kplato specific files
bool completeLoading( KoStore* store ) override;
/// Save kplato specific files
bool completeSaving( KoStore* store ) override;
// used by insert file
struct InsertFileInfo {
QUrl url;
Node *parent;
Node *after;
} m_insertFileInfo;
protected Q_SLOTS:
void slotViewDestroyed();
void addSchedulerPlugin(const QString&, KPlato::SchedulerPlugin *plugin);
void checkForWorkPackage();
void insertFileCompleted();
void insertResourcesFileCompleted();
void insertFileCancelled( const QString& );
void slotInsertSharedProject();
void insertSharedProjectCompleted();
void insertSharedProjectCancelled( const QString& );
void slotNodeChanged(KPlato::Node*, int);
void slotScheduleManagerChanged(KPlato::ScheduleManager *sm, int property);
void setCalculationNeeded();
void slotCalculationFinished(KPlato::Project *project, KPlato::ScheduleManager *sm);
void slotStartCalculation();
void setTaskModulesWatch();
void taskModuleDirChanged();
private:
bool loadAndParse(KoStore* store, const QString& filename, KoXmlDocument& doc);
void loadSchedulerPlugins();
private:
Project *m_project;
QWidget* m_parentWidget;
Config m_config;
Context *m_context;
XMLLoaderObject m_xmlLoader;
bool m_loadingTemplate;
bool m_loadingSharedResourcesTemplate;
QMap m_schedulerPlugins;
QMap m_workpackages;
QFileInfoList m_infoList;
QList m_skipUrls;
QMap m_mergedPackages;
KPlatoAboutPage m_aboutPage;
QDomDocument m_reports;
bool m_viewlistModified;
bool m_checkingForWorkPackages;
QList > m_views;
bool m_loadingSharedProject;
QList m_sharedProjectsFiles;
bool m_skipSharedProjects;
bool m_isTaskModule;
KUndo2Command* m_calculationCommand;
ScheduleManager* m_currentCalculationManager;
ScheduleManager* m_nextCalculationManager;
KDirWatch *m_taskModulesWatch;
};
} //KPlato namespace
#endif
diff --git a/src/kptpart.cpp b/src/kptpart.cpp
index 6b8841dc..222eda4b 100644
--- a/src/kptpart.cpp
+++ b/src/kptpart.cpp
@@ -1,232 +1,252 @@
/* This file is part of the KDE project
Copyright (C) 2012 C. Boemann
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 "kptpart.h"
#include "config/ConfigDialog.h"
#include "kptview.h"
#include "kptmaindocument.h"
#include "kptfactory.h"
#include "welcome/WelcomeView.h"
#include "kpthtmlview.h"
#include "Help.h"
#include "calligraplansettings.h"
#include "kptdebug.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace KPlato;
Part::Part(QObject *parent)
: KoPart(Factory::global(), parent)
, startUpWidget(0)
{
setTemplatesResourcePath(QLatin1String("calligraplan/templates/"));
new Help(KPlatoSettings::contextPath(), KPlatoSettings::contextLanguage());
}
Part::~Part()
{
}
void Part::setDocument(KPlato::MainDocument *document)
{
KoPart::setDocument(document);
m_document = document;
}
KoView *Part::createViewInstance(KoDocument *document, QWidget *parent)
{
// synchronize view selector
View *view = dynamic_cast(views().value(0));
/*FIXME
if (view && m_context) {
QDomDocument doc = m_context->save(view);
m_context->setContent(doc.toString());
}*/
view = new View(this, qobject_cast(document), parent);
// connect(view, SIGNAL(destroyed()), this, SLOT(slotViewDestroyed()));
// connect(document, SIGNAL(viewListItemAdded(const ViewListItem*,const ViewListItem*,int)), view, SLOT(addViewListItem(const ViewListItem*,const ViewListItem*,int)));
// connect(document, SIGNAL(viewListItemRemoved(const ViewListItem*)), view, SLOT(removeViewListItem(const ViewListItem*)));
return view;
}
KoMainWindow *Part::createMainWindow()
{
KoMainWindow *w = new KoMainWindow(PLAN_MIME_TYPE, componentData());
QAction *handbookAction = w->action("help_contents");
if (handbookAction) {
// we do not want to use khelpcenter as we do not install docs
disconnect(handbookAction, 0, 0, 0);
connect(handbookAction, &QAction::triggered, this, &Part::slotHelpContents);
}
return w;
}
void Part::slotHelpContents()
{
QDesktopServices::openUrl(QUrl::fromUserInput(KPlatoSettings::documentationPath()));
}
void Part::showStartUpWidget(KoMainWindow *parent)
{
m_toolbarVisible = parent->factory()->container("mainToolBar", parent)->isVisible();
if (m_toolbarVisible) {
parent->factory()->container("mainToolBar", parent)->hide();
}
if (startUpWidget) {
startUpWidget->show();
} else {
createStarUpWidget(parent);
parent->setCentralWidget(startUpWidget);
}
parent->setPartToOpen(this);
}
void Part::slotOpenTemplate(const QUrl &url)
{
openTemplate(url);
}
void Part::openTemplate(const QUrl &url)
{
debugPlan<<"Open shared resources template:"<setLoadingTemplate(true);
m_document->setLoadingSharedResourcesTemplate(url.fileName() == "SharedResources.plant");
KoPart::openTemplate(url);
m_document->setLoadingTemplate(false);
}
+bool Part::openProjectTemplate(const QUrl &url)
+{
+ QApplication::setOverrideCursor(Qt::BusyCursor);
+ m_document->setLoadingTemplate(true);
+ bool ok = m_document->loadNativeFormat(url.path());
+ m_document->setModified(false);
+ m_document->undoStack()->clear();
+
+ if (ok) {
+ m_document->resetURL();
+ m_document->setEmpty();
+ } else {
+ m_document->showLoadingErrorDialog();
+ m_document->initEmpty();
+ }
+ m_document->setLoadingTemplate(false);
+ QApplication::restoreOverrideCursor();
+ return ok;
+}
+
void Part::openTaskModule(const QUrl &url)
{
Part *part = new Part(0);
MainDocument *doc = new MainDocument(part);
part->setDocument(doc);
doc->setIsTaskModule(true);
mainWindows().first()->openDocument(part, url);
}
void Part::createStarUpWidget(KoMainWindow *parent)
{
startUpWidget = new QStackedWidget(parent);
startUpWidget->addWidget(createWelcomeView(parent));
startUpWidget->addWidget(createIntroductionView());
}
void Part::finish()
{
mainWindows().first()->setRootDocument(document(), this);
if (m_toolbarVisible) {
KoPart::mainWindows().first()->factory()->container("mainToolBar", mainWindows().first())->show();
}
}
QWidget *Part::createWelcomeView(KoMainWindow *mw)
{
MainDocument *doc = static_cast(document());
WelcomeView *v = new WelcomeView(this, doc, startUpWidget);
v->setProject(&(doc->getProject()));
KSharedConfigPtr configPtr = Factory::global().config();
KRecentFilesAction recent("x", 0);
recent.loadEntries(configPtr->group("RecentFiles"));
v->setRecentFiles(recent.actions());
connect(v, &WelcomeView::loadSharedResources, doc, &MainDocument::insertResourcesFile);
connect(v, &WelcomeView::recentProject, mw, &KoMainWindow::slotFileOpenRecent);
connect(v, &WelcomeView::showIntroduction, this, &Part::slotShowIntroduction);
connect(v, &WelcomeView::projectCreated, doc, &MainDocument::slotProjectCreated);
connect(v, &WelcomeView::finished, this, &Part::finish);
connect(v, &WelcomeView::openTemplate, this, &Part::slotOpenTemplate);
return v;
}
void Part::slotShowIntroduction()
{
startUpWidget->setCurrentIndex(1);
slotOpenUrlRequest(static_cast(startUpWidget->currentWidget()), QUrl("about:plan/main"));
}
void Part::slotOpenUrlRequest( HtmlView *v, const QUrl &url )
{
debugPlan<setCurrentIndex(0);
return;
}
if ( url.url().startsWith( QLatin1String( "about:plan" ) ) ) {
MainDocument *doc = static_cast(document());
doc->aboutPage().generatePage( v->htmlPart(), url );
return;
}
}
if ( url.scheme() == QLatin1String("help") ) {
KHelpClient::invokeHelp( "", url.fileName() );
return;
}
// try to open the url
debugPlan<htmlPart().setJScriptEnabled(false);
v->htmlPart().setJavaEnabled(false);
v->htmlPart().setMetaRefreshEnabled(false);
v->htmlPart().setPluginsEnabled(false);
slotOpenUrlRequest( v, QUrl( "about:plan/main" ) );
connect( v, &KPlato::HtmlView::openUrlRequest, this, &KPlato::Part::slotOpenUrlRequest );
return v;
}
void Part::configure(KoMainWindow *mw)
{
//debugPlan;
if( KConfigDialog::showDialog("Plan Settings")) {
return;
}
ConfigDialog *dialog = new ConfigDialog(mw, "Plan Settings", KPlatoSettings::self());
dialog->open();
}
diff --git a/src/kptpart.h b/src/kptpart.h
index be8451e5..27f2c970 100644
--- a/src/kptpart.h
+++ b/src/kptpart.h
@@ -1,83 +1,85 @@
/* This file is part of the KDE project
Copyright (C) 2012 C. Boemann
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 KPTPART_H
#define KPTPART_H
#include
#include "plan_export.h"
#include
class KoView;
class QStackedWidget;
/// The main namespace.
namespace KPlato
{
class MainDocument;
class HtmlView;
class PLAN_EXPORT Part : public KoPart
{
Q_OBJECT
public:
explicit Part(QObject *parent);
~Part() override;
void setDocument(KPlato::MainDocument *document);
/// reimplemented
KoView *createViewInstance(KoDocument *document, QWidget *parent) override;
/// reimplemented
KoMainWindow *createMainWindow() override;
void showStartUpWidget(KoMainWindow *parent) override;
void configure(KoMainWindow *mw) override;
+ bool openProjectTemplate(const QUrl &url) override;
+
public Q_SLOTS:
void openTaskModule(const QUrl& url);
+ void finish();
protected Q_SLOTS:
- void finish();
void slotShowIntroduction();
void slotOpenUrlRequest(KPlato::HtmlView *v, const QUrl &url);
void openTemplate( const QUrl& url ) override;
void slotOpenTemplate(const QUrl& url);
void slotHelpContents();
protected:
void createStarUpWidget(KoMainWindow *parent);
QWidget *createWelcomeView(KoMainWindow *parent);
QWidget *createIntroductionView();
private:
KPlato::MainDocument *m_document;
QPointer startUpWidget;
bool m_toolbarVisible;
};
} //KPlato namespace
#endif
diff --git a/src/kptview.cpp b/src/kptview.cpp
index 9f9e4550..82d6d3ca 100644
--- a/src/kptview.cpp
+++ b/src/kptview.cpp
@@ -1,3231 +1,3247 @@
/* This file is part of the KDE project
Copyright (C) 1998, 1999, 2000 Torben Weis
Copyright (C) 2002 - 2011 Dag Andersen
Copyright (C) 2012 Dag Andersen
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 "kptview.h"
#include
#include
#include "KoDocumentInfo.h"
#include "KoMainWindow.h"
#include
#include
+#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "kptlocale.h"
#include "kptviewbase.h"
#include "kptaccountsview.h"
#include "kptaccountseditor.h"
#include "kptcalendareditor.h"
#include "kptfactory.h"
#include "kptmilestoneprogressdialog.h"
#include "kpttaskdescriptiondialog.h"
#include "kptdocumentsdialog.h"
#include "kptnode.h"
#include "kptmaindocument.h"
#include "kptproject.h"
#include "kptmainprojectdialog.h"
#include "kpttask.h"
#include "kptsummarytaskdialog.h"
#include "kpttaskdialog.h"
#include "kpttaskprogressdialog.h"
#include "kptganttview.h"
#include "kpttaskeditor.h"
#include "kptdependencyeditor.h"
#include "kptperteditor.h"
#include "kptdatetime.h"
#include "kptcommand.h"
#include "kptrelation.h"
#include "kptrelationdialog.h"
#include "kptresourceappointmentsview.h"
#include "kptresourceeditor.h"
#include "kptscheduleeditor.h"
#include "kptresourcedialog.h"
#include "kptresource.h"
#include "kptstandardworktimedialog.h"
#include "kptwbsdefinitiondialog.h"
#include "kptresourceassignmentview.h"
#include "kpttaskstatusview.h"
#include "kptsplitterview.h"
#include "kptpertresult.h"
#include "kptinsertfiledlg.h"
#include "kptloadsharedprojectsdialog.h"
#include "kpthtmlview.h"
#include "about/aboutpage.h"
#include "kptlocaleconfigmoneydialog.h"
#include "kptflatproxymodel.h"
#include "kpttaskstatusmodel.h"
#include "kptworkpackagemergedialog.h"
#include "Help.h"
#include "performance/PerformanceStatusView.h"
#include "performance/ProjectStatusView.h"
#include "reportsgenerator/ReportsGeneratorView.h"
#ifdef PLAN_USE_KREPORT
#include "reports/reportview.h"
#include "reports/reportdata.h"
#endif
#include "kptviewlistdialog.h"
#include "kptviewlistdocker.h"
#include "kptviewlist.h"
#include "kptschedulesdocker.h"
#include "kptpart.h"
#include "kptdebug.h"
#include "calligraplansettings.h"
#include "kptprintingcontrolprivate.h"
// #include "KPtViewAdaptor.h"
#include
using namespace KPlato;
View::View(KoPart *part, MainDocument *doc, QWidget *parent)
: KoView(part, doc, parent),
m_currentEstimateType( Estimate::Use_Expected ),
m_scheduleActionGroup( new QActionGroup( this ) ),
m_readWrite( false ),
m_defaultView(1),
m_partpart (part)
{
//debugPlan;
new Help(KPlatoSettings::contextPath(), KPlatoSettings::contextLanguage());
doc->registerView( this );
setComponentName(Factory::global().componentName(), Factory::global().componentDisplayName());
if ( !doc->isReadWrite() )
setXMLFile( "calligraplan_readonly.rc" );
else
setXMLFile( "calligraplan.rc" );
// new ViewAdaptor( this );
m_sp = new QSplitter( this );
QVBoxLayout *layout = new QVBoxLayout( this );
layout->setMargin(0);
layout->addWidget( m_sp );
ViewListDocker *docker = 0;
if ( mainWindow() == 0 ) {
// Don't use docker if embedded
m_viewlist = new ViewListWidget(doc, m_sp);
m_viewlist->setProject( &( getProject() ) );
connect( m_viewlist, &ViewListWidget::selectionChanged, this, &View::slotSelectionChanged);
connect( this, &View::currentScheduleManagerChanged, m_viewlist, &ViewListWidget::setSelectedSchedule);
connect( m_viewlist, &ViewListWidget::updateViewInfo, this, &View::slotUpdateViewInfo);
} else {
ViewListDockerFactory vl(this);
docker = static_cast(mainWindow()->createDockWidget(&vl));
if (docker->view() != this) {
docker->setView(this);
}
m_viewlist = docker->viewList();
#if 0 //SchedulesDocker
SchedulesDockerFactory sdf;
SchedulesDocker *sd = dynamic_cast( createDockWidget( &sdf ) );
Q_ASSERT( sd );
sd->setProject( &getProject() );
connect(sd, SIGNAL(selectionChanged(KPlato::ScheduleManager*)), SLOT(slotSelectionChanged(KPlato::ScheduleManager*)));
connect(this, &View::currentScheduleManagerChanged, sd, SLOT(setSelectedSchedule(KPlato::ScheduleManager*)));
#endif
}
m_tab = new QStackedWidget( m_sp );
////////////////////////////////////////////////////////////////////////////////////////////////////
// Add sub views
createIntroductionView();
// The menu items
// ------ File
-/* actionCreateTemplate = new QAction( i18n( "&Create Template From Document..." ), this );
+ actionCreateTemplate = new QAction(koIcon("document-save-as-template"), i18n( "Create Project Template..." ), this);
actionCollection()->addAction("file_createtemplate", actionCreateTemplate );
connect( actionCreateTemplate, SIGNAL(triggered(bool)), SLOT(slotCreateTemplate()) );
-*/
- actionCreateNewProject = new QAction( i18n( "&Create New Project..." ), this );
+
+ actionCreateNewProject = new QAction( i18n( "Create New Project..." ), this );
actionCollection()->addAction("file_createnewproject", actionCreateNewProject );
connect( actionCreateNewProject, &QAction::triggered, this, &View::slotCreateNewProject );
// ------ Edit
actionCut = actionCollection()->addAction(KStandardAction::Cut, "edit_cut", this, SLOT(slotEditCut()));
actionCopy = actionCollection()->addAction(KStandardAction::Copy, "edit_copy", this, SLOT(slotEditCopy()));
actionPaste = actionCollection()->addAction(KStandardAction::Paste, "edit_paste", this, SLOT(slotEditPaste()));
// ------ View
actionCollection()->addAction( KStandardAction::Redisplay, "view_refresh" , this, SLOT(slotRefreshView()) );
actionViewSelector = new KToggleAction(i18n("Show Selector"), this);
actionCollection()->addAction("view_show_selector", actionViewSelector );
connect( actionViewSelector, &QAction::triggered, this, &View::slotViewSelector );
// ------ Insert
// ------ Project
actionEditMainProject = new QAction(koIcon("view-time-schedule-edit"), i18n("Edit Main Project..."), this);
actionCollection()->addAction("project_edit", actionEditMainProject );
connect( actionEditMainProject, &QAction::triggered, this, &View::slotProjectEdit );
actionEditStandardWorktime = new QAction(koIcon("configure"), i18n("Define Estimate Conversions..."), this);
actionCollection()->addAction("project_worktime", actionEditStandardWorktime );
connect( actionEditStandardWorktime, &QAction::triggered, this, &View::slotProjectWorktime );
actionDefineWBS = new QAction(koIcon("configure"), i18n("Define WBS Pattern..."), this);
actionCollection()->addAction("tools_define_wbs", actionDefineWBS );
connect( actionDefineWBS, &QAction::triggered, this, &View::slotDefineWBS );
actionCurrencyConfig = new QAction(koIcon("configure"), i18n("Define Currency..."), this);
actionCollection()->addAction( "config_currency", actionCurrencyConfig );
connect( actionCurrencyConfig, &QAction::triggered, this, &View::slotCurrencyConfig );
QAction *actionProjectDescription = new QAction(koIcon("document-edit"), i18n("Edit Description..."), this);
actionCollection()->addAction( "edit_project_description", actionProjectDescription );
connect( actionProjectDescription, &QAction::triggered, this, &View::slotOpenProjectDescription );
// ------ Tools
actionInsertFile = new QAction(koIcon("document-import"), i18n("Insert Project File..."), this);
actionCollection()->addAction("insert_file", actionInsertFile );
connect( actionInsertFile, &QAction::triggered, this, &View::slotInsertFile );
actionLoadSharedProjects = new QAction(koIcon("document-import"), i18n("Load Shared Projects..."), this);
actionCollection()->addAction("load_shared_projects", actionLoadSharedProjects );
connect( actionLoadSharedProjects, &QAction::triggered, this, &View::slotLoadSharedProjects );
#ifdef PLAN_USE_KREPORT
actionOpenReportFile = new QAction(koIcon("document-open"), i18n("Open Report Definition File..."), this);
actionCollection()->addAction( "reportdesigner_open_file", actionOpenReportFile );
connect( actionOpenReportFile, QAction::triggered, this, &View::slotOpenReportFile);
#endif
// ------ Help
actionIntroduction = new QAction(koIcon("dialog-information"), i18n("Introduction to Plan"), this);
actionCollection()->addAction("plan_introduction", actionIntroduction );
connect( actionIntroduction, &QAction::triggered, this, &View::slotIntroduction );
// ------ Popup
actionOpenNode = new QAction(koIcon("document-edit"), i18n("Edit..."), this);
actionCollection()->addAction("node_properties", actionOpenNode );
connect( actionOpenNode, &QAction::triggered, this, &View::slotOpenCurrentNode );
actionTaskProgress = new QAction(koIcon("document-edit"), i18n("Progress..."), this);
actionCollection()->addAction("task_progress", actionTaskProgress );
connect( actionTaskProgress, &QAction::triggered, this, &View::slotTaskProgress );
actionDeleteTask = new QAction(koIcon("edit-delete"), i18n("Delete Task"), this);
actionCollection()->addAction("delete_task", actionDeleteTask );
connect( actionDeleteTask, &QAction::triggered, this, &View::slotDeleteCurrentTask );
actionTaskDescription = new QAction(koIcon("document-edit"), i18n("Description..."), this);
actionCollection()->addAction("task_description", actionTaskDescription );
connect( actionTaskDescription, &QAction::triggered, this, &View::slotTaskDescription );
actionDocuments = new QAction(koIcon("document-edit"), i18n("Documents..."), this);
actionCollection()->addAction("task_documents", actionDocuments );
connect( actionDocuments, &QAction::triggered, this, &View::slotDocuments );
actionIndentTask = new QAction(koIcon("format-indent-more"), i18n("Indent Task"), this);
actionCollection()->addAction("indent_task", actionIndentTask );
connect( actionIndentTask, &QAction::triggered, this, &View::slotIndentTask );
actionUnindentTask= new QAction(koIcon("format-indent-less"), i18n("Unindent Task"), this);
actionCollection()->addAction("unindent_task", actionUnindentTask );
connect( actionUnindentTask, &QAction::triggered, this, &View::slotUnindentTask );
actionMoveTaskUp = new QAction(koIcon("arrow-up"), i18n("Move Task Up"), this);
actionCollection()->addAction("move_task_up", actionMoveTaskUp );
connect( actionMoveTaskUp, &QAction::triggered, this, &View::slotMoveTaskUp );
actionMoveTaskDown = new QAction(koIcon("arrow-down"), i18n("Move Task Down"), this);
actionCollection()->addAction("move_task_down", actionMoveTaskDown );
connect( actionMoveTaskDown, &QAction::triggered, this, &View::slotMoveTaskDown );
actionEditResource = new QAction(koIcon("document-edit"), i18n("Edit Resource..."), this);
actionCollection()->addAction("edit_resource", actionEditResource );
connect( actionEditResource, &QAction::triggered, this, &View::slotEditCurrentResource );
actionEditRelation = new QAction(koIcon("document-edit"), i18n("Edit Dependency..."), this);
actionCollection()->addAction("edit_dependency", actionEditRelation );
connect( actionEditRelation, &QAction::triggered, this, &View::slotModifyCurrentRelation );
actionDeleteRelation = new QAction(koIcon("edit-delete"), i18n("Delete Dependency"), this);
actionCollection()->addAction("delete_dependency", actionDeleteRelation );
connect( actionDeleteRelation, &QAction::triggered, this, &View::slotDeleteRelation );
// Viewlist popup
connect( m_viewlist, &ViewListWidget::createView, this, &View::slotCreateView );
m_workPackageButton = new QToolButton(this);
m_workPackageButton->hide();
m_workPackageButton->setIcon(koIcon("application-x-vnd.kde.plan.work"));
m_workPackageButton->setText(i18n("Work Packages..."));
m_workPackageButton->setToolTip(i18nc("@info:tooltip", "Work packages available"));
m_workPackageButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
connect(m_workPackageButton, &QToolButton::clicked, this, &View::openWorkPackageMergeDialog);
m_estlabel = new QLabel( "", 0 );
if ( statusBar() ) {
addStatusBarItem( m_estlabel, 0, true );
}
connect( &getProject(), &Project::scheduleManagerAdded, this, &View::slotScheduleAdded );
connect( &getProject(), &Project::scheduleManagerRemoved, this, &View::slotScheduleRemoved );
connect( &getProject(), &Project::scheduleManagersSwapped, this, &View::slotScheduleSwapped );
connect( &getProject(), &Project::sigCalculationFinished, this, &View::slotScheduleCalculated );
slotPlugScheduleActions();
connect( doc, &MainDocument::changed, this, &View::slotUpdate );
connect( m_scheduleActionGroup, &QActionGroup::triggered, this, &View::slotViewSchedule );
connect( getPart(), &MainDocument::workPackageLoaded, this, &View::slotWorkPackageLoaded );
// views take time for large projects
QTimer::singleShot(0, this, &View::initiateViews);
const QList pluginFactories =
KoPluginLoader::instantiatePluginFactories(QStringLiteral("calligraplan/extensions"));
foreach (KPluginFactory* factory, pluginFactories) {
QObject *object = factory->create(this, QVariantList());
KXMLGUIClient *clientPlugin = dynamic_cast(object);
if (clientPlugin) {
insertChildClient(clientPlugin);
} else {
// not our/valid plugin, so delete the created object
object->deleteLater();
}
}
//debugPlan<<" end";
}
View::~View()
{
// Disconnect and delete so we do not get called by destroyed() signal
const QMap map = m_scheduleActions; // clazy:exclude=qmap-with-pointer-key
QMap::const_iterator it;
for (it = map.constBegin(); it != map.constEnd(); ++it) {
disconnect(it.key(), &QObject::destroyed, this, &View::slotActionDestroyed);
m_scheduleActionGroup->removeAction(it.key());
delete it.key();
}
ViewBase *view = currentView();
if (view) {
// deactivate view to remove dockers etc
slotGuiActivated(view, false);
}
/* removeStatusBarItem( m_estlabel );
delete m_estlabel;*/
}
void View::initiateViews()
{
QApplication::setOverrideCursor( Qt::WaitCursor );
createViews();
connect( m_viewlist, &ViewListWidget::activated, this, &View::slotViewActivated );
// after createViews() !!
connect( m_viewlist, &ViewListWidget::viewListItemRemoved, this, &View::slotViewListItemRemoved );
// after createViews() !!
connect( m_viewlist, &ViewListWidget::viewListItemInserted, this, &View::slotViewListItemInserted );
ViewListDocker *docker = qobject_cast( m_viewlist->parent() );
if ( docker ) {
// after createViews() !!
connect( m_viewlist, &ViewListWidget::modified, docker, &ViewListDocker::slotModified);
connect( m_viewlist, &ViewListWidget::modified, getPart(), &MainDocument::slotViewlistModified);
connect(getPart(), &MainDocument::viewlistModified, docker, &ViewListDocker::updateWindowTitle);
}
connect( m_tab, &QStackedWidget::currentChanged, this, &View::slotCurrentChanged );
slotSelectDefaultView();
loadContext();
QApplication::restoreOverrideCursor();
}
void View::slotCreateNewProject()
{
debugPlan;
if ( KMessageBox::Continue == KMessageBox::warningContinueCancel( this,
xi18nc( "@info",
"This action cannot be undone."
"Create a new Project from the current project "
"with new project- and task identities."
"Resource- and calendar identities are not changed."
"All scheduling information is removed."
"Do you want to continue?" ) ) )
{
emit currentScheduleManagerChanged(0);
getPart()->createNewProject();
slotOpenNode( &getProject() );
}
}
+void View::slotCreateTemplate()
+{
+ debugPlan;
+ KoFileDialog dlg(nullptr, KoFileDialog::SaveFile, "Create Template");
+ dlg.setNameFilters(QStringList()<<"Plan Template (*.plant)");
+ QString file = dlg.filename();
+ if (!file.isEmpty()) {
+ QUrl url = QUrl::fromUserInput(file);
+ koDocument()->exportDocument(url);
+ qInfo()<context();
if ( ctx && ctx->isLoaded() ) {
debugPlan<<"isLoaded";
KoXmlNode n = ctx->context().namedItem( "categories" );
if ( n.isNull() ) {
warnPlan<<"No categories";
} else {
n = n.firstChild();
for ( ; ! n.isNull(); n = n.nextSibling() ) {
if ( ! n.isElement() ) {
continue;
}
KoXmlElement e = n.toElement();
if (e.tagName() != "category") {
continue;
}
debugPlan<<"category: "<addCategory( ct, cn );
KoXmlNode n1 = e.firstChild();
for ( ; ! n1.isNull(); n1 = n1.nextSibling() ) {
if ( ! n1.isElement() ) {
continue;
}
KoXmlElement e1 = n1.toElement();
if (e1.tagName() != "view") {
continue;
}
ViewBase *v = 0;
QString type = e1.attribute( "viewtype" );
QString tag = e1.attribute( "tag" );
QString name = e1.attribute( "name" );
QString tip = e1.attribute( "tooltip" );
v = createView( cat, type, tag, name, tip );
//KoXmlNode settings = e1.namedItem( "settings " ); ????
KoXmlNode settings = e1.firstChild();
for ( ; ! settings.isNull(); settings = settings.nextSibling() ) {
if ( settings.nodeName() == "settings" ) {
break;
}
}
if ( v && settings.isElement() ) {
debugPlan<<" settings";
v->loadContext( settings.toElement() );
}
}
}
}
} else {
debugPlan<<"Default";
ViewBase *v = 0;
ViewListItem *cat;
QString ct = "Editors";
cat = m_viewlist->addCategory( ct, defaultCategoryInfo( ct ).name );
createCalendarEditor( cat, "CalendarEditor", QString(), TIP_USE_DEFAULT_TEXT );
createAccountsEditor( cat, "AccountsEditor", QString(), TIP_USE_DEFAULT_TEXT );
v = createResourceEditor( cat, "ResourceEditor", QString(), TIP_USE_DEFAULT_TEXT );
v = createTaskEditor( cat, "TaskEditor", QString(), TIP_USE_DEFAULT_TEXT );
m_defaultView = m_tab->count() - 1;
v->showColumns(QList() << NodeModel::NodeName
<< NodeModel::NodeType
<< NodeModel::NodeAllocation
<< NodeModel::NodeEstimateCalendar
<< NodeModel::NodeEstimate
<< NodeModel::NodeOptimisticRatio
<< NodeModel::NodePessimisticRatio
<< NodeModel::NodeRisk
<< NodeModel::NodeResponsible
<< NodeModel::NodeDescription
);
v = createTaskEditor( cat, "TaskConstraintEditor", i18n("Task Constraints"), i18n("Edit task scheduling constraints") );
v->showColumns(QList() << NodeModel::NodeName
<< NodeModel::NodeType
<< NodeModel::NodePriority
<< NodeModel::NodeConstraint
<< NodeModel::NodeConstraintStart
<< NodeModel::NodeConstraintEnd
<< NodeModel::NodeDescription
);
v = createTaskEditor( cat, "TaskCostEditor", i18n("Task Cost"), i18n("Edit task cost") );
v->showColumns(QList() << NodeModel::NodeName
<< NodeModel::NodeType
<< NodeModel::NodeRunningAccount
<< NodeModel::NodeStartupAccount
<< NodeModel::NodeStartupCost
<< NodeModel::NodeShutdownAccount
<< NodeModel::NodeShutdownCost
<< NodeModel::NodeDescription
);
createDependencyEditor( cat, "DependencyEditor", QString(), TIP_USE_DEFAULT_TEXT );
// Do not show by default
// createPertEditor( cat, "PertEditor", QString(), TIP_USE_DEFAULT_TEXT );
createScheduleHandler( cat, "ScheduleHandlerView", QString(), TIP_USE_DEFAULT_TEXT );
ct = "Views";
cat = m_viewlist->addCategory( ct, defaultCategoryInfo( ct ).name );
createGanttView( cat, "GanttView", QString(), TIP_USE_DEFAULT_TEXT );
createMilestoneGanttView( cat, "MilestoneGanttView", QString(), TIP_USE_DEFAULT_TEXT );
createResourceAppointmentsView( cat, "ResourceAppointmentsView", QString(), TIP_USE_DEFAULT_TEXT );
createResourceAppointmentsGanttView( cat, "ResourceAppointmentsGanttView", QString(), TIP_USE_DEFAULT_TEXT );
createAccountsView( cat, "AccountsView", QString(), TIP_USE_DEFAULT_TEXT );
ct = "Execution";
cat = m_viewlist->addCategory( ct, defaultCategoryInfo( ct ).name );
createProjectStatusView( cat, "ProjectStatusView", QString(), TIP_USE_DEFAULT_TEXT );
createPerformanceStatusView( cat, "PerformanceStatusView", QString(), TIP_USE_DEFAULT_TEXT );
v = createTaskStatusView( cat, "TaskStatusView", QString(), TIP_USE_DEFAULT_TEXT );
v = createTaskView( cat, "TaskView", QString(), TIP_USE_DEFAULT_TEXT );
v = createTaskWorkPackageView( cat, "TaskWorkPackageView", QString(), TIP_USE_DEFAULT_TEXT );
ct = "Reports";
cat = m_viewlist->addCategory(ct, defaultCategoryInfo(ct).name);
createReportsGeneratorView(cat, "ReportsGeneratorView", i18n("Generate reports"), TIP_USE_DEFAULT_TEXT);
#ifdef PLAN_USE_KREPORT
// Let user add reports explicitly, we prefer reportsgenerator now
// A little hack to get the user started...
#if 0
ReportView *rv = qobject_cast( createReportView( cat, "ReportView", i18n( "Task Status Report" ), TIP_USE_DEFAULT_TEXT ) );
if ( rv ) {
QDomDocument doc;
doc.setContent( standardTaskStatusReport() );
rv->loadXML( doc );
}
#endif
#endif
}
}
ViewBase *View::createView( ViewListItem *cat, const QString &type, const QString &tag, const QString &name, const QString &tip, int index )
{
ViewBase *v = 0;
//NOTE: type is the same as classname (so if it is changed...)
if ( type == "CalendarEditor" ) {
v = createCalendarEditor( cat, tag, name, tip, index );
} else if ( type == "AccountsEditor" ) {
v = createAccountsEditor( cat, tag, name, tip, index );
} else if ( type == "ResourceEditor" ) {
v = createResourceEditor( cat, tag, name, tip, index );
} else if ( type == "TaskEditor" ) {
v = createTaskEditor( cat, tag, name, tip, index );
} else if ( type == "DependencyEditor" ) {
v = createDependencyEditor( cat, tag, name, tip, index );
} else if ( type == "PertEditor" ) {
v = createPertEditor( cat, tag, name, tip, index );
} else if ( type == "ScheduleEditor" ) {
v = createScheduleEditor( cat, tag, name, tip, index );
} else if ( type == "ScheduleHandlerView" ) {
v = createScheduleHandler( cat, tag, name, tip, index );
} else if ( type == "ProjectStatusView" ) {
v = createProjectStatusView( cat, tag, name, tip, index );
} else if ( type == "TaskStatusView" ) {
v = createTaskStatusView( cat, tag, name, tip, index );
} else if ( type == "TaskView" ) {
v = createTaskView( cat, tag, name, tip, index );
} else if ( type == "TaskWorkPackageView" ) {
v = createTaskWorkPackageView( cat, tag, name, tip, index );
} else if ( type == "GanttView" ) {
v = createGanttView( cat, tag, name, tip, index );
} else if ( type == "MilestoneGanttView" ) {
v = createMilestoneGanttView( cat, tag, name, tip, index );
} else if ( type == "ResourceAppointmentsView" ) {
v = createResourceAppointmentsView( cat, tag, name, tip, index );
} else if ( type == "ResourceAppointmentsGanttView" ) {
v = createResourceAppointmentsGanttView( cat, tag, name, tip, index );
} else if ( type == "AccountsView" ) {
v = createAccountsView( cat, tag, name, tip, index );
} else if ( type == "PerformanceStatusView" ) {
v = createPerformanceStatusView( cat, tag, name, tip, index );
} else if ( type == "ReportsGeneratorView" ) {
v = createReportsGeneratorView(cat, tag, name, tip, index);
} else if ( type == "ReportView" ) {
#ifdef PLAN_USE_KREPORT
v = createReportView( cat, tag, name, tip, index );
#endif
} else {
warnPlan<<"Unknown viewtype: "<type() == ViewListItem::ItemType_SubView ) {
itm->setViewInfo( defaultViewInfo( itm->viewType() ) );
} else if ( itm->type() == ViewListItem::ItemType_Category ) {
ViewInfo vi = defaultCategoryInfo( itm->tag() );
itm->setViewInfo( vi );
}
}
ViewInfo View::defaultViewInfo( const QString &type ) const
{
ViewInfo vi;
if ( type == "CalendarEditor" ) {
vi.name = i18n( "Work & Vacation" );
vi.tip = xi18nc( "@info:tooltip", "Edit working- and vacation days for resources" );
} else if ( type == "AccountsEditor" ) {
vi.name = i18n( "Cost Breakdown Structure" );
vi.tip = xi18nc( "@info:tooltip", "Edit cost breakdown structure." );
} else if ( type == "ResourceEditor" ) {
vi.name = i18n( "Resources" );
vi.tip = xi18nc( "@info:tooltip", "Edit resource breakdown structure" );
} else if ( type == "TaskEditor" ) {
vi.name = i18n( "Tasks" );
vi.tip = xi18nc( "@info:tooltip", "Edit work breakdown structure" );
} else if ( type == "DependencyEditor" ) {
vi.name = i18n( "Dependencies (Graphic)" );
vi.tip = xi18nc( "@info:tooltip", "Edit task dependencies" );
} else if ( type == "PertEditor" ) {
vi.name = i18n( "Dependencies (List)" );
vi.tip = xi18nc( "@info:tooltip", "Edit task dependencies" );
} else if ( type == "ScheduleEditor" ) {
// This view is not used stand-alone atm
vi.name = i18n( "Schedules" );
} else if ( type == "ScheduleHandlerView" ) {
vi.name = i18n( "Schedules" );
vi.tip = xi18nc( "@info:tooltip", "Calculate and analyze project schedules" );
} else if ( type == "ProjectStatusView" ) {
vi.name = i18n( "Project Performance Chart" );
vi.tip = xi18nc( "@info:tooltip", "View project status information" );
} else if ( type == "TaskStatusView" ) {
vi.name = i18n( "Task Status" );
vi.tip = xi18nc( "@info:tooltip", "View task progress information" );
} else if ( type == "TaskView" ) {
vi.name = i18n( "Task Execution" );
vi.tip = xi18nc( "@info:tooltip", "View task execution information" );
} else if ( type == "TaskWorkPackageView" ) {
vi.name = i18n( "Work Package View" );
vi.tip = xi18nc( "@info:tooltip", "View task work package information" );
} else if ( type == "GanttView" ) {
vi.name = i18n( "Gantt" );
vi.tip = xi18nc( "@info:tooltip", "View Gantt chart" );
} else if ( type == "MilestoneGanttView" ) {
vi.name = i18n( "Milestone Gantt" );
vi.tip = xi18nc( "@info:tooltip", "View milestone Gantt chart" );
} else if ( type == "ResourceAppointmentsView" ) {
vi.name = i18n( "Resource Assignments" );
vi.tip = xi18nc( "@info:tooltip", "View resource assignments in a table" );
} else if ( type == "ResourceAppointmentsGanttView" ) {
vi.name = i18n( "Resource Assignments (Gantt)" );
vi.tip = xi18nc( "@info:tooltip", "View resource assignments in Gantt chart" );
} else if ( type == "AccountsView" ) {
vi.name = i18n( "Cost Breakdown" );
vi.tip = xi18nc( "@info:tooltip", "View planned and actual cost" );
} else if ( type == "PerformanceStatusView" ) {
vi.name = i18n( "Tasks Performance Chart" );
vi.tip = xi18nc( "@info:tooltip", "View tasks performance status information" );
} else if ( type == "ReportsGeneratorView" ) {
vi.name = i18n( "Reports Generator" );
vi.tip = xi18nc( "@info:tooltip", "Generate reports" );
} else if ( type == "ReportView" ) {
vi.name = i18n( "Report" );
vi.tip = xi18nc( "@info:tooltip", "View report" );
} else {
warnPlan<<"Unknown viewtype: "<count()-1) : m_visitedViews.at(m_visitedViews.count() - 2);
debugPlan<<"Prev:"<setCurrentIndex(view);
return;
}
if ( url.url().startsWith( QLatin1String( "about:plan" ) ) ) {
getPart()->aboutPage().generatePage( v->htmlPart(), url );
return;
}
}
if ( url.scheme() == QLatin1String("help") ) {
KHelpClient::invokeHelp( "", url.fileName() );
return;
}
// try to open the url
debugPlan<htmlPart().setJScriptEnabled(false);
v->htmlPart().setJavaEnabled(false);
v->htmlPart().setMetaRefreshEnabled(false);
v->htmlPart().setPluginsEnabled(false);
slotOpenUrlRequest( v, QUrl( "about:plan/main" ) );
connect( v, &HtmlView::openUrlRequest, this, &View::slotOpenUrlRequest );
m_tab->addWidget( v );
return v;
}
ViewBase *View::createResourceAppointmentsGanttView( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index )
{
ResourceAppointmentsGanttView *v = new ResourceAppointmentsGanttView(getKoPart(), getPart(), m_tab );
m_tab->addWidget( v );
ViewListItem *i = m_viewlist->addView( cat, tag, name, v, getPart(), "", index );
ViewInfo vi = defaultViewInfo( "ResourceAppointmentsGanttView" );
if ( name.isEmpty() ) {
i->setText( 0, vi.name );
}
if ( tip == TIP_USE_DEFAULT_TEXT ) {
i->setToolTip( 0, vi.tip );
} else {
i->setToolTip( 0, tip );
}
connect( v, &ViewBase::guiActivated, this, &View::slotGuiActivated );
connect( this, &View::currentScheduleManagerChanged, v, &ResourceAppointmentsGanttView::setScheduleManager);
connect( v, &ResourceAppointmentsGanttView::requestPopupMenu, this, &View::slotPopupMenuRequested);
v->setProject( &( getProject() ) );
v->setScheduleManager( currentScheduleManager() );
v->updateReadWrite( m_readWrite );
return v;
}
ViewBase *View::createResourceAppointmentsView( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index )
{
ResourceAppointmentsView *v = new ResourceAppointmentsView(getKoPart(), getPart(), m_tab );
m_tab->addWidget( v );
ViewListItem *i = m_viewlist->addView( cat, tag, name, v, getPart(), "", index );
ViewInfo vi = defaultViewInfo( "ResourceAppointmentsView" );
if ( name.isEmpty() ) {
i->setText( 0, vi.name );
}
if ( tip == TIP_USE_DEFAULT_TEXT ) {
i->setToolTip( 0, vi.tip );
} else {
i->setToolTip( 0, tip );
}
connect( v, &ViewBase::guiActivated, this, &View::slotGuiActivated );
connect( this, &View::currentScheduleManagerChanged, v, &ResourceAppointmentsView::setScheduleManager);
connect( v, &ResourceAppointmentsView::requestPopupMenu, this, &View::slotPopupMenuRequested);
v->setProject( &( getProject() ) );
v->setScheduleManager( currentScheduleManager() );
v->updateReadWrite( m_readWrite );
return v;
}
ViewBase *View::createResourceEditor( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index )
{
ResourceEditor *resourceeditor = new ResourceEditor(getKoPart(), getPart(), m_tab );
resourceeditor->setViewSplitMode(false);
m_tab->addWidget( resourceeditor );
resourceeditor->setProject( &(getProject()) );
ViewListItem *i = m_viewlist->addView( cat, tag, name, resourceeditor, getPart(), "", index );
ViewInfo vi = defaultViewInfo( "ResourceEditor" );
if ( name.isEmpty() ) {
i->setText( 0, vi.name );
}
if ( tip == TIP_USE_DEFAULT_TEXT ) {
i->setToolTip( 0, vi.tip );
} else {
i->setToolTip( 0, tip );
}
connect( resourceeditor, &ViewBase::guiActivated, this, &View::slotGuiActivated );
connect( resourceeditor, &ResourceEditor::deleteObjectList, this, &View::slotDeleteResourceObjects );
connect( resourceeditor, &ResourceEditor::requestPopupMenu, this, &View::slotPopupMenuRequested);
resourceeditor->updateReadWrite( m_readWrite );
return resourceeditor;
}
ViewBase *View::createTaskEditor( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index )
{
TaskEditor *taskeditor = new TaskEditor(getKoPart(), getPart(), m_tab );
taskeditor->setViewSplitMode(false);
m_tab->addWidget( taskeditor );
ViewListItem *i = m_viewlist->addView( cat, tag, name, taskeditor, getPart(), "", index );
ViewInfo vi = defaultViewInfo( "TaskEditor" );
if ( name.isEmpty() ) {
i->setText( 0, vi.name );
}
if ( tip == TIP_USE_DEFAULT_TEXT ) {
i->setToolTip( 0, vi.tip );
} else {
i->setToolTip( 0, tip );
}
taskeditor->setProject( &(getProject()) );
taskeditor->setScheduleManager( currentScheduleManager() );
connect( this, &View::currentScheduleManagerChanged, taskeditor, &TaskEditor::setScheduleManager);
connect( taskeditor, &ViewBase::guiActivated, this, &View::slotGuiActivated );
connect( taskeditor, &TaskEditor::addTask, this, &View::slotAddTask );
connect( taskeditor, &TaskEditor::addMilestone, this, &View::slotAddMilestone );
connect( taskeditor, &TaskEditor::addSubtask, this, &View::slotAddSubTask );
connect( taskeditor, &TaskEditor::addSubMilestone, this, &View::slotAddSubMilestone );
connect(taskeditor, &TaskEditor::deleteTaskList, this, &View::slotDeleteTaskList);
connect( taskeditor, &TaskEditor::moveTaskUp, this, &View::slotMoveTaskUp );
connect( taskeditor, &TaskEditor::moveTaskDown, this, &View::slotMoveTaskDown );
connect( taskeditor, &TaskEditor::indentTask, this, &View::slotIndentTask );
connect( taskeditor, &TaskEditor::unindentTask, this, &View::slotUnindentTask );
connect(taskeditor, &TaskEditor::saveTaskModule, this, &View::saveTaskModule);
connect(taskeditor, &TaskEditor::removeTaskModule, this, &View::removeTaskModule);
connect(taskeditor, &ViewBase::openDocument, static_cast(m_partpart), &Part::openTaskModule);
connect( taskeditor, &TaskEditor::requestPopupMenu, this, &View::slotPopupMenuRequested);
connect( taskeditor, &TaskEditor::openTaskDescription, this, &View::slotOpenTaskDescription);
taskeditor->updateReadWrite( m_readWrite );
return taskeditor;
}
ViewBase *View::createAccountsEditor( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index )
{
AccountsEditor *ae = new AccountsEditor(getKoPart(), getPart(), m_tab );
m_tab->addWidget( ae );
ViewListItem *i = m_viewlist->addView( cat, tag, name, ae, getPart(), "", index );
ViewInfo vi = defaultViewInfo( "AccountsEditor" );
if ( name.isEmpty() ) {
i->setText( 0, vi.name );
}
if ( tip == TIP_USE_DEFAULT_TEXT ) {
i->setToolTip( 0, vi.tip );
} else {
i->setToolTip( 0, tip );
}
ae->draw( getProject() );
connect( ae, &ViewBase::guiActivated, this, &View::slotGuiActivated );
ae->updateReadWrite( m_readWrite );
return ae;
}
ViewBase *View::createCalendarEditor( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index )
{
CalendarEditor *calendareditor = new CalendarEditor(getKoPart(), getPart(), m_tab );
m_tab->addWidget( calendareditor );
ViewListItem *i = m_viewlist->addView( cat, tag, name, calendareditor, getPart(), "", index );
ViewInfo vi = defaultViewInfo( "CalendarEditor" );
if ( name.isEmpty() ) {
i->setText( 0, vi.name );
}
if ( tip == TIP_USE_DEFAULT_TEXT ) {
i->setToolTip( 0, vi.tip );
} else {
i->setToolTip( 0, tip );
}
calendareditor->draw( getProject() );
connect( calendareditor, &ViewBase::guiActivated, this, &View::slotGuiActivated );
connect( calendareditor, &CalendarEditor::requestPopupMenu, this, &View::slotPopupMenuRequested);
calendareditor->updateReadWrite( m_readWrite );
return calendareditor;
}
ViewBase *View::createScheduleHandler( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index )
{
ScheduleHandlerView *handler = new ScheduleHandlerView(getKoPart(), getPart(), m_tab );
m_tab->addWidget( handler );
ViewListItem *i = m_viewlist->addView( cat, tag, name, handler, getPart(), "", index );
ViewInfo vi = defaultViewInfo( "ScheduleHandlerView" );
if ( name.isEmpty() ) {
i->setText( 0, vi.name );
}
if ( tip == TIP_USE_DEFAULT_TEXT ) {
i->setToolTip( 0, vi.tip );
} else {
i->setToolTip( 0, tip );
}
connect( handler->scheduleEditor(), &ScheduleEditor::addScheduleManager, this, &View::slotAddScheduleManager );
connect( handler->scheduleEditor(), &ScheduleEditor::deleteScheduleManager, this, &View::slotDeleteScheduleManager );
connect( handler->scheduleEditor(), &ScheduleEditor::moveScheduleManager, this, &View::slotMoveScheduleManager);
connect( handler->scheduleEditor(), &ScheduleEditor::calculateSchedule, this, &View::slotCalculateSchedule );
connect( handler->scheduleEditor(), &ScheduleEditor::baselineSchedule, this, &View::slotBaselineSchedule );
connect( handler, &ViewBase::guiActivated, this, &View::slotGuiActivated );
connect( this, &View::currentScheduleManagerChanged, handler, &ScheduleHandlerView::currentScheduleManagerChanged );
connect( handler, &ScheduleHandlerView::requestPopupMenu, this, &View::slotPopupMenuRequested);
connect(handler, &ScheduleHandlerView::editNode, this, &View::slotOpenNode);
connect(handler, &ScheduleHandlerView::editResource, this, &View::slotEditResource);
handler->draw( getProject() );
handler->updateReadWrite( m_readWrite );
return handler;
}
ScheduleEditor *View::createScheduleEditor( QWidget *parent )
{
ScheduleEditor *scheduleeditor = new ScheduleEditor(getKoPart(), getPart(), parent );
connect( scheduleeditor, &ScheduleEditor::addScheduleManager, this, &View::slotAddScheduleManager );
connect( scheduleeditor, &ScheduleEditor::deleteScheduleManager, this, &View::slotDeleteScheduleManager );
connect( scheduleeditor, &ScheduleEditor::calculateSchedule, this, &View::slotCalculateSchedule );
connect( scheduleeditor, &ScheduleEditor::baselineSchedule, this, &View::slotBaselineSchedule );
scheduleeditor->updateReadWrite( m_readWrite );
return scheduleeditor;
}
ViewBase *View::createScheduleEditor( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index )
{
ScheduleEditor *scheduleeditor = new ScheduleEditor(getKoPart(), getPart(), m_tab );
m_tab->addWidget( scheduleeditor );
ViewListItem *i = m_viewlist->addView( cat, tag, name, scheduleeditor, getPart(), "", index );
ViewInfo vi = defaultViewInfo( "ScheduleEditor" );
if ( name.isEmpty() ) {
i->setText( 0, vi.name );
}
if ( tip == TIP_USE_DEFAULT_TEXT ) {
i->setToolTip( 0, vi.tip );
} else {
i->setToolTip( 0, tip );
}
scheduleeditor->setProject( &( getProject() ) );
connect( scheduleeditor, &ViewBase::guiActivated, this, &View::slotGuiActivated );
connect( scheduleeditor, &ScheduleEditor::addScheduleManager, this, &View::slotAddScheduleManager );
connect( scheduleeditor, &ScheduleEditor::deleteScheduleManager, this, &View::slotDeleteScheduleManager );
connect( scheduleeditor, &ScheduleEditor::calculateSchedule, this, &View::slotCalculateSchedule );
connect( scheduleeditor, &ScheduleEditor::baselineSchedule, this, &View::slotBaselineSchedule );
scheduleeditor->updateReadWrite( m_readWrite );
return scheduleeditor;
}
ViewBase *View::createDependencyEditor( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index )
{
DependencyEditor *editor = new DependencyEditor(getKoPart(), getPart(), m_tab );
m_tab->addWidget( editor );
ViewListItem *i = m_viewlist->addView( cat, tag, name, editor, getPart(), "", index );
ViewInfo vi = defaultViewInfo( "DependencyEditor" );
if ( name.isEmpty() ) {
i->setText( 0, vi.name );
}
if ( tip == TIP_USE_DEFAULT_TEXT ) {
i->setToolTip( 0, vi.tip );
} else {
i->setToolTip( 0, tip );
}
editor->draw( getProject() );
connect( editor, &ViewBase::guiActivated, this, &View::slotGuiActivated );
connect( editor, &DependencyEditor::addRelation, this, &View::slotAddRelation);
connect( editor, &DependencyEditor::modifyRelation, this, &View::slotModifyRelation);
connect( editor, &DependencyEditor::editRelation, this, &View::slotEditRelation);
connect( editor, &DependencyEditor::editNode, this, &View::slotOpenNode);
connect( editor, &DependencyEditor::addTask, this, &View::slotAddTask );
connect( editor, &DependencyEditor::addMilestone, this, &View::slotAddMilestone );
connect( editor, &DependencyEditor::addSubMilestone, this, &View::slotAddSubMilestone );
connect( editor, &DependencyEditor::addSubtask, this, &View::slotAddSubTask );
connect( editor, &DependencyEditor::deleteTaskList, this, &View::slotDeleteTaskList);
connect( this, &View::currentScheduleManagerChanged, editor, &DependencyEditor::setScheduleManager);
connect( editor, &DependencyEditor::requestPopupMenu, this, &View::slotPopupMenuRequested);
editor->updateReadWrite( m_readWrite );
editor->setScheduleManager( currentScheduleManager() );
return editor;
}
ViewBase *View::createPertEditor( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index )
{
PertEditor *perteditor = new PertEditor(getKoPart(), getPart(), m_tab );
m_tab->addWidget( perteditor );
ViewListItem *i = m_viewlist->addView( cat, tag, name, perteditor, getPart(), "", index );
ViewInfo vi = defaultViewInfo( "PertEditor" );
if ( name.isEmpty() ) {
i->setText( 0, vi.name );
}
if ( tip == TIP_USE_DEFAULT_TEXT ) {
i->setToolTip( 0, vi.tip );
} else {
i->setToolTip( 0, tip );
}
perteditor->draw( getProject() );
connect( perteditor, &ViewBase::guiActivated, this, &View::slotGuiActivated );
m_updatePertEditor = true;
perteditor->updateReadWrite( m_readWrite );
return perteditor;
}
ViewBase *View::createProjectStatusView( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index )
{
ProjectStatusView *v = new ProjectStatusView(getKoPart(), getPart(), m_tab );
m_tab->addWidget( v );
ViewListItem *i = m_viewlist->addView( cat, tag, name, v, getPart(), "", index );
ViewInfo vi = defaultViewInfo( "ProjectStatusView" );
if ( name.isEmpty() ) {
i->setText( 0, vi.name );
}
if ( tip == TIP_USE_DEFAULT_TEXT ) {
i->setToolTip( 0, vi.tip );
} else {
i->setToolTip( 0, tip );
}
connect( v, &ViewBase::guiActivated, this, &View::slotGuiActivated );
connect( this, &View::currentScheduleManagerChanged, v, &ProjectStatusView::setScheduleManager);
v->updateReadWrite( m_readWrite );
v->setProject( &getProject() );
v->setScheduleManager( currentScheduleManager() );
return v;
}
ViewBase *View::createPerformanceStatusView( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index )
{
PerformanceStatusView *v = new PerformanceStatusView(getKoPart(), getPart(), m_tab );
m_tab->addWidget( v );
ViewListItem *i = m_viewlist->addView( cat, tag, name, v, getPart(), "", index );
ViewInfo vi = defaultViewInfo( "PerformanceStatusView" );
if ( name.isEmpty() ) {
i->setText( 0, vi.name );
}
if ( tip == TIP_USE_DEFAULT_TEXT ) {
i->setToolTip( 0, vi.tip );
} else {
i->setToolTip( 0, tip );
}
connect( v, &ViewBase::guiActivated, this, &View::slotGuiActivated );
connect( this, &View::currentScheduleManagerChanged, v, &PerformanceStatusView::setScheduleManager);
connect( v, &PerformanceStatusView::requestPopupMenu, this, &View::slotPopupMenuRequested);
v->updateReadWrite( m_readWrite );
v->setProject( &getProject() );
v->setScheduleManager( currentScheduleManager() );
return v;
}
ViewBase *View::createTaskStatusView( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index )
{
TaskStatusView *taskstatusview = new TaskStatusView(getKoPart(), getPart(), m_tab );
taskstatusview->setViewSplitMode(false);
m_tab->addWidget( taskstatusview );
ViewListItem *i = m_viewlist->addView( cat, tag, name, taskstatusview, getPart(), "", index );
ViewInfo vi = defaultViewInfo( "TaskStatusView" );
if ( name.isEmpty() ) {
i->setText( 0, vi.name );
}
if ( tip == TIP_USE_DEFAULT_TEXT ) {
i->setToolTip( 0, vi.tip );
} else {
i->setToolTip( 0, tip );
}
connect( taskstatusview, &ViewBase::guiActivated, this, &View::slotGuiActivated );
connect( this, &View::currentScheduleManagerChanged, taskstatusview, &TaskStatusView::setScheduleManager);
connect( taskstatusview, &TaskStatusView::requestPopupMenu, this, &View::slotPopupMenuRequested);
connect( taskstatusview, &TaskStatusView::openTaskDescription, this, &View::slotOpenTaskDescription);
taskstatusview->updateReadWrite( m_readWrite );
taskstatusview->draw( getProject() );
taskstatusview->setScheduleManager( currentScheduleManager() );
return taskstatusview;
}
ViewBase *View::createTaskView( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index )
{
TaskView *v = new TaskView(getKoPart(), getPart(), m_tab );
v->setViewSplitMode(false);
m_tab->addWidget( v );
ViewListItem *i = m_viewlist->addView( cat, tag, name, v, getPart(), "", index );
ViewInfo vi = defaultViewInfo( "TaskView" );
if ( name.isEmpty() ) {
i->setText( 0, vi.name );
}
if ( tip == TIP_USE_DEFAULT_TEXT ) {
i->setToolTip( 0, vi.tip );
} else {
i->setToolTip( 0, tip );
}
v->draw( getProject() );
v->setScheduleManager( currentScheduleManager() );
connect( this, &View::currentScheduleManagerChanged, v, &TaskView::setScheduleManager);
connect( v, &ViewBase::guiActivated, this, &View::slotGuiActivated );
connect( v, &TaskView::requestPopupMenu, this, &View::slotPopupMenuRequested);
connect( v, &TaskView::openTaskDescription, this, &View::slotOpenTaskDescription);
v->updateReadWrite( m_readWrite );
return v;
}
ViewBase *View::createTaskWorkPackageView( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index )
{
TaskWorkPackageView *v = new TaskWorkPackageView(getKoPart(), getPart(), m_tab );
v->setViewSplitMode(false);
m_tab->addWidget( v );
ViewListItem *i = m_viewlist->addView( cat, tag, name, v, getPart(), "", index );
ViewInfo vi = defaultViewInfo( "TaskWorkPackageView" );
if ( name.isEmpty() ) {
i->setText( 0, vi.name );
}
if ( tip == TIP_USE_DEFAULT_TEXT ) {
i->setToolTip( 0, vi.tip );
} else {
i->setToolTip( 0, tip );
}
v->setProject( &getProject() );
v->setScheduleManager( currentScheduleManager() );
connect( this, &View::currentScheduleManagerChanged, v, &TaskWorkPackageView::setScheduleManager);
connect( v, &ViewBase::guiActivated, this, &View::slotGuiActivated );
connect( v, &TaskWorkPackageView::requestPopupMenu, this, &View::slotPopupMenuRequested);
connect( v, &TaskWorkPackageView::mailWorkpackage, this, &View::slotMailWorkpackage );
connect( v, &TaskWorkPackageView::publishWorkpackages, this, &View::slotPublishWorkpackages );
connect(v, &TaskWorkPackageView::openWorkpackages, this, &View::openWorkPackageMergeDialog);
connect(this, &View::workPackagesAvailable, v, &TaskWorkPackageView::slotWorkpackagesAvailable);
connect(v, &TaskWorkPackageView::checkForWorkPackages, getPart(), &MainDocument::checkForWorkPackages);
connect(v, &TaskWorkPackageView::loadWorkPackageUrl, this, &View::loadWorkPackage);
connect(v, &TaskWorkPackageView::openTaskDescription, this, &View::slotOpenTaskDescription);
v->updateReadWrite( m_readWrite );
return v;
}
ViewBase *View::createGanttView( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index )
{
GanttView *ganttview = new GanttView(getKoPart(), getPart(), m_tab, koDocument()->isReadWrite() );
m_tab->addWidget( ganttview );
ViewListItem *i = m_viewlist->addView( cat, tag, name, ganttview, getPart(), "", index );
ViewInfo vi = defaultViewInfo( "GanttView" );
if ( name.isEmpty() ) {
i->setText( 0, vi.name );
}
if ( tip == TIP_USE_DEFAULT_TEXT ) {
i->setToolTip( 0, vi.tip );
} else {
i->setToolTip( 0, tip );
}
ganttview->setProject( &( getProject() ) );
ganttview->setScheduleManager( currentScheduleManager() );
connect( ganttview, &ViewBase::guiActivated, this, &View::slotGuiActivated );
/* TODO: Review these
connect( ganttview, SIGNAL(addRelation(KPlato::Node*,KPlato::Node*,int)), SLOT(slotAddRelation(KPlato::Node*,KPlato::Node*,int)) );
connect( ganttview, SIGNAL(modifyRelation(KPlato::Relation*,int)), SLOT(slotModifyRelation(KPlato::Relation*,int)) );
connect( ganttview, SIGNAL(modifyRelation(KPlato::Relation*)), SLOT(slotModifyRelation(KPlato::Relation*)) );
connect( ganttview, SIGNAL(itemDoubleClicked()), SLOT(slotOpenNode()) );
connect( ganttview, SIGNAL(itemRenamed(KPlato::Node*,QString)), this, SLOT(slotRenameNode(KPlato::Node*,QString)) );*/
connect( this, &View::currentScheduleManagerChanged, ganttview, &GanttView::setScheduleManager);
connect( ganttview, &GanttView::requestPopupMenu, this, &View::slotPopupMenuRequested);
connect( ganttview, &GanttView::openTaskDescription, this, &View::slotOpenTaskDescription);
ganttview->updateReadWrite( m_readWrite );
return ganttview;
}
ViewBase *View::createMilestoneGanttView( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index )
{
MilestoneGanttView *ganttview = new MilestoneGanttView(getKoPart(), getPart(), m_tab, koDocument()->isReadWrite() );
m_tab->addWidget( ganttview );
ViewListItem *i = m_viewlist->addView( cat, tag, name, ganttview, getPart(), "", index );
ViewInfo vi = defaultViewInfo( "MilestoneGanttView" );
if ( name.isEmpty() ) {
i->setText( 0, vi.name );
}
if ( tip == TIP_USE_DEFAULT_TEXT ) {
i->setToolTip( 0, vi.tip );
} else {
i->setToolTip( 0, tip );
}
ganttview->setProject( &( getProject() ) );
ganttview->setScheduleManager( currentScheduleManager() );
connect( ganttview, &ViewBase::guiActivated, this, &View::slotGuiActivated );
connect( this, &View::currentScheduleManagerChanged, ganttview, &MilestoneGanttView::setScheduleManager);
connect( ganttview, &MilestoneGanttView::requestPopupMenu, this, &View::slotPopupMenuRequested);
connect( ganttview, &MilestoneGanttView::openTaskDescription, this, &View::slotOpenTaskDescription);
ganttview->updateReadWrite( m_readWrite );
return ganttview;
}
ViewBase *View::createAccountsView( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index )
{
AccountsView *accountsview = new AccountsView(getKoPart(), &getProject(), getPart(), m_tab );
m_tab->addWidget( accountsview );
ViewListItem *i = m_viewlist->addView( cat, tag, name, accountsview, getPart(), "", index );
ViewInfo vi = defaultViewInfo( "AccountsView" );
if ( name.isEmpty() ) {
i->setText( 0, vi.name );
}
if ( tip == TIP_USE_DEFAULT_TEXT ) {
i->setToolTip( 0, vi.tip );
} else {
i->setToolTip( 0, tip );
}
accountsview->setScheduleManager( currentScheduleManager() );
connect( this, &View::currentScheduleManagerChanged, accountsview, &AccountsView::setScheduleManager);
connect( accountsview, &ViewBase::guiActivated, this, &View::slotGuiActivated );
accountsview->updateReadWrite( m_readWrite );
return accountsview;
}
ViewBase *View::createResourceAssignmentView( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index )
{
ResourceAssignmentView *resourceAssignmentView = new ResourceAssignmentView(getKoPart(), getPart(), m_tab );
m_tab->addWidget( resourceAssignmentView );
m_updateResourceAssignmentView = true;
ViewListItem *i = m_viewlist->addView( cat, tag, name, resourceAssignmentView, getPart(), "", index );
ViewInfo vi = defaultViewInfo( "ResourceAssignmentView" );
if ( name.isEmpty() ) {
i->setText( 0, vi.name );
}
if ( tip == TIP_USE_DEFAULT_TEXT ) {
i->setToolTip( 0, vi.tip );
} else {
i->setToolTip( 0, tip );
}
resourceAssignmentView->draw( getProject() );
connect( resourceAssignmentView, &ViewBase::guiActivated, this, &View::slotGuiActivated );
connect( resourceAssignmentView, &ResourceAssignmentView::requestPopupMenu, this, &View::slotPopupMenuRequested);
resourceAssignmentView->updateReadWrite( m_readWrite );
return resourceAssignmentView;
}
ViewBase *View::createReportsGeneratorView(ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index)
{
ReportsGeneratorView *v = new ReportsGeneratorView(getKoPart(), getPart(), m_tab );
m_tab->addWidget( v );
ViewListItem *i = m_viewlist->addView(cat, tag, name, v, getPart(), "", index);
ViewInfo vi = defaultViewInfo( "ReportsGeneratorView" );
if ( name.isEmpty() ) {
i->setText( 0, vi.name );
}
if ( tip == TIP_USE_DEFAULT_TEXT ) {
i->setToolTip( 0, vi.tip );
} else {
i->setToolTip( 0, tip );
}
v->setProject( &getProject() );
connect( this, &View::currentScheduleManagerChanged, v, &ViewBase::setScheduleManager );
connect( this, &View::currentScheduleManagerChanged, v, &ViewBase::slotRefreshView);
v->setScheduleManager( currentScheduleManager() );
connect( v, &ViewBase::guiActivated, this, &View::slotGuiActivated );
connect( v, &ReportsGeneratorView::requestPopupMenu, this, &View::slotPopupMenuRequested);
v->updateReadWrite( m_readWrite );
return v;
}
ViewBase *View::createReportView( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index )
{
#ifdef PLAN_USE_KREPORT
ReportView *v = new ReportView(getKoPart(), getPart(), m_tab );
m_tab->addWidget( v );
ViewListItem *i = m_viewlist->addView( cat, tag, name, v, getPart(), "", index );
ViewInfo vi = defaultViewInfo( "ReportView" );
if ( name.isEmpty() ) {
i->setText( 0, vi.name );
}
if ( tip == TIP_USE_DEFAULT_TEXT ) {
i->setToolTip( 0, vi.tip );
} else {
i->setToolTip( 0, tip );
}
v->setProject( &getProject() );
connect( this, &View::currentScheduleManagerChanged, v, &ReportView::setScheduleManager);
connect( this, &View::currentScheduleManagerChanged, v, SLOT(slotRefreshView()));
v->setScheduleManager( currentScheduleManager() );
connect( v, &ReportView::guiActivated, this, &View::slotGuiActivated);
v->updateReadWrite( m_readWrite );
return v;
#else
Q_UNUSED(cat)
Q_UNUSED(tag)
Q_UNUSED(name)
Q_UNUSED(tip)
Q_UNUSED(index)
return 0;
#endif
}
Project& View::getProject() const
{
return getPart() ->getProject();
}
KoPrintJob * View::createPrintJob()
{
KoView *v = qobject_cast( canvas() );
if ( v == 0 ) {
return 0;
}
return v->createPrintJob();
}
ViewBase *View::currentView() const
{
return qobject_cast( m_tab->currentWidget() );
}
void View::slotEditCut()
{
ViewBase *v = currentView();
if ( v ) {
v->slotEditCut();
}
}
void View::slotEditCopy()
{
ViewBase *v = currentView();
if ( v ) {
v->slotEditCopy();
}
}
void View::slotEditPaste()
{
ViewBase *v = currentView();
if ( v ) {
v->slotEditPaste();
}
}
void View::slotRefreshView()
{
ViewBase *v = currentView();
if ( v ) {
debugPlan<slotRefreshView();
}
}
void View::slotViewSelector( bool show )
{
//debugPlan;
m_viewlist->setVisible( show );
}
void View::slotInsertResourcesFile(const QString &file, const QUrl &projects)
{
getPart()->insertResourcesFile(QUrl(file), projects);
}
void View::slotInsertFile()
{
InsertFileDialog *dlg = new InsertFileDialog( getProject(), currentTask(), this );
connect(dlg, &QDialog::finished, this, &View::slotInsertFileFinished);
dlg->open();
}
void View::slotInsertFileFinished( int result )
{
InsertFileDialog *dlg = qobject_cast( sender() );
if ( dlg == 0 ) {
return;
}
if ( result == QDialog::Accepted ) {
getPart()->insertFile( dlg->url(), dlg->parentNode(), dlg->afterNode() );
}
dlg->deleteLater();
}
void View::slotLoadSharedProjects()
{
LoadSharedProjectsDialog *dlg = new LoadSharedProjectsDialog( getProject(), getPart()->url(), this );
connect(dlg, &QDialog::finished, this, &View::slotLoadSharedProjectsFinished);
dlg->open();
}
void View::slotLoadSharedProjectsFinished( int result )
{
LoadSharedProjectsDialog *dlg = qobject_cast( sender() );
if ( dlg == 0 ) {
return;
}
if ( result == QDialog::Accepted ) {
getPart()->insertSharedProjects(dlg->urls());
}
dlg->deleteLater();
}
void View::slotProjectEdit()
{
slotOpenNode( &getProject() );
}
void View::slotProjectWorktime()
{
StandardWorktimeDialog *dia = new StandardWorktimeDialog( getProject(), this );
connect(dia, &QDialog::finished, this, &View::slotProjectWorktimeFinished);
dia->open();
}
void View::slotProjectWorktimeFinished( int result )
{
StandardWorktimeDialog *dia = qobject_cast( sender() );
if ( dia == 0 ) {
return;
}
if ( result == QDialog::Accepted) {
KUndo2Command * cmd = dia->buildCommand();
if ( cmd ) {
//debugPlan<<"Modifying calendar(s)";
getPart() ->addCommand( cmd ); //also executes
}
}
dia->deleteLater();
}
void View::slotSelectionChanged( ScheduleManager *sm ) {
debugPlan<setChecked( true ); // this doesn't trigger QActionGroup
slotViewSchedule( a );
}
QList View::sortedActionList()
{
QMap lst;
const QMap map = m_scheduleActions; // clazy:exclude=qmap-with-pointer-key
QMap::const_iterator it;
for (it = map.constBegin(); it != map.constEnd(); ++it) {
lst.insert(it.key()->objectName(), it.key());
}
return lst.values();
}
void View::slotScheduleSwapped(ScheduleManager *from, ScheduleManager *to)
{
if (currentScheduleManager() == from) {
QAction *a = m_scheduleActions.key(to);
if (a) {
a->setChecked(true);
}
}
}
void View::slotScheduleRemoved( const ScheduleManager *sch )
{
debugPlan<name();
QAction *a = 0;
QAction *checked = m_scheduleActionGroup->checkedAction();
QMapIterator i( m_scheduleActions );
while (i.hasNext()) {
i.next();
if ( i.value() == sch ) {
a = i.key();
break;
}
}
if ( a ) {
unplugActionList( "view_schedule_list" );
delete a;
plugActionList( "view_schedule_list", sortedActionList() );
if ( checked && checked != a ) {
checked->setChecked( true );
} else if ( ! m_scheduleActions.isEmpty() ) {
m_scheduleActions.firstKey()->setChecked( true );
}
}
slotViewSchedule( m_scheduleActionGroup->checkedAction() );
}
void View::slotScheduleAdded( const ScheduleManager *sch )
{
ScheduleManager *s = const_cast( sch );
QAction *checked = m_scheduleActionGroup->checkedAction();
unplugActionList( "view_schedule_list" );
QAction *act = addScheduleAction( s );
plugActionList( "view_schedule_list", sortedActionList() );
if (!currentScheduleManager()) {
if ( act ) {
act->setChecked( true );
} else if ( ! m_scheduleActions.isEmpty() ) {
m_scheduleActions.firstKey()->setChecked( true );
}
slotViewSchedule( m_scheduleActionGroup->checkedAction() );
}
}
void View::slotScheduleCalculated(Project *project, ScheduleManager *manager)
{
Q_UNUSED(project);
if (manager == currentScheduleManager()) {
slotViewScheduleManager(manager);
}
}
QAction *View::addScheduleAction( ScheduleManager *sch )
{
QAction *act = 0;
QString n = sch->name();
act = new KToggleAction( n, this);
actionCollection()->addAction(n, act );
m_scheduleActions.insert( act, sch );
m_scheduleActionGroup->addAction( act );
//debugPlan<<"Add:"<name();
m_scheduleActions.remove( static_cast( o ) );
}
void View::slotPlugScheduleActions()
{
ScheduleManager *current = currentScheduleManager();
unplugActionList( "view_schedule_list" );
const QMap map = m_scheduleActions; // clazy:exclude=qmap-with-pointer-key
QMap::const_iterator it;
for (it = map.constBegin(); it != map.constEnd(); ++it) {
m_scheduleActionGroup->removeAction(it.key());
delete it.key();
}
m_scheduleActions.clear();
QAction *ca = 0;
foreach( ScheduleManager *sm, getProject().allScheduleManagers() ) {
QAction *act = addScheduleAction(sm);
if (sm == current) {
ca = act;
}
}
plugActionList( "view_schedule_list", sortedActionList() );
if ( ca == 0 && m_scheduleActionGroup->actions().count() > 0 ) {
ca = m_scheduleActionGroup->actions().constFirst();
}
if ( ca ) {
ca->setChecked( true );
}
slotViewSchedule( ca );
}
void View::slotCalculateSchedule( Project *project, ScheduleManager *sm )
{
if ( project == 0 || sm == 0 ) {
return;
}
if ( sm->parentManager() && ! sm->parentManager()->isScheduled() ) {
// the parent must be scheduled
return;
}
CalculateScheduleCmd *cmd = new CalculateScheduleCmd( *project, sm, kundo2_i18nc("@info:status 1=schedule name", "Calculate %1", sm->name() ) );
getPart() ->addCommand( cmd );
slotUpdate();
}
void View::slotRemoveCommands()
{
while ( ! m_undocommands.isEmpty() ) {
m_undocommands.last()->undo();
delete m_undocommands.takeLast();
}
}
void View::slotBaselineSchedule( Project *project, ScheduleManager *sm )
{
if ( project == 0 || sm == 0 ) {
return;
}
if ( ! sm->isBaselined() && project->isBaselined() ) {
KMessageBox::sorry( this, i18n( "Cannot baseline. The project is already baselined." ) );
return;
}
MacroCommand *cmd = nullptr;
if ( sm->isBaselined() ) {
KMessageBox::ButtonCode res = KMessageBox::warningContinueCancel( this, i18n( "This schedule is baselined. Do you want to remove the baseline?" ) );
if ( res == KMessageBox::Cancel ) {
return;
}
cmd = new MacroCommand(kundo2_i18n("Reset baseline %1", sm->name()));
cmd->addCommand(new ResetBaselineScheduleCmd(*sm));
} else {
cmd = new MacroCommand(kundo2_i18n( "Baseline %1", sm->name() ) );
if (sm->schedulingMode() == ScheduleManager::AutoMode) {
cmd->addCommand(new ModifyScheduleManagerSchedulingModeCmd(*sm, ScheduleManager::ManualMode));
}
cmd->addCommand( new BaselineScheduleCmd( *sm, kundo2_i18n( "Baseline %1", sm->name() ) ));
}
getPart() ->addCommand( cmd );
}
void View::slotAddScheduleManager( Project *project )
{
if ( project == 0 ) {
return;
}
ScheduleManager *sm = project->createScheduleManager();
AddScheduleManagerCmd *cmd = new AddScheduleManagerCmd( *project, sm, -1, kundo2_i18n( "Add schedule %1", sm->name() ) );
getPart() ->addCommand( cmd );
}
void View::slotDeleteScheduleManager( Project *project, ScheduleManager *sm )
{
if ( project == 0 || sm == 0) {
return;
}
DeleteScheduleManagerCmd *cmd = new DeleteScheduleManagerCmd( *project, sm, kundo2_i18n( "Delete schedule %1", sm->name() ) );
getPart() ->addCommand( cmd );
}
void View::slotMoveScheduleManager( ScheduleManager *sm, ScheduleManager *parent, int index )
{
if ( sm == 0 ) {
return;
}
MoveScheduleManagerCmd *cmd = new MoveScheduleManagerCmd( sm, parent, index, kundo2_i18n( "Move schedule %1", sm->name() ) );
getPart() ->addCommand( cmd );
}
void View::slotAddSubTask()
{
Task * node = getProject().createTask( getPart() ->config().taskDefaults() );
SubTaskAddDialog *dia = new SubTaskAddDialog( getProject(), *node, currentNode(), getProject().accounts(), this );
connect(dia, &QDialog::finished, this, &View::slotAddSubTaskFinished);
dia->open();
}
void View::slotAddSubTaskFinished( int result )
{
SubTaskAddDialog *dia = qobject_cast( sender() );
if ( dia == 0 ) {
return;
}
if ( result == QDialog::Accepted) {
KUndo2Command *m = dia->buildCommand();
getPart() ->addCommand( m ); // add task to project
}
dia->deleteLater();
}
void View::slotAddTask()
{
Task * node = getProject().createTask( getPart() ->config().taskDefaults() );
TaskAddDialog *dia = new TaskAddDialog( getProject(), *node, currentNode(), getProject().accounts(), this );
connect(dia, &QDialog::finished, this, &View::slotAddTaskFinished);
dia->open();
}
void View::slotAddTaskFinished( int result )
{
TaskAddDialog *dia = qobject_cast( sender() );
if ( dia == 0 ) {
return;
}
if ( result == QDialog::Accepted) {
KUndo2Command *m = dia->buildCommand();
getPart() ->addCommand( m ); // add task to project
}
dia->deleteLater();
}
void View::slotAddMilestone()
{
Task * node = getProject().createTask();
node->estimate() ->clear();
TaskAddDialog *dia = new TaskAddDialog( getProject(), *node, currentNode(), getProject().accounts(), this );
connect(dia, &QDialog::finished, this, &View::slotAddMilestoneFinished);
dia->open();
}
void View::slotAddMilestoneFinished( int result )
{
TaskAddDialog *dia = qobject_cast( sender() );
if ( dia == 0 ) {
return;
}
if ( result == QDialog::Accepted) {
MacroCommand *c = new MacroCommand( kundo2_i18n( "Add milestone" ) );
c->addCommand( dia->buildCommand() );
getPart() ->addCommand( c ); // add task to project
}
dia->deleteLater();
}
void View::slotAddSubMilestone()
{
Task * node = getProject().createTask();
node->estimate() ->clear();
SubTaskAddDialog *dia = new SubTaskAddDialog( getProject(), *node, currentNode(), getProject().accounts(), this );
connect(dia, &QDialog::finished, this, &View::slotAddSubMilestoneFinished);
dia->open();
}
void View::slotAddSubMilestoneFinished( int result )
{
SubTaskAddDialog *dia = qobject_cast( sender() );
if ( dia == 0 ) {
return;
}
if ( result == QDialog::Accepted) {
MacroCommand *c = new MacroCommand( kundo2_i18n( "Add sub-milestone" ) );
c->addCommand( dia->buildCommand() );
getPart() ->addCommand( c ); // add task to project
}
dia->deleteLater();
}
void View::slotDefineWBS()
{
//debugPlan;
Project &p = getProject();
WBSDefinitionDialog *dia = new WBSDefinitionDialog( p, p.wbsDefinition(), this );
connect(dia, &QDialog::finished, this, &View::slotDefineWBSFinished);
dia->open();
}
void View::slotDefineWBSFinished( int result )
{
//debugPlan;
WBSDefinitionDialog *dia = qobject_cast( sender() );
if ( dia == 0 ) {
return;
}
if ( result == QDialog::Accepted ) {
KUndo2Command *cmd = dia->buildCommand();
if ( cmd ) {
getPart()->addCommand( cmd );
}
}
dia->deleteLater();
}
void View::slotIntroduction()
{
m_tab->setCurrentIndex(0);
}
Calendar *View::currentCalendar()
{
ViewBase *v = dynamic_cast( m_tab->currentWidget() );
if ( v == 0 ) {
return 0;
}
return v->currentCalendar();
}
Node *View::currentNode() const
{
ViewBase *v = dynamic_cast( m_tab->currentWidget() );
if ( v == 0 ) {
return 0;
}
Node * task = v->currentNode();
if ( 0 != task ) {
return task;
}
return &( getProject() );
}
Task *View::currentTask() const
{
ViewBase *v = dynamic_cast( m_tab->currentWidget() );
if ( v == 0 ) {
return 0;
}
Node * task = v->currentNode();
if ( task ) {
return dynamic_cast( task );
}
return 0;
}
Resource *View::currentResource()
{
ViewBase *v = dynamic_cast( m_tab->currentWidget() );
if ( v == 0 ) {
return 0;
}
return v->currentResource();
}
ResourceGroup *View::currentResourceGroup()
{
ViewBase *v = dynamic_cast( m_tab->currentWidget() );
if ( v == 0 ) {
return 0;
}
return v->currentResourceGroup();
}
void View::slotOpenCurrentNode()
{
//debugPlan;
Node * node = currentNode();
slotOpenNode( node );
}
void View::slotOpenNode( Node *node )
{
//debugPlan;
if ( !node )
return ;
switch ( node->type() ) {
case Node::Type_Project: {
Project * project = static_cast( node );
MainProjectDialog *dia = new MainProjectDialog( *project, this );
connect(dia, &MainProjectDialog::dialogFinished, this, &View::slotProjectEditFinished);
connect(dia, &MainProjectDialog::sigLoadSharedResources, this, &View::slotInsertResourcesFile);
connect(dia, &MainProjectDialog::loadResourceAssignments, getPart(), &MainDocument::loadResourceAssignments);
connect(dia, &MainProjectDialog::clearResourceAssignments, getPart(), &MainDocument::clearResourceAssignments);
dia->open();
break;
}
case Node::Type_Subproject:
//TODO
break;
case Node::Type_Task: {
Task *task = static_cast( node );
TaskDialog *dia = new TaskDialog( getProject(), *task, getProject().accounts(), this );
connect(dia, &QDialog::finished, this, &View::slotTaskEditFinished);
dia->open();
break;
}
case Node::Type_Milestone: {
// Use the normal task dialog for now.
// Maybe milestone should have it's own dialog, but we need to be able to
// enter a duration in case we accidentally set a tasks duration to zero
// and hence, create a milestone
Task *task = static_cast