diff --git a/extras/filemanagertemplates/TextDocument.desktop b/extras/filemanagertemplates/TextDocument.desktop index 46b54fb5ec6..1e8b0759db3 100644 --- a/extras/filemanagertemplates/TextDocument.desktop +++ b/extras/filemanagertemplates/TextDocument.desktop @@ -1,102 +1,102 @@ [Desktop Entry] Name=Text Document... Name[bg]=Текстов документ... Name[br]=Teul skrid ... Name[bs]=Tekstualni dokument... Name[ca]=Document de text... Name[ca@valencia]=Document de text... Name[cs]=Textový dokument Name[cy]=Dogfen Destun... Name[da]=Tekstdokument... Name[de]=Textdokument ... Name[el]=Έγγραφο κειμένου... Name[en_GB]=Text Document... Name[eo]=Tekstdokumento... Name[es]=Documento de texto... Name[et]=Tekstidokument... Name[eu]=Testu-dokumentua... Name[fa]=سند متنی... Name[fi]=Tekstitiedosto… Name[fr]=Document texte... Name[fy]=Tekst dokumint... Name[ga]=Cáipéis Téacs... Name[gl]=Documento de texto… Name[he]=מסמך טקסט... Name[hi]=पाठ दस्तावेज़... Name[hne]=पाठ कागद... Name[hr]=Tekstualni dokument … Name[hu]=KWord-dokumentum... Name[ia]=Documento de texto... Name[is]=Textaskjal... Name[it]=Documenti di testo... Name[ja]=テキスト文書... Name[kk]=Мәтін құжаты... Name[ko]=텍스트 문서... Name[lt]=Tekstinis dokumentas... Name[lv]=Teksta dokuments... Name[mr]=पाठ्य दस्तऐवज... Name[ms]=Dokumen Teks... Name[nb]=Tekstdokument … Name[nds]=Textdokment... Name[ne]=पाठ कागजात... Name[nl]=Tekstdocument... Name[pa]=ਪਾਠ ਦਸਤਾਵੇਜ਼... Name[pl]=Dokument tekstowy... Name[pt]=Documento de Texto... Name[pt_BR]=Documento de Texto... Name[ru]=Документ Calligra Words... Name[se]=Teakstadokumeanta … Name[sk]=Textový dokument... Name[sl]=Besedilni dokument ... Name[sv]=Textdokument... Name[ta]=உரை ஆவணம்... Name[tg]=Матни Ҳуҷҷат... Name[tr]=Metin Belgesi... Name[uk]=Текстовий документ... Name[uz]=Matn hujjati Name[uz@cyrillic]=Матн ҳужжати Name[wa]=Documint tecse... Name[x-test]=xxText Document...xx Name[zh_CN]=文本文档... Name[zh_TW]=文字文件... Comment=New Words document: Comment[bg]=Нов документ на Words: Comment[bs]=Novi Words dokument: Comment[ca]=Document nou del Words: Comment[ca@valencia]=Document nou del Words: Comment[cs]=Nový dokument aplikace Words: Comment[da]=Nyt Words-dokument: Comment[de]=Neues Words-Dokument: Comment[el]=Νέο έγγραφο Words: Comment[en_GB]=New Words document: Comment[es]=Nuevo documento de Words: Comment[et]=Uus Wordsi dokument: Comment[eu]=Words dokumentu berria: Comment[fi]=Uusi Words-tiedosto: Comment[fr]=Nouveau document Words : -Comment[gl]=Novo documento de Words: +Comment[gl]=Novo documento de Words: Comment[hu]=Új Words dokumentum: Comment[ia]=Nove documento de Words: Comment[it]=Nuovo documento di Words: Comment[ja]=新しい Words 文書: Comment[kk]=Жаңа Words құжаты: Comment[ko]=새 Words 문서: Comment[mr]=नवीन वर्डस् दस्तऐवज : Comment[nb]=Nytt Words-dokument: Comment[nds]=Nieg Words-Dokment: Comment[nl]=Nieuw Words-document: Comment[pl]=Nowy dokument Słów: Comment[pt]=Novo documento do Words: Comment[pt_BR]=Novo documento do Words: Comment[ru]=Новый документ Calligra Words: Comment[sk]=Nový dokument Words: Comment[sl]=Nov dokument za Words: Comment[sv]=Nytt Words-dokument: Comment[tr]=Yeni Words belgesi Comment[uk]=Новий документ Words: Comment[x-test]=xxNew Words document:xx Comment[zh_CN]=新建 Words 文档: Comment[zh_TW]=新建 Words 文件: Type=Link URL=.source/TextDocument.odt Icon=application-vnd.oasis.opendocument.text diff --git a/filters/karbon/xaml/karbon_xaml_export.desktop b/filters/karbon/xaml/karbon_xaml_export.desktop index f9f0073c001..908fa4a4274 100644 --- a/filters/karbon/xaml/karbon_xaml_export.desktop +++ b/filters/karbon/xaml/karbon_xaml_export.desktop @@ -1,42 +1,42 @@ [Desktop Entry] Icon= Name=Karbon WVG Export Filter Name[bs]=Karbon WVG izvozni filter Name[ca]=Filtre d'exportació WVG per al Karbon Name[ca@valencia]=Filtre d'exportació WVG per al Karbon Name[cs]=Exportní filtr do formátu WVG pro Karbon Name[da]=Karbon WVG-eksportfilter Name[de]=Karbon WVG-Exportfilter Name[el]=Φίλτρο εξαγωγής WVG του Karbon Name[en_GB]=Karbon WVG Export Filter Name[es]=Filtro de Karbon de exportación a WVG Name[et]=Karboni WVG ekspordifilter Name[eu]=Karbon-en WVG esportazio-iragazkia Name[fi]=Karbonin WVG-vientisuodatin Name[fr]=Filtre d'exportation WVG de Karbon -Name[gl]=Filtro para Karbon de exportación de WVG +Name[gl]=Filtro para Karbon de exportación de WVG Name[hu]=Karbon WVG exportszűrő Name[it]=Filtro di esportazione WVG per Karbon Name[ja]=Karbon WVG エクスポートフィルタ Name[kk]=Karbon -> WVG экспорт сүзгісі Name[ko]=Karbon WVG 내보내기 필터 Name[mr]=कार्बन WVG निर्यात गाळणी Name[nb]=WVG-eksportfiler for Karbon Name[nl]= WVG-exportfilter voor Karbon Name[pl]=Filtr eksportu WVG z Karbon Name[pt]=Filtro de Exportação de WVG para o Karbon Name[pt_BR]=Filtro de exportação de WVG para Karbon Name[ru]=Фильтр экспорта рисунков Karbon в WVG Name[sk]=WVG filter pre export z Karbon Name[sl]=Izvozni filter WVG za Karbon Name[sv]=Karbon WVG-exportfilter Name[tr]=Karbon WVG Dışa Aktarma Süzgeci Name[uk]=Фільтр експорту WVG для Karbon Name[x-test]=xxKarbon WVG Export Filterxx Name[zh_CN]=Karbon WVG 导出过滤器 X-KDE-ServiceTypes=Calligra/Filter Type=Service X-KDE-Export=image/wvg+xml X-KDE-Import=application/x-karbon X-KDE-Library=karbonxamlexport X-KDE-Weight=1 diff --git a/filters/words/msword-odf/words_msword_thumbnail.desktop b/filters/words/msword-odf/words_msword_thumbnail.desktop index 18b5686d24a..797d1090fe3 100644 --- a/filters/words/msword-odf/words_msword_thumbnail.desktop +++ b/filters/words/msword-odf/words_msword_thumbnail.desktop @@ -1,41 +1,41 @@ [Desktop Entry] Type=Service Name=Microsoft Word Documents Name[bs]=Microsoft Word dokumenti Name[ca]=Documents del Microsoft Word Name[ca@valencia]=Documents del Microsoft Word Name[cs]=Dokumenty Microsoft Word Name[da]=Microsoft Word-dokumenter Name[de]=Microsoft Word Dokumente Name[el]=Έγγραφα Microsoft Word Name[en_GB]=Microsoft Word Documents Name[es]=Documentos Microsoft Word Name[et]=Microsoft Wordi dokumendid Name[eu]=Microsoft Word dokumentuak Name[fi]=Microsoft Word -tiedostot Name[fr]=Documents Microsoft Word -Name[gl]=Documentos de Microsoft Word +Name[gl]=Documentos de Microsoft Word Name[hu]=Microsoft Word dokumentumok Name[it]=Documenti Microsoft Word Name[ja]=Microsoft Word 文書 Name[kk]=Microsoft Word құжаттары Name[ko]=Microsoft Word 문서 Name[lt]=Microsoft Word dokumentai Name[nb]=Microsoft Word dokumenter Name[nl]=Microsoft Word-documenten Name[pl]=Dokumenty Microsoft Word Name[pt]=Documentos do Microsoft Word Name[pt_BR]=Documentos do Microsoft Word Name[sk]=Dokumenty Microsoft Word Name[sl]=Dokumenti Microsoft Word Name[sv]=Microsoft Word-dokument Name[tr]=Microsoft Word Belgeleri Name[uk]=Документи Microsoft Word Name[x-test]=xxMicrosoft Word Documentsxx Name[zh_CN]=Microsoft Word 文本文档 X-KDE-ServiceTypes=ThumbCreator MimeType=application/msword; X-KDE-Library=calligrathumbnail CacheThumbnail=true diff --git a/gemini/lib/CMakeLists.txt b/gemini/lib/CMakeLists.txt index 1de54e32860..9d005a04446 100644 --- a/gemini/lib/CMakeLists.txt +++ b/gemini/lib/CMakeLists.txt @@ -1,20 +1,27 @@ project(gemini) set(gemini_SRCS GeminiMainWindow.cpp ) +<<<<<<< HEAD add_library(gemini SHARED ${gemini_SRCS}) generate_export_header(gemini) +======= +kde4_add_library(gemini SHARED ${gemini_SRCS}) +>>>>>>> master target_link_libraries(gemini Qt5::Quick Qt5::Gui Qt5::Core Qt5::Widgets ) +<<<<<<< HEAD set_target_properties(gemini PROPERTIES VERSION ${GENERIC_CALLIGRA_LIB_VERSION} SOVERSION ${GENERIC_CALLIGRA_LIB_SOVERSION} ) install(TARGETS gemini ${INSTALL_TARGETS_DEFAULT_ARGS}) +======= +>>>>>>> master diff --git a/gemini/lib/GeminiMainWindow.cpp b/gemini/lib/GeminiMainWindow.cpp index 201bf36ad5d..ca382e3a17a 100644 --- a/gemini/lib/GeminiMainWindow.cpp +++ b/gemini/lib/GeminiMainWindow.cpp @@ -1,230 +1,233 @@ /* This file is part of the KDE project * Copyright (C) 2015 Dan Leinir Turthra Jensen * * 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 "GeminiMainWindow.h" #include "GeminiModeSwitchEvent.h" #include #include #include #include #include +<<<<<<< HEAD #ifdef Q_OS_WIN // Slate mode/docked detection stuff #include #define SM_CONVERTIBLESLATEMODE 0x2003 #define SM_SYSTEMDOCKED 0x2004 #endif +======= +>>>>>>> master struct View { View() : quickView(0), widget(0) {} QQuickView* quickView; QWidget* widget; QWidget* getWidget(QWidget* parent = 0) { QWidget* view; if(widget) { view = widget; } else { QWidget* container = QWidget::createWindowContainer(quickView); view = new QWidget(parent); view->setLayout(new QVBoxLayout()); view->layout()->setContentsMargins(0,0,0,0); view->layout()->setSpacing(0); view->layout()->addWidget(container); } return view; } }; class GeminiMainWindow::Private { public: Private(GeminiMainWindow* qq) : q(qq) , fullScreenThrottle(new QTimer(qq)) , currentState(UnknownState) , stateLocked(false) { fullScreenThrottle->setInterval(500); fullScreenThrottle->setSingleShot(true); // Initialise the event receiver map to empty eventReceivers.insert(CreateState, 0); eventReceivers.insert(EditState, 0); eventReceivers.insert(ViewState, 0); // Initialise the view map to empty views.insert(CreateState, 0); views.insert(EditState, 0); views.insert(ViewState, 0); } GeminiMainWindow* q; QTimer* fullScreenThrottle; GeminiState previousState; GeminiState currentState; bool stateLocked; QMap views; QMap eventReceivers; GeminiModeSynchronisationObject* syncObject; }; GeminiMainWindow::GeminiMainWindow(QWidget* parent, Qt::WindowFlags flags) : QMainWindow(parent, flags) , d(new Private(this)) { } GeminiMainWindow::~GeminiMainWindow() { delete d; } GeminiMainWindow::GeminiState GeminiMainWindow::currentState() const { return d->currentState; } bool GeminiMainWindow::fullScreen() const { return (windowState() & Qt::WindowFullScreen) == Qt::WindowFullScreen; } void GeminiMainWindow::setFullScreen(bool newState) { if(newState) { if(d->fullScreenThrottle->isActive()) { // not a good thing... you need to avoid this happening. This exists to avoid a death-loop, // such as what might happen if readermode is enabled when the window is not maximised // as this causes a resize loop which makes readermode switch between enabled and disabled, // which in turn makes fullScreen be set and reset all the time... very bad, so let's try // and avoid that. } else { setWindowState(windowState() | Qt::WindowFullScreen); } } else { // this is really unpleasant... however, fullscreen is very twitchy, and exiting it as below // will cause an inconsistent state, so we simply assume exiting fullscreen leaves you maximised. // It isn't optimal, but it is the best state for now, this has taken too long to work out. // setWindowState(windowState() & ~Qt::WindowFullScreen); // should really do it, but... it doesn't. So, we end up with what we have next: showMaximized(); } d->fullScreenThrottle->start(); emit fullScreenChanged(); } void GeminiMainWindow::changeState(GeminiMainWindow::GeminiState newState, bool lockNewState) { d->syncObject = new GeminiModeSynchronisationObject; if(centralWidget()) { //Notify the view we are switching away from that we are about to switch away from it //giving it the possibility to set up the synchronisation object. GeminiModeSwitchEvent aboutToSwitchEvent(GeminiModeSwitchEvent::AboutToSwitchViewModeEvent, d->eventReceivers[d->currentState], d->eventReceivers[newState], d->syncObject); QApplication::sendEvent(d->eventReceivers[d->currentState], &aboutToSwitchEvent); centralWidget()->setParent(0); } View* view = d->views[newState]; setCentralWidget(view->getWidget()); qApp->processEvents(); if(view->quickView) view->quickView->setVisible(true); resize(size()); d->previousState = d->currentState; d->currentState = newState; emit currentStateChanged(); QTimer::singleShot(50, this, SLOT(stateChanging())); } void GeminiMainWindow::stateChanging() { qApp->processEvents(); //Notify the new view that we just switched to it, passing our synchronisation object //so it can use those values to sync with the old view. GeminiModeSwitchEvent switchedEvent(GeminiModeSwitchEvent::SwitchedToThisModeEvent, d->eventReceivers[d->previousState], d->eventReceivers[d->currentState], d->syncObject); QApplication::sendEvent(d->eventReceivers[d->currentState], &switchedEvent); d->syncObject = 0; qApp->processEvents(); } bool GeminiMainWindow::stateLocked() const { return d->stateLocked; } void GeminiMainWindow::setStateLocked(bool locked) { d->stateLocked = locked; emit stateLockedChanged(); } void GeminiMainWindow::setViewForState(QWidget* widget, GeminiMainWindow::GeminiState state) { View* view = d->views[state]; view->quickView = 0; view->widget = widget; } void GeminiMainWindow::setViewForState(QQuickView* quickView, GeminiMainWindow::GeminiState state) { View* view = d->views[state]; view->quickView = quickView; view->widget = 0; } void GeminiMainWindow::setEventReceiverForState(QObject* receiver, GeminiMainWindow::GeminiState state) { d->eventReceivers[state] = receiver; } #ifdef Q_OS_WIN bool GeminiMainWindow::winEvent( MSG * message, long * result ) { if (message && message->message == WM_SETTINGCHANGE && message->lParam && !d->stateLocked) { if (wcscmp(TEXT("ConvertibleSlateMode"), (TCHAR *) message->lParam) == 0 || wcscmp(TEXT("SystemDockMode"), (TCHAR *) message->lParam) == 0) { bool slateMode = (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0); bool undocked = !(GetSystemMetrics(SM_SYSTEMDOCKED) != 0); if(slateMode || undocked) { // find out if we are entirely without sensible input devices, or portrait // if we are, change to ViewState. EditState will do for now as an autoswitch... changeState(EditState); } else { // If we are neither slate nor undocked, then we're in clamshell or we are docked, which is the same thing. changeState(CreateState); } *result = 0; return true; } } return false; } #endif diff --git a/gemini/lib/GeminiMainWindow.h b/gemini/lib/GeminiMainWindow.h index 99a688e83e5..1aa8ab676db 100644 --- a/gemini/lib/GeminiMainWindow.h +++ b/gemini/lib/GeminiMainWindow.h @@ -1,81 +1,88 @@ /* This file is part of the KDE project * Copyright (C) 2015 Dan Leinir Turthra Jensen * * 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 GEMINIMAINWINDOW_H #define GEMINIMAINWINDOW_H #include +<<<<<<< HEAD #include "gemini_export.h" +======= +>>>>>>> master class QQuickView; /** * \short * */ +<<<<<<< HEAD class GEMINI_EXPORT GeminiMainWindow : public QMainWindow +======= +class GeminiMainWindow : public QMainWindow +>>>>>>> master { Q_OBJECT Q_PROPERTY(GeminiState currentState READ currentState NOTIFY currentStateChanged) Q_PROPERTY(bool fullScreen READ fullScreen WRITE setFullScreen NOTIFY fullScreenChanged) Q_ENUMS(GeminiState) public: enum GeminiState { AllStates = -3, UnknownState = -2, NoState = -1, CreateState = 1, EditState = 2, ViewState = 3 }; explicit GeminiMainWindow(QWidget* parent = 0, Qt::WindowFlags flags = 0); virtual ~GeminiMainWindow(); GeminiState currentState() const; bool fullScreen() const; void setFullScreen(bool newState); bool stateLocked() const; void setStateLocked(bool locked); void changeState(GeminiState newState, bool lockNewState = false); void setViewForState(QWidget* widget, GeminiState state); void setViewForState(QQuickView* quickView, GeminiState state); void setEventReceiverForState(QObject* receiver, GeminiState state); Q_SIGNALS: void stateLockedChanged(); void currentStateChanged(); void fullScreenChanged(); private Q_SLOTS: void stateChanging(); private: class Private; Private* d; #ifdef Q_OS_WIN bool winEvent(MSG * message, long * result); #endif }; #endif // GEMINIMAINWINDOW_H diff --git a/gemini/lib/GeminiModeSwitchEvent.h b/gemini/lib/GeminiModeSwitchEvent.h index 5741b974143..c7c3ead595f 100644 --- a/gemini/lib/GeminiModeSwitchEvent.h +++ b/gemini/lib/GeminiModeSwitchEvent.h @@ -1,70 +1,76 @@ /* * This file is part of the KDE project * Copyright (C) 2013 Arjen Hiemstra * Copyright (C) 2015 Dan Leinir Turthra Jensen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef GEMINIMODESWITCHEVENT_H #define GEMINIMODESWITCHEVENT_H #include struct GeminiModeSynchronisationObject { GeminiModeSynchronisationObject() : initialized(false) { } bool initialized; }; class GeminiModeSwitchEvent : public QEvent { public: +<<<<<<< HEAD /** * Which type of event you are dealing with. You will only receive this in two cases: * When you are about to switch away from a particular mode (sent to fromView before switching) * When you have been made the current mode (sent to toView after switching) */ enum GeminiModeEventType { AboutToSwitchViewModeEvent = QEvent::User + 1, ///< Write information into the event (and mark the sync object as initialized) SwitchedToThisModeEvent ///< Read information out of the event +======= + enum GeminiModeEventType { + AboutToSwitchViewModeEvent = QEvent::User + 1, + SwitchedToThisModeEvent ///< This is the case when +>>>>>>> master }; inline GeminiModeSwitchEvent(GeminiModeEventType type, QObject* fromView, QObject* toView, GeminiModeSynchronisationObject* syncObject) : QEvent(static_cast(type)) , m_fromView(fromView) , m_toView(toView) , m_syncObject(syncObject) { } inline QObject* fromView() const { return m_fromView; } inline QObject* toView() const { return m_toView; } inline GeminiModeSynchronisationObject* synchronisationObject() const { return m_syncObject; } private: QObject* m_fromView; QObject* m_toView; GeminiModeSynchronisationObject* m_syncObject; }; #endif // GEMINIMODESWITCHEVENT_H diff --git a/karbon/data/org.kde.karbon.appdata.xml b/karbon/data/org.kde.karbon.appdata.xml index 58b005520b0..3d96026785b 100644 --- a/karbon/data/org.kde.karbon.appdata.xml +++ b/karbon/data/org.kde.karbon.appdata.xml @@ -1,395 +1,395 @@ org.kde.karbon.desktop CC0-1.0 GPL-2.0+ Karbon Karbon Karbon Karbon Karbon Karbon Karbon Karbon Karbon Karbon Karbon Karbon Karbon Karbon Karbon Karbon Karbon Karbon Karbon Karbon Karbon Karbon Karbon Karbon xxKarbonxx Karbon Scalable Graphics Grafika koja se može skalirati Gràfics escalables Gràfics escalables Škálovatelná grafika Skalierbare Vektorgrafik Scalable Graphics Gráficos escalables Vektorgraafika Skaalautuva grafiikka Graphisme vectoriel Gráficos de tamaño variábel Graphicos scalabile Grafica scalabile 画像の寸法 Vectorafbeeldingen Skalowalna grafika Gráficos Vectoriais Imagens vetoriais Škálovateľná grafika Skalbar grafik Програма для роботи з масштабованою графікою xxScalable Graphicsxx 可缩放图像

Karbon is a vector drawing application with a user interface that is easy to use, highly customizable and extensible. That makes Karbon a great application for users starting to explore the world of vector graphics as well as for artists wanting to create breathtaking vector art.

Karbon je vektorska aplikacija za crtanje s korisničkim sučeljem koje je jednostavno za korištenje , vrlo prilagodljivo i proširivo . To čini Karbon odličnom aplikacijom za korisnike koji počinju istraživati ​​svijet vektorske grafike , kao i za umjetnike koji žele stvoriti prekrasnu vektorsku umjetnost .

El Karbon és una aplicació de dibuix vectorial amb una interfície d'usuari senzilla d'utilitzar, que es pot personalitzar i ampliar molt. Això converteix el Karbon en una gran aplicació per usuaris que comencin a explorar el món dels gràfics vectorials i també pels artistes que volen crear art vectorial que deixi bocabadat.

El Karbon és una aplicació de dibuix vectorial amb una interfície d'usuari senzilla d'utilitzar, que es pot personalitzar i ampliar molt. Això converteix el Karbon en una gran aplicació per usuaris que comencen a explorar el món dels gràfics vectorials i també pels artistes que volen crear art vectorial que deixi bocabadat.

Karbon is a vector drawing application with a user interface that is easy to use, highly customisable and extensible. That makes Karbon a great application for users starting to explore the world of vector graphics as well as for artists wanting to create breathtaking vector art.

Karbon es una aplicación de dibujo vectorial que dispone de una interfaz de usuario intuitiva, altamente personalizable y extensible. Todo ello hace que Karbon sea una gran aplicación para aquellos usuarios que empiezan a explorar el mundo de los gráficos vectoriales, así como para los artistas que desean crear impresionantes piezas de arte vectorial.

Karbon on vektorgraafikarakendus hõlpsasti kasutatava, äärmiselt kohandatava ja laiendatava kasutajaliidesega. See muudab Karboni imeheaks abivahendiks algajale, kes alles uudistab vektorgraafika maailma, aga ka kunstnikele, kes soovivad luua hingematvalt kaunist vektorgraafikat.

Karbon on vektorigrafiikkasovellus, jonka käyttöliittymä on helppo ja laajasti mukautettavissa ja laajennettavissa. Karbon on näin loistava sovellus vektorigrafiikan maailmaan vasta tutustuville käyttäjille samoin kuin henkeäsalpaavaa vektoritaidetta luoville taiteilijoille.

Karbon est une application de dessin vectoriel avec une interface facile à utiliser, personnalisable et extensible. Cela fait de Karbon une application majeure pour les utilisateurs s'initiant au dessin vectoriel et pour les artistes voulant créer des œuvres à couper le souffle.

Karbon é un aplicativo de debuxo vectorial cunha interface de usuario fácil de usar, personalizar e ampliar. Iso fai de Karbon un gran aplicativo para usuarios que comezan a explorar o mundo das imaxes vectoriais, pero tamén para artistas que queren crear impresionantes obras de arte vectoriais.

Karbon è un'applicazione di disegno vettoriale con un'interfaccia utente facile da utilizzare, altamente personalizzabile ed estendibile. Ciò rende Karbon un'ottima applicazione per gli utenti che iniziano a esplorare il mondo della grafica vettoriale così come per gli artisti che vogliono creare straordinarie opere vettoriali.

Karbon is een toepassing voor tekenen met vectoren met een gebruikersinterface dat gemakkelijk is te gebruiken, zeer goed aan te passen en uit te breiden. Dit maakt Karbon een geweldige toepassing voor gebruikers die de wereld van grafiek met vectoren aan het verkennen zijn evenals voor kunstenaars die adembenemende vectorkunst willen maken.

Karbon jest programem do rysowania wektorowego z układem sterowania, który jest łatwy w użyciu, wysoce dostosowywalny i rozszerzalny. To czyni Karbon wspaniałym programem dla użytkowników zaczynających poznawanie świata grafiki wektorowej, a artystów zachęca do tworzenie sztuki wektorowej zapierającej dech w piersiach.

O Karbon é uma aplicação de desenho vectorial com uma interface simples de usar, facilmente configurável e modular. Isto torna o Karbon uma óptima aplicação para os utilizadores que começam a explorar o mundo dos gráficos vectoriais, assim como para os artistas que desejam criar arte vectorial espectacular.

Karbon é um aplicativo de desenho vetorial com uma interface simples de usar, facilmente configurável e expansível. Isso torna o Karbon um ótimo aplicativo para usuários que começam a explorar o mundo dos gráficos vetoriais, assim como para artistas que desejam criar arte vetorial espetacular.

Karbon je vektorová kresliaca aplikácia s používateľským rozhraním jednoduchým na používanie, veľmi prispôsobiteľná a rozšíriteľná. Toto robí z Karbonu výbornú aplikáciu pre používateľov, ktorí začínajú objavovať sveet vektorovej grafiky, ako aj pre umelcov, ktorí chcú vytvárať dych vyrážajúce vektorové umenie.

Karbon är ett vektorritprogram med ett användargränssnitt som är lätt att använda, ytterst anpassningsbart och utökningsbart. Det gör Karbon till ett utmärkt program för användare som börjar utforska vektorgrafikvärlden samt för konstnärer som vill skapa hänförande vektorkonst.

Karbon — програма для векторного малювання з простим, гнучким та придатним до розширення інтерфейсом користувача. Це робить Karbon чудовою програмою для користувачів, які починають знайомитися зі світом векторної графіки, а також для художників, які хочуть створити захопливі векторні твори.

xxKarbon is a vector drawing application with a user interface that is easy to use, highly customizable and extensible. That makes Karbon a great application for users starting to explore the world of vector graphics as well as for artists wanting to create breathtaking vector art.xx

Karbon 是一个矢量绘图程序,具有易用,高度可定制和可扩展的用户界面。它是一个理想的工具,帮助用户探索矢量图形,帮助艺术家创作令人惊叹的矢量艺术作品。

Features:

Svojstva:

Característiques:

Característiques:

Vlastnosti:

Funktionen:

Features:

Características:

Omadused:

Ominaisuuksia:

Fonctionnalités :

Funcionalidades:

Characteristicas

Funzionalità:

機能:

Mogelijkheden:

Możliwości:

Funcionalidades:

Funcionalidades:

Funkcie:

Funktioner:

Можливості:

xxFeatures:xx

功能:

  • Loading support for ODG, SVG, WPG, WMF, EPS/PS
  • Učitavanje podrške za ODG, SVG, WPG, WMF, EPS/PS
  • Permet llegir ODG, SVG, WPG, WMF, EPS/PS
  • Permet llegir ODG, SVG, WPG, WMF, EPS/PS
  • Unterstützung für das Laden von ODG, SVG, WPG, WMF, EPS/PS
  • Loading support for ODG, SVG, WPG, WMF, EPS/PS
  • Admite la carga de ODG, SVG, WPG, WMF, EPS/PS
  • ODG, SVG, WPG, WMF, EPS/PS laadimise toetamine
  • Lukutuki ODG-, SVG-, WPG-, WMF- ja EPS/PS-muodoista
  • Lecture des formats ODG, SVG, WPG, WMF, EPS/PS
  • Posibilidade de cargar ODG, SVG, WPG, WMF e EPS/PS.
  • Cargante supporto pro ODG, SVG, WPG, WMF, EPS/PS
  • Supporto per il caricamento di ODG, SVG, WPG, WMF, EPS/PS
  • 読み込み可能な形式: ODG, SVG, WPG, WMF, EPS/PS
  • Ondersteuning voor laden van ODG, SVG, WPG, WMF, EPS/PS
  • Obsługa wczytywania dla ODG, SVG, WPG, WMF, EPS/PS
  • Suporte do carregamento de imagens em ODG, SVG, WPG, WMF, EPS/PS
  • Suporte para carregamento de arquivos ODG, SVG, WPG, WMF e EPS/PS
  • Podpora čítania pre ODG, SVG, WPG, WMF, EPS/PS
  • Stöd för att läsa in ODG, SVG, WPG, WMF, EPS/PS
  • Підтримка завантаження даних ODG, SVG, WPG, WMF, EPS/PS.
  • xxLoading support for ODG, SVG, WPG, WMF, EPS/PSxx
  • 加载支持 ODG,SVG,WPG,WMF,EPS/PS
  • Writing support for ODG, SVG, PNG, PDF, WMF
  • Pisanje podrške za ODG, SVG, WPG, WMF, EPS/PS
  • Permet gravar ODG, SVG, PNG, PDF, WMF
  • Permet gravar ODG, SVG, PNG, PDF, WMF
  • Unterstützung für das Schreiben von ODG, SVG, PNG, PDF, WMF
  • Writing support for ODG, SVG, PNG, PDF, WMF
  • Admite la escritura de ODG, SVG, PNG, PDF, WMF
  • ODG, SVG, PNG, PDF, WMF kirjutamine toetamine
  • Kirjoitustuki ODG-, SVG-, PNG-, PDF- ja WMF-muotoihin
  • Écriture des formats ODG, SVG, PNG, PDF, WMF
  • Posibilidade de xerar ODG, SVG, PNG, PDF e WMF.
  • Supporto de scriber pro ODG, SVG, PNG, PDF, WMF
  • Supporto per la scrittura di ODG, SVG, PNG, PDF, WMF
  • 書き込み可能な形式: ODG, SVG, PNG, PDF, WMF
  • Ondersteuning voor schrijven van ODG, SVG, PNG, PDF, WMF
  • Obsługa zapisywania dla ODG, SVG, PNG, PDF, WMF
  • Suporte da gravação de imagens em ODG, SVG, PNG, PDF, WMF
  • Suporte para gravação de arquivos ODG, SVG, PNG, PDF e WMF
  • Podpora zápisu pre ODG, SVG, PNG, PDF, WMF
  • Stöd för att skriva ut ODG, SVG, PNG, PDF, WMF
  • Підтримка запису у форматах ODG, SVG, PNG, PDF, WMF.
  • xxWriting support for ODG, SVG, PNG, PDF, WMFxx
  • 写入支持 ODG,SVG,PNG,PDF,WMF
  • Customizable user interface with freely placeable toolbars and dockers
  • Prilagodljiv korisnički interfejs sa gdje se moze slobodno staviti alatne trake i dockers
  • Interfície d'usuari que es pot personalitzar que permet situar lliurement barres d'eines i acobladors
  • Interfície d'usuari que es pot personalitzar que permet situar lliurement barres d'eines i acobladors
  • Anpassungsfähige Bedienungsoberfläche mit frei platzierbaren Werkzeugleisten und andockbaren Fenstern
  • Customisable user interface with freely placeable toolbars and dockers
  • Interfaz de usuario personalizable con barras de herramientas y paneles que se pueden posicionar libremente en cualquier lugar.
  • Kohandatav kasutajaliides vabalt liigutatavate tööriistaribade ja dokkidega
  • Mukautettava käyttöliittymä, jonka työkalurivit ja telakat ovat vapaasti sijoitettavissa
  • Interface utilisateur personnalisable avec des barres d'outil librement déplaçables.
  • Interface de usuario personalizábel con barras de ferramentas e docas que poden recolocarse libremente.
  • Interfacie de usator personalisabile con barra de instrumentos e stivatores (dockers) liberemente positionabile
  • Interfaccia utente personalizzabile con barre degli strumenti posizionabili liberamente e aree di aggancio
  • Aan te passen gebruikersinterface met vrij te plaatsen werkbalken en verankeringen
  • Układ sterowania z dowolnie umieszczanymi paskami narzędzi i dokowaniami
  • Interface de utilizador configurável com barras e áreas acopláveis livres
  • Interface de usuário configurável com barras de ferramentas e áreas acopláveis que podem ser facilmente ajustadas
  • Nastaviteľné používateľské rozhranie s voľne umiestniteľnými panelmi nástrojov a dockermi
  • Anpassningsbart användargränssnitt med verktygsrader och paneler som kan placeras fritt
  • Придатний до налаштовування інтерфейс користувача з довільним розташуванням панелей інструментів та бічних панелей.
  • xxCustomizable user interface with freely placeable toolbars and dockersxx
  • 可自定义用户界面,包含可自由放置的工具栏和停靠栏
  • Layer docker for easy handling of complex documents including preview thumbnails, support for grouping shapes via drag and drop, controlling visibility of shapes or locking
  • Sloj lučki radnik za jednostavno rukovanje složenim dokumentima , uključujući pregled sličica , podršku za grupiranje oblika putem drag and drop , kontroliranje vidljivost oblika ili zaključavanje
  • Acoblador de capa per a una gestió senzilla de documents complexos incloent la vista prèvia de miniatures, permet agrupar formes via arrossegar i deixar anar, controlar la visibilitat de les formes o el bloqueig.
  • Acoblador de capa per a una gestió senzilla de documents complexos incloent la vista prèvia de miniatures, permet agrupar formes via arrossegar i deixar anar, controlar la visibilitat de les formes o el bloqueig.
  • Layer docker for easy handling of complex documents including preview thumbnails, support for grouping shapes via drag and drop, controlling visibility of shapes or locking
  • Panel de capas para un sencillo manejo de documentos complejos, que incluye vista previa de miniaturas y agrupación de figuras mediante la operación de arrastrar y soltar, controlando la visibilidad de las figuras o su bloqueo.
  • Kihtide dokk keerukamate dokumentide hõlpsaks töötlemiseks, kaasa arvatud pisipiltide eelvaatlus, kujundite rühmitamise toetamine ainult lohistamisega, kujundite nähtavuse ja lukustamise määramine
  • Monimutkaisten tiedostojen helppoon hallintaan tasotelakka, joka sisältää esikatselukuvat, muotojen ryhmittelyn tuen vetämällä ja pudottamalla sekä muotojen näkyvyyden ja lukitsemisen hallinnan
  • Conteneurs de calques pour la manipulation facile de documents complexes incluant les vignettes d'aperçu, la prise en charge du groupement de formes par glisser-déposer, contrôle de la visibilité des formes et verrouillage
  • Doca de capas para xestionar facilmente documentos complexos. Inclúe miniaturas de vista previa, permite agrupar formas arrastrando e soltando, controlar a visibilidade das formas ou bloquealas.
  • Area di aggancio di livelli per una facile gestione di documenti complessi incluse miniature di anteprima, supporto di forme raggruppate tramite il trascinamento e rilascio, controllo della visibilità delle forme e blocco
  • Laagverankering voor gemakkelijke behandeling van complexe documenten inclusief voorbeeldminiaturen, ondersteuning voor groeperen van vormen via slepen en laten vallen, besturing van zichtbaarheid van vormen of vastzetten
  • Dokowanie warstw dla łatwiejszej obsługi złożonych dokumentów zawierający: podgląd miniatur, obsługę grupowania kształtów poprzez przeciągnij i upuść, sterowanie widocznością kształtów czy blokowanie.
  • Área de camadas para o tratamento de documentos complexos, incluindo miniaturas da antevisão, suporte para o agrupamento de formas por arrastamento, o controlo da visibilidade das formas ou o seu bloqueio
  • Área de camadas para tratamento de documentos complexos, incluindo miniaturas, suporte a agrupamento de formas com arrastar e soltar, controle de visibilidade das formas ou seu bloqueio
  • Docker vrstiev pre ľahkú manipuláciu so zložitými dokumentami vrátane náhľadu miniatúr, podpora pre zoskupovanie tvarov cez drag and drop, ovládanie viditeľnosti tvarov alebo zamykanie
  • Lagerpanel för enkel hantering av komplexa dokument inklusive miniatyrbilder för förhandsgranskning, stöd för att gruppera former via drag och släpp, styra eller låsning synlighet av former
  • Панель шарів для полегшення обробки складних документів з мініатюрами об’єктів, підтримка групування форм перетягуванням зі скиданням, керування показом форм та блокуванням.
  • xxLayer docker for easy handling of complex documents including preview thumbnails, support for grouping shapes via drag and drop, controlling visibility of shapes or lockingxx
  • 图层停靠栏用于方便处理复杂文档,包括缩略图预览,支持拖拽组合形状,控制形状的可见性或锁定。
  • Advanced path editing tool with great on-canvas editing capabilities
  • Alat za napredno uređivanje puta s velikom mogućnosti uređivanja na platnu
  • Eina avançada d'edició de camins amb una gran capacitat d'edició en el llenç
  • Eina avançada d'edició de camins amb una gran capacitat d'edició en el llenç
  • Advanced path editing tool with great on-canvas editing capabilities
  • Herramienta de edición avanzada de rutas con grandes capacidades de edición en el lienzo
  • Täiustatud kompleksjoone muutmise tööriist suurepäraste otse lõuendil redigeerimise võimalustega
  • Edistynyt polunmuokkaustyökalu, jolla on erinomaiset muokkausominaisuudet
  • Outil d'édition de chemin avancé avec des capacités d'édition dans les canevas performantes
  • Ferramenta avanzada de edición de rutas cunha gran funcionalidade de edición sobre o lenzo.
  • Strumento avanzato di modifica di tracciati con grandi capacità di modifica sul posto
  • Geavanceerde padbewerkingsgereedschap met prima bewerkingsmiddelen op het werkblad
  • Zaawansowane narzędzia edytowania ścieżki z szerokimi możliwościami edytowania na płótnie
  • Ferramenta de edição de caminhos avançada, com grandes capacidade de edição no local
  • Ferramenta avançada para edição de caminhos, com ótima capacidade de edição no local
  • Pokročilý nástroj na úpravu ciest s výbornými schopnosťami editácie na plátne
  • Avancerat konturredigeringsverktyg med utmärkta redigeringsmöjligheter direkt på duken
  • Інструмент редагування контурів з чудовими можливостями редагування безпосередньо на полотні.
  • xxAdvanced path editing tool with great on-canvas editing capabilitiesxx
  • 高级路径编辑工具,以及强大的画布编辑能力
  • Various drawing tools for creating path shapes including a draw path tool, a pencil tool as well as a calligraphy drawing tool
  • Razni alati za crtanje za kreiranje put oblike uključujući i put alat nacrtati ,olovka alat , kao i kaligrafija alat za crtanje
  • Diverses eines de dibuix per crear formes de camí incloent una eina de dibuix de camins, una eina de llapis i també una eina de dibuix de cal·ligrafia.
  • Diverses eines de dibuix per crear formes de camí incloent una eina de dibuix de camins, una eina de llapis i també una eina de dibuix de cal·ligrafia.
  • Various drawing tools for creating path shapes including a draw path tool, a pencil tool as well as a calligraphy drawing tool
  • Diversas herramientas de dibujo para crear figuras con rutas, entre las que se incluyen una herramienta de dibujo de rutas, una herramienta de pincel y una herramienta de dibujo caligráfico.
  • Mitmesugused kompleksjoontest kujundite loomise vahendid, sealhulgas kompleksjoone joonistamise tööriist, pliiatsitööriist ning kalligraafia loomise tööriist
  • Eri piirrostyökalut polkumuotojen luontiin: polunpiirto-, kynä- ja kalligrafinen piirrostyökalu
  • Outils de dessin variés incluant un outil de création de chemin, un crayon ainsi qu'un outil pour la calligraphie
  • Varias ferramentas de debuxo para crear formas de rutas, incluíndo unha ferramenta de debuxo de rutas, unha ferramenta de lapis, e unha ferramenta de debuxo caligráfico.
  • Vari strumenti di disegno per creare percorsi e forme che include uno strumento di tracciati, un matita e uno strumento calligrafico
  • Verschillende tekengereedschappen voor het maken van padvormen inclusief een tekenhulpmiddel voor paden, een potloodhulpmiddel evenals een tekengereedschap voor kalligrafie
  • Różne narzędzia rysownicze do tworzenia kształtów ścieżek uwzględniając w tym: narzędzie rysowania ścieżki, narzędzie ołówka, a także kaligraficzne narzędzia rysownicze
  • Diversas ferramentas de desenho para criar formas de caminhos, incluindo uma ferramenta de desenho de caminhos, uma ferramenta de lápis e uma ferramenta de desenho caligráfico
  • Diversas ferramentas de desenho para criar formas de caminhos, incluindo uma ferramenta de desenho de caminhos, uma ferramenta de lápis e uma ferramenta de desenho caligráfico
  • Rôzne kresliace nástroje na vytváranie tvarov ciest vrátane nástroja na kreslenie cesty, nástroja ceruzky ako aj kaligrafického kresliaceho nástroja
  • Diverse ritverktyg för att skapa konturformer som inkluderar ett konturritverktyg, ett pennverktyg samt ett kalligrafiskt ritverktyg
  • Різноманітні інструменти малювання для створення контурів, зокрема інструмент малювання контуру, олівець та інструмент каліграфічного малювання.
  • xxVarious drawing tools for creating path shapes including a draw path tool, a pencil tool as well as a calligraphy drawing toolxx
  • 多种绘图工具用于创作路径形状,包括路径绘制工具,铅笔工具和书法绘制工具
  • Gradient and pattern tools for easy on-canvas editing of gradient and pattern styles
  • Gradijent i uzorak alata za jednostavno na - platnu uređivanje gradijent i uzorak stilova
  • Eines de degradats i patrons per a una edició senzilla sobre el llenç d'estils de degradats i patrons
  • Eines de degradats i patrons per a una edició senzilla sobre el llenç d'estils de degradats i patrons
  • Gradient and pattern tools for easy on-canvas editing of gradient and pattern styles
  • Herramientas de degradados y patrones para una sencilla edición de estilos de degradados y patrones en el lienzo
  • Ülemineku- ja mustritööriistad üleminekute ja mustrite stiilide hõlpsaks redigeerimiseks otse lõuendil
  • Työkalut liukuvärien ja täyttökuvioiden helppoon muokkaukseen
  • Outils de gradient et de tramage pour l'édition facile de styles de gradients et de trames
  • Ferramentas de gradacións e padróns para editar degradados e estilos de padróns facilmente sobre o lenzo.
  • Strumenti di gradienti e motivi per una facile modifica sul posto di stili di gradienti e motivi
  • Hulpmiddelen voor gradiënten en patronen voor gemakkelijk werken op het werkblad van gradiënten en patroonstijlen
  • Narzędzia gradientu i wzorca dla łatwiejszego ich edytowania na płótnie
  • Ferramentas de gradientes e padrões para uma edição simples no local dos estilos dos gradientes e dos padrões
  • Ferramentas de gradientes e padrões para fácil edição no local dos estilos dos gradientes e dos padrões
  • Nástroje na prechody a vzory pre ľahké editovanie na plátne štýlov prechodov a vzorov
  • Tonings- och mönsterverktyg för enkelt redigering av tonings- och mönsterstilar direkt på duken
  • Інструменти градієнта і візерунка для полегшення редагування на полотні областей з заповненням градієнтом і візерунком.
  • xxGradient and pattern tools for easy on-canvas editing of gradient and pattern stylesxx
  • 渐变和图案工具可以轻松地在画布上编辑渐变和图案样式
  • Top notch snapping facilities for guided drawing and editing (e.g. snapping to grid, guide lines, path nodes, bounding boxes, orthogonal positions, intersections of path shapes or extensions of lines and paths)
  • Vrhunska snapping objekti za vođene crtanje i uređivanje ( npr snapping na mrežu , vodič linije , staze čvorova , granični kutije , okomita pozicija , preplitanja put oblikuje ili proširenja linija i staze )
  • Capacitats òptimes d'ajust per dibuix guiat i edició (p.e. ajust a graella, línies de guia, nodes de camins, caixes contenidores, posicions ortogonals, interseccions de formes de camí o extensions de línies i camins)
  • Capacitats òptimes d'ajust per dibuix guiat i edició (p.e. ajust a graella, línies de guia, nodes de camins, caixes contenidores, posicions ortogonals, interseccions de formes de camí o extensions de línies i camins)
  • Top notch snapping facilities for guided drawing and editing (e.g. snapping to grid, guide lines, path nodes, bounding boxes, orthogonal positions, intersections of path shapes or extensions of lines and paths)
  • Capacidades de ajuste óptimas para el dibujo y la edición guiados (por ejemplo, ajustar a la rejilla, líneas guías, nodos de ruta, cuadros delimitadores, posiciones ortogonales, intersecciones de formas de rutas o extensiones de líneas y rutas)
  • Äärmiselt tulusad haardetööriistad juhtjoonte järgi joonistamiseks ja redigeerimiseks (nt tõmme alusvõrgule, juhtjooned, kompleksjoone sõlmed, piirdekastid, kompleksjoontest kujundite lõikekohad jms)
  • Huippulaatuinen kiinnitysominaisuus ohjattuun piirtämiseen ja muokkaukseen (esim. kiinnitys ruudukkoon, apuviivoihin, rajauslaatikkoon, kohtisuoraan asemaan, leikkaukseen, polkumuotoon tai viivojen ja polkujen jatkeisiin)
  • Fonctionnalités d'alignement top-niveau pour guider le dessin et l'édition (p.ex. alignement sur la grille, chemin nodal, boîtes, positions orthogonales, intersections de formes ou extensions de lignes ou de formes)
  • -
  • Funcionalidades de axuste de última xeración para editar e debuxar de maneira guiada (por exemplo, axustar á grade, liñas de guía, nodos de rutas, caixas de límites, posicións ortogonais, cruce de formas de rutas ou extensións de liñas e rutas).
  • +
  • Funcionalidades de axuste de última xeración para editar e debuxar de maneira guiada (por exemplo, axustar á grade, liñas de guía, nodos de rutas, caixas de límites, posicións ortogonais, cruzamento de formas de rutas ou extensións de liñas e rutas).
  • Capacità di alto livello di regolazione per disegno e modifica guidata (ad es. aggancio alla griglia, linee guida, nodi di tracciato, riquadri collegati, posizioni ortgonali, intersezioni di forme di tracciato o estensioni di linee e tracciati)
  • Excellente vastklik faciliteiten voor geleid tekenen en bewerken (bijv. vastklikken aan raster, gidslijnen, padpunten, begrenzingsvakken, orthogonale posities, kruispunten van padvormen of extensies van lijnen en paden)
  • Możliwości przyciągania z najwyższej półki rysowania i edytowania ze wspomaganiem (np. przyciąganie do siatki, -prowadnic, węzłów ścieżki, pól ograniczających, prostopadłych położeń, przecięć kształtów ścieżek lub wydłużeń linii i ścieżek)
  • Capacidades de ajuste óptimas para o desenho e edição guiado (p.ex., ajustes à grelha, linhas-guias, nós de caminhos, áreas envolventes, posições ortogonais, intersecções de formas de caminhos ou extensões de linhas e caminhos)
  • Capacidades de melhor ajuste para desenho e edição guiado (p.ex., ajustes à grade, linhas-guias, nós de caminhos, caixas delimitadoras, posições ortogonais, intersecções de formas de caminhos ou extensões de linhas e caminhos)
  • Schopnosti prichytenia na vrch pre sprevádzané kreslenie a editovanie (napr. prichytenie k mriežke, pomocné čiary, uzly cesty, hraničné boxy, ortogonálne polohy, priesečníky tvarov cesty alebo rozšírenia čiar a ciest)
  • Väldigt bra låsfunktioner för att rita och redigera med styrning (t.ex. låsa till rutnät, styrlinjer, konturnoder, omgivande rutor, ortogonala positioner, korsningar av konturformer eller förlängningar av linjer och konturer)
  • Можливості використання прилипання та малювання за напрямними (прилипання до сітки, напрямні, вузли контурів, обмежувальні рамки, ортогональне розташування, перетини та розширення ліній і контурів).
  • xxTop notch snapping facilities for guided drawing and editing (e.g. snapping to grid, guide lines, path nodes, bounding boxes, orthogonal positions, intersections of path shapes or extensions of lines and paths)xx
  • 顶端对齐工具可以引导绘制和编辑(比如吸附到网格,参考线,路径节点,边界框,正交位置,路径焦点或线的延长线)
  • Includes many predefined shapes including basic shapes like stars, circle/ellipse, rectangle, image
  • Uključuje mnoge predefinisane oblike uključujući i osnovne oblike poput zvijezda , krugova / elipsa, pravougaonika, slika
  • Inclou moltes formes predefinides bàsiques com estels, cercles/el·lipses, rectangles, imatges
  • Inclou moltes formes predefinides bàsiques com estels, cercles/el·lipses, rectangles, imatges
  • Enthält viele vordefinierte Objekte einschließlich einfacher Objekte wie Sterne, Kreise, Ellipsen, Rechtecke und Bilder
  • Includes many predefined shapes including basic shapes like stars, circle/ellipse, rectangle, image
  • Incluye muchas formas predefinidas, entre otras figuras básicas como estrellas, círculos/elipses, rectángulos, imágenes
  • Hulk valmiskujundeid, sealhulgas tähed, ringid ja ellipsid, ristkülikud, pildid
  • Lukuisia esimääritettyjä muotoja (perusmuodot kuten tähdet, ympyrä ja soikio, nelikulmio, kuva)
  • Inclut de nombreuses formes prédéfinies, telles que les étoiles, cercles/ellipses, rectangles, images
  • Inclúe moitas formas predefinidas, entre elas formas básicas como estrelas, círculos, elipses, rectángulos e imaxes.
  • Include molte forme predefinite tra cui forme base come stelle, cerchi/ellissi, rettangoli e immagini
  • Omvat vele voorgedefinieerde vormen inclusief basisvormen als ster, cirkel/ellips, rechthoek, afbeelding
  • Zawiera wiele uprzednio stworzonych kształtów, do których można zaliczyć gwiazdy, okręgi, elipsy, prostokąty, obrazy
  • Inclui diversas formas predefinidas, incluindo formas básicas como as estrelas, círculos/elipses, rectângulos, imagens
  • Inclui diversas formas predefinidas, incluindo formas básicas como estrelas, círculos/elipses, retângulos e imagens
  • Obsahuje mnoho preddefinovaných tvarov vrátane základných tvarov ako hviezdy, kružnica/elipsa, obdĺžnik, obrázok
  • Innehåller många fördefinierade former inklusive grundläggande former som stjärnor, cirkel/ellips, rektangel, bild
  • Передбачено багато готових форм, зокрема базові форми зірки, кола або еліпса, прямокутника та зображення.
  • xxIncludes many predefined shapes including basic shapes like stars, circle/ellipse, rectangle, imagexx
  • 包含许多预定义形状,如星形,圆形/椭圆,矩形,图像
  • Artistic text shape with support for following path outlines (i.e. text on path)
  • Umjetnički oblik tekst s podrškom za sljedeći put naglašava ( tj tekst na putu )
  • Formes de text artístic que permeten camins de contorns de seguiment (p.e. text en camins)
  • Formes de text artístic que permeten camins de contorns de seguiment (p.e. text en camins)
  • Artistic text shape with support for following path outlines (i.e. text on path)
  • Forma de texto artístico con soporte para contornos de seguimiento de rutas (es decir, texto sobre una ruta)
  • Kunstiline tekstikujund, mis toetab kompleksjooni, st võimaldab asetada teksti kompleksjoonele
  • Taiteelliset tekstimuodot polunseurantatuella
  • Formes de texte artistiques prenant par exemple en charge la création de texte le long d'une courbe
  • Forma de texto artístico que permite seguir o contorno de rutas (é dicir, texto sobre rutas).
  • Forme di testo artistico con supporto per le bordature che seguono il tracciato (ad es. testo su tracciato)
  • Artistieke tekstvormen met ondersteuning voor het volden van paden (dwz. tekst op een pad)
  • Kształty artystycznego tekstu z obsługą dla następujących zarysów ścieżek (tj. tekst na ścieżce)
  • Forma de texto artístico com suporte para caminhos de seguimento (i.e., texto ao longo de um caminho)
  • Forma de texto artístico com suporte para caminhos de seguimento (isto é, texto no caminho)
  • Umelecký textový tvar s podporou pre nasledovacie obrysy cesty (napr. text na ceste)
  • Artistisk textform med stöd för att följa konturlinjer (t.ex. text på en kontur)
  • Форма художнього тексту для розташування тексту вздовж контуру.
  • xxArtistic text shape with support for following path outlines (i.e. text on path)xx
  • 艺术字形状,支持跟随路径轮廓(即路径上的文本)
  • Complex path operations and effects like boolean set operations, path flattening, rounding and refining as well as whirl/pinch effects
  • Kompleksne staze poslovanja i učinci poput Booleova postavljanje poslovanja , put ravnanje , zaokruživanje i rafiniranje kao vrtlog / za hvatanje učinci
  • Operacions complexes de camins i efectes com operacions de conjunts booleans, aplanament de camins, arrodoniment i afinació i també efectes de gir i pessic
  • Operacions complexes de camins i efectes com operacions de conjunts booleans, aplanament de camins, arrodoniment i afinació i també efectes de gir i pessic
  • Complex path operations and effects like boolean set operations, path flattening, rounding and refining as well as whirl/pinch effects
  • Operaciones de ruta complejas y efectos como operaciones booleanas con conjuntos, aplanamiento de rutas, redondeo y refinación así como también efectos de arremolinar/apretar
  • Ka keerukamad kompleksjoone operatsioonid ja efektid, näiteks tõeväärtustega operatsioonid, kompleksjoonte lamendamine, ümardamine ja täpsustamine, keerise efekt jms
  • Monimutkaiset polku-operaatiot ja -tehosteet kuten totuusarvo-operaatiot, polun tasoitus, pyöristys ja hienosäätö sekä pyörre- ja nipistystehosteet
  • Opérations de chemins complexes et effets tels que les opérateurs booléens, mise à plat et ajustements, de même que les effets de spirale et de pincement
  • Operacións de rutas complexas e efectos como operacións de grupos de valores booleanos; aplanamento, arredondamento e refinamento de rutas; así como efectos de xiro e picada.
  • Operazioni complesse su tracciati ed effetti del tipo operazioni su insiemi booleani, appiattimento di tracciati, arrotondamento e affinamento così come effetti di vortice/pizzico
  • Complexe bewerkingen van paden en effecten zoals booleaanse set bewerkingen, afvlakken van paden, afronding en verfijning evenals wervel/put-effecten
  • Złożone działania i efekty na ścieżce takie jak działania boolean, spłaszczanie ścieżki, zaokrąglanie, a także efekty polepszające wraz z efektami wiru/rozdmuchania
  • Opções complexas com caminhos e efeitos como as operações booleanas com conjuntos, o alisamento de caminhos, o arredondamento e a afinação, para além da ondulação/embate
  • Operações complexas com caminhos e efeitos, como operações booleanas com conjuntos, o nivelamento de caminhos, o arredondamento e refinamento, assim como efeitos de ondulação/aperto
  • Komplexné cestné operácie a efekty ako logické operácie, splošťovanie cesty, zaobľovanie a zjemňovanie ako aj efekty vírov.
  • Komplexa konturoperationer och effekter som Booleska mängdoperationer, konturutplattning, rundning och förfining samt virvla- och klämeffekter
  • Складні дії над контурами та ефекти, зокрема набір булівських операцій, спрощення контуру, заокруглення та покращення, ефекти вихору та втягування
  • xxComplex path operations and effects like boolean set operations, path flattening, rounding and refining as well as whirl/pinch effectsxx
  • 复杂路径操作和效果,例如布尔运算,路径扁平化,简化和优化,以及旋转和揉捏特效
  • Extensible by writing plugins for new tools, shapes and dockers
  • Extensible pisanjem dodataka za novim alatima , oblika i modnog brenda Dockers
  • Ampliable mitjançant l'escriptura de connectors per eines noves, formes i acobladors
  • Ampliable mitjançant l'escriptura de connectors per eines noves, formes i acobladors
  • Erweiterbar durch das Schreiben von Modulen für neue Werkzeuge, Objekte und andockbaren Dialogen
  • Extensible by writing plugins for new tools, shapes and dockers
  • Extensible mediante la escritura de complementos para nuevas herramientas, formas y paneles
  • Laiendamisvõimalus pluginate kirjutamise abil uute tööriistade, kujundite ja dokkide tarbeks
  • Laajennettavissa kirjoittamalla liitännäisiä uusille työkaluille, muodoille ja telakoille
  • Extensible par l'écriture de modules pour de nouveaux outils, formes et conteneurs
  • Permite ampliar as súas funcionalidades mediante complementos de ferramentas novas, de formas e de docas.
  • Espandibile tramite la scrittura di estensioni per nuovi strumenti, forme e aree di aggancio
  • Uit te breiden dor het schrijven van plug-ins voor nieuwe hulpmiddelen, vormen en verankering
  • Rozszerzalne wtyczki zapisu dla nowych narzędzi, kształtów i dokowań
  • Modular, através da criação de 'plugins' para novas ferramentas, formas e áreas acopláveis
  • Expansível através da criação de plugins para novas ferramentas, formas e áreas acopláveis
  • Rozšíriteľný pomocou písania pluginov pre nové nástroje, tvary a dockery
  • Utökningsbart genom att skriva insticksprogram för nya verktyg, former och paneler
  • Можливість розширення додатками нових інструментів, форм та панелей.
  • xxExtensible by writing plugins for new tools, shapes and dockersxx
  • 可通过工具,形状和停靠栏插件扩展功能
http://www.calligra.org/karbon/ https://bugs.kde.org/enter_bug.cgi?format=guided&product=karbon https://cdn.kde.org/screenshots/karbon/karbon.png KDE calligrakarbon
diff --git a/karbon/stencils/Cisco/government_building.desktop b/karbon/stencils/Cisco/government_building.desktop index 3b3dcb17d76..c976a304b6f 100644 --- a/karbon/stencils/Cisco/government_building.desktop +++ b/karbon/stencils/Cisco/government_building.desktop @@ -1,34 +1,34 @@ [Desktop Entry] Name=Government Building Name[bg]=Правителствена сграда Name[bs]=Zgrada vlade Name[ca]=Edifici governamental Name[ca@valencia]=Edifici governamental Name[da]=Regeringsbygning Name[de]=Regierungsgebäude Name[el]=Κυβερνητικό κτήριο Name[en_GB]=Government Building Name[es]=Edificio gubernamental Name[et]=Valitsushoone Name[eu]=Gobernuaren eraikina Name[fr]=Government Building -Name[gl]=Edificio gubernamental +Name[gl]=Edificio gobernamental Name[hu]=Kormányzati épület Name[it]=Edificio governativo Name[kk]=Үкіметтік мекеме Name[lt]=Vyriausybinis pastatas Name[nb]=Offentlig bygning Name[nds]=Regerengebüüd Name[nl]=Overheidsgebouw Name[pl]=Rządowa budowla Name[pt]=Edifício Governamental Name[pt_BR]=Edifício governamental Name[ru]=Правительственное здание Name[sk]=Vládna budova Name[sl]=Vladna stavba Name[sv]=Statlig byggnad Name[tr]=Hükümet Binası Name[uk]=Урядова будівля Name[x-test]=xxGovernment Buildingxx Name[zh_CN]=政府建筑 Name[zh_TW]=政府建築 diff --git a/karbon/stencils/Cisco/university.desktop b/karbon/stencils/Cisco/university.desktop index 905a6ac7ead..174ed62e4b8 100644 --- a/karbon/stencils/Cisco/university.desktop +++ b/karbon/stencils/Cisco/university.desktop @@ -1,42 +1,42 @@ [Desktop Entry] Name=University Name[bg]=Университет Name[bs]=Univerzitet Name[ca]=Universitat Name[ca@valencia]=Universitat Name[cs]=Univerzita Name[da]=Universitet Name[de]=Universität Name[el]=Πανεπιστήμιο Name[en_GB]=University Name[eo]=Universitato Name[es]=Universidad Name[et]=Ülikool Name[eu]=Unibertsitatea Name[fi]=Yliopisto Name[fr]=Université -Name[gl]=Universidade +Name[gl]=Universidade Name[hu]=Egyetem Name[ia]=Universitate Name[it]=Università Name[ja]=大学 Name[kk]=Университет Name[ko]=대학교 Name[lt]=Universitetas Name[mr]=विद्यापीठ Name[nb]=Universitet Name[nds]=Universiteet Name[nl]=Universiteit Name[pl]=Uniwersytet Name[pt]=Universidade Name[pt_BR]=Universidade Name[ru]=Университет Name[sk]=Univerzita Name[sl]=Univerza Name[sv]=Universitet Name[tr]=Üniversite Name[ug]=ئالىي مەكتەپ Name[uk]=Університет Name[x-test]=xxUniversityxx Name[zh_CN]=大学 Name[zh_TW]=大學 diff --git a/karbon/stencils/Cisco/wireless.desktop b/karbon/stencils/Cisco/wireless.desktop index 8668ccfe723..5f4bb029b4a 100644 --- a/karbon/stencils/Cisco/wireless.desktop +++ b/karbon/stencils/Cisco/wireless.desktop @@ -1,41 +1,41 @@ [Desktop Entry] Name=Wireless Name[bg]=Безжично Name[bs]=Wireless -Name[ca]=Sense fils -Name[ca@valencia]=Sense fils +Name[ca]=Sense fil +Name[ca@valencia]=Sense fil Name[cs]=Bezdrátové Name[da]=Trådløs Name[de]=Drahtlos Name[el]=Ασύρματο Name[en_GB]=Wireless Name[eo]=Sendrata Name[es]=Inalámbrico Name[et]=Juhtmeta Name[eu]=Haririk gabekoa Name[fi]=Langaton Name[fr]=Wireless Name[ga]=Gan Sreang Name[gl]=Sen fíos Name[hu]=Vezeték nélküli Name[ia]=Wireless (Sin Cablos) Name[it]=Wireless Name[ja]=ワイヤレス Name[kk]=Сымсыз Name[ko]=무선 Name[mr]=वायरलेस Name[nb]=Trådløs Name[nl]=Draadloos Name[pl]=Bezprzewodowa Name[pt]=Sem-Fios Name[pt_BR]=Rede sem fio Name[ru]=Беспроводное Name[sk]=Bezdrôtové Name[sl]=Brezžično Name[sv]=Trådlös Name[tr]=Kablosuz Name[ug]=سىمسىز Name[uk]=Бездротовий Name[x-test]=xxWirelessxx Name[zh_CN]=无线 Name[zh_TW]=無線 diff --git a/karbon/stencils/Cisco/wireless_bridge.desktop b/karbon/stencils/Cisco/wireless_bridge.desktop index 15f2100c04c..1ef30c9d336 100644 --- a/karbon/stencils/Cisco/wireless_bridge.desktop +++ b/karbon/stencils/Cisco/wireless_bridge.desktop @@ -1,35 +1,35 @@ [Desktop Entry] Name=Wireless Bridge Name[bg]=Безжичен мост Name[bs]=Bežični most -Name[ca]=Pont sense fils -Name[ca@valencia]=Pont sense fils +Name[ca]=Pont sense fil +Name[ca@valencia]=Pont sense fil Name[da]=Trådløs bro Name[de]=Drahtlose Brücke Name[el]=Γέφυρα ασύρματης επικοινωνίας Name[en_GB]=Wireless Bridge Name[es]=Puente inalámbrico Name[et]=Juhtmeta side sild Name[eu]=Haririk gabeko zubia Name[fi]=Langaton silta Name[fr]=Wireless Bridge Name[gl]=Ponte sen fíos Name[hu]=Vezeték nélküli híd Name[it]=Bridge wireless Name[ja]=ワイヤレスブリッジ Name[kk]=Сымсыз көпір Name[lt]=Belaidis tiltas Name[nb]=Trådløs bru Name[nds]=Funknettwark-Brüch Name[nl]=Wireless Bridge Name[pl]=Mostek bezprzewodowy Name[pt]=Ponte Sem-Fios Name[pt_BR]=Ponte sem fio Name[ru]=Беспроводной мост Name[sk]=Bezdrôtový most Name[sv]=Trådlös brygga Name[tr]=Kablosuz Köprü Name[uk]=Бездротовий міст Name[x-test]=xxWireless Bridgexx Name[zh_CN]=无线网络桥接器 Name[zh_TW]=無線橋接器 diff --git a/karbon/stencils/Cisco/wireless_connectivity.desktop b/karbon/stencils/Cisco/wireless_connectivity.desktop index e7f5f7a64a7..3f8c68fb024 100644 --- a/karbon/stencils/Cisco/wireless_connectivity.desktop +++ b/karbon/stencils/Cisco/wireless_connectivity.desktop @@ -1,34 +1,34 @@ [Desktop Entry] Name=Wireless Connectivity Name[bg]=Безжична свързаност Name[bs]=Bežična povezivanja -Name[ca]=Connectivitat sense fils -Name[ca@valencia]=Connectivitat sense fils +Name[ca]=Connectivitat sense fil +Name[ca@valencia]=Connectivitat sense fil Name[da]=Trådløs tilslutning Name[de]=Kabellose Anschlussmöglichkeit Name[el]=Συνδεσιμότητα ασύρματης επικοινωνίας Name[en_GB]=Wireless Connectivity Name[es]=Conectividad inalámbrica Name[et]=Juhtmeta ühendus Name[eu]=Haririk gabeko konektagarritasuna Name[fi]=Langaton yhteys Name[fr]=Connectivité Wireless Name[gl]=Conectividade sen fíos Name[hu]=Vezeték nélküli összekapcsolhatóság Name[it]=Connettività wireless Name[kk]=Сымсыз қосылым Name[lt]=Bevielis ryšys Name[nb]=Trådløs forbindelse Name[nl]=Draadloze verbinding Name[pl]=Połączenie bezprzewodowe Name[pt]=Conectividade Sem-Fios Name[pt_BR]=Conectividade sem fio Name[ru]=Беспроводное подключение Name[sk]=Bezdrôtová konektivita Name[sl]=Brezžična povezljivost Name[sv]=Trådlös anslutning Name[tr]=Kablosuz Bağlantı Name[uk]=Можливість бездротового з'єднання Name[x-test]=xxWireless Connectivityxx Name[zh_CN]=无线网络连通性 Name[zh_TW]=無線連線 diff --git a/karbon/stencils/Cisco/wireless_location_appliance.desktop b/karbon/stencils/Cisco/wireless_location_appliance.desktop index 33d1f09f434..1846ae0b499 100644 --- a/karbon/stencils/Cisco/wireless_location_appliance.desktop +++ b/karbon/stencils/Cisco/wireless_location_appliance.desktop @@ -1,29 +1,29 @@ [Desktop Entry] Name=Wireless Location Appliance Name[bs]=Bežični Uređaj za Lokaciju -Name[ca]=Aplicació d'ubicació sense fils -Name[ca@valencia]=Aplicació d'ubicació sense fils +Name[ca]=Aplicació d'ubicació sense fil +Name[ca@valencia]=Aplicació d'ubicació sense fil Name[da]=Wireless Location Appliance Name[de]=Drahtlose „Location Appliance“ Name[el]=Συσκευή ασύρματης θέσης Name[en_GB]=Wireless Location Appliance Name[es]=Dispositivo de localización inalámbrico Name[et]=Wireless Location Appliance Name[eu]=Haririk gabeko kokaleku-gailua Name[fr]=Wireless Location Appliance Name[gl]=Dispositivo de localización sen fíos Name[it]=Wireless Location Appliance Name[kk]=Орнын анықтау сымсыз аппараты Name[nb]=Trådløst lokaliseringsutstyr Name[nl]=Appliance voor draadloze locatie Name[pl]=Zastosowanie bezprzewodowego położenia Name[pt]=Módulo Localização Sem-Fios Name[pt_BR]=Aplicação de localização da rede sem fio Name[ru]=Устройство беспроводного расположения Name[sk]=Prostriedok bezdrôtovej polohy Name[sv]=Trådlös lokaliseringsutrustning Name[tr]=Kablosuz Konum Aracı Name[uk]=Пристрій бездротового розташування Name[x-test]=xxWireless Location Appliancexx Name[zh_CN]=无线网络位置器械 Name[zh_TW]=無線位置裝置 diff --git a/karbon/stencils/Cisco/wireless_router.desktop b/karbon/stencils/Cisco/wireless_router.desktop index 311df78c76e..39676eae4aa 100644 --- a/karbon/stencils/Cisco/wireless_router.desktop +++ b/karbon/stencils/Cisco/wireless_router.desktop @@ -1,35 +1,35 @@ [Desktop Entry] Name=Wireless router Name[bs]=Bežični ruter -Name[ca]=Encaminador sense fils -Name[ca@valencia]=Encaminador sense fils +Name[ca]=Encaminador sense fil +Name[ca@valencia]=Encaminador sense fil Name[da]=Trådløs router Name[de]=Funk-Router Name[el]=Ασύρματος δρομολογητής Name[en_GB]=Wireless router Name[es]=Enrutador inalámbrico Name[et]=Juhtmeta side marsruuter Name[eu]=Haririk gabeko bideratzailea Name[fi]=Langaton reititin Name[fr]=Routeur Wireless Name[gl]=Encamiñador sen fíos Name[hu]=Vezeték nélküli router Name[it]=Router wireless Name[ja]=ワイヤレスルータ Name[kk]=Сымсыз маршруттауышы Name[lt]=Bevielis maršrutizatorius Name[nb]=Trådløs ruter Name[nds]=Funknettweger Name[nl]=Draadloze router Name[pl]=Bezprzewodowy router Name[pt]=Encaminhador sem-fios Name[pt_BR]=Roteador de rede sem fio Name[ru]=Маршрутизатор беспроводной сети Name[sk]=Bezdrôtový router Name[sl]=Brezžični usmerjevalnik Name[sv]=Trådlös router Name[tr]=Kablosuz yönlendirici Name[uk]=Бездротовий маршрутизатор Name[x-test]=xxWireless routerxx Name[zh_CN]=无线路由器 Name[zh_TW]=無線路由器 diff --git a/karbon/stencils/Cisco/wireless_transport.desktop b/karbon/stencils/Cisco/wireless_transport.desktop index 263789c15e8..7dd3e47d98e 100644 --- a/karbon/stencils/Cisco/wireless_transport.desktop +++ b/karbon/stencils/Cisco/wireless_transport.desktop @@ -1,33 +1,33 @@ [Desktop Entry] Name=Wireless Transport Name[bg]=Безжичен пренос Name[bs]=Bežični transport -Name[ca]=Transport sense fils -Name[ca@valencia]=Transport sense fils +Name[ca]=Transport sense fil +Name[ca@valencia]=Transport sense fil Name[da]=Wireless Transport Name[de]=Drahtlose Übertragung Name[el]=Ασύρματη μεταφορά Name[en_GB]=Wireless Transport Name[es]=Transporte inalámbrico Name[et]=Juhtmeta side Name[eu]=Haririk gabeko garraioa Name[fr]=Wireless Transport Name[gl]=Transporte sen fíos Name[hu]=Vezeték nélküli adatátvitel Name[it]=Trasporto wireless Name[kk]=Сымсыз тасымал Name[lt]=Bevielė sąsaja Name[nb]=Trådløs transport Name[nds]=Funköverdregen Name[nl]=Draadloos transport Name[pl]=Bezprzewodowe przesyłanie Name[pt]=Transporte Sem-Fios Name[pt_BR]=Transporte sem fio Name[ru]=Беспроводной транспорт Name[sk]=Bezdrôtový prenos Name[sv]=Trådlös överföring Name[tr]=Kablosuz Aktarım Name[uk]=Бездротова передача Name[x-test]=xxWireless Transportxx Name[zh_CN]=无线网络传输 Name[zh_TW]=無線傳輸 diff --git a/karbon/stencils/Scenegraph/callback.desktop b/karbon/stencils/Scenegraph/callback.desktop index bb2026e54f6..5af7d15cf15 100644 --- a/karbon/stencils/Scenegraph/callback.desktop +++ b/karbon/stencils/Scenegraph/callback.desktop @@ -1,33 +1,33 @@ [Desktop Entry] Name=callback Name[bs]=povratni poziv Name[ca]=crida de retorn Name[ca@valencia]=crida de retorn Name[cs]=zpětné volání Name[da]=callback Name[de]=Rückruf Name[el]=επανάκληση Name[en_GB]=callback Name[es]=devolución de llamada Name[et]=Tagasiside Name[eu]=atzeradeia Name[fr]=callback -Name[gl]=Volta +Name[gl]=resposta Name[hu]=visszahívás Name[it]=callback Name[ja]=コールバック Name[kk]=қарсы шақыру Name[nb]=tilbakekall Name[nds]=Torüchroop Name[nl]=terugbelverzoek Name[pl]=polecenie zwrotne Name[pt]=retorno Name[pt_BR]=retorno Name[ru]=Возврат Name[sk]=spätné volanie Name[sl]=povratni klic Name[sv]=återanrop Name[tr]=geriçağırma Name[uk]=Повернення Name[x-test]=xxcallbackxx Name[zh_TW]=回撥 diff --git a/libs/flake/flake.desktop b/libs/flake/flake.desktop index 18e81aad444..88e92880998 100644 --- a/libs/flake/flake.desktop +++ b/libs/flake/flake.desktop @@ -1,92 +1,92 @@ [Desktop Entry] Name=Flake Plugin Name[bs]=Dodatak za pahuljicu Name[ca]=Connector Flake Name[ca@valencia]=Connector Flake Name[cs]=Modul Flake Name[da]=Flake-plugin Name[de]=Flake-Modul Name[el]=Πρόσθετο flake Name[en_GB]=Flake Plugin Name[es]=Complemento de Flake Name[et]=Helbekese plugin Name[eu]=Flake plugina Name[fa]=وصله Flake Name[fi]=Flake-liitännäinen Name[fr]=Module externe de flocons Name[fy]=Flake Plugin Name[ga]=Breiseán Flake Name[gl]=Complemento de Flake Name[hi]=फ्लेक प्लगइन Name[hne]=फ्लेक प्लगइन Name[hr]=Priključak Flake Name[hu]=Pehely bővítmény Name[it]=Estensione Flake Name[ja]=Flake プラグイン Name[kk]=Flake плагині Name[lv]=Flake spraudnis Name[ms]=Plug masuk Flake Name[nb]=Flake programtillegg Name[nds]=Flake-Moduul Name[ne]=फ्लेक प्लगइन Name[nl]=Flake-plug-in Name[pl]=Wtyczka płatków Name[pt]='Plugin' do Flake Name[pt_BR]=Plugin do Flake Name[ru]=Модуль Flake Name[sk]=Vločkový plugin Name[sl]=Vstavek Flake Name[sv]=Flake-insticksprogram Name[tr]=Flake Eklentisi Name[uk]=Додаток Flake Name[wa]=Tchôke-divins Flake Name[x-test]=xxFlake Pluginxx Name[zh_CN]=Flake 插件 Name[zh_TW]=Flake 外掛程式 Type=ServiceType X-KDE-ServiceType=Calligra/Flake Comment=A plugin that contains a set of a shape and a tool Comment[bs]=Dodatak koji sadrži kolekciju oblika i alata Comment[ca]=Un connector que conté un conjunt d'una forma i una eina Comment[ca@valencia]=Un connector que conté un conjunt d'una forma i una eina Comment[cs]=Modul, jež obsahuje sadu tvarů a nástroj Comment[da]=Et plugin som består af et sæt af en form og et værktøj Comment[de]=Ein Modul, das einen Satz an Objekten und ein Werkzeug enthält Comment[el]=Ένα πρόσθετο που περιέχει ένα σύνολο σχήματος και εργαλείου Comment[en_GB]=A plugin that contains a set of a shape and a tool Comment[es]=Un complemento que contiene un conjunto de una forma y una herramienta Comment[et]=Kujundeid ja tööriistu sisaldav plugin Comment[eu]=Forma multzo bat eta tresna bat dituen plugina Comment[fi]=Liitännäinen, joka sisältää muodon ja vastaavan työkalun Comment[fr]=Un module externe qui contient un ensemble de formes et un outil Comment[ga]=Breiseán a bhfuil giuirléid agus uirlis ann -Comment[gl]=Complemento que contén un grupo de obxectos e unha ferramenta. +Comment[gl]=Complemento que contén un grupo de obxectos e unha ferramenta. Comment[hi]=एक प्लगइन जिसमें आकात तथा औजार का सेट है Comment[hne]=एक प्लगइन जेमां आकात अउ औजार के सेट हे Comment[it]=Un'estensione contenente un insieme di una forma e uno strumento Comment[ja]=シェイプとツールのセットを含むプラグイン Comment[kk]=Бір қатар қалып пен құралдан тұратын плагині Comment[lv]=Spraudnis, kas satur figūras un rīka komplektu Comment[nb]=Et programtillegg som inneholder en form med tilhørende verktøy Comment[nds]=En Moduul, dat en Formsett un en Warktüüch bargt Comment[ne]=आकार र उपकरण सेट समाविष्ट गर्ने एउटा प्लगइन Comment[nl]=Een plug-in, die een aantal vormen en gereedschappen bevat Comment[pl]=Wtyczka, która zawiera zestaw kształtu i narzędzi Comment[pt]=Um 'plugin' que contém um conjunto de uma forma e uma ferramenta Comment[pt_BR]=Um plugin que contém um conjunto de uma forma e uma ferramenta Comment[ru]=Модуль, содержащий набор фигур и инструмент. Comment[sk]=Plugin ktorý obsahuje sadu tvaru a nástroja Comment[sv]=Ett insticksprogram som innehåller en formmängd och ett verktyg Comment[ta]=ஒரு வடிவம் மற்றும் கருவியை எகொண்டது சொருகி எனப்படும் Comment[tr]=Bir şekil de bir aracı içeren bir eklenti Comment[uk]=Додаток, що містить набір з форми та інструмента Comment[wa]=On tchôke-divins k' a on hopea d' fômes eyet usteyes Comment[x-test]=xxA plugin that contains a set of a shape and a toolxx Comment[zh_CN]=一个包含一组形状和工具的插件 Comment[zh_TW]=包含元件與工具集的外掛程式 [PropertyDef::X-Flake-MinVersion] Type=int [PropertyDef::X-Flake-PluginVersion] Type=int [PropertyDef::X-KDE-PluginInfo-Name] Type=QString diff --git a/libs/text/texteditingplugin.desktop b/libs/text/texteditingplugin.desktop index 0cd981e9f0f..a41d077aea4 100644 --- a/libs/text/texteditingplugin.desktop +++ b/libs/text/texteditingplugin.desktop @@ -1,82 +1,82 @@ [Desktop Entry] Name=Text Editing plugin for the Calligra text tool Name[bs]=Plugin za editovanje teksta za Calligra tekst alat Name[ca]=Connector d'edició de text per a l'eina de text del Calligra Name[ca@valencia]=Connector d'edició de text per a l'eina de text del Calligra Name[cs]=Modul pro úpravy textu nástroje Calligra pro text Name[da]=Plugin til tekstredigering til Calligras tekstværktøj Name[de]=Modul zur Textbearbeitung für das Calligra-Textwerkzeug Name[el]=Πρόσθετο επεξεργασίας κειμένου για το εργαλείο κειμένου του Calligra Name[en_GB]=Text Editing plugin for the Calligra text tool Name[es]=Complemento de edición de texto para la herramienta de texto de Calligra Name[et]=Calligra tekstitööriista teksti redigeerimise plugin Name[eu]=Testua editatzeko plugina Calligra testu-tresnarako Name[fi]=Tekstinmuokkausliitännäinen Calligran tekstityökalua varten Name[fr]=Module externe d'édition de texte pour l'outil texte de Calligra -Name[gl]=Complemento de edición de texto para a ferramenta de texto de Calligra +Name[gl]=Complemento de edición de texto para a ferramenta de texto de Calligra Name[hu]=Szövegszerkesztő bővítmény a Calligra szövegeszközhöz Name[it]=Estensione di modifica del testo per lo strumento di testo di Calligra Name[ja]=Calligra テキストツールのためのテキスト編集プラグイン Name[kk]=Calligra мәтін құралына арналған мәтін өңдеу плагині Name[ko]=Calligra 텍스트 도구용 텍스트 편집 플러그인 Name[nb]=Programtillegg for tekstredigering for Calligra tekstverktøy Name[nds]=Textbewerk-Moduul för dat Calligra-Textwarktüüch Name[nl]=Tekstbewerkingsplug-in voor het tekstgereedschap van Calligra Name[pl]=Wtyczka edycji tekstu dla narzędzia tekstu Calligra Name[pt]='Plugin' de edição de texto para a ferramenta de texto do Calligra Name[pt_BR]=Plugin de edição de texto para a ferramenta de texto do Calligra Name[ru]=Модуль редактирования текста для Calligra Name[sk]=Plugin textového editora pre textový nástroj Calligra Name[sv]=Insticksprogram med textredigering för Calligra textverktyg Name[tr]=Calligra metin aracı için Metin Düzenleme eklentisi Name[uk]=Додаток редагування тексту для текстового редактора Calligra Name[x-test]=xxText Editing plugin for the Calligra text toolxx Name[zh_CN]=Calligra 文本工具的文本编辑插件 Name[zh_TW]=Calligra 文字工具的文字編輯外掛程式 Type=ServiceType X-KDE-ServiceType=Calligra/Text-EditingPlugin Comment=Definition of a text-editing plugin Comment[bs]=Definicija plugina za editovanje teksta Comment[ca]=Definició d'un connector d'edició de text Comment[ca@valencia]=Definició d'un connector d'edició de text Comment[da]=Definition af et plugin til tekstredigering Comment[de]=Definition eines Moduls zur Textbearbeitung Comment[el]=Καθορισμός ενός πρόσθετου επεξεργασίας κειμένου Comment[en_GB]=Definition of a text-editing plugin Comment[es]=Definición de un complemento de edición de texto Comment[et]=Teksti redigeerimise plugina definitsioon Comment[eu]=Testua editatzeko plugin baten definizioa Comment[fi]=Tekstinmuokkausliitännäisen määrittely Comment[fr]=Définition d'un module externe d'édition de texte Comment[gl]=Definición dun complemento de edición de texto Comment[hi]=पाठ संपादन प्लगइन की परिभाषा Comment[hne]=पाठ संपादन प्लगइन के परिभासा Comment[hu]=Egy szövegszerkesztő bővítmény meghatározása Comment[it]=Definizione di un'estensione di modifica di testo Comment[ja]=テキスト編集プラグインの定義 Comment[kk]=Мәтін-өңдеу плагинінің анықтамасы Comment[ko]=텍스트 편집 플러그인 정의 Comment[lv]=Teksta rediģēšanas spraudņa definīcija Comment[nb]=Definisjon av et programtillegg for tekstredigering Comment[nds]=Definitschoon vun en Textbewerken-Moduul Comment[ne]=पाठ सम्पादन प्लगइनको परिभाषा Comment[nl]=Definitie van een tekstinvoerplug-in Comment[pl]=Definicja wtyczki edytowania tekstu Comment[pt]=Definição de um 'plugin' de edição de texto Comment[pt_BR]=Definição de um plugin de edição de texto Comment[ru]=Определение объекта для редактирования текста Comment[sk]=Definícia pluginu na editáciu textu Comment[sv]=Definition av ett Insticksprogram för textredigering Comment[ta]=உரை-தொகுப்பானின் சொருகல் வரையறை Comment[tr]=Metin düzenleme eklentisi tanımı Comment[uk]=Визначення додатка для зміни тексту Comment[wa]=Definixha d' on tchôke-divins d' aspougnaedje di tecse Comment[x-test]=xxDefinition of a text-editing pluginxx Comment[zh_CN]=文本编辑插件的定义 Comment[zh_TW]=文字編輯外掛程式定義 [PropertyDef::X-KoText-MinVersion] Type=int [PropertyDef::X-KoText-PluginVersion] Type=int [PropertyDef::X-KDE-PluginInfo-Name] Type=QString diff --git a/plan/about/aboutpage.cpp b/plan/about/aboutpage.cpp index 62b220ec5d1..6207764bc41 100644 --- a/plan/about/aboutpage.cpp +++ b/plan/about/aboutpage.cpp @@ -1,323 +1,322 @@ /* This file is part of the KDE project Copyright (C) 2009, 2011 Dag Andersen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "aboutpage.h" #include "kptproject.h" #include #include #include #include #include #include #include #include #include #include #include KPlatoAboutPage::KPlatoAboutPage() : m_project( 0 ) { } KPlatoAboutPage::~KPlatoAboutPage() { } QString KPlatoAboutPage::main() { KIconLoader *iconloader = KIconLoader::global(); QString res = loadFile( QStandardPaths::locate(QStandardPaths::GenericDataLocation, "calligraplan/about/main.html" )); if ( res.isEmpty() ) { return res; } const char *const up_icon_id = koIconNameCStr("go-up"); const QString up_icon_path = iconloader->iconPath(up_icon_id, KIconLoader::Small); const char *const continue_icon_id = (QApplication::isRightToLeft() ? koIconNameCStr("go-previous") : koIconNameCStr("go-next")); const QString continue_icon_path = iconloader->iconPath(continue_icon_id, KIconLoader::Small); QString icon_up = ""; QString icon_path = ""; res = res.arg( QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kf5/infopage/kde_infopage.css" ) ); if ( qApp->layoutDirection() == Qt::RightToLeft ) res = res.arg( "@import \"%1\";" ).arg( QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kf5/infopage/kde_infopage_rtl.css" ) ); else res = res.arg( "" ); res = res.arg( i18n( "Plan" ) ) .arg( i18nc("KDE 4 tag line, see http://kde.org/img/kde40.png", "Be free.") ) .arg( i18n("Plan is a Project Planning and Management application.") ) .arg( i18n("Welcome to Plan.") ) .arg( i18n("These introductory pages should give you an idea of how to use Plan and what you can use it for.") ) .arg( icon_path ).arg( i18n( "A short introduction." ) ) .arg( icon_path ).arg( i18n( "Tips on how to manipulate and inspect data." ) ) .arg( icon_path ).arg( i18n( "A small tutorial to get you started." ) ) .arg( icon_up ).arg( i18n( "Close" ) ) .arg( i18n( "Note: To view these pages when you are in other parts of Plan, choose the menu option Help -> Introduction to Plan." ) ) ; return res; } QString KPlatoAboutPage::intro() { KIconLoader *iconloader = KIconLoader::global(); QString res = loadFile( QStandardPaths::locate(QStandardPaths::GenericDataLocation, "calligraplan/about/intro.html" )); if ( res.isEmpty() ) { return res; } const char *const up_icon_id = koIconNameCStr("go-up"); const QString up_icon_path = iconloader->iconPath(up_icon_id, KIconLoader::Small); QString icon_up = ""; const char *const prev_icon_id = koIconNameCStr("go-previous"); const QString prev_icon_path = iconloader->iconPath(prev_icon_id, KIconLoader::Small); const char *const next_icon_id = koIconNameCStr("go-next"); const QString next_icon_path = iconloader->iconPath(next_icon_id, KIconLoader::Small); const QString continue_icon_path = QApplication::isRightToLeft() ? prev_icon_path : next_icon_path; const QString back_icon_path = QApplication::isRightToLeft() ? next_icon_path : prev_icon_path; res = res.arg( QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kf5/infopage/kde_infopage.css" ) ); if ( qApp->layoutDirection() == Qt::RightToLeft ) res = res.arg( "@import \"%1\";" ).arg( QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kf5/infopage/kde_infopage_rtl.css" ) ); else res = res.arg( "" ); res = res.arg( i18n("Plan is a Project Planning and Management application.") ) .arg( i18n( "Plan is intended for managing moderately large projects with multiple resources. To enable you to model your project adequately, Plan offers different types of task dependencies and timing constraints. Usually you will define your tasks, estimate the effort needed to perform each task, allocate resources and then schedule the project according to the dependency network and resource availability." - "

You can find more information in the documentation " - "or online at http://www.calligra.org/plan

" + "

You can find more information online at https://userbase.kde.org/Plan

" ) ) .arg( icon_up ) .arg( i18n( "Close" ) ) .arg( "" ).arg( continue_icon_path ) .arg( i18n( "Next: Tips" ) ) ; return res; } QString KPlatoAboutPage::tips() { QString res = loadFile( QStandardPaths::locate(QStandardPaths::GenericDataLocation, "calligraplan/about/tips.html" )); if ( res.isEmpty() ) { return res; } KIconLoader *iconloader = KIconLoader::global(); QString viewmag_icon_path = iconloader->iconPath(koIconNameCStr("zoom-in"), KIconLoader::Small); QString history_icon_path = iconloader->iconPath(koIconNameCStr("view-history"), KIconLoader::Small); QString openterm_icon_path = iconloader->iconPath(koIconNameCStr("utilities-terminal"), KIconLoader::Small); QString locationbar_erase_rtl_icon_path = iconloader->iconPath(koIconNameCStr("edit-clear-locationbar-rtl"), KIconLoader::Small); QString locationbar_erase_icon_path = iconloader->iconPath(koIconNameCStr("edit-clear-locationbar-ltr"), KIconLoader::Small); QString window_fullscreen_icon_path = iconloader->iconPath(koIconNameCStr("view-fullscreen"), KIconLoader::Small); QString view_left_right_icon_path = iconloader->iconPath(koIconNameCStr("view-split-left-right"), KIconLoader::Small); const char *const up_icon_id = koIconNameCStr("go-up"); const QString up_icon_path = iconloader->iconPath(up_icon_id, KIconLoader::Small); QString icon_up = ""; const char *const prev_icon_id = koIconNameCStr("go-previous"); const QString prev_icon_path = iconloader->iconPath(prev_icon_id, KIconLoader::Small); const char *const next_icon_id = koIconNameCStr("go-next"); const QString next_icon_path = iconloader->iconPath(next_icon_id, KIconLoader::Small); const QString continue_icon_path = QApplication::isRightToLeft() ? prev_icon_path : next_icon_path; const QString back_icon_path = QApplication::isRightToLeft() ? next_icon_path : prev_icon_path; res = res.arg( QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kf5/infopage/kde_infopage.css" ) ); if ( qApp->layoutDirection() == Qt::RightToLeft ) res = res.arg( "@import \"%1\";" ).arg( QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kf5/infopage/kde_infopage_rtl.css" ) ); else res = res.arg( "" ); res = res.arg( i18n("Editing tips.") ) .arg( i18n( "
To edit project data, different views and editors can be selected in the View Selector docker." "
The views are generally used to inspect data after the project has been scheduled. No data will appear in the views if the project has not been scheduled. Scheduling is done in the Schedules editor." "
You can edit attributes in the various editors by selecting the item you want to edit (doubleclick or press F2), or open a dialog using the context menu." "" ) ) .arg( icon_up ) .arg( i18n( "Close" ) ) .arg( "" ).arg( continue_icon_path ) .arg( i18n( "Next: Create a simple project" ) ) ; return res; } QString KPlatoAboutPage::tutorial( const QString &header, const QString &text, const QString &nextpage, const QString &nexttext) { QString res = loadFile( QStandardPaths::locate(QStandardPaths::GenericDataLocation, "calligraplan/about/tutorial.html" )); if ( res.isEmpty() ) { return res; } KIconLoader *iconloader = KIconLoader::global(); const char *const up_icon_id = koIconNameCStr("go-up"); const QString up_icon_path = iconloader->iconPath(up_icon_id, KIconLoader::Small); QString icon_up = ""; const char *const prev_icon_id = koIconNameCStr("go-previous"); const QString prev_icon_path = iconloader->iconPath(prev_icon_id, KIconLoader::Small); const char *const next_icon_id = koIconNameCStr("go-next"); const QString next_icon_path = iconloader->iconPath(next_icon_id, KIconLoader::Small); const QString continue_icon_path = QApplication::isRightToLeft() ? prev_icon_path : next_icon_path; const QString back_icon_path = QApplication::isRightToLeft() ? next_icon_path : prev_icon_path; res = res.arg( QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kf5/infopage/kde_infopage.css" ) ); if ( qApp->layoutDirection() == Qt::RightToLeft ) res = res.arg( "@import \"%1\";" ).arg( QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kf5/infopage/kde_infopage_rtl.css" ) ); else res = res.arg( "" ); res = res.arg( header ) .arg( text ) .arg( "about:close" ) .arg( icon_up ) .arg( i18n("Close") ) .arg( "about:plan/" + nextpage ) .arg( "" ).arg( continue_icon_path ) .arg( nexttext ) ; return res; } QString KPlatoAboutPage::tutorial1() { return tutorial( i18n("Create the simplest project ever."), i18nc( "1=datetime", "Select the task editor Editors->Tasks:" "
    " "
  • Create a task by selecting Add Task in the toolbar.
  • " "
  • Set Type to Duration.
  • " "
  • Set Estimate to 8 hours.
  • " "
  • Set Constraint to As Soon As Possible.
  • " "
" "Select the schedules editor Editors->Schedules:" "
    " "
  • Create a schedule by selecting Add Schedule in the toolbar.
  • " "
  • Calculate the schedule by selecting Calculate in the toolbar.
  • " "
" "The task should now have been scheduled to start %1 with a duration of 8 hours. You can check this by selecting the Gantt chart Views->Gantt." , KFormat().formatRelativeDateTime(m_project->startTime(), QLocale::LongFormat) ), "tutorial2", i18n( "Next: Resource allocation" ) ); } QString KPlatoAboutPage::tutorial2() { DateTime dt = m_project->constraintStartTime(); if ( m_project->defaultCalendar() ) { dt = m_project->defaultCalendar()->firstAvailableAfter( dt, m_project->constraintEndTime() ); } return tutorial( i18n("Allocate a resource to the task."), i18nc( "1=datetime", "Select the task editor Editors->Tasks:" "
    " "
  • Enter a name (e.g. 'John') in the Allocation column." " (Plan will automatically create a resource with name 'John' under resource group 'Resources'.
  • " "
  • Set Type to Effort.
  • " "
" "Now you need to schedule the project again with the new allocation:" "
Select the schedules editor Editors->Schedules and calculate the schedule by selecting Calculate in the toolbar." "

The task should be scheduled to start %1 with a duration of 8 hours. You can check this by selecting the Gantt chart Views->Gantt.

" , KFormat().formatRelativeDateTime(dt, QLocale::LongFormat) ), "main", i18n( "Next: Introduction" ) ); } void KPlatoAboutPage::generatePage( KHTMLPart &part, const QUrl &url) { QString html; if (url.url() == "about:plan/main") html = main(); else if (url.url() == "about:plan/intro") html = intro(); else if (url.url() == "about:plan/tips") html = tips(); else if (url.url() == "about:plan/tutorial") html = tutorial1(); else if (url.url() == "about:plan/tutorial1") html = tutorial1(); else if (url.url() == "about:plan/tutorial2") html = tutorial2(); else html = main(); part.begin(); part.write( html ); part.end(); } QString KPlatoAboutPage::loadFile( const QString& file ) { QString res; if ( file.isEmpty() ) return res; QFile f( file ); if ( !f.open( QIODevice::ReadOnly ) ) return res; QTextStream t( &f ); res = t.readAll(); // otherwise all embedded objects are referenced as about:/... QString basehref = QLatin1String("\n"); res.replace("", "\n\t" + basehref, Qt::CaseInsensitive); return res; } diff --git a/plan/kptmaindocument.cpp b/plan/kptmaindocument.cpp index dc4f9056263..7c82a042bc5 100644 --- a/plan/kptmaindocument.cpp +++ b/plan/kptmaindocument.cpp @@ -1,1454 +1,1496 @@ /* 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 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 "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 "kptcommand.h" #include "calligraplansettings.h" #include "kpttask.h" #include "KPlatoXmlLoader.h" #include "kptpackage.h" #include "kptworkpackagemergedialog.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_checkingForWorkPackages( false ), + m_loadingSharedProject(false), + m_isTaskModule(false) { Q_ASSERT(part); setAlwaysAllowSaving(true); m_config.setReadWrite( true ); 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); QTimer::singleShot ( 5000, this, SLOT(autoCheckForWorkPackages()) ); } MainDocument::~MainDocument() { qDeleteAll( m_schedulerPlugins ); if ( m_project ) { m_project->deref(); // deletes if last user } qDeleteAll( m_mergedPackages ); delete m_context; } 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, SIGNAL(pluginLoaded(QString,SchedulerPlugin*)), this, SLOT(addSchedulerPlugin(QString,SchedulerPlugin*))); loader->loadAllPlugins(); } void MainDocument::addSchedulerPlugin( const QString &key, SchedulerPlugin *plugin) { debugPlan<setConfig( m_config ); } void MainDocument::setProject( Project *project ) { if ( m_project ) { disconnect( m_project, SIGNAL(projectChanged()), this, SIGNAL(changed()) ); delete m_project; } m_project = project; if ( m_project ) { connect( m_project, SIGNAL(projectChanged()), this, SIGNAL(changed()) ); // m_project->setConfig( config() ); m_project->setSchedulerPlugins( m_schedulerPlugins ); } m_aboutPage.setProject( project ); emit changed(); } 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 ); 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 ); 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; QDomDocument document( "plan" ); document.appendChild( document.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) ); QDomElement doc = document.createElement( "plan" ); doc.setAttribute( "editor", "Plan" ); doc.setAttribute( "mime", "application/x-vnd.kde.plan" ); doc.setAttribute( "version", PLAN_FILE_SYNTAX_VERSION ); document.appendChild( doc ); // Save the project m_project->save( doc ); return document; } QDomDocument MainDocument::saveWorkPackageXML( const Node *node, long id, Resource *resource ) { debugPlan; QDomDocument document( "plan" ); document.appendChild( document.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) ); QDomElement doc = document.createElement( "planwork" ); doc.setAttribute( "editor", "Plan" ); doc.setAttribute( "mime", "application/x-vnd.kde.plan.work" ); doc.setAttribute( "version", PLANWORK_FILE_SYNTAX_VERSION ); doc.setAttribute( "plan-version", PLAN_FILE_SYNTAX_VERSION ); document.appendChild( doc ); // Work package info QDomElement wp = document.createElement( "workpackage" ); if ( resource ) { wp.setAttribute( "owner", resource->name() ); wp.setAttribute( "owner-id", resource->id() ); } wp.setAttribute( "time-tag", QDateTime::currentDateTime().toString( Qt::ISODate ) ); 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() ) { warnPlan<<"wrote:"<m_specialOutputFlag == SaveEncrypted ) { backend = KoStore::Encrypted; debugPlan <<"Saving using encrypted backend."; }*/ #endif QByteArray mimeType = "application/x-vnd.kde.plan.work"; debugPlan <<"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() ) { debugPlan <<"saveToStream failed"; delete store; return false; } node->documents().saveToStore( store ); debugPlan <<"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 ) { //debugPlan<<_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 ) { debugPlan<bad() ) { // d->lastErrorMessage = i18n( "Not a valid Calligra file: %1", file ); debugPlan<<"bad store"<open( "root" ) ) { // "old" file format (maindoc.xml) // i18n( "File does not have a maindoc.xml: %1", file ); debugPlan<<"No root"<device(), &errorMsg, &errorLine, &errorColumn ); if ( ! ok ) { errorPlan << "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 ); } 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() ) { debugPlan << "No mime type specified!"; setErrorMessage( i18n( "Invalid document. No mimetype specified." ) ); return 0; } else if ( value == "application/x-vnd.kde.kplato.work" ) { m_xmlLoader.setMimetype( value ); m_xmlLoader.setWorkVersion( plan.attribute( "version", "0.0.0" ) ); proj = new Project( m_config ); KPlatoXmlLoader loader( m_xmlLoader, proj ); ok = loader.loadWorkpackage( plan ); if ( ! ok ) { setErrorMessage( loader.errorMessage() ); delete proj; return 0; } package = loader.package(); package->timeTag = QDateTime::fromString( loader.timeTag(), Qt::ISODate ); } else if ( value != "application/x-vnd.kde.plan.work" ) { debugPlan << "Unknown mime type " << value; setErrorMessage( i18n( "Invalid document. Expected mimetype application/x-vnd.kde.plan.work, got %1", value ) ); return 0; } else { QString syntaxVersion = plan.attribute( "version", "0.0.0" ); m_xmlLoader.setWorkVersion( syntaxVersion ); if ( syntaxVersion > 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" ); //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 ); } debugPlan<<"Task set:"<task->name(); } m_xmlLoader.stopLoad(); } if ( ok && proj->id() == project.id() && proj->childNode( 0 ) ) { ok = project.nodeDict().contains( proj->childNode( 0 )->id() ); if ( ok && m_mergedPackages.contains( package->timeTag ) ) { ok = false; // already merged } if ( ok && package->timeTag.isValid() && ! m_mergedPackages.contains( package->timeTag ) ) { m_mergedPackages[ package->timeTag ] = proj; // register this for next time } if ( ok && ! package->timeTag.isValid() ) { warnPlan<<"Work package is not time tagged:"<childNode( 0 )->name()<url; ok = false; } } if ( ! ok ) { delete proj; delete package; return 0; } Q_ASSERT( package ); 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()<<"->"<numChildren() == 0 ) { return; } m_checkingForWorkPackages = true; if ( ! keep ) { qDeleteAll( m_mergedPackages ); m_mergedPackages.clear(); } QDir dir( m_config.retrieveUrl().path(), "*.planwork" ); m_infoList = dir.entryInfoList( QDir::Files | QDir::Readable, QDir::Time ); checkForWorkPackage(); return; } void MainDocument::checkForWorkPackage() { if ( ! m_infoList.isEmpty() ) { loadWorkPackage( *m_project, QUrl::fromLocalFile( m_infoList.takeLast().absoluteFilePath() ) ); if ( ! m_infoList.isEmpty() ) { QTimer::singleShot ( 0, this, SLOT(checkForWorkPackage()) ); return; } // all files read // remove other projects QMutableMapIterator it( m_workpackages ); while ( it.hasNext() ) { it.next(); Package *package = it.value(); if ( package->project->id() != m_project->id() ) { delete package->project; delete package; it.remove(); } } // Merge our workpackages if ( ! m_workpackages.isEmpty() ) { WorkPackageMergeDialog *dlg = new WorkPackageMergeDialog( i18n( "New work packages detected. Merge data with existing tasks?" ), m_workpackages ); connect(dlg, SIGNAL(finished(int)), SLOT(workPackageMergeDialogFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } } } void MainDocument::workPackageMergeDialogFinished( int result ) { WorkPackageMergeDialog *dlg = qobject_cast( sender() ); if ( dlg == 0 ) { return; } if ( result == KoDialog::Yes ) { // merge the oldest first foreach( int i, dlg->checkedList() ) { mergeWorkPackage( m_workpackages.values().at( i ) ); } // 'Yes' was hit so terminate all packages foreach( const Package *p, m_workpackages.values() ) { terminateWorkPackage( p ); } } qDeleteAll( m_workpackages ); m_workpackages.clear(); m_checkingForWorkPackages = false; dlg->deleteLater(); } void MainDocument::mergeWorkPackages() { foreach ( Package *package, m_workpackages ) { mergeWorkPackage( package ); } } void MainDocument::terminateWorkPackage( const Package *package ) { QFile file( package->url.path() ); if ( ! file.exists() ) { return; } if ( KPlatoSettings::deleteFile() || KPlatoSettings::saveUrl().isEmpty() ) { file.remove(); } else if ( KPlatoSettings::saveFile() && ! KPlatoSettings::saveUrl().isEmpty() ) { QDir dir( KPlatoSettings::saveUrl().path() ); if ( ! dir.exists() ) { if ( ! dir.mkpath( dir.path() ) ) { //TODO message debugPlan<<"Could not create directory:"<project); if ( proj.id() == m_project->id() && proj.childNode( 0 ) ) { const Task *from = package->task; Task *to = package->toTask; if ( to && from ) { mergeWorkPackage( to, from, package ); } } } void MainDocument::mergeWorkPackage( Task *to, const Task *from, const Package *package ) { Resource *resource = m_project->findResource( package->ownerId ); if ( resource == 0 ) { KMessageBox::error( 0, i18n( "The package owner '%1' is not a resource in this project. You must handle this manually.", package->ownerName ) ); return; } MacroCommand *cmd = new MacroCommand( kundo2_noi18n("Merge workpackage") ); Completion &org = to->completion(); const Completion &curr = from->completion(); if ( package->settings.progress ) { if ( org.isStarted() != curr.isStarted() ) { cmd->addCommand( new ModifyCompletionStartedCmd(org, curr.isStarted() ) ); } if ( org.isFinished() != curr.isFinished() ) { cmd->addCommand( new ModifyCompletionFinishedCmd( org, curr.isFinished() ) ); } if ( org.startTime() != curr.startTime() ) { cmd->addCommand( new ModifyCompletionStartTimeCmd( org, curr.startTime() ) ); } if ( org.finishTime() != curr.finishTime() ) { cmd->addCommand( new ModifyCompletionFinishTimeCmd( org, curr.finishTime() ) ); } // TODO: review how/if to merge data from different resources // remove entries foreach ( const QDate &d, org.entries().keys() ) { if ( ! curr.entries().contains( d ) ) { debugPlan<<"remove entry "<addCommand( new RemoveCompletionEntryCmd( org, d ) ); } } // add new entries / modify existing foreach ( const QDate &d, curr.entries().keys() ) { if ( org.entries().contains( d ) && curr.entry( d ) == org.entry( d ) ) { continue; } Completion::Entry *e = new Completion::Entry( *( curr.entry( d ) ) ); cmd->addCommand( new ModifyCompletionEntryCmd( org, d, e ) ); } } if ( package->settings.usedEffort ) { Completion::UsedEffort *ue = new Completion::UsedEffort(); Completion::Entry prev; Completion::EntryList::ConstIterator entriesIt = curr.entries().constBegin(); const Completion::EntryList::ConstIterator entriesEnd = curr.entries().constEnd(); for (; entriesIt != entriesEnd; ++entriesIt) { const QDate &d = entriesIt.key(); const Completion::Entry &e = *entriesIt.value(); // set used effort from date entry and remove used effort from date entry Completion::UsedEffort::ActualEffort effort( e.totalPerformed - prev.totalPerformed ); ue->setEffort( d, effort ); prev = e; } cmd->addCommand( new AddCompletionUsedEffortCmd( org, resource, ue ) ); } bool docsaved = false; if ( package->settings.documents ) { //TODO: handle remote files QMap::const_iterator it = package->documents.constBegin(); QMap::const_iterator end = package->documents.constEnd(); for ( ; it != end; ++it ) { const QUrl src = QUrl::fromLocalFile(it.key()); KIO::CopyJob *job = KIO::move( src, it.value(), KIO::Overwrite ); if ( job->exec() ) { docsaved = true; //TODO: async debugPlan<<"Moved file:"<isEmpty() ) { KMessageBox::information( 0, i18n( "Nothing to save from this package" ) ); } // add a copy to our tasks list of transmitted packages WorkPackage *wp = new WorkPackage( from->workPackage() ); wp->setParentTask( to ); if ( ! wp->transmitionTime().isValid() ) { wp->setTransmitionTime( package->timeTag ); } wp->setTransmitionStatus( WorkPackage::TS_Receive ); cmd->addCommand( new WorkPackageAddCmd( m_project, to, wp ) ); addCommand( cmd ); } void MainDocument::paintContent( QPainter &, const QRect &) { // Don't embed this app!!! } void MainDocument::slotViewDestroyed() { } void MainDocument::setLoadingTemplate(bool loading) { m_loadingTemplate = loading; } void MainDocument::setLoadingSharedResourcesTemplate(bool loading) { m_loadingSharedResourcesTemplate = loading; } bool MainDocument::completeLoading( KoStore *store ) { // If we get here the new project is loaded and set + if (m_loadingSharedProject) { + // this file is loaded by another project + // to read resource appointments, + // so we must not load any extra stuff + return true; + } if ( m_loadingTemplate ) { //debugPlan<<"Loading template, generate unique ids"; m_project->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()) { QUrl url = QUrl::fromLocalFile(m_project->sharedResourcesFile()); if (url.isValid()) { - insertResourcesFile(url, m_project->sharedProjectsUrl()); + 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 simmulate 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, SIGNAL(completed()), SLOT(insertFileCompleted())); connect(doc, SIGNAL(canceled(QString)), SLOT(insertFileCancelled(QString))); 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 ); part->setDocument( doc ); doc->disconnect(); // doc shall not handle feedback from openUrl() doc->setAutoSave( 0 ); //disable connect(doc, SIGNAL(completed()), SLOT(insertResourcesFileCompleted())); connect(doc, SIGNAL(canceled(QString)), SLOT(insertFileCancelled(QString))); doc->openUrl( url ); } void MainDocument::insertResourcesFileCompleted() { debugPlan<( 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() +{ + for (Resource *r : m_project->resourceList()) { + r->clearExternalAppointments(); + } +} + +void MainDocument::loadResourceAssignments(QUrl url) +{ + insertSharedProjects(url); + 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:"<resourceList()) { - r->clearExternalAppointments(); - } + clearResourceAssignments(); } void MainDocument::slotInsertSharedProject() { debugPlan<setDocument( doc ); doc->disconnect(); // doc shall not handle feedback from openUrl() doc->setAutoSave( 0 ); //disable + doc->m_loadingSharedProject = true; connect(doc, SIGNAL(completed()), SLOT(insertSharedProjectCompleted())); connect(doc, SIGNAL(canceled(QString)), SLOT(insertSharedProjectCancelled(QString))); doc->openUrl(m_sharedProjectsFiles.takeFirst()); } void MainDocument::insertSharedProjectCompleted() { debugPlan<( sender() ); if (doc) { Project &p = doc->getProject(); debugPlan<id()<<"Loaded project:"<id()) { - for (Resource *r : p.resourceList()) { - Resource *res = m_project->resource(r->id()); - debugPlan<<"Resource:"<name()<<"->"<isShared()) { - for (const Appointment *a : r->appointments()) { - Appointment *app = new Appointment(*a); - app->setAuxcilliaryInfo(p.name()); - res->addExternalAppointment(p.id(), app); - debugPlan<name()<<"added:"<auxcilliaryInfo()<id() && p.isScheduled(ANYSCHEDULED)) { + // FIXME: improve! + // find a suitable schedule + ScheduleManager *sm = 0; + for (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) { + for (Resource *r : p.resourceList()) { + Resource *res = m_project->resource(r->id()); + if (res && res->isShared()) { + for (const Appointment *a : r->appointments(sm->scheduleId())) { + Appointment *app = new Appointment(*a); + app->setAuxcilliaryInfo(p.name()); + res->addExternalAppointment(p.id(), app); + debugPlan<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 ) { debugPlan<( 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) { debugPlan<<&project; // Just in case, remove stuff not related to resources for (Node *n : project.childNodeIterator()) { delete n; } for (ScheduleManager *m : project.allScheduleManagers()) { delete m; } // Mark all resources / groups as shared for (ResourceGroup *g : project.resourceGroups()) { g->setShared(true); } for (Resource *r : project.resourceList()) { r->setShared(true); } // Mark all calendars shared for (Calendar *c : project.allCalendars()) { c->setShared(true); } // check if any shared stuff has been removed QList removedGroups; QList removedResources; QList removedCalendars; QStringList removed; for (ResourceGroup *g : m_project->resourceGroups()) { if (g->isShared() && !project.findResourceGroup(g->id())) { removedGroups << g; removed << i18n("Group: %1", g->name()); } } for (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 : 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 : removedResources) { RemoveResourceCmd cmd(r->parentGroup(), r); cmd.redo(); } for (ResourceGroup *g : 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 : removedCalendars) { CalendarRemoveCmd cmd(m_project, c); cmd.redo(); } break; case KMessageBox::No: // Convert for (Resource *r : removedResources) { r->setShared(false); m_project->removeResourceId(r->id()); r->setId(m_project->uniqueResourceId()); m_project->insertResourceId(r->id(), r); } for (ResourceGroup *g : removedGroups) { g->setShared(false); m_project->removeResourceGroupId(g->id()); g->setId(m_project->uniqueResourceGroupId()); m_project->insertResourceGroupId(g->id(), g); } for (Calendar *c : 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 existsing objects for (ResourceGroup *g : project.resourceGroups()) { ResourceGroup *group = m_project->findResourceGroup(g->id()); if (group) { group->setName(g->name()); group->setType(g->type()); } } for (Resource *r : project.resourceList()) { Resource *resource = m_project->findResource(r->id()); if (resource) { 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()); } } for (Calendar *c : project.allCalendars()) { Calendar *calendar = m_project->findCalendar(c->id()); if (calendar) { *calendar = *c; } } // insert new objects 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<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 *c = 0; if (inweek) { c = week; qDebug()<addCalendar(c, week); qDebug()<addCalendar(c); qDebug()<setHolidayRegion(KPlatoSettings::region()); } #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->generateUniqueIds(); 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().values() ) { 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/plan/kptmaindocument.h b/plan/kptmaindocument.h index bbc10cf24f4..9725315f130 100644 --- a/plan/kptmaindocument.h +++ b/plan/kptmaindocument.h @@ -1,237 +1,248 @@ /* 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 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 "kplato_export.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" /// The main namespace. namespace KPlato { class DocumentChild; class Project; class Context; class SchedulerPlugin; class ViewListItem; class View; class Package; class KPLATO_EXPORT MainDocument : public KoDocument { Q_OBJECT public: explicit MainDocument(KoPart *part); ~MainDocument(); /// reimplemented from KoDocument virtual QByteArray nativeFormatMimeType() const { return PLAN_MIME_TYPE; } /// reimplemented from KoDocument virtual QByteArray nativeOasisMimeType() const { return ""; } /// reimplemented from KoDocument virtual QStringList extraNativeMimeTypes() const { return QStringList() << PLAN_MIME_TYPE; } void setReadWrite( bool rw ); void configChanged(); virtual void paintContent( QPainter& painter, const QRect& rect); void setProject( Project *project ); Project &getProject() { return *m_project; } const Project &getProject() const { return * m_project; } /** * Return the set of SupportedSpecialFormats that the kplato wants to * offer in the "Save" file dialog. * Note: SaveEncrypted is not supported. */ virtual int supportedSpecialFormats() const { return SaveAsDirectoryStore; } // The load and save functions. Look in the file kplato.dtd for info virtual bool loadXML( const KoXmlDocument &document, KoStore *store ); virtual QDomDocument saveXML(); /// 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 */) { return false; } bool loadOdf( KoOdfReadStore & odfStore ); 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 ); void mergeWorkPackages(); void mergeWorkPackage( const Package *package ); void terminateWorkPackage( const Package *package ); /// 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 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(); using KoDocument::setModified; public Q_SLOTS: void setModified( bool mod ); /// Inserts an item into all other views than @p view void insertViewListItem( View *view, const ViewListItem *item, const ViewListItem *parent, int index ); /// Removes the view list item from all other views than @p view void removeViewListItem( View *view, const ViewListItem *item ); /// View selector has been modified void viewlistModified(); /// Check for workpackages /// If @p keep is true, packages that has been refused will not be checked for again void checkForWorkPackages( bool keep = false ); void setLoadingTemplate( bool ); void setLoadingSharedResourcesTemplate( bool ); void insertResourcesFile(const QUrl &url, const QUrl &projects = QUrl()); void slotProjectCreated(); - /// Prepare for insertion of resource bookings of shared resources from the project(s) in @p url + /// 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); + bool isTaskModule() const; + Q_SIGNALS: void changed(); void workPackageLoaded(); void viewlistModified( bool ); void viewListItemAdded(const ViewListItem *item, const ViewListItem *parent, int index); void viewListItemRemoved(const ViewListItem *item); void insertSharedProject(); protected: /// Load kplato specific files virtual bool completeLoading( KoStore* store ); /// Save kplato specific files virtual bool completeSaving( KoStore* store ); void mergeWorkPackage( Task *to, const Task *from, const Package *package ); // used by insert file struct InsertFileInfo { QUrl url; Node *parent; Node *after; } m_insertFileInfo; protected Q_SLOTS: void slotViewDestroyed(); void addSchedulerPlugin( const QString&, SchedulerPlugin *plugin ); void autoCheckForWorkPackages(); void checkForWorkPackage(); void insertFileCompleted(); void insertResourcesFileCompleted(); void insertFileCancelled( const QString& ); void slotInsertSharedProject(); void insertSharedProjectCompleted(); void insertSharedProjectCancelled( const QString& ); void workPackageMergeDialogFinished( int result ); 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; 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_isTaskModule; }; } //KPlato namespace #endif diff --git a/plan/kptpart.cpp b/plan/kptpart.cpp index 67e5e5f7080..4ea97910fc4 100644 --- a/plan/kptpart.cpp +++ b/plan/kptpart.cpp @@ -1,188 +1,211 @@ /* 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. */ #include "kptpart.h" #include "kptview.h" #include "kptmaindocument.h" #include "kptfactory.h" #include "welcome/WelcomeView.h" #include "kpthtmlview.h" #include #include #include #include #include #include #include #include #include +#include Part::Part(QObject *parent) : KoPart(Factory::global(), parent) , startUpWidget(0) { setTemplatesResourcePath(QLatin1String("calligraplan/templates/")); } 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() { - return new KoMainWindow(PLAN_MIME_TYPE, componentData()); + 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() +{ + // TODO: make url configurable to enable users to install their own docs + QDesktopServices::openUrl(QUrl(QStringLiteral("https://userbase.kde.org/Plan/Manual"))); } void Part::showStartUpWidget(KoMainWindow *parent, bool alwaysShow) { Q_UNUSED(alwaysShow); 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::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); } +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.items()); connect(v, SIGNAL(loadSharedResources(const QUrl&, const QUrl&)), doc, SLOT(insertResourcesFile(const QUrl&, const QUrl&))); connect(v, SIGNAL(recentProject(const QUrl&)), mw, SLOT(slotFileOpenRecent(const QUrl&))); connect(v, SIGNAL(showIntroduction()), this, SLOT(slotShowIntroduction())); connect(v, SIGNAL(projectCreated()), doc, SLOT(slotProjectCreated())); connect(v, SIGNAL(finished()), this, SLOT(finish())); connect(v, SIGNAL(openTemplate(QUrl)), this, SLOT(openTemplate(QUrl))); 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, SIGNAL(openUrlRequest(HtmlView*,QUrl)), SLOT(slotOpenUrlRequest(HtmlView*,QUrl)) ); return v; } diff --git a/plan/kptpart.h b/plan/kptpart.h index ac754c679f8..8e66ce5fec1 100644 --- a/plan/kptpart.h +++ b/plan/kptpart.h @@ -1,75 +1,78 @@ /* 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 "kplato_export.h" #include class KoView; class QStackedWidget; /// The main namespace. namespace KPlato { class MainDocument; class HtmlView; class KPLATO_EXPORT Part : public KoPart { Q_OBJECT public: explicit Part(QObject *parent); virtual ~Part(); void setDocument(KPlato::MainDocument *document); /// reimplemented virtual KoView *createViewInstance(KoDocument *document, QWidget *parent); /// reimplemented virtual KoMainWindow *createMainWindow(); virtual void showStartUpWidget(KoMainWindow *parent, bool alwaysShow = false); protected Q_SLOTS: void finish(); void slotShowIntroduction(); void slotOpenUrlRequest( HtmlView *v, const QUrl &url ); virtual void openTemplate( const QUrl& url ); + void openTaskModule(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/plan/kptview.cpp b/plan/kptview.cpp index 5dcda88215a..029c4d96419 100644 --- a/plan/kptview.cpp +++ b/plan/kptview.cpp @@ -1,3224 +1,3257 @@ /* 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 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 "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 #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 "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 "ConfigProjectPanel.h" #include "ConfigWorkVacationPanel.h" #include "kpttaskdefaultpanel.h" #include "kptworkpackageconfigpanel.h" #include "kptcolorsconfigpanel.h" #include "kptinsertfiledlg.h" #include "kpthtmlview.h" #include "about/aboutpage.h" #include "kptlocaleconfigmoneydialog.h" #include "kptflatproxymodel.h" #include "kpttaskstatusmodel.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 namespace KPlato { //------------------------------- ConfigDialog::ConfigDialog(QWidget *parent, const QString& name, KConfigSkeleton *config ) : KConfigDialog( parent, name, config ), m_config( config ) { KConfigDialogManager::changedMap()->insert("KRichTextWidget", SIGNAL(textChanged()) ); } bool ConfigDialog::hasChanged() { QRegExp kcfg( "kcfg_*" ); foreach ( KRichTextWidget *w, findChildren( kcfg ) ) { KConfigSkeletonItem *item = m_config->findItem( w->objectName().mid(5) ); if ( ! item->isEqual( w->toHtml() ) ) { return true; } } return false; } void ConfigDialog::updateSettings() { bool changed = false; QRegExp kcfg( "kcfg_*" ); foreach ( KRichTextWidget *w, findChildren( kcfg ) ) { KConfigSkeletonItem *item = m_config->findItem( w->objectName().mid(5) ); if ( ! item ) { warnPlan << "The setting '" << w->objectName().mid(5) << "' has disappeared!"; continue; } if ( ! item->isEqual( QVariant( w->toHtml() ) ) ) { item->setProperty( QVariant( w->toHtml() ) ); changed = true; } } if ( changed ) { m_config->save(); } } void ConfigDialog::updateWidgets() { QRegExp kcfg( "kcfg_*" ); foreach ( KRichTextWidget *w, findChildren( kcfg ) ) { KConfigSkeletonItem *item = m_config->findItem( w->objectName().mid(5) ); if ( ! item ) { warnPlan << "The setting '" << w->objectName().mid(5) << "' has disappeared!"; continue; } if ( ! item->isEqual( QVariant( w->toHtml() ) ) ) { w->setHtml( item->property().toString() ); } } } void ConfigDialog::updateWidgetsDefault() { bool usedefault = m_config->useDefaults( true ); updateWidgets(); m_config->useDefaults( usedefault ); } bool ConfigDialog::isDefault() { bool bUseDefaults = m_config->useDefaults(true); bool result = !hasChanged(); m_config->useDefaults(bUseDefaults); return result; } //------------------------------------ View::View(KoPart *part, MainDocument *doc, QWidget *parent) : KoView(part, doc, parent), m_currentEstimateType( Estimate::Use_Expected ), m_scheduleActionGroup( new QActionGroup( this ) ), m_trigged( false ), m_nextScheduleManager( 0 ), m_readWrite( false ), m_defaultView(1), m_partpart (part) { //debugPlan; 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, SIGNAL(selectionChanged(ScheduleManager*)), SLOT(slotSelectionChanged(ScheduleManager*)) ); connect( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), m_viewlist, SLOT(setSelectedSchedule(ScheduleManager*)) ); connect( m_viewlist, SIGNAL(updateViewInfo(ViewListItem*)), SLOT(slotUpdateViewInfo(ViewListItem*)) ); } 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(ScheduleManager*)), SLOT(slotSelectionChanged(ScheduleManager*)) ); connect( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), sd, SLOT(setSelectedSchedule(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 ); actionCollection()->addAction("file_createtemplate", actionCreateTemplate ); connect( actionCreateTemplate, SIGNAL(triggered(bool)), SLOT(slotCreateTemplate()) ); actionCreateNewProject = new QAction( i18n( "&Create New Project..." ), this ); actionCollection()->addAction("file_createnewproject", actionCreateNewProject ); connect( actionCreateNewProject, SIGNAL(triggered(bool)), SLOT(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, SIGNAL(triggered(bool)), SLOT(slotViewSelector(bool)) ); // ------ Insert // ------ Project actionEditMainProject = new QAction(koIcon("view-time-schedule-edit"), i18n("Edit Main Project..."), this); actionCollection()->addAction("project_edit", actionEditMainProject ); connect( actionEditMainProject, SIGNAL(triggered(bool)), SLOT(slotProjectEdit()) ); actionEditStandardWorktime = new QAction(koIcon("configure"), i18n("Define Estimate Conversions..."), this); actionCollection()->addAction("project_worktime", actionEditStandardWorktime ); connect( actionEditStandardWorktime, SIGNAL(triggered(bool)), SLOT(slotProjectWorktime()) ); // ------ Tools actionDefineWBS = new QAction(koIcon("configure"), i18n("Define WBS Pattern..."), this); actionCollection()->addAction("tools_define_wbs", actionDefineWBS ); connect( actionDefineWBS, SIGNAL(triggered(bool)), SLOT(slotDefineWBS()) ); actionInsertFile = new QAction(koIcon("document-import"), i18n("Insert Project File..."), this); actionCollection()->addAction("insert_file", actionInsertFile ); connect( actionInsertFile, SIGNAL(triggered(bool)), SLOT(slotInsertFile()) ); // ------ Settings actionConfigure = new QAction(koIcon("configure"), i18n("Configure Plan..."), this); actionCollection()->addAction("configure", actionConfigure ); connect( actionConfigure, SIGNAL(triggered(bool)), SLOT(slotConfigure()) ); actionCurrencyConfig = new QAction(koIcon("configure"), i18n("Define Currency..."), this); actionCollection()->addAction( "config_currency", actionCurrencyConfig ); connect( actionCurrencyConfig, SIGNAL(triggered(bool)), SLOT(slotCurrencyConfig()) ); #ifdef PLAN_USE_KREPORT actionOpenReportFile = new QAction(koIcon("document-open"), i18n("Open Report Definition File..."), this); actionCollection()->addAction( "reportdesigner_open_file", actionOpenReportFile ); connect( actionOpenReportFile, SIGNAL(triggered(bool)), SLOT(slotOpenReportFile()) ); #endif // ------ Help actionIntroduction = new QAction(koIcon("dialog-information"), i18n("Introduction to Plan"), this); actionCollection()->addAction("plan_introduction", actionIntroduction ); connect( actionIntroduction, SIGNAL(triggered(bool)), SLOT(slotIntroduction()) ); // ------ Popup actionOpenNode = new QAction(koIcon("document-edit"), i18n("Edit..."), this); actionCollection()->addAction("node_properties", actionOpenNode ); connect( actionOpenNode, SIGNAL(triggered(bool)), SLOT(slotOpenNode()) ); actionTaskProgress = new QAction(koIcon("document-edit"), i18n("Progress..."), this); actionCollection()->addAction("task_progress", actionTaskProgress ); connect( actionTaskProgress, SIGNAL(triggered(bool)), SLOT(slotTaskProgress()) ); actionDeleteTask = new QAction(koIcon("edit-delete"), i18n("Delete Task"), this); actionCollection()->addAction("delete_task", actionDeleteTask ); connect( actionDeleteTask, SIGNAL(triggered(bool)), SLOT(slotDeleteTask()) ); actionTaskDescription = new QAction(koIcon("document-edit"), i18n("Description..."), this); actionCollection()->addAction("task_description", actionTaskDescription ); connect( actionTaskDescription, SIGNAL(triggered(bool)), SLOT(slotTaskDescription()) ); actionIndentTask = new QAction(koIcon("format-indent-more"), i18n("Indent Task"), this); actionCollection()->addAction("indent_task", actionIndentTask ); connect( actionIndentTask, SIGNAL(triggered(bool)), SLOT(slotIndentTask()) ); actionUnindentTask= new QAction(koIcon("format-indent-less"), i18n("Unindent Task"), this); actionCollection()->addAction("unindent_task", actionUnindentTask ); connect( actionUnindentTask, SIGNAL(triggered(bool)), SLOT(slotUnindentTask()) ); actionMoveTaskUp = new QAction(koIcon("arrow-up"), i18n("Move Task Up"), this); actionCollection()->addAction("move_task_up", actionMoveTaskUp ); connect( actionMoveTaskUp, SIGNAL(triggered(bool)), SLOT(slotMoveTaskUp()) ); actionMoveTaskDown = new QAction(koIcon("arrow-down"), i18n("Move Task Down"), this); actionCollection()->addAction("move_task_down", actionMoveTaskDown ); connect( actionMoveTaskDown, SIGNAL(triggered(bool)), SLOT(slotMoveTaskDown()) ); actionEditResource = new QAction(koIcon("document-edit"), i18n("Edit Resource..."), this); actionCollection()->addAction("edit_resource", actionEditResource ); connect( actionEditResource, SIGNAL(triggered(bool)), SLOT(slotEditResource()) ); actionEditRelation = new QAction(koIcon("document-edit"), i18n("Edit Dependency..."), this); actionCollection()->addAction("edit_dependency", actionEditRelation ); connect( actionEditRelation, SIGNAL(triggered(bool)), SLOT(slotModifyRelation()) ); actionDeleteRelation = new QAction(koIcon("edit-delete"), i18n("Delete Dependency"), this); actionCollection()->addAction("delete_dependency", actionDeleteRelation ); connect( actionDeleteRelation, SIGNAL(triggered(bool)), SLOT(slotDeleteRelation()) ); // Viewlist popup connect( m_viewlist, SIGNAL(createView()), SLOT(slotCreateView()) ); m_estlabel = new QLabel( "", 0 ); if ( statusBar() ) { addStatusBarItem( m_estlabel, 0, true ); } connect( &getProject(), SIGNAL(scheduleChanged(MainSchedule*)), SLOT(slotScheduleChanged(MainSchedule*)) ); connect( &getProject(), SIGNAL(scheduleAdded(const MainSchedule*)), SLOT(slotScheduleAdded(const MainSchedule*)) ); connect( &getProject(), SIGNAL(scheduleRemoved(const MainSchedule*)), SLOT(slotScheduleRemoved(const MainSchedule*)) ); slotPlugScheduleActions(); connect( doc, SIGNAL(changed()), SLOT(slotUpdate()) ); connect( m_scheduleActionGroup, SIGNAL(triggered(QAction*)), SLOT(slotViewSchedule(QAction*)) ); connect( getPart(), SIGNAL(workPackageLoaded()), SLOT(slotWorkPackageLoaded()) ); // hide unused dockers QTimer::singleShot( 0, this, SLOT(hideToolDocker()) ); // create views after dockers hidden, views take time for large projects QTimer::singleShot( 100, this, SLOT(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(); } } + // do not watch task module changes if we are editing one + if (!doc->isTaskModule()) { + QString dir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); + if (!dir.isEmpty()) { + dir += "/taskmodules"; + m_dirwatch.addDir(dir, KDirWatch::WatchFiles); + QStringList modules = KoResourcePaths::findAllResources( "calligraplan_taskmodules", "*.plan", KoResourcePaths::NoDuplicates|KoResourcePaths::Recursive ); + for (const QString &f : modules) { + m_dirwatch.addFile(f); + } + connect(&m_dirwatch, SIGNAL(created(QString)), this, SLOT(taskModuleFileChanged(QString))); + connect(&m_dirwatch, SIGNAL(deleted(QString)), this, SLOT(taskModuleFileChanged(QString))); + } + } //debugPlan<<" end"; } View::~View() { ViewBase *view = currentView(); if (view) { // deactivate view to remove dockers etc slotGuiActivated(view, false); } /* removeStatusBarItem( m_estlabel ); delete m_estlabel;*/ } // hackish way to get rid of unused dockers, but as long as no official way exists... void View::hideToolDocker() { if ( mainWindow() ) { QStringList lst; lst << "KPlatoViewList" << "Scripting"; QStringList names; foreach ( QDockWidget *w, mainWindow()->dockWidgets() ) { if ( ! lst.contains( w->objectName() ) ) { names << w->windowTitle(); w->setFeatures( QDockWidget::DockWidgetClosable ); w->hide(); } } foreach(const KActionCollection *c, KActionCollection::allCollections()) { KActionMenu *a = qobject_cast(c->action("settings_dockers_menu")); if ( a ) { QList actions = a->menu()->actions(); foreach ( QAction *act, actions ) { if ( names.contains( act->text() ) ) { a->removeAction( act ); } } a->addSeparator(); break; } } } } void View::initiateViews() { QApplication::setOverrideCursor( Qt::WaitCursor ); createViews(); connect( m_viewlist, SIGNAL(activated(ViewListItem*,ViewListItem*)), SLOT(slotViewActivated(ViewListItem*,ViewListItem*)) ); // after createViews() !! connect( m_viewlist, SIGNAL(viewListItemRemoved(ViewListItem*)), SLOT(slotViewListItemRemoved(ViewListItem*)) ); // after createViews() !! connect( m_viewlist, SIGNAL(viewListItemInserted(ViewListItem*,ViewListItem*,int)), SLOT(slotViewListItemInserted(ViewListItem*,ViewListItem*,int)) ); QDockWidget *docker = qobject_cast( m_viewlist->parent() ); if ( docker ) { // after createViews() !! connect( m_viewlist, SIGNAL(modified()), docker, SLOT(slotModified())); connect( m_viewlist, SIGNAL(modified()), getPart(), SLOT(viewlistModified())); connect(getPart(), SIGNAL(viewlistModified(bool)), docker, SLOT(updateWindowTitle(bool))); } connect( m_tab, SIGNAL(currentChanged(int)), this, SLOT(slotCurrentChanged(int)) ); slotSelectDefaultView(); loadContext(); QApplication::restoreOverrideCursor(); } void View::slotCreateTemplate() { KoTemplateCreateDia::createTemplate(koDocument()->documentPart()->templatesResourcePath(), ".plant", getPart(), this); } 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::createViews() { Context *ctx = getPart()->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"; 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 ); createResourceEditor( cat, "ResourceEditor", QString(), TIP_USE_DEFAULT_TEXT ); createTaskEditor( cat, "TaskEditor", QString(), TIP_USE_DEFAULT_TEXT ); createDependencyEditor( cat, "DependencyEditor", QString(), TIP_USE_DEFAULT_TEXT ); 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 ); createTaskStatusView( cat, "TaskStatusView", QString(), TIP_USE_DEFAULT_TEXT ); createTaskView( cat, "TaskView", QString(), TIP_USE_DEFAULT_TEXT ); 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 // A little hack to get the user started... 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 } } 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, SIGNAL(openUrlRequest(HtmlView*,QUrl)), SLOT(slotOpenUrlRequest(HtmlView*,QUrl)) ); 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, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); connect( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), v, SLOT(setScheduleManager(ScheduleManager*)) ); connect( v, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); 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, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); connect( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), v, SLOT(setScheduleManager(ScheduleManager*)) ); connect( v, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); 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 ); 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, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); connect( resourceeditor, SIGNAL(deleteObjectList(QObjectList)), SLOT(slotDeleteResourceObjects(QObjectList)) ); connect( resourceeditor, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); 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 ); m_tab->addWidget( taskeditor ); m_defaultView = m_tab->count() - 1; 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, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), taskeditor, SLOT(setScheduleManager(ScheduleManager*)) ); connect( taskeditor, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); connect( taskeditor, SIGNAL(addTask()), SLOT(slotAddTask()) ); connect( taskeditor, SIGNAL(addMilestone()), SLOT(slotAddMilestone()) ); connect( taskeditor, SIGNAL(addSubtask()), SLOT(slotAddSubTask()) ); connect( taskeditor, SIGNAL(addSubMilestone()), SLOT(slotAddSubMilestone()) ); connect( taskeditor, SIGNAL(deleteTaskList(QList)), SLOT(slotDeleteTask(QList)) ); connect( taskeditor, SIGNAL(moveTaskUp()), SLOT(slotMoveTaskUp()) ); connect( taskeditor, SIGNAL(moveTaskDown()), SLOT(slotMoveTaskDown()) ); connect( taskeditor, SIGNAL(indentTask()), SLOT(slotIndentTask()) ); connect( taskeditor, SIGNAL(unindentTask()), SLOT(slotUnindentTask()) ); connect(taskeditor, SIGNAL(saveTaskModule(QUrl,Project*)), SLOT(saveTaskModule(QUrl,Project*))); connect(taskeditor, SIGNAL(removeTaskModule(QUrl)), SLOT(removeTaskModule(QUrl))); + connect(taskeditor, SIGNAL(openDocument(QUrl)), static_cast(m_partpart), SLOT(openTaskModule(QUrl))); + connect(this, SIGNAL(taskModulesChanged(QStringList)), taskeditor, SLOT(setTaskModules(QStringList))); connect( taskeditor, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); taskeditor->updateReadWrite( m_readWrite ); // last: QStringList modules = KoResourcePaths::findAllResources( "calligraplan_taskmodules", "*.plan", KoResourcePaths::NoDuplicates|KoResourcePaths::Recursive ); debugPlan<setTaskModules( modules ); 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, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); 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, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); connect( calendareditor, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); 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(), SIGNAL(addScheduleManager(Project*)), SLOT(slotAddScheduleManager(Project*)) ); connect( handler->scheduleEditor(), SIGNAL(deleteScheduleManager(Project*,ScheduleManager*)), SLOT(slotDeleteScheduleManager(Project*,ScheduleManager*)) ); connect( handler->scheduleEditor(), SIGNAL(moveScheduleManager(ScheduleManager*,ScheduleManager*,int)), SLOT(slotMoveScheduleManager(ScheduleManager*,ScheduleManager*,int))); connect( handler->scheduleEditor(), SIGNAL(calculateSchedule(Project*,ScheduleManager*)), SLOT(slotCalculateSchedule(Project*,ScheduleManager*)) ); connect( handler->scheduleEditor(), SIGNAL(baselineSchedule(Project*,ScheduleManager*)), SLOT(slotBaselineSchedule(Project*,ScheduleManager*)) ); connect( handler, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); connect( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), handler, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)) ); connect( handler, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); connect(handler, SIGNAL(editNode(Node*)), this, SLOT(slotOpenNode(Node*))); connect(handler, SIGNAL(editResource(Resource*)), this, SLOT(slotEditResource(Resource*))); handler->draw( getProject() ); handler->updateReadWrite( m_readWrite ); return handler; } ScheduleEditor *View::createScheduleEditor( QWidget *parent ) { ScheduleEditor *scheduleeditor = new ScheduleEditor(getKoPart(), getPart(), parent ); connect( scheduleeditor, SIGNAL(addScheduleManager(Project*)), SLOT(slotAddScheduleManager(Project*)) ); connect( scheduleeditor, SIGNAL(deleteScheduleManager(Project*,ScheduleManager*)), SLOT(slotDeleteScheduleManager(Project*,ScheduleManager*)) ); connect( scheduleeditor, SIGNAL(calculateSchedule(Project*,ScheduleManager*)), SLOT(slotCalculateSchedule(Project*,ScheduleManager*)) ); connect( scheduleeditor, SIGNAL(baselineSchedule(Project*,ScheduleManager*)), SLOT(slotBaselineSchedule(Project*,ScheduleManager*)) ); 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, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); connect( scheduleeditor, SIGNAL(addScheduleManager(Project*)), SLOT(slotAddScheduleManager(Project*)) ); connect( scheduleeditor, SIGNAL(deleteScheduleManager(Project*,ScheduleManager*)), SLOT(slotDeleteScheduleManager(Project*,ScheduleManager*)) ); connect( scheduleeditor, SIGNAL(calculateSchedule(Project*,ScheduleManager*)), SLOT(slotCalculateSchedule(Project*,ScheduleManager*)) ); connect( scheduleeditor, SIGNAL(baselineSchedule(Project*,ScheduleManager*)), SLOT(slotBaselineSchedule(Project*,ScheduleManager*)) ); 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, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); connect( editor, SIGNAL(addRelation(Node*,Node*,int)), SLOT(slotAddRelation(Node*,Node*,int)) ); connect( editor, SIGNAL(modifyRelation(Relation*,int)), SLOT(slotModifyRelation(Relation*,int)) ); connect( editor, SIGNAL(modifyRelation(Relation*)), SLOT(slotModifyRelation(Relation*)) ); connect( editor, SIGNAL(editNode(Node*)), SLOT(slotOpenNode(Node*)) ); connect( editor, SIGNAL(addTask()), SLOT(slotAddTask()) ); connect( editor, SIGNAL(addMilestone()), SLOT(slotAddMilestone()) ); connect( editor, SIGNAL(addSubMilestone()), SLOT(slotAddSubMilestone()) ); connect( editor, SIGNAL(addSubtask()), SLOT(slotAddSubTask()) ); connect( editor, SIGNAL(deleteTaskList(QList)), SLOT(slotDeleteTask(QList)) ); connect( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), editor, SLOT(setScheduleManager(ScheduleManager*)) ); connect( editor, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); 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, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); 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, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); connect( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), v, SLOT(setScheduleManager(ScheduleManager*)) ); 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, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); connect( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), v, SLOT(setScheduleManager(ScheduleManager*)) ); connect( v, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); 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 ); 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, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); connect( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), taskstatusview, SLOT(setScheduleManager(ScheduleManager*)) ); connect( taskstatusview, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); 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 ); 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, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), v, SLOT(setScheduleManager(ScheduleManager*)) ); connect( v, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); connect( v, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); 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 ); 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, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), v, SLOT(setScheduleManager(ScheduleManager*)) ); connect( v, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); connect( v, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); connect( v, SIGNAL(mailWorkpackage(Node*,Resource*)), SLOT(slotMailWorkpackage(Node*,Resource*)) ); connect( v, SIGNAL(mailWorkpackages(QList,Resource*)), SLOT(slotMailWorkpackages(QList,Resource*)) ); connect(v, SIGNAL(checkForWorkPackages()), getPart(), SLOT(checkForWorkPackages())); 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, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); /* TODO: Review these connect( ganttview, SIGNAL(addRelation(Node*,Node*,int)), SLOT(slotAddRelation(Node*,Node*,int)) ); connect( ganttview, SIGNAL(modifyRelation(Relation*,int)), SLOT(slotModifyRelation(Relation*,int)) ); connect( ganttview, SIGNAL(modifyRelation(Relation*)), SLOT(slotModifyRelation(Relation*)) ); connect( ganttview, SIGNAL(itemDoubleClicked()), SLOT(slotOpenNode()) ); connect( ganttview, SIGNAL(itemRenamed(Node*,QString)), this, SLOT(slotRenameNode(Node*,QString)) );*/ connect( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), ganttview, SLOT(setScheduleManager(ScheduleManager*)) ); connect( ganttview, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); 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, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); connect( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), ganttview, SLOT(setScheduleManager(ScheduleManager*)) ); connect( ganttview, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); 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, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), accountsview, SLOT(setScheduleManager(ScheduleManager*)) ); connect( accountsview, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); 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, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); connect( resourceAssignmentView, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); 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, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), v, SLOT(setScheduleManager(ScheduleManager*)) ); connect( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), v, SLOT(slotRefreshView())); v->setScheduleManager( currentScheduleManager() ); connect( v, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); connect( v, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); 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, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), v, SLOT(setScheduleManager(ScheduleManager*)) ); connect( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), v, SLOT(slotRefreshView())); v->setScheduleManager( currentScheduleManager() ); connect( v, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); v->updateReadWrite( m_readWrite ); return v; #else 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, SIGNAL(finished(int)), SLOT(slotInsertFileFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } 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::slotProjectEdit() { slotOpenNode( &getProject() ); } void View::slotProjectWorktime() { StandardWorktimeDialog *dia = new StandardWorktimeDialog( getProject(), this ); connect(dia, SIGNAL(finished(int)), this, SLOT(slotProjectWorktimeFinished(int))); dia->show(); dia->raise(); dia->activateWindow(); } 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<expected() ); if ( idx < 0 ) { debugPlan<expected(); return; } QAction *a = m_scheduleActions.keys().at( idx ); Q_ASSERT( a ); a->setChecked( true ); // this doesn't trigger QActionGroup slotViewSchedule( a ); } QList View::sortedActionList() { QMap lst; foreach ( QAction *a, m_scheduleActions.keys() ) { lst.insert( a->objectName(), a ); } return lst.values(); } void View::slotScheduleRemoved( const MainSchedule *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.keys().first()->setChecked( true ); } } slotViewSchedule( m_scheduleActionGroup->checkedAction() ); } void View::slotScheduleAdded( const MainSchedule *sch ) { if ( sch->type() != Schedule::Expected ) { return; // Only view expected } MainSchedule *s = const_cast( sch ); // debugPlan<name()<<" deleted="<isDeleted()<<"scheduled="<isScheduled(); QAction *checked = m_scheduleActionGroup->checkedAction(); if ( ! sch->isDeleted() && sch->isScheduled() ) { unplugActionList( "view_schedule_list" ); QAction *act = addScheduleAction( s ); plugActionList( "view_schedule_list", sortedActionList() ); if ( checked ) { checked->setChecked( true ); } else if ( act ) { act->setChecked( true ); } else if ( ! m_scheduleActions.isEmpty() ) { m_scheduleActions.keys().first()->setChecked( true ); } } slotViewSchedule( m_scheduleActionGroup->checkedAction() ); } void View::slotScheduleChanged( MainSchedule *sch ) { // debugPlan<name()<<" deleted="<isDeleted()<<"scheduled="<isScheduled(); if ( sch->isDeleted() || ! sch->isScheduled() ) { slotScheduleRemoved( sch ); return; } if ( m_scheduleActions.values().contains( sch ) ) { slotScheduleRemoved( sch ); // hmmm, how to avoid this? } slotScheduleAdded( sch ); } QAction *View::addScheduleAction( Schedule *sch ) { QAction *act = 0; if ( ! sch->isDeleted() && sch->isScheduled() ) { QString n = sch->name(); act = new KToggleAction( n, this); actionCollection()->addAction(n, act ); m_scheduleActions.insert( act, sch ); m_scheduleActionGroup->addAction( act ); //debugPlan<<"Add:"<manager(); } //emit currentScheduleManagerChanged( 0 ); setLabel( 0 ); m_nextScheduleManager = sm; // Performance is very dependent on schedule manager change since a lot is recalculated // In case of multiple changes, only issue the last change if ( ! m_trigged ) { m_trigged = true; //emit currentScheduleManagerChanged( 0 ); QTimer::singleShot( 0, this, SLOT(slotViewScheduleManager()) ); } } void View::slotActionDestroyed( QObject *o ) { //debugPlan<name(); m_scheduleActions.remove( static_cast( o ) ); // slotViewSchedule( m_scheduleActionGroup->checkedAction() ); } void View::slotPlugScheduleActions() { //debugPlan<removeAction( act ); delete act; } m_scheduleActions.clear(); QAction *ca = 0; foreach( ScheduleManager *sm, getProject().allScheduleManagers() ) { Schedule *sch = sm->expected(); if ( sch == 0 ) { continue; } QAction *act = addScheduleAction( sch ); if ( act && id == sch->id() ) { ca = act; } } plugActionList( "view_schedule_list", sortedActionList() ); if ( ca == 0 && m_scheduleActionGroup->actions().count() > 0 ) { ca = m_scheduleActionGroup->actions().first(); } if ( ca ) { ca->setChecked( true ); } slotViewSchedule( ca ); } void View::slotProjectCalculated( ScheduleManager *sm ) { // we only get here if current schedule was calculated if ( sm->isScheduled() ) { slotSelectionChanged( sm ); } } 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; } if ( sm == currentScheduleManager() ) { connect( project, SIGNAL(projectCalculated(ScheduleManager*)), this, SLOT(slotProjectCalculated(ScheduleManager*)) ); } 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; } KUndo2Command *cmd; 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 ResetBaselineScheduleCmd( *sm, kundo2_i18n( "Reset baseline %1", sm->name() ) ); } else { cmd = 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, SIGNAL(finished(int)), SLOT(slotAddSubTaskFinished(int))); dia->show(); dia->raise(); dia->activateWindow(); } 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, SIGNAL(finished(int)), SLOT(slotAddTaskFinished(int))); dia->show(); dia->raise(); dia->activateWindow(); } 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, SIGNAL(finished(int)), SLOT(slotAddMilestoneFinished(int))); dia->show(); dia->raise(); dia->activateWindow(); } 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, SIGNAL(finished(int)), SLOT(slotAddSubMilestoneFinished(int))); dia->show(); dia->raise(); dia->activateWindow(); } 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, SIGNAL(finished(int)), SLOT(slotDefineWBSFinished(int))); dia->show(); dia->raise(); dia->activateWindow(); } 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::slotConfigure() { //debugPlan; if( KConfigDialog::showDialog("Plan Settings") ) { return; } ConfigDialog *dialog = new ConfigDialog( this, "Plan Settings", KPlatoSettings::self() ); dialog->addPage(new ConfigProjectPanel(), i18n("Project Defaults"), koIconName("calligraplan") ); dialog->addPage(new ConfigWorkVacationPanel(), i18n("Work & Vacation"), koIconName("view-calendar") ); dialog->addPage(new TaskDefaultPanel(), i18n("Task Defaults"), koIconName("view-task") ); dialog->addPage(new ColorsConfigPanel(), i18n("Task Colors"), koIconName("fill-color") ); dialog->addPage(new WorkPackageConfigPanel(), i18n("Work Package"), koIconName("calligraplanwork") ); dialog->show(); } 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::slotOpenNode() { //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, SIGNAL(dialogFinished(int)), SLOT(slotProjectEditFinished(int))); - connect(dia, SIGNAL(sigLoadSharedResources(const QString&, const QUrl&)), this, SLOT(slotInsertResourcesFile(const QString&, const QUrl&))); + connect(dia, SIGNAL(sigLoadSharedResources(const QString&, const QUrl&, bool)), this, SLOT(slotInsertResourcesFile(const QString&, const QUrl&))); + connect(dia, &MainProjectDialog::loadResourceAssignments, getPart(), &MainDocument::loadResourceAssignments); + connect(dia, &MainProjectDialog::clearResourceAssignments, getPart(), &MainDocument::clearResourceAssignments); dia->show(); dia->raise(); dia->activateWindow(); 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, SIGNAL(finished(int)), SLOT(slotTaskEditFinished(int))); dia->show(); dia->raise(); dia->activateWindow(); 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( node ); TaskDialog *dia = new TaskDialog( getProject(), *task, getProject().accounts(), this ); connect(dia, SIGNAL(finished(int)), SLOT(slotTaskEditFinished(int))); dia->show(); dia->raise(); dia->activateWindow(); break; } case Node::Type_Summarytask: { Task *task = dynamic_cast( node ); Q_ASSERT( task ); SummaryTaskDialog *dia = new SummaryTaskDialog( *task, this ); connect(dia, SIGNAL(finished(int)), SLOT(slotSummaryTaskEditFinished(int))); dia->show(); dia->raise(); dia->activateWindow(); break; } default: break; // avoid warnings } } void View::slotProjectEditFinished( int result ) { MainProjectDialog *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::slotTaskEditFinished( int result ) { TaskDialog *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::slotSummaryTaskEditFinished( int result ) { SummaryTaskDialog *dia = qobject_cast( sender() ); if ( dia == 0 ) { return; } if ( result == QDialog::Accepted) { KUndo2Command * cmd = dia->buildCommand(); if ( cmd ) { getPart() ->addCommand( cmd ); } } dia->deleteLater(); } ScheduleManager *View::currentScheduleManager() const { Schedule *s = m_scheduleActions.value( m_scheduleActionGroup->checkedAction() ); return s == 0 ? 0 : s->manager(); } long View::activeScheduleId() const { Schedule *s = m_scheduleActions.value( m_scheduleActionGroup->checkedAction() ); return s == 0 ? -1 : s->id(); } void View::setActiveSchedule( long id ) { if ( id != -1 ) { QMap::const_iterator it = m_scheduleActions.constBegin(); for (; it != m_scheduleActions.constEnd(); ++it ) { if ( it.value()->id() == id ) { it.key()->setChecked( true ); slotViewSchedule( it.key() ); // signal not emitted from group, so trigger it here break; } } } } void View::slotTaskProgress() { //debugPlan; Node * node = currentNode(); if ( !node ) return ; switch ( node->type() ) { case Node::Type_Project: { break; } case Node::Type_Subproject: //TODO break; case Node::Type_Task: { Task *task = dynamic_cast( node ); Q_ASSERT( task ); TaskProgressDialog *dia = new TaskProgressDialog( *task, currentScheduleManager(), getProject().standardWorktime(), this ); connect(dia, SIGNAL(finished(int)), SLOT(slotTaskProgressFinished(int))); dia->show(); dia->raise(); dia->activateWindow(); break; } case Node::Type_Milestone: { Task *task = dynamic_cast( node ); Q_ASSERT( task ); MilestoneProgressDialog *dia = new MilestoneProgressDialog( *task, this ); connect(dia, SIGNAL(finished(int)), SLOT(slotMilestoneProgressFinished(int))); dia->show(); dia->raise(); dia->activateWindow(); break; } case Node::Type_Summarytask: { // TODO break; } default: break; // avoid warnings } } void View::slotTaskProgressFinished( int result ) { TaskProgressDialog *dia = qobject_cast(sender() ); if ( dia == 0 ) { return; } if ( result == QDialog::Accepted) { KUndo2Command * m = dia->buildCommand(); if ( m ) { getPart() ->addCommand( m ); } } dia->deleteLater(); } void View::slotMilestoneProgressFinished( int result ) { MilestoneProgressDialog *dia = qobject_cast(sender() ); if ( dia == 0 ) { return; } if ( result == QDialog::Accepted) { KUndo2Command * m = dia->buildCommand(); if ( m ) { getPart() ->addCommand( m ); } } dia->deleteLater(); } void View::slotTaskDescription() { //debugPlan; Node * node = currentNode(); if ( !node ) return ; switch ( node->type() ) { case Node::Type_Project: { break; } case Node::Type_Subproject: //TODO break; case Node::Type_Task: case Node::Type_Milestone: case Node::Type_Summarytask: { Task *task = dynamic_cast( node ); Q_ASSERT( task ); TaskDescriptionDialog *dia = new TaskDescriptionDialog( *task, this ); connect(dia, SIGNAL(finished(int)), SLOT(slotTaskDescriptionFinished(int))); dia->show(); dia->raise(); dia->activateWindow(); break; } default: break; // avoid warnings } } void View::slotTaskDescriptionFinished( int result ) { TaskDescriptionDialog *dia = qobject_cast(sender() ); if ( dia == 0 ) { return; } if ( result == QDialog::Accepted) { KUndo2Command * m = dia->buildCommand(); if ( m ) { getPart() ->addCommand( m ); } } dia->deleteLater(); } void View::slotDeleteTask( QList lst ) { //debugPlan; foreach ( Node *n, lst ) { if ( n->isScheduled() ) { KMessageBox::ButtonCode res = KMessageBox::warningContinueCancel( this, i18n( "A task that has been scheduled will be deleted. This will invalidate the schedule." ) ); if ( res == KMessageBox::Cancel ) { return; } break; } } if ( lst.count() == 1 ) { getPart()->addCommand( new NodeDeleteCmd( lst.takeFirst(), kundo2_i18n( "Delete task" ) ) ); return; } int num = 0; MacroCommand *cmd = new MacroCommand( kundo2_i18np( "Delete task", "Delete tasks", lst.count() ) ); while ( !lst.isEmpty() ) { Node *node = lst.takeFirst(); if ( node == 0 || node->parentNode() == 0 ) { debugPlan << ( node ?"Task is main project" :"No current task" ); continue; } bool del = true; foreach ( Node *n, lst ) { if ( node->isChildOf( n ) ) { del = false; // node is going to be deleted when we delete n break; } } if ( del ) { //debugPlan<name(); cmd->addCommand( new NodeDeleteCmd( node, kundo2_i18n( "Delete task" ) ) ); num++; } } if ( num > 0 ) { getPart()->addCommand( cmd ); } else { delete cmd; } } void View::slotDeleteTask( Node *node ) { //debugPlan; if ( node == 0 || node->parentNode() == 0 ) { debugPlan << ( node ?"Task is main project" :"No current task" ); return ; } if ( node->isScheduled() ) { KMessageBox::ButtonCode res = KMessageBox::warningContinueCancel( this, i18n( "This task has been scheduled. This will invalidate the schedule." ) ); if ( res == KMessageBox::Cancel ) { return; } } NodeDeleteCmd *cmd = new NodeDeleteCmd( node, kundo2_i18n( "Delete task" ) ); getPart() ->addCommand( cmd ); } void View::slotDeleteTask() { //debugPlan; return slotDeleteTask( currentNode() ); } void View::slotIndentTask() { //debugPlan; Node * node = currentNode(); if ( node == 0 || node->parentNode() == 0 ) { debugPlan << ( node ?"Task is main project" :"No current task" ); return ; } if ( getProject().canIndentTask( node ) ) { NodeIndentCmd * cmd = new NodeIndentCmd( *node, kundo2_i18n( "Indent task" ) ); getPart() ->addCommand( cmd ); } } void View::slotUnindentTask() { //debugPlan; Node * node = currentNode(); if ( node == 0 || node->parentNode() == 0 ) { debugPlan << ( node ?"Task is main project" :"No current task" ); return ; } if ( getProject().canUnindentTask( node ) ) { NodeUnindentCmd * cmd = new NodeUnindentCmd( *node, kundo2_i18n( "Unindent task" ) ); getPart() ->addCommand( cmd ); } } void View::slotMoveTaskUp() { //debugPlan; Node * task = currentNode(); if ( 0 == task ) { // is always != 0. At least we would get the Project, but you never know who might change that // so better be careful errorPlan << "No current task" << endl; return ; } if ( Node::Type_Project == task->type() ) { debugPlan <<"The root node cannot be moved up"; return ; } if ( getProject().canMoveTaskUp( task ) ) { NodeMoveUpCmd * cmd = new NodeMoveUpCmd( *task, kundo2_i18n( "Move task up" ) ); getPart() ->addCommand( cmd ); } } void View::slotMoveTaskDown() { //debugPlan; Node * task = currentNode(); if ( 0 == task ) { // is always != 0. At least we would get the Project, but you never know who might change that // so better be careful return ; } if ( Node::Type_Project == task->type() ) { debugPlan <<"The root node cannot be moved down"; return ; } if ( getProject().canMoveTaskDown( task ) ) { NodeMoveDownCmd * cmd = new NodeMoveDownCmd( *task, kundo2_i18n( "Move task down" ) ); getPart() ->addCommand( cmd ); } } void View::slotAddRelation( Node *par, Node *child ) { //debugPlan; Relation * rel = new Relation( par, child ); AddRelationDialog *dia = new AddRelationDialog( getProject(), rel, this ); connect(dia, SIGNAL(finished(int)), SLOT(slotAddRelationFinished(int))); dia->show(); dia->raise(); dia->activateWindow(); } void View::slotAddRelationFinished( int result ) { AddRelationDialog *dia = qobject_cast(sender() ); if ( dia == 0 ) { return; } if ( result == QDialog::Accepted) { KUndo2Command * m = dia->buildCommand(); if ( m ) { getPart() ->addCommand( m ); } } dia->deleteLater(); } void View::slotAddRelation( Node *par, Node *child, int linkType ) { //debugPlan; if ( linkType == Relation::FinishStart || linkType == Relation::StartStart || linkType == Relation::FinishFinish ) { Relation * rel = new Relation( par, child, static_cast( linkType ) ); getPart() ->addCommand( new AddRelationCmd( getProject(), rel, kundo2_i18n( "Add task dependency" ) ) ); } else { slotAddRelation( par, child ); } } void View::slotModifyRelation( Relation *rel ) { //debugPlan; ModifyRelationDialog *dia = new ModifyRelationDialog( getProject(), rel, this ); connect(dia, SIGNAL(finished(int)), SLOT(slotModifyRelationFinished(int))); dia->show(); dia->raise(); dia->activateWindow(); } void View::slotModifyRelationFinished( int result ) { ModifyRelationDialog *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::slotModifyRelation( Relation *rel, int linkType ) { //debugPlan; if ( linkType == Relation::FinishStart || linkType == Relation::StartStart || linkType == Relation::FinishFinish ) { getPart() ->addCommand( new ModifyRelationTypeCmd( rel, static_cast( linkType ) ) ); } else { slotModifyRelation( rel ); } } void View::slotModifyRelation() { ViewBase *v = dynamic_cast( m_tab->currentWidget() ); if ( v == 0 ) { return; } Relation *rel = v->currentRelation(); if ( rel ) { slotModifyRelation( rel ); } } void View::slotDeleteRelation() { ViewBase *v = dynamic_cast( m_tab->currentWidget() ); if ( v == 0 ) { return; } Relation *rel = v->currentRelation(); if ( rel ) { getPart()->addCommand( new DeleteRelationCmd( getProject(), rel, kundo2_i18n( "Delete task dependency" ) ) ); } } void View::slotEditResource() { //debugPlan; slotEditResource( currentResource() ); } void View::slotEditResource( Resource *resource ) { if ( resource == 0 ) { return ; } ResourceDialog *dia = new ResourceDialog( getProject(), resource, this ); connect(dia, SIGNAL(finished(int)), SLOT(slotEditResourceFinished(int))); dia->show(); dia->raise(); dia->activateWindow(); } void View::slotEditResourceFinished( int result ) { //debugPlan; ResourceDialog *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::slotDeleteResource( Resource *resource ) { getPart()->addCommand( new RemoveResourceCmd( resource->parentGroup(), resource, kundo2_i18n( "Delete resource" ) ) ); } void View::slotDeleteResourceGroup( ResourceGroup *group ) { getPart()->addCommand( new RemoveResourceGroupCmd( group->project(), group, kundo2_i18n( "Delete resourcegroup" ) ) ); } void View::slotDeleteResourceObjects( QObjectList lst ) { //debugPlan; foreach ( QObject *o, lst ) { Resource *r = qobject_cast( o ); if ( r && r->isScheduled() ) { KMessageBox::ButtonCode res = KMessageBox::warningContinueCancel( this, i18n( "A resource that has been scheduled will be deleted. This will invalidate the schedule." ) ); if ( res == KMessageBox::Cancel ) { return; } break; } ResourceGroup *g = qobject_cast( o ); if ( g && g->isScheduled() ) { KMessageBox::ButtonCode res = KMessageBox::warningContinueCancel( this, i18n( "A resource that has been scheduled will be deleted. This will invalidate the schedule." ) ); if ( res == KMessageBox::Cancel ) { return; } break; } } if ( lst.count() == 1 ) { Resource *r = qobject_cast( lst.first() ); if ( r ) { slotDeleteResource( r ); } else { ResourceGroup *g = qobject_cast( lst.first() ); if ( g ) { slotDeleteResourceGroup( g ); } } return; } // int num = 0; MacroCommand *cmd = 0, *rc = 0, *gc = 0; foreach ( QObject *o, lst ) { Resource *r = qobject_cast( o ); if ( r ) { if ( rc == 0 ) rc = new MacroCommand( KUndo2MagicString() ); rc->addCommand( new RemoveResourceCmd( r->parentGroup(), r ) ); continue; } ResourceGroup *g = qobject_cast( o ); if ( g ) { if ( gc == 0 ) gc = new MacroCommand( KUndo2MagicString() ); gc->addCommand( new RemoveResourceGroupCmd( g->project(), g ) ); } } if ( rc || gc ) { KUndo2MagicString s; if ( rc && gc ) { s = kundo2_i18n( "Delete resourcegroups and resources" ); } else if ( rc ) { s = kundo2_i18np( "Delete resource", "Delete resources", lst.count() ); } else { s = kundo2_i18np( "Delete resourcegroup", "Delete resourcegroups", lst.count() ); } cmd = new MacroCommand( s ); } if ( rc ) cmd->addCommand( rc ); if ( gc ) cmd->addCommand( gc ); if ( cmd ) getPart()->addCommand( cmd ); } void View::updateReadWrite( bool readwrite ) { m_readWrite = readwrite; m_viewlist->setReadWrite( readwrite ); } MainDocument *View::getPart() const { return ( MainDocument * ) koDocument(); } KoPart *View::getKoPart() const { return m_partpart; } void View::slotConnectNode() { //debugPlan; /* NodeItem *curr = ganttview->currentItem(); if (curr) { debugPlan<<"node="<getNode().name(); }*/ } QMenu * View::popupMenu( const QString& name ) { //debugPlan; if ( factory() ) { return ( ( QMenu* ) factory() ->container( name, this ) ); } debugPlan<<"No factory"; return 0L; } void View::slotUpdate() { //debugPlan<<"calculate="<currentWidget() ); } void View::slotGuiActivated( ViewBase *view, bool activate ) { //FIXME: Avoid unplug if possible, it flashes the gui // always unplug, in case they already are plugged foreach( const QString &name, view->actionListNames() ) { unplugActionList( name ); } if ( activate ) { foreach( const QString &name, view->actionListNames() ) { plugActionList( name, view->actionList( name ) ); } foreach ( DockWidget *ds, view->dockers() ) { m_dockers.append( ds ); ds->activate( mainWindow() ); } if (!m_dockers.isEmpty()) {debugPlan<<"Added dockers:"<deactivate( mainWindow() ); } } } void View::guiActivateEvent( bool activated ) { if ( activated ) { // plug my own actionlists, they may be gone slotPlugScheduleActions(); } // propagate to sub-view ViewBase *v = dynamic_cast( m_tab->currentWidget() ); if ( v ) { v->setGuiActive( activated ); } } void View::slotViewListItemRemoved( ViewListItem *item ) { getPart()->removeViewListItem( this, item ); } void View::removeViewListItem( const ViewListItem *item ) { if ( item == 0 ) { return; } ViewListItem *itm = m_viewlist->findItem( item->tag() ); if ( itm == 0 ) { return; } m_viewlist->removeViewListItem( itm ); return; } void View::slotViewListItemInserted( ViewListItem *item, ViewListItem *parent, int index ) { getPart()->insertViewListItem( this, item, parent, index ); } void View::addViewListItem( const ViewListItem *item, const ViewListItem *parent, int index ) { if ( item == 0 ) { return; } if ( parent == 0 ) { if ( item->type() != ViewListItem::ItemType_Category ) { return; } m_viewlist->blockSignals( true ); ViewListItem *cat = m_viewlist->addCategory( item->tag(), item->text( 0 ) ); cat->setToolTip( 0, item->toolTip( 0 ) ); m_viewlist->blockSignals( false ); return; } ViewListItem *cat = m_viewlist->findCategory( parent->tag() ); if ( cat == 0 ) { return; } m_viewlist->blockSignals( true ); createView( cat, item->viewType(), item->tag(), item->text( 0 ), item->toolTip( 0 ), index ); m_viewlist->blockSignals( false ); } void View::createReportView(const QDomDocument &doc) { #ifdef PLAN_USE_KREPORT QPointer vd = new ViewListReportsDialog( this, *m_viewlist, doc, this ); vd->exec(); // FIXME make non-crash delete vd; #endif } void View::slotOpenReportFile() { #ifdef PLAN_USE_KREPORT QFileDialog *dlg = new QFileDialog(this); connect(dlg, SIGNAL(finished(int)), SLOT(slotOpenReportFileFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); #endif } void View::slotOpenReportFileFinished( int result ) { #ifdef PLAN_USE_KREPORT QFileDialog *fdlg = qobject_cast( sender() ); if ( fdlg == 0 || result != QDialog::Accepted ) { return; } QString fn = fdlg->selectedFiles().value(0); if ( fn.isEmpty() ) { return; } QFile file( fn ); if ( ! file.open( QIODevice::ReadOnly | QIODevice::Text ) ) { KMessageBox::sorry( this, xi18nc( "@info", "Cannot open file:
%1", fn ) ); return; } QDomDocument doc; doc.setContent( &file ); createReportView(doc); #endif } void View::slotReportDesignFinished( int /*result */) { #ifdef PLAN_USE_KREPORT if ( sender() ) { sender()->deleteLater(); } #endif } void View::slotCreateView() { ViewListDialog *dlg = new ViewListDialog( this, *m_viewlist, this ); connect(dlg, SIGNAL(finished(int)), SLOT(slotCreateViewFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } void View::slotCreateViewFinished( int ) { if ( sender() ) { sender()->deleteLater(); } } void View::slotViewActivated( ViewListItem *item, ViewListItem *prev ) { QApplication::setOverrideCursor( Qt::WaitCursor ); if ( prev && prev->type() == ViewListItem::ItemType_Category && m_viewlist->previousViewItem() ) { // A view is shown anyway... ViewBase *v = qobject_cast( m_viewlist->previousViewItem()->view() ); if ( v ) { v->setGuiActive( false ); } } else if ( prev && prev->type() == ViewListItem::ItemType_SubView ) { ViewBase *v = qobject_cast( prev->view() ); if ( v ) { v->setGuiActive( false ); } } if ( item && item->type() == ViewListItem::ItemType_SubView ) { //debugPlan<<"Activate:"<setCurrentWidget( item->view() ); // Add sub-view specific gui ViewBase *v = dynamic_cast( m_tab->currentWidget() ); if ( v ) { v->setGuiActive( true ); } } QApplication::restoreOverrideCursor(); } QWidget *View::canvas() const { return m_tab->currentWidget();//KoView::canvas(); } KoPageLayout View::pageLayout() const { return currentView()->pageLayout(); } QPrintDialog *View::createPrintDialog( KoPrintJob *printJob, QWidget *parent ) { debugPlan<( printJob ); if ( ! job ) { return 0; } QPrintDialog *dia = KoView::createPrintDialog( job, parent ); PrintingDialog *j = dynamic_cast( job ); if ( j ) { new PrintingControlPrivate( j, dia ); } return dia; } void View::slotCurrentChanged( int view ) { m_visitedViews << view; ViewListItem *item = m_viewlist->findItem( qobject_cast( m_tab->currentWidget() ) ); m_viewlist->setCurrentItem( item ); } void View::slotSelectDefaultView() { m_tab->setCurrentIndex(qMin(m_defaultView, m_tab->count()-1)); } void View::updateView( QWidget * ) { QApplication::setOverrideCursor( Qt::WaitCursor ); //setScheduleActionsEnabled(); QWidget *widget2; widget2 = m_viewlist->findView( "ResourceAssignmentView" ); if ( widget2 && m_updateResourceAssignmentView ) static_cast( widget2 ) ->draw( getProject() ); m_updateResourceAssignmentView = false; QApplication::restoreOverrideCursor(); } void View::slotRenameNode( Node *node, const QString& name ) { //debugPlan<type() ) { case Node::Type_Task: s = kundo2_i18n( "Modify task name" ); break; case Node::Type_Milestone: s = kundo2_i18n( "Modify milestone name" ); break; case Node::Type_Summarytask: s = kundo2_i18n( "Modify summarytask name" ); break; case Node::Type_Project: s = kundo2_i18n( "Modify project name" ); break; } NodeModifyNameCmd * cmd = new NodeModifyNameCmd( *node, name, s ); getPart() ->addCommand( cmd ); } } void View::slotPopupMenu( const QString& menuname, const QPoint & pos ) { QMenu * menu = this->popupMenu( menuname ); if ( menu ) { //debugPlan<actions().count(); ViewBase *v = qobject_cast( m_tab->currentWidget() ); //debugPlan< lst; if ( v ) { lst = v->contextActionList(); debugPlan<addSeparator(); foreach ( QAction *a, lst ) { menu->addAction( a ); } } } menu->exec( pos ); foreach ( QAction *a, lst ) { menu->removeAction( a ); } } } void View::slotPopupMenu( const QString& menuname, const QPoint &pos, ViewListItem *item ) { //debugPlan<context(); if ( ctx == 0 || ! ctx->isLoaded() ) { return false; } KoXmlElement n = ctx->context(); QString cv = n.attribute( "current-view" ); if ( ! cv.isEmpty() ) { m_viewlist->setSelected( m_viewlist->findItem( cv ) ); } else debugPlan<<"No current view"; long id = n.attribute( "current-schedule", "-1" ).toLong(); if ( id != -1 ) { setActiveSchedule( id ); } else debugPlan<<"No current schedule"; return true; } void View::saveContext( QDomElement &me ) const { //debugPlan; long id = activeScheduleId(); if ( id != -1 ) { me.setAttribute( "current-schedule", QString::number((qlonglong)id) ); } ViewListItem *item = m_viewlist->findItem( qobject_cast( m_tab->currentWidget() ) ); if ( item ) { me.setAttribute("current-view", item->tag() ); } m_viewlist->save( me ); } bool View::loadWorkPackage( Project &project, const QUrl &url ) { return getPart()->loadWorkPackage( project, url ); } void View::setLabel( ScheduleManager *sm ) { //debugPlan; Schedule *s = sm == 0 ? 0 : sm->expected(); if ( s && !s->isDeleted() && s->isScheduled() ) { m_estlabel->setText( sm->name() ); return; } m_estlabel->setText( xi18nc( "@info:status", "Not scheduled" ) ); } void View::slotWorkPackageLoaded() { debugPlan<workPackages(); } void View::slotMailWorkpackage( Node *node, Resource *resource ) { debugPlan; QTemporaryFile tmpfile(QDir::tempPath() + QLatin1String("/calligraplanwork_XXXXXX") + QLatin1String( ".planwork" )); tmpfile.setAutoRemove( false ); if ( ! tmpfile.open() ) { debugPlan<<"Failed to open file"; KMessageBox::error(0, i18n("Failed to open temporary file" ) ); return; } QUrl url = QUrl::fromLocalFile( tmpfile.fileName() ); if ( ! getPart()->saveWorkPackageUrl( url, node, activeScheduleId(), resource ) ) { debugPlan<<"Failed to save to file"; KMessageBox::error(0, xi18nc( "@info", "Failed to save to temporary file:
%1", url.url() ) ); return; } QStringList attachURLs; attachURLs << url.url(); QString to = resource == 0 ? node->leader() : ( resource->name() + " <" + resource->email() + '>' ); QString cc; QString bcc; QString subject = i18n( "Work Package: %1", node->name() ); QString body = i18nc( "1=project name, 2=task name", "%1\n%2", getProject().name(), node->name() ); QString messageFile; KToolInvocation::invokeMailer( to, cc, bcc, subject, body, messageFile, attachURLs ); } void View::slotMailWorkpackages( const QList &nodes, Resource *resource ) { debugPlan; if ( resource == 0 ) { warnPlan<<"No resource, we don't handle node->leader() yet"; return; } QString to = resource->name() + " <" + resource->email() + '>'; QString subject = i18n( "Work Package for project: %1", getProject().name() ); QString body; QStringList attachURLs; foreach ( Node *n, nodes ) { QTemporaryFile tmpfile(QDir::tempPath() + QLatin1String("/calligraplanwork_XXXXXX") + QLatin1String( ".planwork" )); tmpfile.setAutoRemove( false ); if ( ! tmpfile.open() ) { debugPlan<<"Failed to open file"; KMessageBox::error(0, i18n("Failed to open temporary file" ) ); return; } QUrl url = QUrl::fromLocalFile( tmpfile.fileName() ); if ( ! getPart()->saveWorkPackageUrl( url, n, activeScheduleId(), resource ) ) { debugPlan<<"Failed to save to file"; KMessageBox::error(0, xi18nc( "@info", "Failed to save to temporary file:
%1", url.url() ) ); return; } attachURLs << url.url(); body += n->name() + '\n'; } QString cc; QString bcc; QString messageFile; KToolInvocation::invokeMailer( to, cc, bcc, subject, body, messageFile, attachURLs ); } void View::slotCurrencyConfig() { LocaleConfigMoneyDialog *dlg = new LocaleConfigMoneyDialog( getProject().locale(), this ); connect(dlg, SIGNAL(finished(int)), SLOT(slotCurrencyConfigFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } void View::slotCurrencyConfigFinished( int result ) { LocaleConfigMoneyDialog *dlg = qobject_cast( sender() ); if ( dlg == 0 ) { return; } if ( result == QDialog::Accepted ) { KUndo2Command *c = dlg->buildCommand( getProject() ); if ( c ) { getPart()->addCommand( c ); } } dlg->deleteLater(); } void View::saveTaskModule( const QUrl &url, Project *project ) { // NOTE: workaround: KoResourcePaths::saveLocation( "calligraplan_taskmodules" ); does not work const QString dir = KoResourcePaths::saveLocation( "appdata", "taskmodules/" ); debugPlan<<"dir="<setDocument( doc ); doc->disconnect(); // doc shall not handle feedback from openUrl() doc->setAutoSave( 0 ); //disable doc->insertProject( *project, 0, 0 ); // FIXME: destroys project, find better way doc->getProject().setName( project->name() ); doc->getProject().setLeader( project->leader() ); doc->getProject().setDescription( project->description() ); doc->saveNativeFormat( dir + url.fileName() ); part->deleteLater(); // also deletes document debugPlan<

" "" "" "%1" "" "" "predefined" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "") .arg( i18n( "Report" ), i18nc( "Project manager", "Manager:" ), i18n( "Project:" ), i18n( "Task Status Report" ), i18nc( "As in: Page 1 of 2", "of" ), i18n( "Page" ), i18nc( "Task name", "Name" ), i18nc( "Task completion", "Completion (%)" ) ); #endif return s; } } //KPlato namespace diff --git a/plan/kptview.h b/plan/kptview.h index 4fa03a83199..6645080d10d 100644 --- a/plan/kptview.h +++ b/plan/kptview.h @@ -1,453 +1,458 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999, 2000 Torben Weis Copyright (C) 2002 - 2010 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 KPTVIEW_H #define KPTVIEW_H #include "kplato_export.h" #include #include "kptcontext.h" #include "kptviewbase.h" #include #include #include +#include class QMenu; class QPrintDialog; class QStackedWidget; class QSplitter; class QUrl; class KUndo2Command; class QAction; class KToggleAction; class QLabel; class KConfigSkeleton; class KConfigSkeletonItem; class KoView; namespace KPlato { class View; class ViewBase; class ViewListItem; class ViewListWidget; struct ViewInfo; class AccountsView; class GanttView; class PertEditor; class AccountsEditor; class TaskEditor; class CalendarEditor; class ScheduleEditor; class ScheduleManager; class CalculateScheduleCmd; class ResourceAssignmentView; class TaskStatusView; class Calendar; class MainDocument; class Part; class Node; class Project; class Task; class MainSchedule; class Schedule; class Resource; class ResourceGroup; class Relation; class Context; class ViewAdaptor; class HtmlView; class ReportView; class ReportDesignDialog; class DockWidget; class ConfigDialog : public KConfigDialog { Q_OBJECT public: ConfigDialog( QWidget *parent, const QString &name, KConfigSkeleton *config ); protected Q_SLOTS: /// Return true if any widget has changed virtual bool hasChanged(); /** * Update the settings from the dialog. * Virtual function for custom additions. * * Example use: User clicks Ok or Apply button in a configure dialog. */ virtual void updateSettings(); /** * Update the dialog based on the settings. * Virtual function for custom additions. * * Example use: Initialisation of dialog. * Example use: User clicks Reset button in a configure dialog. */ virtual void updateWidgets(); /** * Update the dialog based on the default settings. * Virtual function for custom additions. * * Example use: User clicks Defaults button in a configure dialog. */ virtual void updateWidgetsDefault(); /** * Returns whether the current state of the dialog is * the same as the default configuration. */ virtual bool isDefault(); private: KConfigSkeleton *m_config; QMap m_signalsmap; QMap m_itemmap; QMap m_propertymap; }; //------------- class KPLATO_EXPORT View : public KoView { Q_OBJECT public: explicit View(KoPart *part, MainDocument *doc, QWidget *parent = 0); ~View(); MainDocument *getPart() const; KoPart *getKoPart() const; Project& getProject() const; QMenu *popupMenu( const QString& name ); virtual bool loadContext(); virtual void saveContext( QDomElement &context ) const; /// Load the workpackage from @p url into @p project. Return true if successful, else false. bool loadWorkPackage( Project &project, const QUrl &url ); QWidget *canvas() const; KoPageLayout pageLayout() const; ScheduleManager *currentScheduleManager() const; long activeScheduleId() const; void setActiveSchedule( long id ); /// Returns the default view information like standard name and tooltip for view type @p type ViewInfo defaultViewInfo( const QString &type ) const; /// Returns the default category information like standard name and tooltip for category type @p type ViewInfo defaultCategoryInfo( const QString &type ) const; ViewBase *createTaskEditor( ViewListItem *cat, const QString &tag, const QString &name = QString(), const QString &tip = QString(), int index = -1 ); ViewBase *createResourceEditor( ViewListItem *cat, const QString &tag, const QString &name = QString(), const QString &tip = QString(), int index = -1 ); ViewBase *createAccountsEditor( ViewListItem *cat, const QString &tag, const QString &name = QString(), const QString &tip = QString(), int index = -1 ); ViewBase *createCalendarEditor( ViewListItem *cat, const QString &tag, const QString &name = QString(), const QString &tip = QString(), int index = -1 ); ViewBase *createScheduleHandler( ViewListItem *cat, const QString &tag, const QString &name = QString(), const QString &tip = QString(), int index = -1 ); ScheduleEditor *createScheduleEditor( QWidget *parent ); ViewBase *createScheduleEditor( ViewListItem *cat, const QString &tag, const QString &name = QString(), const QString &tip = QString(), int index = -1 ); ViewBase *createDependencyEditor( ViewListItem *cat, const QString &tag, const QString &name = QString(), const QString &tip = QString(), int index = -1 ); ViewBase *createPertEditor( ViewListItem *cat, const QString &tag, const QString &name = QString(), const QString &tip = QString(), int index = -1 ); ViewBase *createProjectStatusView( ViewListItem *cat, const QString &tag, const QString &name = QString(), const QString &tip = QString(), int index = -1 ); ViewBase *createPerformanceStatusView( ViewListItem *cat, const QString &tag, const QString &name = QString(), const QString &tip = QString(), int index = -1 ); ViewBase *createTaskStatusView( ViewListItem *cat, const QString &tag, const QString &name = QString(), const QString &tip = QString(), int index = -1 ); ViewBase *createTaskView( ViewListItem *cat, const QString &tag, const QString &name = QString(), const QString &tip = QString(), int index = -1 ); ViewBase *createTaskWorkPackageView( ViewListItem *cat, const QString &tag, const QString &name = QString(), const QString &tip = QString(), int index = -1 ); ViewBase *createGanttView( ViewListItem *cat, const QString &tag, const QString &name = QString(), const QString &tip = QString(), int index = -1 ); ViewBase *createMilestoneGanttView( ViewListItem *cat, const QString &tag, const QString &name = QString(), const QString &tip = QString(), int index = -1 ); ViewBase *createResourceAppointmentsView( ViewListItem *cat, const QString &tag, const QString &name = QString(), const QString &tip = QString(), int index = -1 ); ViewBase *createResourceAppointmentsGanttView( ViewListItem *cat, const QString &tag, const QString &name = QString(), const QString &tip = QString(), int index = -1 ); ViewBase *createAccountsView( ViewListItem *cat, const QString &tag, const QString &name = QString(), const QString &tip = QString(), int index = -1 ); ViewBase *createResourceAssignmentView( ViewListItem *cat, const QString &tag, const QString &name = QString(), const QString &tip = QString(), int index = -1 ); ViewBase *createChartView( ViewListItem *cat, const QString &tag, const QString &name = QString(), const QString &tip = QString(), int index = -1 ); ViewBase *createReportView( ViewListItem *cat, const QString &tag, const QString &name = QString(), const QString &tip = QString(), int index = -1 ); ViewBase *createReportsGeneratorView( ViewListItem *cat, const QString &tag, const QString &name = QString(), const QString &tip = QString(), int index = -1 ); KoPrintJob * createPrintJob(); QPrintDialog* createPrintDialog(KoPrintJob*, QWidget*); virtual KoZoomController *zoomController() const { return 0; } Q_SIGNALS: void currentScheduleManagerChanged( ScheduleManager *sm ); + void taskModulesChanged(const QStringList &modules); public Q_SLOTS: void slotUpdate(); void slotCreateTemplate(); void slotCreateNewProject(); void slotEditResource(); void slotEditResource( Resource *resource ); void slotEditCut(); void slotEditCopy(); void slotEditPaste(); void slotRefreshView(); void slotViewSelector( bool show ); void slotAddTask(); void slotAddSubTask(); void slotAddMilestone(); void slotAddSubMilestone(); void slotProjectEdit(); void slotDefineWBS(); void slotCurrencyConfig(); void slotCreateView(); void slotConfigure(); void slotIntroduction(); void slotAddRelation( Node *par, Node *child ); void slotModifyRelation( Relation *rel ); void slotAddRelation( Node *par, Node *child, int linkType ); void slotModifyRelation( Relation *rel, int linkType ); void slotModifyRelation(); void slotDeleteRelation(); void slotRenameNode( Node *node, const QString& name ); void slotPopupMenu( const QString& menuname, const QPoint &pos ); void slotPopupMenu( const QString& menuname, const QPoint &pos, ViewListItem *item ); void addViewListItem( const ViewListItem *item, const ViewListItem *parent, int index ); void removeViewListItem( const ViewListItem *item ); void slotOpenReportFile(); protected Q_SLOTS: void slotGuiActivated( ViewBase *view, bool ); void slotViewActivated( ViewListItem*, ViewListItem* ); void slotPlugScheduleActions(); void slotViewSchedule( QAction *act ); void slotScheduleChanged( MainSchedule* ); void slotScheduleAdded( const MainSchedule * ); void slotScheduleRemoved( const MainSchedule * ); void slotSelectionChanged( ScheduleManager *sm ); void slotAddScheduleManager( Project *project ); void slotDeleteScheduleManager( Project *project, ScheduleManager *sm ); void slotMoveScheduleManager( ScheduleManager *sm, ScheduleManager *parent, int index ); void slotCalculateSchedule( Project*, ScheduleManager* ); void slotBaselineSchedule( Project *project, ScheduleManager *sm ); void slotProjectWorktime(); void slotOpenNode(); void slotOpenNode( Node *node ); void slotTaskProgress(); void slotTaskDescription(); void slotDeleteTask( QList lst ); void slotDeleteTask( Node *node ); void slotDeleteTask(); void slotIndentTask(); void slotUnindentTask(); void slotMoveTaskUp(); void slotMoveTaskDown(); void slotConnectNode(); void slotDeleteResource( Resource *resource ); void slotDeleteResourceGroup( ResourceGroup *group ); void slotDeleteResourceObjects( QObjectList ); void slotCurrentChanged( int ); void slotSelectDefaultView(); void slotInsertResourcesFile(const QString&, const QUrl &projects); void slotInsertFile(); void slotWorkPackageLoaded(); void slotMailWorkpackage( Node *node, Resource *resource = 0 ); void slotMailWorkpackages( const QList &nodes, Resource *resource = 0 ); void slotOpenUrlRequest( HtmlView *v, const QUrl &url ); void slotProjectCalculated( ScheduleManager *sm ); void slotUpdateViewInfo( ViewListItem *itm ); void createReportView(const QDomDocument &doc); void saveTaskModule( const QUrl &url, Project *project ); void removeTaskModule( const QUrl &url ); + void taskModuleFileChanged(const QString &path); + protected: virtual void guiActivateEvent( bool activated ); virtual void updateReadWrite( bool readwrite ); QList sortedActionList(); QAction *addScheduleAction( Schedule *sch ); void setLabel( ScheduleManager *sm = 0 ); Task *currentTask() const; Node *currentNode() const; Resource *currentResource(); ResourceGroup *currentResourceGroup(); Calendar *currentCalendar(); void updateView( QWidget *widget ); ViewBase *currentView() const; ViewBase *createIntroductionView(); private Q_SLOTS: void slotActionDestroyed( QObject *o ); void slotViewListItemRemoved( ViewListItem *item ); void slotViewListItemInserted( ViewListItem *item, ViewListItem *parent, int index ); void slotProjectEditFinished( int result ); void slotTaskEditFinished( int result ); void slotSummaryTaskEditFinished( int result ); void slotEditResourceFinished( int result ); void slotProjectWorktimeFinished( int result ); void slotDefineWBSFinished( int result ); void slotCurrencyConfigFinished( int result ); void slotInsertFileFinished( int result ); void slotAddSubTaskFinished( int result ); void slotAddTaskFinished( int result ); void slotAddSubMilestoneFinished( int result ); void slotAddMilestoneFinished( int result ); void slotTaskProgressFinished( int result ); void slotMilestoneProgressFinished( int result ); void slotTaskDescriptionFinished( int result ); void slotAddRelationFinished( int result ); void slotModifyRelationFinished( int result ); void slotReportDesignFinished( int result ); void slotOpenReportFileFinished( int result ); void slotCreateViewFinished( int result ); void slotRemoveCommands(); void hideToolDocker(); void initiateViews(); void slotViewScheduleManager(); private: void createViews(); ViewBase *createView( ViewListItem *cat, const QString &type, const QString &tag, const QString &name, const QString &tip, int index = -1 ); QString standardTaskStatusReport() const; private: QSplitter *m_sp; QStackedWidget *m_tab; ViewListWidget *m_viewlist; ViewListItem *m_viewlistItem; // requested popupmenu item //QDockWidget *m_toolbox; int m_viewGrp; int m_defaultFontSize; int m_currentEstimateType; bool m_updateAccountsview; bool m_updateResourceAssignmentView; bool m_updatePertEditor; QLabel *m_estlabel; ViewAdaptor* m_dbus; QActionGroup *m_scheduleActionGroup; QMap m_scheduleActions; // if multiple changes occur, only issue the last change bool m_trigged; ScheduleManager *m_nextScheduleManager; QMultiMap m_calculationcommands; QList m_undocommands; bool m_readWrite; int m_defaultView; QList m_visitedViews; QList m_dockers; // ------ File QAction *actionCreateTemplate; QAction *actionCreateNewProject; // ------ Edit QAction *actionCut; QAction *actionCopy; QAction *actionPaste; // ------ View KToggleAction *actionViewSelector; // ------ Insert // ------ Project QAction *actionEditMainProject; // ------ Tools QAction *actionEditStandardWorktime; QAction *actionDefineWBS; QAction *actionInsertFile; QAction *actionCurrencyConfig; QAction *actionOpenReportFile; // ------ Settings QAction *actionConfigure; // ------ Help QAction *actionIntroduction; // ------ Popup QAction *actionOpenNode; QAction *actionTaskProgress; QAction *actionTaskDescription; QAction *actionDeleteTask; QAction *actionIndentTask; QAction *actionUnindentTask; QAction *actionMoveTaskUp; QAction *actionMoveTaskDown; QAction *actionEditResource; QAction *actionEditRelation; QAction *actionDeleteRelation; //Test QAction *actNoInformation; QMap m_reportActionMap; KoPart *m_partpart; + KDirWatch m_dirwatch; }; } //Kplato namespace #endif diff --git a/plan/kptviewlist.cpp b/plan/kptviewlist.cpp index e1ac07b18af..8ddffe93fb3 100644 --- a/plan/kptviewlist.cpp +++ b/plan/kptviewlist.cpp @@ -1,856 +1,869 @@ /* This file is part of the KDE project Copyright (C) 2007 -2010 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 "kptviewlist.h" #include #include #include #include #include #include #include #include #include #include #include "KoDocument.h" #include "kptviewbase.h" #include "kptmaindocument.h" #include "kptviewlistdialog.h" #include "kptviewlistdocker.h" #include "kptschedulemodel.h" +#include "WhatsThis.h" #include #include namespace KPlato { // class ViewCategoryDelegate : public QItemDelegate { public: ViewCategoryDelegate( QObject *parent, QTreeView *view ) : QItemDelegate( parent ), m_view( view ) {} QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const; virtual void paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const; private: QTreeView *m_view; }; QSize ViewCategoryDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const { const QAbstractItemModel * model = index.model(); Q_ASSERT( model ); if ( model->parent( index ).isValid() ) { return QItemDelegate::sizeHint( option, index ); } return QItemDelegate::sizeHint( option, index ).expandedTo( QSize( 0, 16 ) ); } void ViewCategoryDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const { const QAbstractItemModel * model = index.model(); Q_ASSERT( model ); if ( !model->parent( index ).isValid() ) { // this is a top-level item. QStyleOptionButton buttonOption; buttonOption.state = option.state; buttonOption.rect = option.rect; buttonOption.palette = option.palette; buttonOption.features = QStyleOptionButton::None; m_view->style() ->drawControl( QStyle::CE_PushButton, &buttonOption, painter, m_view ); QStyleOption branchOption; static const int i = 9; // ### hardcoded in qcommonstyle.cpp QRect r = option.rect; branchOption.rect = QRect( r.left() + i / 2, r.top() + ( r.height() - i ) / 2, i, i ); branchOption.palette = option.palette; branchOption.state = QStyle::State_Children; if ( m_view->isExpanded( index ) ) branchOption.state |= QStyle::State_Open; m_view->style() ->drawPrimitive( QStyle::PE_IndicatorBranch, &branchOption, painter, m_view ); // draw text QRect textrect = QRect( r.left() + i * 2, r.top(), r.width() - ( ( 5 * i ) / 2 ), r.height() ); QString text = elidedText( option.fontMetrics, textrect.width(), Qt::ElideMiddle, model->data( index, Qt::DisplayRole ).toString() ); m_view->style() ->drawItemText( painter, textrect, Qt::AlignLeft|Qt::AlignVCenter, option.palette, m_view->isEnabled(), text ); } else { QItemDelegate::paint( painter, option, index ); } } ViewListItem::ViewListItem( const QString &tag, const QStringList &strings, int type ) : QTreeWidgetItem( strings, type ), m_tag( tag ) { } ViewListItem::ViewListItem( QTreeWidget *parent, const QString &tag, const QStringList &strings, int type ) : QTreeWidgetItem( parent, strings, type ), m_tag( tag ) { } ViewListItem::ViewListItem( QTreeWidgetItem *parent, const QString &tag, const QStringList &strings, int type ) : QTreeWidgetItem( parent, strings, type ), m_tag( tag ) { } void ViewListItem::setReadWrite( bool rw ) { if ( type() == ItemType_SubView ) { static_cast( view() )->updateReadWrite( rw ); } } void ViewListItem::setView( ViewBase *view ) { setData( 0, ViewListItem::DataRole_View, qVariantFromValue(static_cast( view ) ) ); } ViewBase *ViewListItem::view() const { if ( data(0, ViewListItem::DataRole_View ).isValid() ) { return static_cast( data(0, ViewListItem::DataRole_View ).value() ); } return 0; } void ViewListItem::setDocument( KoDocument *doc ) { setData( 0, ViewListItem::DataRole_Document, qVariantFromValue(static_cast( doc ) ) ); } KoDocument *ViewListItem::document() const { if ( data(0, ViewListItem::DataRole_Document ).isValid() ) { return static_cast( data(0, ViewListItem::DataRole_Document ).value() ); } return 0; } QString ViewListItem::viewType() const { if ( type() != ItemType_SubView ) { return QString(); } QString name = view()->metaObject()->className(); if ( name.contains( ':' ) ) { name = name.remove( 0, name.lastIndexOf( ':' ) + 1 ); } return name; } void ViewListItem::save( QDomElement &element ) const { element.setAttribute( "itemtype", QString::number(type()) ); element.setAttribute( "tag", tag() ); if ( type() == ItemType_SubView ) { element.setAttribute( "viewtype", viewType() ); element.setAttribute( "name", m_viewinfo.name == text( 0 ) ? "" : text( 0 ) ); element.setAttribute( "tooltip", m_viewinfo.tip == toolTip( 0 ) ? TIP_USE_DEFAULT_TEXT : toolTip( 0 ) ); } else if ( type() == ItemType_Category ) { debugPlan<This is the list of available views and editors." - "You can configure the list by using the context menu:" - "" - "Rename categories or views" - "Configure. Move, remove, rename or edit tool tip for categories or views" - "Insert categories and views" - "" - ) ); - header() ->hide(); setRootIsDecorated( false ); setItemDelegate( new ViewCategoryDelegate( this, this ) ); setItemsExpandable( true ); setSelectionMode( QAbstractItemView::SingleSelection ); setDragDropMode( QAbstractItemView::InternalMove ); //setContextMenuPolicy( Qt::ActionsContextMenu ); connect( this, SIGNAL(itemPressed(QTreeWidgetItem*,int)), SLOT(handleMousePress(QTreeWidgetItem*)) ); } void ViewListTreeWidget::drawRow( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const { QTreeWidget::drawRow( painter, option, index ); } void ViewListTreeWidget::handleMousePress( QTreeWidgetItem *item ) { //debugPlan; if ( item == 0 ) return ; if ( item->parent() == 0 ) { setItemExpanded( item, !isItemExpanded( item ) ); return ; } } void ViewListTreeWidget::mousePressEvent ( QMouseEvent *event ) { if ( event->button() == Qt::RightButton ) { QTreeWidgetItem *item = itemAt( event->pos() ); if ( item && item->type() == ViewListItem::ItemType_Category ) { setCurrentItem( item ); emit customContextMenuRequested( event->pos() ); event->accept(); return; } } QTreeWidget::mousePressEvent( event ); } void ViewListTreeWidget::save( QDomElement &element ) const { int cnt = topLevelItemCount(); if ( cnt == 0 ) { return; } QDomElement cs = element.ownerDocument().createElement( "categories" ); element.appendChild( cs ); for ( int i = 0; i < cnt; ++i ) { ViewListItem *itm = static_cast( topLevelItem( i ) ); if ( itm->type() != ViewListItem::ItemType_Category ) { continue; } QDomElement c = cs.ownerDocument().createElement( "category" ); cs.appendChild( c ); emit const_cast( this )->updateViewInfo( itm ); itm->save( c ); for ( int j = 0; j < itm->childCount(); ++j ) { ViewListItem *vi = static_cast( itm->child( j ) ); if ( vi->type() != ViewListItem::ItemType_SubView ) { continue; } QDomElement el = c.ownerDocument().createElement( "view" ); c.appendChild( el ); emit const_cast( this )->updateViewInfo( vi ); vi->save( el ); QDomElement elm = el.ownerDocument().createElement( "settings" ); el.appendChild( elm ); static_cast( vi->view() )->saveContext( elm ); } } } // void ViewListTreeWidget::startDrag( Qt::DropActions supportedActions ) { QModelIndexList indexes = selectedIndexes(); if ( indexes.count() == 1 ) { ViewListItem *item = static_cast( itemFromIndex( indexes.at( 0 ) ) ); Q_ASSERT( item ); QTreeWidgetItem *root = invisibleRootItem(); int count = root->childCount(); if ( item && item->type() == ViewListItem::ItemType_Category ) { root->setFlags( root->flags() | Qt::ItemIsDropEnabled ); for ( int i = 0; i < count; ++i ) { QTreeWidgetItem * ch = root->child( i ); ch->setFlags( ch->flags() & ~Qt::ItemIsDropEnabled ); } } else if ( item ) { root->setFlags( root->flags() & ~Qt::ItemIsDropEnabled ); for ( int i = 0; i < count; ++i ) { QTreeWidgetItem * ch = root->child( i ); ch->setFlags( ch->flags() | Qt::ItemIsDropEnabled ); } } } QTreeWidget::startDrag( supportedActions ); } void ViewListTreeWidget::dropEvent( QDropEvent *event ) { QTreeWidget::dropEvent( event ); if ( event->isAccepted() ) { emit modified(); } } ViewListItem *ViewListTreeWidget::findCategory( const QString &cat ) { QTreeWidgetItem * item; int cnt = topLevelItemCount(); for ( int i = 0; i < cnt; ++i ) { item = topLevelItem( i ); if ( static_cast(item)->tag() == cat ) return static_cast(item); } return 0; } ViewListItem *ViewListTreeWidget::category( const KoView *view ) const { QTreeWidgetItem * item; int cnt = topLevelItemCount(); for ( int i = 0; i < cnt; ++i ) { item = topLevelItem( i ); for ( int c = 0; c < item->childCount(); ++c ) { if ( view == static_cast( item->child( c ) )->view() ) { return static_cast( item ); } } } return 0; } //----------------------- ViewListWidget::ViewListWidget( MainDocument *part, QWidget *parent )//QString name, KXmlGuiWindow *parent ) : QWidget( parent ), m_part( part ), m_prev( 0 ), m_temp( 0 ) { setObjectName("ViewListWidget"); + WhatsThis::add(this, + xi18nc("@info:whatsthis", + "View Selector" + "This is the list of views and editors." + "You can configure the list by using the context menu:" + "" + "Rename categories or views" + "Configure. Move, remove, rename or edit tool tip for categories or views" + "Insert categories and views" + "" + "More..." + "", "https://userbase.kde.org/Plan/Manual/View_Selector")); + m_viewlist = new ViewListTreeWidget( this ); m_viewlist->setEditTriggers( QAbstractItemView::NoEditTriggers ); connect(m_viewlist, SIGNAL(modified()), this, SIGNAL(modified())); m_currentSchedule = new KComboBox( this ); m_model.setFlat( true ); m_sfModel.setFilterKeyColumn ( ScheduleModel::ScheduleScheduled ); m_sfModel.setFilterRole( Qt::EditRole ); m_sfModel.setFilterFixedString( "true" ); m_sfModel.setDynamicSortFilter ( true ); m_sfModel.setSourceModel( &m_model ); m_currentSchedule->setModel( &m_sfModel ); + WhatsThis::add(m_currentSchedule, + xi18nc("@info:whatsthis", + "Schedule selector" + "" + "Select the schedule to be used." + "Unscheduled tasks are only shown in editors" + "More..." + "", "https://userbase.kde.org/Plan/Howto/")); + QVBoxLayout *l = new QVBoxLayout( this ); l->setMargin( 0 ); l->addWidget( m_viewlist ); l->addWidget( m_currentSchedule ); connect( m_viewlist, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), SLOT(slotActivated(QTreeWidgetItem*,QTreeWidgetItem*)) ); connect( m_viewlist, SIGNAL(itemChanged(QTreeWidgetItem*,int)), SLOT(slotItemChanged(QTreeWidgetItem*,int)) ); setupContextMenus(); connect( m_currentSchedule, SIGNAL(activated(int)), SLOT(slotCurrentScheduleChanged(int)) ); connect( &m_model, SIGNAL(scheduleManagerAdded(ScheduleManager*)), SLOT(slotScheduleManagerAdded(ScheduleManager*)) ); connect( m_viewlist, SIGNAL(updateViewInfo(ViewListItem*)), SIGNAL(updateViewInfo(ViewListItem*)) ); } ViewListWidget::~ViewListWidget() { } void ViewListWidget::setReadWrite( bool rw ) { foreach ( ViewListItem *c, categories() ) { for ( int i = 0; i < c->childCount(); ++i ) { static_cast( c->child( i ) )->setReadWrite( rw ); } } } void ViewListWidget::slotItemChanged( QTreeWidgetItem */*item*/, int /*col */) { //debugPlan; } void ViewListWidget::slotActivated( QTreeWidgetItem *item, QTreeWidgetItem *prev ) { if ( m_prev ) { m_prev->setData( 0, Qt::BackgroundRole, QVariant() ); } if ( item && item->type() == ViewListItem::ItemType_Category ) { return ; } emit activated( static_cast( item ), static_cast( prev ) ); if ( item ) { QVariant v = QBrush( QColor( Qt::yellow ) ); item->setData( 0, Qt::BackgroundRole, v ); m_prev = static_cast( item ); } } ViewListItem *ViewListWidget::addCategory( const QString &tag, const QString& name ) { //debugPlan ; ViewListItem *item = m_viewlist->findCategory( tag ); if ( item == 0 ) { item = new ViewListItem( m_viewlist, tag, QStringList( name ), ViewListItem::ItemType_Category ); item->setExpanded( true ); item->setFlags( item->flags() | Qt::ItemIsEditable ); } return item; } QList ViewListWidget::categories() const { QList lst; QTreeWidgetItem *item; int cnt = m_viewlist->topLevelItemCount(); for ( int i = 0; i < cnt; ++i ) { item = m_viewlist->topLevelItem( i ); if ( item->type() == ViewListItem::ItemType_Category ) lst << static_cast( item ); } return lst; } ViewListItem *ViewListWidget::findCategory( const QString &tag ) const { return m_viewlist->findCategory( tag ); } ViewListItem *ViewListWidget::category( const KoView *view ) const { return m_viewlist->category( view ); } QString ViewListWidget::uniqueTag( const QString &seed ) const { QString tag = seed; for ( int i = 1; findItem( tag ); ++i ) { tag = QString("%1-%2").arg( seed ).arg( i ); } return tag; } ViewListItem *ViewListWidget::addView(QTreeWidgetItem *category, const QString &tag, const QString &name, ViewBase *view, KoDocument *doc, const QString &iconName, int index) { ViewListItem * item = new ViewListItem( uniqueTag( tag ), QStringList( name ), ViewListItem::ItemType_SubView ); item->setView( view ); item->setDocument( doc ); if (! iconName.isEmpty()) { item->setData(0, Qt::DecorationRole, QIcon::fromTheme(iconName)); } item->setFlags( ( item->flags() | Qt::ItemIsEditable ) & ~Qt::ItemIsDropEnabled ); insertViewListItem( item, category, index ); connect(view, SIGNAL(optionsModified()), SLOT(setModified())); return item; } void ViewListWidget::setSelected( QTreeWidgetItem *item ) { //debugPlan<currentItem(); if ( item == 0 && m_viewlist->currentItem() ) { m_viewlist->currentItem()->setSelected( false ); if ( m_prev ) { m_prev->setData( 0, Qt::BackgroundRole, QVariant() ); } } m_viewlist->setCurrentItem( item ); //debugPlan<currentItem(); } void ViewListWidget::setCurrentItem( QTreeWidgetItem *item ) { m_viewlist->setCurrentItem( item ); //debugPlan<currentItem(); } ViewListItem *ViewListWidget::currentItem() const { return static_cast( m_viewlist->currentItem() ); } ViewListItem *ViewListWidget::currentCategory() const { ViewListItem *item = static_cast( m_viewlist->currentItem() ); if ( item == 0 ) { return 0; } if ( item->type() == ViewListItem::ItemType_Category ) { return item; } return static_cast( item->parent() ); } KoView *ViewListWidget::findView( const QString &tag ) const { ViewListItem *i = findItem( tag ); if ( i == 0 ) { return 0; } return i->view(); } ViewListItem *ViewListWidget::findItem( const QString &tag ) const { ViewListItem *item = findItem( tag, m_viewlist->invisibleRootItem() ); if ( item == 0 ) { QTreeWidgetItem *parent = m_viewlist->invisibleRootItem(); for (int i = 0; i < parent->childCount(); ++i ) { item = findItem( tag, parent->child( i ) ); if ( item != 0 ) { break; } } } return item; } ViewListItem *ViewListWidget::findItem( const QString &tag, QTreeWidgetItem *parent ) const { if ( parent == 0 ) { return findItem( tag, m_viewlist->invisibleRootItem() ); } for (int i = 0; i < parent->childCount(); ++i ) { ViewListItem * ch = static_cast( parent->child( i ) ); if ( ch->tag() == tag ) { //debugPlan<invisibleRootItem() ); } for (int i = 0; i < parent->childCount(); ++i ) { ViewListItem * ch = static_cast( parent->child( i ) ); if ( ch->view() == view ) { //debugPlan<type() != ViewListItem::ItemType_Category ) { return; } debugPlan<type(); if ( m_contextitem->childCount() > 0 ) { if ( KMessageBox::warningContinueCancel( this, i18n( "Removing this category will also remove all its views." ) ) == KMessageBox::Cancel ) { return; } } // first remove all views in this category while ( m_contextitem->childCount() > 0 ) { ViewListItem *itm = static_cast( m_contextitem->child( 0 ) ); takeViewListItem( itm ); delete itm->view(); delete itm; } takeViewListItem( m_contextitem ); delete m_contextitem; m_contextitem = 0; emit modified(); } void ViewListWidget::slotRemoveView() { if ( m_contextitem ) { takeViewListItem( m_contextitem ); delete m_contextitem->view(); delete m_contextitem; emit modified(); } } void ViewListWidget::slotEditViewTitle() { //QTreeWidgetItem *item = m_viewlist->currentItem(); if ( m_contextitem ) { debugPlan<type(); QString title = m_contextitem->text( 0 ); m_viewlist->editItem( m_contextitem ); if ( title != m_contextitem->text( 0 ) ) { emit modified(); } } } void ViewListWidget::slotConfigureItem() { if ( m_contextitem == 0 ) { return; } KoDialog *dlg = 0; if ( m_contextitem->type() == ViewListItem::ItemType_Category ) { debugPlan<type(); dlg = new ViewListEditCategoryDialog( *this, m_contextitem, this ); } else if ( m_contextitem->type() == ViewListItem::ItemType_SubView ) { dlg = new ViewListEditViewDialog( *this, m_contextitem, this ); } if ( dlg ) { connect(dlg, SIGNAL(finished(int)), SLOT(slotDialogFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } } void ViewListWidget::slotDialogFinished( int result ) { if ( result == QDialog::Accepted ) { emit modified(); } if ( sender() ) { sender()->deleteLater(); } } void ViewListWidget::slotEditDocumentTitle() { //QTreeWidgetItem *item = m_viewlist->currentItem(); if ( m_contextitem ) { debugPlan<type(); QString title = m_contextitem->text( 0 ); m_viewlist->editItem( m_contextitem ); } } int ViewListWidget::removeViewListItem( ViewListItem *item ) { QTreeWidgetItem *p = item->parent(); if ( p == 0 ) { p = m_viewlist->invisibleRootItem(); } int i = p->indexOfChild( item ); if ( i != -1 ) { p->takeChild( i ); emit modified(); } return i; } void ViewListWidget::addViewListItem( ViewListItem *item, QTreeWidgetItem *parent, int index ) { QTreeWidgetItem *p = parent; if ( p == 0 ) { p = m_viewlist->invisibleRootItem(); } if ( index == -1 ) { index = p->childCount(); } p->insertChild( index, item ); emit modified(); } int ViewListWidget::takeViewListItem( ViewListItem *item ) { while ( item->childCount() > 0 ) { takeViewListItem( static_cast( item->child( 0 ) ) ); } int pos = removeViewListItem( item ); if ( pos != -1 ) { emit viewListItemRemoved( item ); if ( item == m_prev ) { m_prev = 0; } if ( m_prev ) { setCurrentItem( m_prev ); } } return pos; } void ViewListWidget::insertViewListItem( ViewListItem *item, QTreeWidgetItem *parent, int index ) { addViewListItem( item, parent, index ); emit viewListItemInserted( item, static_cast( parent ), index ); } void ViewListWidget::setupContextMenus() { // NOTE: can't use xml file as there may not be a factory() QAction *action; // view actions action = new QAction(koIcon("edit-rename"), xi18nc("@action:inmenu rename view", "Rename"), this); connect( action, SIGNAL(triggered(bool)), this, SLOT(slotEditViewTitle()) ); m_viewactions.append( action ); action = new QAction(koIcon("configure"), xi18nc("@action:inmenu configure view", "Configure..."), this ); connect( action, SIGNAL(triggered(bool)), this, SLOT(slotConfigureItem()) ); m_viewactions.append( action ); action = new QAction(koIcon("list-remove"), xi18nc("@action:inmenu remove view", "Remove"), this); connect( action, SIGNAL(triggered(bool)), this, SLOT(slotRemoveView()) ); m_viewactions.append( action ); action = new QAction( this ); action->setSeparator( true ); m_viewactions.append( action ); // Category actions action = new QAction(koIcon("edit-rename"), xi18nc("@action:inmenu rename view category", "Rename"), this); connect( action, SIGNAL(triggered(bool)), SLOT(renameCategory()) ); m_categoryactions.append( action ); action = new QAction(koIcon("configure"), xi18nc("@action:inmenu configure view category", "Configure..."), this); connect( action, SIGNAL(triggered(bool)), this, SLOT(slotConfigureItem()) ); m_categoryactions.append( action ); action = new QAction(koIcon("list-remove"), xi18nc("@action:inmenu Remove view category", "Remove"),this); connect( action, SIGNAL(triggered(bool)), this, SLOT(slotRemoveCategory()) ); m_categoryactions.append( action ); action = new QAction( this ); action->setSeparator( true ); m_categoryactions.append( action ); // list actions action = new QAction(koIcon("list-add"), xi18nc("@action:inmenu Insert View", "Insert..."), this); connect( action, SIGNAL(triggered(bool)), this, SLOT(slotAddView()) ); m_listactions.append( action ); } void ViewListWidget::renameCategory() { if ( m_contextitem ) { QString title = m_contextitem->text( 0 ); m_viewlist->editItem( m_contextitem, 0 ); } } void ViewListWidget::contextMenuEvent ( QContextMenuEvent *event ) { QMenu menu; QList lst; m_contextitem = static_cast(m_viewlist->itemAt( event->pos() ) ); if ( m_contextitem == 0 ) { lst += m_listactions; } else { if ( m_contextitem->type() == ViewListItem::ItemType_Category ) { lst += m_categoryactions; } else if ( m_contextitem->type() == ViewListItem::ItemType_SubView ) { lst += m_viewactions; ViewBase *v = dynamic_cast( m_contextitem->view() ); if ( v ) { lst += v->viewlistActionList(); } } lst += m_listactions; } if ( ! lst.isEmpty() ) { //menu.addTitle( i18n( "Edit" ) ); foreach ( QAction *a, lst ) { menu.addAction( a ); } } if ( ! menu.actions().isEmpty() ) { menu.exec( event->globalPos() ); } } void ViewListWidget::save( QDomElement &element ) const { m_viewlist->save( element ); } void ViewListWidget::setProject( Project *project ) { debugPlan<currentIndex(), m_currentSchedule->modelColumn() ); debugPlan<setCurrentIndex( idx.row() ); debugPlan< * * 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 "kptviewlistdocker.h" #include "kptviewlist.h" #include "kptview.h" +#include "WhatsThis.h" #include "kptdebug.h" #include namespace KPlato { ViewListDocker::ViewListDocker(View *view) { updateWindowTitle( false ); setView(view); } ViewListDocker::~ViewListDocker() { } View *ViewListDocker::view() { return m_view; } void ViewListDocker::setView(View *view) { m_view = view; QWidget *wdg = widget(); if (wdg) delete wdg; m_viewlist = new ViewListWidget(view->getPart(), this); + setWhatsThis(m_viewlist->whatsThis()); setWidget(m_viewlist); m_viewlist->setProject( &( view->getProject() ) ); connect( m_viewlist, SIGNAL(selectionChanged(ScheduleManager*)), view, SLOT(slotSelectionChanged(ScheduleManager*)) ); connect( view, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), m_viewlist, SLOT(setSelectedSchedule(ScheduleManager*)) ); connect( m_viewlist, SIGNAL(updateViewInfo(ViewListItem*)), view, SLOT(slotUpdateViewInfo(ViewListItem*)) ); } void ViewListDocker::slotModified() { setWindowTitle( xi18nc( "@title:window", "View Selector [modified]" ) ); } void ViewListDocker::updateWindowTitle( bool modified ) { if ( modified ) { setWindowTitle( xi18nc( "@title:window", "View Selector [modified]" ) ); } else { setWindowTitle(xi18nc( "@title:window", "View Selector")); } } //---------- ViewListDockerFactory::ViewListDockerFactory(View *view) { m_view = view; } QString ViewListDockerFactory::id() const { return QString("KPlatoViewList"); } QDockWidget* ViewListDockerFactory::createDockWidget() { ViewListDocker *widget = new ViewListDocker(m_view); widget->setObjectName(id()); return widget; } } //namespace KPlato diff --git a/plan/libs/kernel/kptaccount.cpp b/plan/libs/kernel/kptaccount.cpp index 3ea859c9542..b4d32da70a1 100644 --- a/plan/libs/kernel/kptaccount.cpp +++ b/plan/libs/kernel/kptaccount.cpp @@ -1,902 +1,957 @@ /* This file is part of the KDE project Copyright (C) 2005, 2006, 2007, 2012 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 "kptaccount.h" #include "kptduration.h" #include "kptproject.h" #include "kptdebug.h" #include #include #include namespace KPlato { Account::Account() : m_name(), m_description(), m_list(0), m_parent(0), m_accountList(), m_costPlaces() { } Account::Account(const QString& name, const QString& description) : m_name(name), m_description(description), m_list(0), m_parent(0), m_accountList(), m_costPlaces() { } Account::~Account() { //debugPlan<accountDeleted(this); // default account } - if (m_list) - m_list->accountDeleted(this); - - while (!m_accountList.isEmpty()) + while (!m_accountList.isEmpty()) { delete m_accountList.takeFirst(); - - while (!m_costPlaces.isEmpty()) + } + while (!m_costPlaces.isEmpty()) { delete m_costPlaces.takeFirst(); + } + take(this); } bool Account::isDefaultAccount() const { return m_list == 0 ? false : m_list->defaultAccount() == this; } void Account::changed() { if ( m_list ) { m_list->accountChanged( this ); } } void Account::setName(const QString& name) { if (findAccount() == this) { removeId(); } m_name = name; insertId(); changed(); } void Account::setDescription(const QString& desc) { m_description = desc; changed(); } void Account::insert(Account *account, int index) { Q_ASSERT(account); int i = index == -1 ? m_accountList.count() : index; m_accountList.insert(i, account); account->setList(m_list); account->setParent(this); insertId(account); account->insertChildren(); } void Account::insertChildren() { foreach (Account *a, m_accountList) { a->setList(m_list); a->setParent(this); insertId(a); a->insertChildren(); } } void Account::take(Account *account) { if (account == 0) { return; } - if (account->parent() == this) { - int i = m_accountList.indexOf(account); - if (i != -1) - m_accountList.removeAt(i); - } else if (account->parent()) { - account->parent()->take(account); - } else { - m_list->take(account); + if (account->parent()) { + if (account->m_list) { + // emits remove signals, + // sets account->m_list = 0, + // calls us again + account->m_list->take(account); + } else { + // child account has been removed from Accounts + // so now we can remove child account from us + m_accountList.removeAt(m_accountList.indexOf(account)); + } + } else if (account->m_list) { + // we are top level so just needs Accounts to remove us + account->m_list->take(account); } //debugPlan<name(); } bool Account::isChildOf( const Account *account) const { if ( m_parent == 0 ) { return false; } if ( m_parent == account ) { return true; } return m_parent->isChildOf( account ); } bool Account::isBaselined( long id ) const { foreach ( CostPlace *p, m_costPlaces ) { if ( p->isBaselined( id ) ) { return true; } } return false; } bool Account::load(KoXmlElement &element, Project &project) { m_name = element.attribute("name"); m_description = element.attribute("description"); KoXmlNode n = element.firstChild(); for ( ; ! n.isNull(); n = n.nextSibling() ) { if ( ! n.isElement() ) { continue; } KoXmlElement e = n.toElement(); if (e.tagName() == "costplace") { Account::CostPlace *child = new Account::CostPlace(this); if (child->load(e, project)) { append(child); } else { delete child; } } else if (e.tagName() == "account") { Account *child = new Account(); if (child->load(e, project)) { m_accountList.append(child); } else { // TODO: Complain about this warnPlan<<"Loading failed"; delete child; } } } return true; } void Account::save(QDomElement &element) const { QDomElement me = element.ownerDocument().createElement("account"); element.appendChild(me); me.setAttribute("name", m_name); me.setAttribute("description", m_description); foreach (Account::CostPlace *cp, m_costPlaces) { cp->save(me); } foreach (Account *a, m_accountList) { a->save(me); } } -Account::CostPlace *Account::findCostPlace(const Node &node) const { +Account::CostPlace *Account::findCostPlace(const Resource &resource) const +{ foreach (Account::CostPlace *cp, m_costPlaces) { - if (&node == cp->node()) { + if (&resource == cp->resource()) { return cp; } } return 0; } -Account::CostPlace *Account::findCostPlace(const Resource &resource) const { +Account::CostPlace *Account::findRunning(const Resource &resource) const { foreach (Account::CostPlace *cp, m_costPlaces) { - if (&resource == cp->resource()) { + if (&resource == cp->resource() && cp->running()) { return cp; } } return 0; } -Account::CostPlace *Account::findRunning(const Resource &resource) const { - Account::CostPlace *cp = findCostPlace(resource); - return cp && cp->running() ? cp : 0; -} - void Account::removeRunning(const Resource &resource) { Account::CostPlace *cp = findRunning(resource); - if (cp) { + if (cp && cp->running()) { cp->setRunning(false); if (cp->isEmpty()) { deleteCostPlace(cp); } } } void Account::addRunning(Resource &resource) { - Account::CostPlace *cp = findCostPlace(resource); + Account::CostPlace *cp = findRunning(resource); if (cp) { cp->setRunning(true); changed(); return; } cp = new CostPlace(this, &resource, true); append(cp); changed(); } -Account::CostPlace *Account::findRunning(const Node &node) const { - Account::CostPlace *cp = findCostPlace(node); - return cp && cp->running() ? cp : 0; +Account::CostPlace *Account::findCostPlace(const Node &node) const +{ + foreach (Account::CostPlace *cp, m_costPlaces) { + if (&node == cp->node()) { + return cp; + } + } + return 0; +} + +Account::CostPlace *Account::findRunning(const Node &node) const +{ + for (CostPlace *cp : m_costPlaces) { + if (cp->node() == &node && cp->running()) { + return cp; + } + } + return 0; } void Account::removeRunning(const Node &node) { - Account::CostPlace *cp = findRunning(node); + CostPlace *cp = findRunning(node); if (cp) { cp->setRunning(false); if (cp->isEmpty()) { deleteCostPlace(cp); } + changed(); } } void Account::addRunning(Node &node) { Account::CostPlace *cp = findCostPlace(node); if (cp) { cp->setRunning(true); changed(); return; } cp = new CostPlace(this, &node, true); append(cp); changed(); } Account::CostPlace *Account::findStartup(const Node &node) const { - Account::CostPlace *cp = findCostPlace(node); - return cp && cp->startup() ? cp : 0; + for (CostPlace *cp : m_costPlaces) { + if (cp->node() == &node && cp->startup()) { + return cp; + } + } + return 0; } void Account::removeStartup(const Node &node) { Account::CostPlace *cp = findStartup(node); if (cp) { cp->setStartup(false); if (cp->isEmpty()) { deleteCostPlace(cp); } changed(); } } void Account::addStartup(Node &node) { Account::CostPlace *cp = findCostPlace(node); if (cp) { cp->setStartup(true); changed(); return; } cp = new CostPlace(this, &node, false, true, false); append(cp); changed(); } Account::CostPlace *Account::findShutdown(const Node &node) const { - Account::CostPlace *cp = findCostPlace(node); - return cp && cp->shutdown() ? cp : 0; + for (CostPlace *cp : m_costPlaces) { + if (cp->node() == &node && cp->shutdown()) { + return cp; + } + } + return 0; } void Account::removeShutdown(const Node &node) { Account::CostPlace *cp = findShutdown(node); if (cp) { cp->setShutdown(false); if (cp->isEmpty()) { deleteCostPlace(cp); } changed(); } } void Account::addShutdown(Node &node) { Account::CostPlace *cp = findCostPlace(node); if (cp) { cp->setShutdown(true); changed(); return; } cp = new CostPlace(this, &node, false, false, true); append(cp); changed(); } Account *Account::findAccount(const QString &id) const { if (m_list) return m_list->findAccount(id); return 0; } bool Account::removeId(const QString &id) { return (m_list ? m_list->removeId(id) : false); } bool Account::insertId() { return insertId(this); } bool Account::insertId(Account *account) { return (m_list ? m_list->insertId(account) : false); } void Account::deleteCostPlace(CostPlace *cp) { //debugPlan; int i = m_costPlaces.indexOf(cp); if (i != -1) m_costPlaces.removeAt(i); delete cp; } EffortCostMap Account::plannedCost(long id) const { return plannedCost( QDate(), QDate(), id ); } EffortCostMap Account::plannedCost(const QDate &start, const QDate &end, long id) const { EffortCostMap ec; if ( ! isElement() ) { foreach ( Account *a, m_accountList ) { ec += a->plannedCost( start, end, id ); } } foreach (Account::CostPlace *cp, m_costPlaces) { ec += plannedCost( *cp, start, end, id ); } if (isDefaultAccount()) { QList list = m_list == 0 ? QList() : m_list->allNodes(); foreach (Node *n, list) { if ( n->numChildren() > 0 ) { continue; } if (n->runningAccount() == 0) { ec += n->plannedEffortCostPrDay(start, end, id); } if (n->startupAccount() == 0) { if ( ( ! start.isValid() || n->startTime( id ).date() >= start ) && ( ! end.isValid() || n->startTime( id ).date() <= end ) ) { ec.add(n->startTime( id ).date(), EffortCost(Duration::zeroDuration, n->startupCost())); } } if (n->shutdownAccount() == 0) { if ( ( ! start.isValid() || n->endTime( id ).date() >= start ) && ( ! end.isValid() || n->endTime( id ).date() <= end ) ) { ec.add(n->endTime( id ).date(), EffortCost(Duration::zeroDuration, n->shutdownCost())); } } } } return ec; } EffortCostMap Account::plannedCost( const Account::CostPlace &cp, const QDate &start, const QDate &end, long id) const { EffortCostMap ec; if ( cp.node() ) { Node &node = *(cp.node()); //debugPlan<<"n="<name(); if (cp.running()) { ec += node.plannedEffortCostPrDay(start, end, id); } if (cp.startup()) { if ( ( ! start.isValid() || node.startTime( id ).date() >= start ) && ( ! end.isValid() || node.startTime( id ).date() <= end ) ) { ec.add(node.startTime( id ).date(), EffortCost(Duration::zeroDuration, node.startupCost())); } } if (cp.shutdown()) { if ( ( ! start.isValid() || node.endTime( id ).date() >= start ) && ( ! end.isValid() || node.endTime( id ).date() <= end ) ) { ec.add(node.endTime( id ).date(), EffortCost(Duration::zeroDuration, node.shutdownCost())); } } } else if ( cp.resource() ) { if ( cp.running() ) { ec += cp.resource()->plannedEffortCostPrDay(start, end, id); } } return ec; } EffortCostMap Account::actualCost(long id) const { return actualCost( QDate(), QDate(), id ); } EffortCostMap Account::actualCost(const QDate &start, const QDate &end, long id) const { EffortCostMap ec; if ( ! isElement() ) { foreach ( Account *a, m_accountList ) { ec += a->actualCost( start, end, id ); } } foreach (Account::CostPlace *cp, costPlaces()) { ec += actualCost( *cp, start, end, id ); } if (isDefaultAccount()) { QList list = m_list == 0 ? QList() : m_list->allNodes(); foreach (Node *n, list) { if ( n->numChildren() > 0 ) { continue; } if (n->runningAccount() == 0) { //debugPlan<<"default, running:"<name(); ec += n->actualEffortCostPrDay(start, end, id); } Task *t = dynamic_cast( n ); // only tasks have completion if ( t ) { if (n->startupAccount() == 0 && t->completion().isStarted()) { const QDate startDate = t->completion().startTime().date(); if ( ( ! start.isValid() || startDate >= start ) && ( ! end.isValid() || startDate <= end ) ) { ec.add(startDate, EffortCost(Duration::zeroDuration, n->startupCost())); } } if (n->shutdownAccount() == 0 && t->completion().isFinished()) { //debugPlan<<"default, shutdown:"<name(); const QDate finishDate = t->completion().finishTime().date(); if ( ( ! start.isValid() || finishDate >= start ) && ( ! end.isValid() || finishDate <= end ) ) { ec.add(finishDate, EffortCost(Duration::zeroDuration, n->shutdownCost())); } } } } } return ec; } EffortCostMap Account::actualCost(const Account::CostPlace &cp, const QDate &start, const QDate &end, long id) const { EffortCostMap ec; if ( cp.node() ) { Node &node = *(cp.node()); if (cp.running()) { ec += node.actualEffortCostPrDay(start, end, id); } Task *t = dynamic_cast( &node ); // only tasks have completion if ( t ) { if (cp.startup() && t->completion().isStarted()) { const QDate startDate = t->completion().startTime().date(); if ( ( ! start.isValid() || startDate >= start ) && ( ! end.isValid() || startDate <= end ) ) { ec.add(startDate, EffortCost(Duration::zeroDuration, node.startupCost())); } } if (cp.shutdown() && t->completion().isFinished()) { const QDate finishDate = t->completion().finishTime().date(); if ( ( ! start.isValid() || finishDate >= start ) && ( ! end.isValid() || finishDate <= end ) ) { ec.add(finishDate, EffortCost(Duration::zeroDuration, node.shutdownCost())); } } } } else if ( cp.resource() && m_list ) { foreach ( Node *n, m_list->allNodes() ) { if ( n->type() == Node::Type_Task ) { ec += n->actualEffortCostPrDay( cp.resource(), start, end, id ); } } } return ec; } //------------------------------------ Account::CostPlace::CostPlace(Account *acc, Node *node, bool running, bool strtup, bool shutdown) : m_account(acc), m_objectId(node->id()), m_node(node), m_resource(0), m_running( false ), m_startup( false ), m_shutdown( false ) { if (node) { if (running) setRunning(running); if (strtup) setStartup(strtup); if (shutdown) setShutdown(shutdown); } } Account::CostPlace::CostPlace(Account *acc, Resource *resource, bool running) : m_account(acc), m_objectId(resource->id()), m_node(0), m_resource(resource), m_running( false ), m_startup( false ), m_shutdown( false ) { if (resource) { if (running) setRunning(running); } } Account::CostPlace::~CostPlace() { + if (m_node) { - if (m_running) + if (m_running) { + m_running = false; m_node->setRunningAccount(0); - if (m_startup) + } + if (m_startup) { + m_startup = false; m_node->setStartupAccount(0); - if (m_shutdown) + } + if (m_shutdown) { + m_shutdown = false; m_node->setShutdownAccount(0); + } } if (m_resource) { - if (m_running) + if (m_running) { + m_running = false; m_resource->setAccount(0); + } } } bool Account::CostPlace::isBaselined( long id ) const { if ( m_node ) { if ( m_running ) { if ( m_node->isBaselined( id ) ) { return true; } } if ( m_startup ) { if ( m_node->isBaselined( id ) ) { return true; } } if ( m_shutdown ) { if ( m_node->isBaselined( id ) ) { return true; } } } if ( m_resource ) { if ( m_running ) { if ( m_resource->isBaselined( id ) ) { return true; } } } return false; } void Account::CostPlace::setNode(Node* node) { Q_ASSERT( ! m_node ); m_node = node; } void Account::CostPlace::setResource(Resource* resource) { Q_ASSERT( ! m_resource ); m_resource = resource; } -void Account::CostPlace::setRunning(bool on ) { +void Account::CostPlace::setRunning(bool on ) +{ + if (m_running == on) { + return; + } m_running = on; if (m_node) { m_node->setRunningAccount(on ? m_account : 0); } else if ( m_resource ) { m_resource->setAccount(on ? m_account : 0); } } -void Account::CostPlace::setStartup(bool on ) { +void Account::CostPlace::setStartup(bool on ) +{ + if (m_startup == on) { + return; + } m_startup = on; if (m_node) m_node->setStartupAccount(on ? m_account : 0); } -void Account::CostPlace::setShutdown(bool on ) { +void Account::CostPlace::setShutdown(bool on ) +{ + if (m_shutdown == on) { + return; + } m_shutdown = on; if (m_node) m_node->setShutdownAccount(on ? m_account : 0); } //TODO bool Account::CostPlace::load(KoXmlElement &element, Project &project) { //debugPlan; m_objectId = element.attribute("object-id"); if (m_objectId.isEmpty()) { // check old format m_objectId = element.attribute("node-id"); if (m_objectId.isEmpty()) { errorPlan<<"No object id"; return false; } } m_node = project.findNode(m_objectId); if (m_node == 0) { m_resource = project.findResource(m_objectId); if ( m_resource == 0 ) { errorPlan<<"Cannot find object with id: "<setList(this); account->setParent(0); // incase... insertId(account); account->insertChildren(); } else { int i = index == -1 ? parent->accountList().count() : index; emit accountToBeAdded( parent, i ); parent->insert( account, i ); } //debugPlan<name(); emit accountAdded( account ); } void Accounts::take(Account *account){ if (account == 0) { return; } + account->m_list = 0; removeId(account->name()); if (account->parent()) { emit accountToBeRemoved( account ); account->parent()->take(account); emit accountRemoved( account ); //debugPlan<name(); return; } int i = m_accountList.indexOf(account); if (i != -1) { emit accountToBeRemoved( account ); m_accountList.removeAt(i); emit accountRemoved( account ); } //debugPlan<name(); } bool Accounts::load(KoXmlElement &element, Project &project) { KoXmlNode n = element.firstChild(); for ( ; ! n.isNull(); n = n.nextSibling() ) { if ( ! n.isElement() ) { continue; } KoXmlElement e = n.toElement(); if (e.tagName() == "account") { Account *child = new Account(); if (child->load(e, project)) { insert(child); } else { // TODO: Complain about this warnPlan<<"Loading failed"; delete child; } } } if (element.hasAttribute("default-account")) { m_defaultAccount = findAccount(element.attribute("default-account")); if (m_defaultAccount == 0) { warnPlan<<"Could not find default account."; } } return true; } void Accounts::save(QDomElement &element) const { QDomElement me = element.ownerDocument().createElement("accounts"); element.appendChild(me); if (m_defaultAccount) { me.setAttribute("default-account", m_defaultAccount->name()); } foreach (Account *a, m_accountList) { a->save(me); } } QStringList Accounts::costElements() const { QStringList l; foreach (const QString &key, m_idDict.uniqueKeys()) { if (m_idDict[key]->isElement()) l << key; } return l; } QStringList Accounts::nameList() const { return m_idDict.uniqueKeys(); } Account *Accounts::findRunningAccount(const Resource &resource) const { foreach (Account *a, m_idDict) { if (a->findRunning(resource)) { return a; } } return 0; } Account *Accounts::findRunningAccount(const Node &node) const { foreach (Account *a, m_idDict) { if (a->findRunning(node)) return a; } return 0; } Account *Accounts::findStartupAccount(const Node &node) const { foreach (Account *a, m_idDict) { if (a->findStartup(node)) return a; } return 0; } Account *Accounts::findShutdownAccount(const Node &node) const { foreach (Account *a, m_idDict) { if (a->findShutdown(node)) return a; } return 0; } Account *Accounts::findAccount(const QString &id) const { return m_idDict.value(id); } bool Accounts::insertId(Account *account) { Q_ASSERT(account); Account *a = findAccount(account->name()); if (a == 0) { //debugPlan<<"'"<name()<<"' inserted"; m_idDict.insert(account->name(), account); return true; } if (a == account) { debugPlan<<"'"<name()<<"' already exists"; return true; } //TODO: Create unique id? warnPlan<<"Insert failed, creating unique id"; account->setName( uniqueId( account->name() ) ); // setName() calls insertId !! return false; } bool Accounts::removeId(const QString &id) { bool res = m_idDict.remove(id); //debugPlan< Accounts::allNodes() const { return m_project.allNodes(); } #ifndef NDEBUG void Accounts::printDebug(const QString& indent) { debugPlan<printDebug( indent + " !" ); } } void Account::printDebug(const QString& indent) { debugPlan<printDebug( indent + " !" ); } } #endif } //namespace KPlato diff --git a/plan/libs/kernel/kptaccount.h b/plan/libs/kernel/kptaccount.h index 3c10649048a..3c0ad4484c4 100644 --- a/plan/libs/kernel/kptaccount.h +++ b/plan/libs/kernel/kptaccount.h @@ -1,298 +1,298 @@ /* This file is part of the KDE project Copyright (C) 2005 - 2007 Dag Andersen Copyright (C) 2011 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 KPTACCOUNT_H #define KPTACCOUNT_H #include "kplatokernel_export.h" #include #include #include "kptglobal.h" #include "kpteffortcostmap.h" #include "kptnode.h" #include "kptresource.h" #include class QDomElement; class QStringList; namespace KPlato { class Accounts; class Account; /** * Account holds one account. * An account can have any number of sub-accounts. * Account names must be unique. */ class KPLATOKERNEL_EXPORT Account { public: /** * Constructor. */ Account(); /** * */ explicit Account(const QString& name, const QString& description=QString()); /** * Destructor. */ ~Account(); QString name() const { return m_name; } void setName(const QString& name); QString description() const { return m_description; } void setDescription(const QString& desc); bool isElement() const { return m_accountList.isEmpty(); } bool isDefaultAccount() const; Accounts *list() const { return m_list; } void setList(Accounts *list) { m_list = list; } Account *parent() const { return m_parent; } void setParent(Account *parent) { m_parent = parent; } void clear() { m_accountList.clear(); } void insert(Account *account, int index = -1); void take(Account *account); bool isChildOf( const Account *account ) const; void insertChildren(); int indexOf( Account *account ) const { return m_accountList.indexOf( account ); } bool isBaselined( long id = BASELINESCHEDULE ) const; bool load(KoXmlElement &element, Project &project); void save(QDomElement &element) const; const QList &accountList() const { return m_accountList; } int childCount() const { return m_accountList.count(); } Account *childAt( int index ) const { return m_accountList.value( index ); } Account *findAccount() const { return findAccount(m_name); } Account *findAccount(const QString &id) const; bool removeId() { return removeId(m_name); } bool removeId(const QString &id); bool insertId(); bool insertId(Account *account); void changed(); class CostPlace { public: /// Create an empty cost place CostPlace() : m_account(0), m_objectId(), m_node(0), m_resource(0), m_running(false), m_startup(false), m_shutdown(false) {} /// Create an empty cost place for account @p acc explicit CostPlace(Account *acc) : m_account(acc), m_objectId(), m_node(0), m_resource(0), m_running(false), m_startup(false), m_shutdown(false) {} /// Create a cost place for a task CostPlace(Account *acc, Node *node, bool running=false, bool strtup=false, bool shutdown=false); /// Create a cost place for a resource CostPlace(Account *acc, Resource *resource, bool running=false); explicit CostPlace(CostPlace *cp) { m_account = cp->m_account; m_objectId = cp->m_objectId; m_node = cp->m_node; m_resource = cp->m_resource; m_running = cp->m_running; m_startup = cp->m_startup; m_shutdown = cp->m_shutdown; } ~CostPlace(); bool isBaselined( long id = BASELINESCHEDULE ) const; bool isEmpty() { return !(m_running || m_startup || m_shutdown); } Node *node() const { return m_node; } void setNode( Node *node ); Resource *resource() const { return m_resource; } void setResource( Resource *resource ); bool running() const { return m_running; } void setRunning(bool on ); bool startup() const { return m_startup; } void setStartup(bool on); bool shutdown() const { return m_shutdown; } void setShutdown(bool on); bool load(KoXmlElement &element, Project &project); void save(QDomElement &element) const; // for loading xml void setObjectId( const QString &id ); QString objectId() const; private: Account *m_account; QString m_objectId; Node *m_node; Resource *m_resource; bool m_running; bool m_startup; bool m_shutdown; }; void append(CostPlace *cp) { m_costPlaces.append(cp); } const QList &costPlaces() const {return m_costPlaces; } Account::CostPlace *findCostPlace(const Node &node) const; Account::CostPlace *findCostPlace(const Resource &resource) const; CostPlace *findRunning(const Resource &resource) const; void removeRunning(const Resource &resource); void addRunning(Resource &resource); CostPlace *findRunning(const Node &node) const; void removeRunning(const Node &node); void addRunning(Node &node); CostPlace *findStartup(const Node &node) const; void removeStartup(const Node &node); void addStartup(Node &node); CostPlace *findShutdown(const Node &node) const; void removeShutdown(const Node &node); void addShutdown(Node &node); void deleteCostPlace(CostPlace *cp); EffortCostMap plannedCost(long id = BASELINESCHEDULE) const; EffortCostMap plannedCost(const QDate &start, const QDate &end, long id = BASELINESCHEDULE) const; EffortCostMap actualCost(long id = BASELINESCHEDULE) const; EffortCostMap actualCost(const QDate &start, const QDate &end, long id = BASELINESCHEDULE) const; protected: EffortCostMap plannedCost(const CostPlace &cp, const QDate &start, const QDate &end, long id ) const; EffortCostMap actualCost(const Account::CostPlace &cp, const QDate &start, const QDate &end, long id) const; private: QString m_name; QString m_description; + friend class Accounts; Accounts *m_list; Account *m_parent; QList m_accountList; QList m_costPlaces; #ifndef NDEBUG public: void printDebug(const QString& indent); #endif }; typedef QList AccountList; typedef QListIterator AccountListIterator; /** * Accounts administrates all accounts. */ class KPLATOKERNEL_EXPORT Accounts : public QObject { Q_OBJECT public: explicit Accounts(Project &project); ~Accounts(); Account *defaultAccount() const { return m_defaultAccount; } void setDefaultAccount(Account *account); /// Return the planned cost from all cost places of this account added to cost from all sub-accounts EffortCostMap plannedCost(const Account &account, long id = BASELINESCHEDULE) const; /// Return the planned cost from all cost places of this account added to cost from all sub-accounts /// for the interval @p start to @p end inclusive EffortCostMap plannedCost(const Account &account, const QDate &start, const QDate &end, long id = BASELINESCHEDULE) const; /// Return the actual cost from all cost places of this account added to cost from all sub-accounts EffortCostMap actualCost(const Account &account, long id = BASELINESCHEDULE) const; /// Return the actual cost from all cost places of this account added to cost from all sub-accounts /// for the interval @p start to @p end inclusive EffortCostMap actualCost(const Account &account, const QDate &start, const QDate &end, long id = BASELINESCHEDULE) const; void clear() { m_accountList.clear(); m_idDict.clear(); } void insert(Account *account, Account *parent=0, int index = -1); void take(Account *account); bool load(KoXmlElement &element, Project &project); void save(QDomElement &element) const; QStringList costElements() const; QStringList nameList() const; const AccountList &accountList() const { return m_accountList; } int accountCount() const { return m_accountList.count(); } Account *accountAt( int index ) const { return m_accountList.value( index ); } int indexOf( Account *account ) const { return m_accountList.indexOf( account ); } Account *findRunningAccount(const Resource &resource) const; Account *findRunningAccount(const Node &node) const; Account *findStartupAccount(const Node &node) const; Account *findShutdownAccount(const Node &node) const; Account *findAccount(const QString &id) const; bool insertId(Account *account); bool removeId(const QString &id); QString uniqueId( const QString &seed ) const; - void accountDeleted(Account *account) - { if (account == m_defaultAccount) m_defaultAccount = 0; } + void accountDeleted(Account *account); void accountChanged( Account *account ); QList allAccounts() const { return m_idDict.values(); } QList allNodes() const; Q_SIGNALS: void accountAdded( const Account * ); void accountToBeAdded( const Account *, int ); void accountRemoved( const Account * ); void accountToBeRemoved( const Account * ); void changed( Account *); void defaultAccountChanged(); private: Project &m_project; AccountList m_accountList; QMap m_idDict; Account *m_defaultAccount; #ifndef NDEBUG public: void printDebug(const QString& indent); #endif }; } //namespace KPlato #endif diff --git a/plan/libs/kernel/kptcommand.cpp b/plan/libs/kernel/kptcommand.cpp index 653d9215a86..a6792800668 100644 --- a/plan/libs/kernel/kptcommand.cpp +++ b/plan/libs/kernel/kptcommand.cpp @@ -1,3706 +1,3747 @@ /* This file is part of the KDE project Copyright (C) 2004 - 2007 Dag Andersen Copyright (C) 2011 Dag Andersen Copyright (C) 2016 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 "kptcommand.h" #include "kptaccount.h" #include "kptappointment.h" #include "kptproject.h" #include "kpttask.h" #include "kptcalendar.h" #include "kptrelation.h" #include "kptresource.h" #include "kptdocuments.h" #include "kptlocale.h" #include "kptdebug.h" #include const QLoggingCategory &PLANCMDINSPROJECT_LOG() { static const QLoggingCategory category("calligra.plan.command.insertProject"); return category; } #define debugPlanInsertProject qCDebug(PLANCMDINSPROJECT_LOG) #define warnPlanInsertProject qCWarning(PLANCMDINSPROJECT_LOG) #define errorPlanInsertProject qCCritical(PLANCMDINSPROJECT_LOG) namespace KPlato { void NamedCommand::setSchScheduled() { QMap::ConstIterator it; for ( it = m_schedules.constBegin(); it != m_schedules.constEnd(); ++it ) { //debugPlan << it.key() ->name() <<":" << it.value(); it.key() ->setScheduled( it.value() ); } } void NamedCommand::setSchScheduled( bool state ) { QMap::ConstIterator it; for ( it = m_schedules.constBegin(); it != m_schedules.constEnd(); ++it ) { //debugPlan << it.key() ->name() <<":" << state; it.key() ->setScheduled( state ); } } void NamedCommand::addSchScheduled( Schedule *sch ) { //debugPlan << sch->id() <<":" << sch->isScheduled(); m_schedules.insert( sch, sch->isScheduled() ); foreach ( Appointment * a, sch->appointments() ) { if ( a->node() == sch ) { m_schedules.insert( a->resource(), a->resource() ->isScheduled() ); } else if ( a->resource() == sch ) { m_schedules.insert( a->node(), a->node() ->isScheduled() ); } } } //--------- MacroCommand::~MacroCommand() { while ( ! cmds.isEmpty() ) { delete cmds.takeLast(); } } void MacroCommand::addCommand( KUndo2Command *cmd ) { cmds.append( cmd ); } void MacroCommand::execute() { foreach ( KUndo2Command *c, cmds ) { c->redo(); } } void MacroCommand::unexecute() { for (int i = cmds.count() - 1; i >= 0; --i) { cmds.at( i )->undo(); } } //------------------------------------------------- CalendarAddCmd::CalendarAddCmd( Project *project, Calendar *cal, int pos, Calendar *parent, const KUndo2MagicString& name ) : NamedCommand( name ), m_project( project ), m_cal( cal ), m_pos( pos ), m_parent( parent ), m_mine( true ) { //debugPlan<name(); Q_ASSERT( project != 0 ); } CalendarAddCmd::~CalendarAddCmd() { if ( m_mine ) delete m_cal; } void CalendarAddCmd::execute() { if ( m_project ) { m_project->addCalendar( m_cal, m_parent, m_pos ); m_mine = false; } //debugPlan<name()<<" added to:"<name(); } void CalendarAddCmd::unexecute() { if ( m_project ) { m_project->takeCalendar( m_cal ); m_mine = true; } //debugPlan<name(); } CalendarRemoveCmd::CalendarRemoveCmd( Project *project, Calendar *cal, const KUndo2MagicString& name ) : NamedCommand( name ), m_project( project ), m_parent( cal->parentCal() ), m_cal( cal ), m_index( -1 ), m_mine( false ), m_cmd( new MacroCommand(KUndo2MagicString()) ) { Q_ASSERT( project != 0 ); m_index = m_parent ? m_parent->indexOf( cal ) : project->indexOf( cal ); foreach ( Resource *r, project->resourceList() ) { if ( r->calendar( true ) == cal ) { m_cmd->addCommand( new ModifyResourceCalendarCmd( r, 0 ) ); } } if ( project->defaultCalendar() == cal ) { m_cmd->addCommand( new ProjectModifyDefaultCalendarCmd( project, 0 ) ); } foreach ( Calendar *c, cal->calendars() ) { m_cmd->addCommand( new CalendarRemoveCmd( project, c ) ); } } CalendarRemoveCmd::~CalendarRemoveCmd() { delete m_cmd; if ( m_mine ) delete m_cal; } void CalendarRemoveCmd::execute() { m_cmd->execute(); m_project->takeCalendar( m_cal ); m_mine = true; } void CalendarRemoveCmd::unexecute() { m_project->addCalendar( m_cal, m_parent, m_index ); m_cmd->unexecute(); m_mine = false; } CalendarMoveCmd::CalendarMoveCmd( Project *project, Calendar *cal, int position, Calendar *parent, const KUndo2MagicString& name ) : NamedCommand( name ), m_project( project ), m_cal( cal ), m_newpos( position ), m_newparent( parent ), m_oldparent( cal->parentCal() ) { //debugPlan<name(); Q_ASSERT( project != 0 ); m_oldpos = m_oldparent ? m_oldparent->indexOf( cal ) : project->indexOf( cal ); } void CalendarMoveCmd::execute() { m_project->takeCalendar( m_cal ); m_project->addCalendar( m_cal, m_newparent, m_newpos ); } void CalendarMoveCmd::unexecute() { m_project->takeCalendar( m_cal ); m_project->addCalendar( m_cal, m_oldparent, m_oldpos ); } CalendarModifyNameCmd::CalendarModifyNameCmd( Calendar *cal, const QString& newvalue, const KUndo2MagicString& name ) : NamedCommand( name ), m_cal( cal ) { m_oldvalue = cal->name(); m_newvalue = newvalue; //debugPlan<name(); } void CalendarModifyNameCmd::execute() { m_cal->setName( m_newvalue ); //debugPlan<name(); } void CalendarModifyNameCmd::unexecute() { m_cal->setName( m_oldvalue ); //debugPlan<name(); } CalendarModifyParentCmd::CalendarModifyParentCmd( Project *project, Calendar *cal, Calendar *newvalue, const KUndo2MagicString& name ) : NamedCommand( name ), m_project( project ), m_cal( cal ), m_cmd( new MacroCommand( KUndo2MagicString() ) ), m_oldindex( -1 ), m_newindex( -1 ) { m_oldvalue = cal->parentCal(); m_newvalue = newvalue; m_oldindex = m_oldvalue ? m_oldvalue->indexOf( cal ) : m_project->indexOf( cal ); if ( newvalue ) { m_cmd->addCommand( new CalendarModifyTimeZoneCmd( cal, newvalue->timeZone() ) ); } //debugPlan<name(); } CalendarModifyParentCmd::~CalendarModifyParentCmd() { delete m_cmd; } void CalendarModifyParentCmd::execute() { m_project->takeCalendar( m_cal ); m_project->addCalendar( m_cal, m_newvalue, m_newindex ); m_cmd->execute(); } void CalendarModifyParentCmd::unexecute() { m_cmd->unexecute(); m_project->takeCalendar( m_cal ); m_project->addCalendar( m_cal, m_oldvalue, m_oldindex ); } CalendarModifyTimeZoneCmd::CalendarModifyTimeZoneCmd( Calendar *cal, const QTimeZone &value, const KUndo2MagicString& name ) : NamedCommand( name ), m_cal( cal ), m_newvalue( value ), m_cmd( new MacroCommand( KUndo2MagicString() ) ) { m_oldvalue = cal->timeZone(); foreach ( Calendar *c, cal->calendars() ) { m_cmd->addCommand( new CalendarModifyTimeZoneCmd( c, value ) ); } //debugPlan<name(); } CalendarModifyTimeZoneCmd::~CalendarModifyTimeZoneCmd() { delete m_cmd; } void CalendarModifyTimeZoneCmd::execute() { m_cmd->execute(); m_cal->setTimeZone( m_newvalue ); } void CalendarModifyTimeZoneCmd::unexecute() { m_cal->setTimeZone( m_oldvalue ); m_cmd->unexecute(); } #ifdef HAVE_KHOLIDAYS CalendarModifyHolidayRegionCmd::CalendarModifyHolidayRegionCmd( Calendar *cal, const QString &value, const KUndo2MagicString& name ) : NamedCommand( name ), m_cal( cal ), m_newvalue( value ) { m_oldvalue = cal->holidayRegionCode(); } CalendarModifyHolidayRegionCmd::~CalendarModifyHolidayRegionCmd() { } void CalendarModifyHolidayRegionCmd::execute() { m_cal->setHolidayRegion( m_newvalue ); } void CalendarModifyHolidayRegionCmd::unexecute() { m_cal->setHolidayRegion( m_oldvalue ); } #endif CalendarAddDayCmd::CalendarAddDayCmd( Calendar *cal, CalendarDay *newvalue, const KUndo2MagicString& name ) : NamedCommand( name ), m_cal( cal ), m_mine( true ) { m_newvalue = newvalue; //debugPlan<name(); } CalendarAddDayCmd::~CalendarAddDayCmd() { //debugPlan; if ( m_mine ) delete m_newvalue; } void CalendarAddDayCmd::execute() { //debugPlan<name(); m_cal->addDay( m_newvalue ); m_mine = false; } void CalendarAddDayCmd::unexecute() { //debugPlan<name(); m_cal->takeDay( m_newvalue ); m_mine = true; } CalendarRemoveDayCmd::CalendarRemoveDayCmd( Calendar *cal,CalendarDay *day, const KUndo2MagicString& name ) : NamedCommand( name ), m_cal( cal ), m_value( day ), m_mine( false ) { //debugPlan<name(); // TODO check if any resources uses this calendar init(); } CalendarRemoveDayCmd::CalendarRemoveDayCmd( Calendar *cal, const QDate &day, const KUndo2MagicString& name ) : NamedCommand( name ), m_cal( cal ), m_mine( false ) { m_value = cal->findDay( day ); //debugPlan<name(); // TODO check if any resources uses this calendar init(); } void CalendarRemoveDayCmd::init() { } void CalendarRemoveDayCmd::execute() { //debugPlan<name(); m_cal->takeDay( m_value ); m_mine = true; } void CalendarRemoveDayCmd::unexecute() { //debugPlan<name(); m_cal->addDay( m_value ); m_mine = false; } CalendarModifyDayCmd::CalendarModifyDayCmd( Calendar *cal, CalendarDay *value, const KUndo2MagicString& name ) : NamedCommand( name ), m_cal( cal ), m_mine( true ) { m_newvalue = value; m_oldvalue = cal->findDay( value->date() ); //debugPlan<name()<<" old:("<takeDay( m_oldvalue ); } m_cal->addDay( m_newvalue ); m_mine = false; } void CalendarModifyDayCmd::unexecute() { //debugPlan; m_cal->takeDay( m_newvalue ); if ( m_oldvalue ) { m_cal->addDay( m_oldvalue ); } m_mine = true; } CalendarModifyStateCmd::CalendarModifyStateCmd( Calendar *calendar, CalendarDay *day, CalendarDay::State value, const KUndo2MagicString& name ) : NamedCommand( name ), m_calendar( calendar ), m_day( day ), m_cmd( new MacroCommand( KUndo2MagicString() ) ) { m_newvalue = value; m_oldvalue = (CalendarDay::State)day->state(); if ( value != CalendarDay::Working ) { foreach ( TimeInterval *ti, day->timeIntervals() ) { m_cmd->addCommand( new CalendarRemoveTimeIntervalCmd( calendar, day, ti ) ); } } } CalendarModifyStateCmd::~CalendarModifyStateCmd() { delete m_cmd; } void CalendarModifyStateCmd::execute() { //debugPlan; m_cmd->execute(); m_calendar->setState( m_day, m_newvalue ); } void CalendarModifyStateCmd::unexecute() { //debugPlan; m_calendar->setState( m_day, m_oldvalue ); m_cmd->unexecute(); } CalendarModifyTimeIntervalCmd::CalendarModifyTimeIntervalCmd( Calendar *calendar, TimeInterval &newvalue, TimeInterval *value, const KUndo2MagicString& name ) : NamedCommand( name ), m_calendar( calendar ) { m_value = value; // keep pointer m_oldvalue = *value; // save value m_newvalue = newvalue; } void CalendarModifyTimeIntervalCmd::execute() { //debugPlan; m_calendar->setWorkInterval( m_value, m_newvalue ); } void CalendarModifyTimeIntervalCmd::unexecute() { //debugPlan; m_calendar->setWorkInterval( m_value, m_oldvalue ); } CalendarAddTimeIntervalCmd::CalendarAddTimeIntervalCmd( Calendar *calendar, CalendarDay *day, TimeInterval *value, const KUndo2MagicString& name ) : NamedCommand( name ), m_calendar( calendar ), m_day( day ), m_value( value ), m_mine( true ) { } CalendarAddTimeIntervalCmd::~CalendarAddTimeIntervalCmd() { if ( m_mine ) delete m_value; } void CalendarAddTimeIntervalCmd::execute() { //debugPlan; m_calendar->addWorkInterval( m_day, m_value ); m_mine = false; } void CalendarAddTimeIntervalCmd::unexecute() { //debugPlan; m_calendar->takeWorkInterval( m_day, m_value ); m_mine = true; } CalendarRemoveTimeIntervalCmd::CalendarRemoveTimeIntervalCmd( Calendar *calendar, CalendarDay *day, TimeInterval *value, const KUndo2MagicString& name ) : CalendarAddTimeIntervalCmd( calendar, day, value, name ) { m_mine = false ; } void CalendarRemoveTimeIntervalCmd::execute() { CalendarAddTimeIntervalCmd::unexecute(); } void CalendarRemoveTimeIntervalCmd::unexecute() { CalendarAddTimeIntervalCmd::execute(); } CalendarModifyWeekdayCmd::CalendarModifyWeekdayCmd( Calendar *cal, int weekday, CalendarDay *value, const KUndo2MagicString& name ) : NamedCommand( name ), m_weekday( weekday ), m_cal( cal ), m_value( value ), m_orig( *( cal->weekday( weekday ) ) ) { //debugPlan << cal->name() <<" (" << value <<")"; } CalendarModifyWeekdayCmd::~CalendarModifyWeekdayCmd() { //debugPlan << m_weekday <<":" << m_value; delete m_value; } void CalendarModifyWeekdayCmd::execute() { m_cal->setWeekday( m_weekday, *m_value ); } void CalendarModifyWeekdayCmd::unexecute() { m_cal->setWeekday( m_weekday, m_orig ); } CalendarModifyDateCmd::CalendarModifyDateCmd( Calendar *cal, CalendarDay *day, const QDate &value, const KUndo2MagicString& name ) : NamedCommand( name ), m_cal( cal ), m_day( day ), m_newvalue( value ), m_oldvalue( day->date() ) { //debugPlan << cal->name() <<" (" << value <<")"; } void CalendarModifyDateCmd::execute() { m_cal->setDate( m_day, m_newvalue ); } void CalendarModifyDateCmd::unexecute() { m_cal->setDate( m_day, m_oldvalue ); } ProjectModifyDefaultCalendarCmd::ProjectModifyDefaultCalendarCmd( Project *project, Calendar *cal, const KUndo2MagicString& name ) : NamedCommand( name ), m_project( project ), m_newvalue( cal ), m_oldvalue( project->defaultCalendar() ) { //debugPlan << cal->name() <<" (" << value <<")"; } void ProjectModifyDefaultCalendarCmd::execute() { m_project->setDefaultCalendar( m_newvalue ); } void ProjectModifyDefaultCalendarCmd::unexecute() { m_project->setDefaultCalendar( m_oldvalue ); } NodeDeleteCmd::NodeDeleteCmd( Node *node, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( node ), m_index( -1 ) { m_parent = node->parentNode(); m_mine = false; m_project = static_cast( node->projectNode() ); if ( m_project ) { foreach ( Schedule * s, m_project->schedules() ) { if ( s && s->isScheduled() ) { // Only invalidate schedules this node is part of Schedule *ns = node->findSchedule( s->id() ); if ( ns && ! ns->isDeleted() ) { addSchScheduled( s ); } } } } m_cmd = new MacroCommand( KUndo2MagicString() ); QList lst = node->childNodeIterator(); for ( int i = lst.count(); i > 0; --i ) { m_cmd->addCommand( new NodeDeleteCmd( lst[ i - 1 ] ) ); } if ( node->runningAccount() ) { m_cmd->addCommand( new NodeModifyRunningAccountCmd( *node, node->runningAccount(), 0 ) ); } if ( node->startupAccount() ) { m_cmd->addCommand( new NodeModifyRunningAccountCmd( *node, node->startupAccount(), 0 ) ); } if ( node->shutdownAccount() ) { m_cmd->addCommand( new NodeModifyRunningAccountCmd( *node, node->shutdownAccount(), 0 ) ); } } NodeDeleteCmd::~NodeDeleteCmd() { if ( m_mine ) delete m_node; delete m_cmd; while ( !m_appointments.isEmpty() ) delete m_appointments.takeFirst(); } void NodeDeleteCmd::execute() { if ( m_parent && m_project ) { m_index = m_parent->findChildNode( m_node ); //debugPlan<name()<<""<dependChildNodes() ) { m_relCmd.addCommand( new DeleteRelationCmd( *m_project, r ) ); } foreach ( Relation * r, m_node->dependParentNodes() ) { m_relCmd.addCommand( new DeleteRelationCmd( *m_project, r ) ); } } m_relCmd.execute(); if ( m_cmd ) { m_cmd->execute(); } m_project->takeTask( m_node ); m_mine = true; setSchScheduled( false ); } } void NodeDeleteCmd::unexecute() { if ( m_parent && m_project ) { //debugPlan<name()<<""<addSubTask( m_node, m_index, m_parent ); if ( m_cmd ) { m_cmd->unexecute(); } m_relCmd.unexecute(); m_mine = false; setSchScheduled(); } } TaskAddCmd::TaskAddCmd( Project *project, Node *node, Node *after, const KUndo2MagicString& name ) : NamedCommand( name ), m_project( project ), m_node( node ), m_after( after ), m_added( false ) { // set some reasonable defaults for normally calculated values if ( after && after->parentNode() && after->parentNode() != project ) { node->setStartTime( after->parentNode() ->startTime() ); node->setEndTime( node->startTime() + node->duration() ); } else { if ( project->constraint() == Node::MustFinishOn ) { node->setEndTime( project->endTime() ); node->setStartTime( node->endTime() - node->duration() ); } else { node->setStartTime( project->startTime() ); node->setEndTime( node->startTime() + node->duration() ); } } node->setEarlyStart( node->startTime() ); node->setLateFinish( node->endTime() ); node->setWorkStartTime( node->startTime() ); node->setWorkEndTime( node->endTime() ); } TaskAddCmd::~TaskAddCmd() { if ( !m_added ) delete m_node; } void TaskAddCmd::execute() { //debugPlan<name(); m_project->addTask( m_node, m_after ); m_added = true; } void TaskAddCmd::unexecute() { m_project->takeTask( m_node ); m_added = false; } SubtaskAddCmd::SubtaskAddCmd( Project *project, Node *node, Node *parent, const KUndo2MagicString& name ) : NamedCommand( name ), m_project( project ), m_node( node ), m_parent( parent ), m_added( false ), m_cmd( 0 ) { // set some reasonable defaults for normally calculated values node->setStartTime( parent->startTime() ); node->setEndTime( node->startTime() + node->duration() ); node->setEarlyStart( node->startTime() ); node->setLateFinish( node->endTime() ); node->setWorkStartTime( node->startTime() ); node->setWorkEndTime( node->endTime() ); // Summarytasks can't have resources, so remove resource requests from the new parent foreach ( ResourceGroupRequest *r, parent->requests().requests() ) { if ( m_cmd == 0 ) m_cmd = new MacroCommand( KUndo2MagicString() ); m_cmd->addCommand( new RemoveResourceGroupRequestCmd( r ) ); } // Also remove accounts if ( parent->runningAccount() ) { if ( m_cmd == 0 ) m_cmd = new MacroCommand( KUndo2MagicString() ); m_cmd->addCommand( new NodeModifyRunningAccountCmd( *parent, parent->runningAccount(), 0 ) ); } if ( parent->startupAccount() ) { if ( m_cmd == 0 ) m_cmd = new MacroCommand( KUndo2MagicString() ); m_cmd->addCommand( new NodeModifyStartupAccountCmd( *parent, parent->startupAccount(), 0 ) ); } if ( parent->shutdownAccount() ) { if ( m_cmd == 0 ) m_cmd = new MacroCommand( KUndo2MagicString() ); m_cmd->addCommand( new NodeModifyShutdownAccountCmd( *parent, parent->shutdownAccount(), 0 ) ); } } SubtaskAddCmd::~SubtaskAddCmd() { delete m_cmd; if ( !m_added ) delete m_node; } void SubtaskAddCmd::execute() { m_project->addSubTask( m_node, m_parent ); if ( m_cmd ) { m_cmd->execute(); } m_added = true; } void SubtaskAddCmd::unexecute() { m_project->takeTask( m_node ); if ( m_cmd ) { m_cmd->unexecute(); } m_added = false; } NodeModifyNameCmd::NodeModifyNameCmd( Node &node, const QString& nodename, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( node ), newName( nodename ), oldName( node.name() ) { } void NodeModifyNameCmd::execute() { m_node.setName( newName ); } void NodeModifyNameCmd::unexecute() { m_node.setName( oldName ); } NodeModifyLeaderCmd::NodeModifyLeaderCmd( Node &node, const QString& leader, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( node ), newLeader( leader ), oldLeader( node.leader() ) { } void NodeModifyLeaderCmd::execute() { m_node.setLeader( newLeader ); } void NodeModifyLeaderCmd::unexecute() { m_node.setLeader( oldLeader ); } NodeModifyDescriptionCmd::NodeModifyDescriptionCmd( Node &node, const QString& description, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( node ), newDescription( description ), oldDescription( node.description() ) { } void NodeModifyDescriptionCmd::execute() { m_node.setDescription( newDescription ); } void NodeModifyDescriptionCmd::unexecute() { m_node.setDescription( oldDescription ); } NodeModifyConstraintCmd::NodeModifyConstraintCmd( Node &node, Node::ConstraintType c, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( node ), newConstraint( c ), oldConstraint( static_cast( node.constraint() ) ) { } void NodeModifyConstraintCmd::execute() { m_node.setConstraint( newConstraint ); } void NodeModifyConstraintCmd::unexecute() { m_node.setConstraint( oldConstraint ); } NodeModifyConstraintStartTimeCmd::NodeModifyConstraintStartTimeCmd( Node &node, const QDateTime& dt, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( node ), newTime( dt ), oldTime( node.constraintStartTime() ) { if ( node.projectNode() ) { m_timeZone = static_cast( node.projectNode() )->timeZone(); } } void NodeModifyConstraintStartTimeCmd::execute() { m_node.setConstraintStartTime( DateTime( newTime, m_timeZone ) ); } void NodeModifyConstraintStartTimeCmd::unexecute() { m_node.setConstraintStartTime( oldTime ); } NodeModifyConstraintEndTimeCmd::NodeModifyConstraintEndTimeCmd( Node &node, const QDateTime& dt, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( node ), newTime( dt ), oldTime( node.constraintEndTime() ) { if ( node.projectNode() ) { m_timeZone = static_cast( node.projectNode() )->timeZone(); } } void NodeModifyConstraintEndTimeCmd::execute() { m_node.setConstraintEndTime( DateTime( newTime, m_timeZone ) ); } void NodeModifyConstraintEndTimeCmd::unexecute() { m_node.setConstraintEndTime( oldTime ); } NodeModifyStartTimeCmd::NodeModifyStartTimeCmd( Node &node, const QDateTime& dt, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( node ), newTime( dt ), oldTime( node.startTime() ) { m_timeZone = static_cast( node.projectNode() )->timeZone(); } void NodeModifyStartTimeCmd::execute() { m_node.setStartTime( DateTime( newTime, m_timeZone ) ); } void NodeModifyStartTimeCmd::unexecute() { m_node.setStartTime( oldTime ); } NodeModifyEndTimeCmd::NodeModifyEndTimeCmd( Node &node, const QDateTime& dt, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( node ), newTime( dt ), oldTime( node.endTime() ) { m_timeZone = static_cast( node.projectNode() )->timeZone(); } void NodeModifyEndTimeCmd::execute() { m_node.setEndTime( DateTime( newTime, m_timeZone ) ); } void NodeModifyEndTimeCmd::unexecute() { m_node.setEndTime( oldTime ); } NodeModifyIdCmd::NodeModifyIdCmd( Node &node, const QString& id, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( node ), newId( id ), oldId( node.id() ) { } void NodeModifyIdCmd::execute() { m_node.setId( newId ); } void NodeModifyIdCmd::unexecute() { m_node.setId( oldId ); } NodeIndentCmd::NodeIndentCmd( Node &node, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( node ), m_newparent( 0 ), m_newindex( -1 ), m_cmd( 0 ) { } NodeIndentCmd::~NodeIndentCmd() { delete m_cmd; } void NodeIndentCmd::execute() { m_oldparent = m_node.parentNode(); m_oldindex = m_oldparent->findChildNode( &m_node ); Project *p = dynamic_cast( m_node.projectNode() ); if ( p && p->indentTask( &m_node, m_newindex ) ) { m_newparent = m_node.parentNode(); m_newindex = m_newparent->findChildNode( &m_node ); // Summarytasks can't have resources, so remove resource requests from the new parent if ( m_cmd == 0 ) { foreach ( ResourceGroupRequest *r, m_newparent->requests().requests() ) { if ( m_cmd == 0 ) m_cmd = new MacroCommand( KUndo2MagicString() ); m_cmd->addCommand( new RemoveResourceGroupRequestCmd( r ) ); } // Also remove accounts if ( m_newparent->runningAccount() ) { if ( m_cmd == 0 ) m_cmd = new MacroCommand( KUndo2MagicString() ); m_cmd->addCommand( new NodeModifyRunningAccountCmd( *m_newparent, m_newparent->runningAccount(), 0 ) ); } if ( m_newparent->startupAccount() ) { if ( m_cmd == 0 ) m_cmd = new MacroCommand( KUndo2MagicString() ); m_cmd->addCommand( new NodeModifyStartupAccountCmd( *m_newparent, m_newparent->startupAccount(), 0 ) ); } if ( m_newparent->shutdownAccount() ) { if ( m_cmd == 0 ) m_cmd = new MacroCommand( KUndo2MagicString() ); m_cmd->addCommand( new NodeModifyShutdownAccountCmd( *m_newparent, m_newparent->shutdownAccount(), 0 ) ); } } if ( m_cmd ) { m_cmd->execute(); } } } void NodeIndentCmd::unexecute() { Project * p = dynamic_cast( m_node.projectNode() ); if ( m_newindex != -1 && p && p->unindentTask( &m_node ) ) { m_newindex = -1; if ( m_cmd ) { m_cmd->unexecute(); } } } NodeUnindentCmd::NodeUnindentCmd( Node &node, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( node ), m_newparent( 0 ), m_newindex( -1 ) {} void NodeUnindentCmd::execute() { m_oldparent = m_node.parentNode(); m_oldindex = m_oldparent->findChildNode( &m_node ); Project *p = dynamic_cast( m_node.projectNode() ); if ( p && p->unindentTask( &m_node ) ) { m_newparent = m_node.parentNode(); m_newindex = m_newparent->findChildNode( &m_node ); } } void NodeUnindentCmd::unexecute() { Project * p = dynamic_cast( m_node.projectNode() ); if ( m_newindex != -1 && p && p->indentTask( &m_node, m_oldindex ) ) { m_newindex = -1; } } NodeMoveUpCmd::NodeMoveUpCmd( Node &node, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( node ), m_moved( false ) { m_project = static_cast( m_node.projectNode() ); } void NodeMoveUpCmd::execute() { if ( m_project ) { m_moved = m_project->moveTaskUp( &m_node ); } } void NodeMoveUpCmd::unexecute() { if ( m_project && m_moved ) { m_project->moveTaskDown( &m_node ); } m_moved = false; } NodeMoveDownCmd::NodeMoveDownCmd( Node &node, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( node ), m_moved( false ) { m_project = static_cast( m_node.projectNode() ); } void NodeMoveDownCmd::execute() { if ( m_project ) { m_moved = m_project->moveTaskDown( &m_node ); } } void NodeMoveDownCmd::unexecute() { if ( m_project && m_moved ) { m_project->moveTaskUp( &m_node ); } m_moved = false; } NodeMoveCmd::NodeMoveCmd( Project *project, Node *node, Node *newParent, int newPos, const KUndo2MagicString& name ) : NamedCommand( name ), m_project( project ), m_node( node ), m_newparent( newParent ), m_newpos( newPos ), m_moved( false ) { m_oldparent = node->parentNode(); Q_ASSERT( m_oldparent ); } void NodeMoveCmd::execute() { if ( m_project ) { m_oldpos = m_oldparent->indexOf( m_node ); m_moved = m_project->moveTask( m_node, m_newparent, m_newpos ); if ( m_moved ) { if ( m_cmd.isEmpty() ) { // Summarytasks can't have resources, so remove resource requests from the new parent foreach ( ResourceGroupRequest *r, m_newparent->requests().requests() ) { m_cmd.addCommand( new RemoveResourceGroupRequestCmd( r ) ); } // TODO appointments ?? } m_cmd.execute(); } } } void NodeMoveCmd::unexecute() { if ( m_project && m_moved ) { m_moved = m_project->moveTask( m_node, m_oldparent, m_oldpos ); m_cmd.unexecute(); } m_moved = false; } AddRelationCmd::AddRelationCmd( Project &project, Relation *rel, const KUndo2MagicString& name ) : NamedCommand( name ), m_rel( rel ), m_project( project ) { m_taken = true; } AddRelationCmd::~AddRelationCmd() { if ( m_taken ) delete m_rel; } void AddRelationCmd::execute() { //debugPlan<parent()<<" to"<child(); m_taken = false; m_project.addRelation( m_rel, false ); } void AddRelationCmd::unexecute() { m_taken = true; m_project.takeRelation( m_rel ); } DeleteRelationCmd::DeleteRelationCmd( Project &project, Relation *rel, const KUndo2MagicString& name ) : NamedCommand( name ), m_rel( rel ), m_project( project ) { m_taken = false; } DeleteRelationCmd::~DeleteRelationCmd() { if ( m_taken ) delete m_rel; } void DeleteRelationCmd::execute() { //debugPlan<parent()<<" to"<child(); m_taken = true; m_project.takeRelation( m_rel ); } void DeleteRelationCmd::unexecute() { m_taken = false; m_project.addRelation( m_rel, false ); } ModifyRelationTypeCmd::ModifyRelationTypeCmd( Relation *rel, Relation::Type type, const KUndo2MagicString& name ) : NamedCommand( name ), m_rel( rel ), m_newtype( type ) { m_oldtype = rel->type(); m_project = dynamic_cast( rel->parent() ->projectNode() ); } void ModifyRelationTypeCmd::execute() { if ( m_project ) { m_project->setRelationType( m_rel, m_newtype ); } } void ModifyRelationTypeCmd::unexecute() { if ( m_project ) { m_project->setRelationType( m_rel, m_oldtype ); } } ModifyRelationLagCmd::ModifyRelationLagCmd( Relation *rel, Duration lag, const KUndo2MagicString& name ) : NamedCommand( name ), m_rel( rel ), m_newlag( lag ) { m_oldlag = rel->lag(); m_project = dynamic_cast( rel->parent() ->projectNode() ); } void ModifyRelationLagCmd::execute() { if ( m_project ) { m_project->setRelationLag( m_rel, m_newlag ); } } void ModifyRelationLagCmd::unexecute() { if ( m_project ) { m_project->setRelationLag( m_rel, m_oldlag ); } } AddResourceRequestCmd::AddResourceRequestCmd( ResourceGroupRequest *group, ResourceRequest *request, const KUndo2MagicString& name ) : NamedCommand( name ), m_group( group ), m_request( request ) { m_mine = true; } AddResourceRequestCmd::~AddResourceRequestCmd() { if ( m_mine ) delete m_request; } void AddResourceRequestCmd::execute() { //debugPlan<<"group="<project() ); if ( m_group->project() ) { m_group->project()->addResource( m_group, m_resource, m_index ); m_mine = false; //debugPlan<<"added:"<project() ); if ( m_group->project() ) { m_group->project()->takeResource( m_group, m_resource ); //debugPlan<<"removed:"<project() ); } RemoveResourceCmd::RemoveResourceCmd( ResourceGroup *group, Resource *resource, const KUndo2MagicString& name ) : AddResourceCmd( group, resource, name ) { //debugPlan<requests(); if ( group->project() ) { foreach ( Schedule * s, group->project()->schedules() ) { Schedule *rs = resource->findSchedule( s->id() ); if ( rs && ! rs->isDeleted() ) { debugPlan<name(); addSchScheduled( s ); } } } if ( resource->account() ) { m_cmd.addCommand( new ResourceModifyAccountCmd( *resource, resource->account(), 0 ) ); } } RemoveResourceCmd::~RemoveResourceCmd() { while ( !m_appointments.isEmpty() ) delete m_appointments.takeFirst(); } void RemoveResourceCmd::execute() { foreach ( ResourceRequest * r, m_requests ) { r->parent() ->takeResourceRequest( r ); //debugPlan<<"Remove request for"<resource()->name(); } AddResourceCmd::unexecute(); m_cmd.execute(); setSchScheduled( false ); } void RemoveResourceCmd::unexecute() { foreach ( ResourceRequest * r, m_requests ) { r->parent() ->addResourceRequest( r ); //debugPlan<<"Add request for"<resource()->name(); } m_cmd.unexecute(); AddResourceCmd::execute(); setSchScheduled(); } MoveResourceCmd::MoveResourceCmd( ResourceGroup *group, Resource *resource, const KUndo2MagicString& name ) : NamedCommand( name ), m_project( *(group->project()) ), m_resource( resource ), m_oldvalue( resource->parentGroup() ), m_newvalue( group ) { foreach ( ResourceRequest * r, resource->requests() ) { cmd.addCommand( new RemoveResourceRequestCmd( r->parent(), r ) ); } } void MoveResourceCmd::execute() { cmd.execute(); m_project.moveResource( m_newvalue, m_resource ); } void MoveResourceCmd::unexecute() { m_project.moveResource( m_oldvalue, m_resource ); cmd.unexecute(); } ModifyResourceNameCmd::ModifyResourceNameCmd( Resource *resource, const QString& value, const KUndo2MagicString& name ) : NamedCommand( name ), m_resource( resource ), m_newvalue( value ) { m_oldvalue = resource->name(); } void ModifyResourceNameCmd::execute() { m_resource->setName( m_newvalue ); } void ModifyResourceNameCmd::unexecute() { m_resource->setName( m_oldvalue ); } ModifyResourceInitialsCmd::ModifyResourceInitialsCmd( Resource *resource, const QString& value, const KUndo2MagicString& name ) : NamedCommand( name ), m_resource( resource ), m_newvalue( value ) { m_oldvalue = resource->initials(); } void ModifyResourceInitialsCmd::execute() { m_resource->setInitials( m_newvalue ); } void ModifyResourceInitialsCmd::unexecute() { m_resource->setInitials( m_oldvalue ); } ModifyResourceEmailCmd::ModifyResourceEmailCmd( Resource *resource, const QString& value, const KUndo2MagicString& name ) : NamedCommand( name ), m_resource( resource ), m_newvalue( value ) { m_oldvalue = resource->email(); } void ModifyResourceEmailCmd::execute() { m_resource->setEmail( m_newvalue ); } void ModifyResourceEmailCmd::unexecute() { m_resource->setEmail( m_oldvalue ); } ModifyResourceAutoAllocateCmd::ModifyResourceAutoAllocateCmd( Resource *resource,bool value, const KUndo2MagicString& name ) : NamedCommand( name ), m_resource( resource ), m_newvalue( value ) { m_oldvalue = resource->autoAllocate(); } void ModifyResourceAutoAllocateCmd::execute() { m_resource->setAutoAllocate( m_newvalue ); } void ModifyResourceAutoAllocateCmd::unexecute() { m_resource->setAutoAllocate( m_oldvalue ); } ModifyResourceTypeCmd::ModifyResourceTypeCmd( Resource *resource, int value, const KUndo2MagicString& name ) : NamedCommand( name ), m_resource( resource ), m_newvalue( value ) { m_oldvalue = resource->type(); } void ModifyResourceTypeCmd::execute() { m_resource->setType( ( Resource::Type ) m_newvalue ); } void ModifyResourceTypeCmd::unexecute() { m_resource->setType( ( Resource::Type ) m_oldvalue ); } ModifyResourceUnitsCmd::ModifyResourceUnitsCmd( Resource *resource, int value, const KUndo2MagicString& name ) : NamedCommand( name ), m_resource( resource ), m_newvalue( value ) { m_oldvalue = resource->units(); } void ModifyResourceUnitsCmd::execute() { m_resource->setUnits( m_newvalue ); } void ModifyResourceUnitsCmd::unexecute() { m_resource->setUnits( m_oldvalue ); } ModifyResourceAvailableFromCmd::ModifyResourceAvailableFromCmd( Resource *resource, const QDateTime& value, const KUndo2MagicString& name ) : NamedCommand( name ), m_resource( resource ), m_newvalue( value ) { m_oldvalue = resource->availableFrom(); m_timeZone = resource->timeZone(); } void ModifyResourceAvailableFromCmd::execute() { m_resource->setAvailableFrom( DateTime( m_newvalue, m_timeZone ) ); } void ModifyResourceAvailableFromCmd::unexecute() { m_resource->setAvailableFrom( m_oldvalue ); } ModifyResourceAvailableUntilCmd::ModifyResourceAvailableUntilCmd( Resource *resource, const QDateTime& value, const KUndo2MagicString& name ) : NamedCommand( name ), m_resource( resource ), m_newvalue( value ) { m_oldvalue = resource->availableUntil(); m_timeZone = resource->timeZone(); } void ModifyResourceAvailableUntilCmd::execute() { m_resource->setAvailableUntil( DateTime( m_newvalue, m_timeZone ) ); } void ModifyResourceAvailableUntilCmd::unexecute() { m_resource->setAvailableUntil( m_oldvalue ); } ModifyResourceNormalRateCmd::ModifyResourceNormalRateCmd( Resource *resource, double value, const KUndo2MagicString& name ) : NamedCommand( name ), m_resource( resource ), m_newvalue( value ) { m_oldvalue = resource->normalRate(); } void ModifyResourceNormalRateCmd::execute() { m_resource->setNormalRate( m_newvalue ); } void ModifyResourceNormalRateCmd::unexecute() { m_resource->setNormalRate( m_oldvalue ); } ModifyResourceOvertimeRateCmd::ModifyResourceOvertimeRateCmd( Resource *resource, double value, const KUndo2MagicString& name ) : NamedCommand( name ), m_resource( resource ), m_newvalue( value ) { m_oldvalue = resource->overtimeRate(); } void ModifyResourceOvertimeRateCmd::execute() { m_resource->setOvertimeRate( m_newvalue ); } void ModifyResourceOvertimeRateCmd::unexecute() { m_resource->setOvertimeRate( m_oldvalue ); } ModifyResourceCalendarCmd::ModifyResourceCalendarCmd( Resource *resource, Calendar *value, const KUndo2MagicString& name ) : NamedCommand( name ), m_resource( resource ), m_newvalue( value ) { m_oldvalue = resource->calendar( true ); } void ModifyResourceCalendarCmd::execute() { m_resource->setCalendar( m_newvalue ); } void ModifyResourceCalendarCmd::unexecute() { m_resource->setCalendar( m_oldvalue ); } ModifyRequiredResourcesCmd::ModifyRequiredResourcesCmd( Resource *resource, const QStringList &value, const KUndo2MagicString& name ) : NamedCommand( name ), m_resource( resource ), m_newvalue( value ) { m_oldvalue = resource->requiredIds(); } void ModifyRequiredResourcesCmd::execute() { m_resource->setRequiredIds( m_newvalue ); } void ModifyRequiredResourcesCmd::unexecute() { m_resource->setRequiredIds( m_oldvalue ); } AddResourceTeamCmd::AddResourceTeamCmd( Resource *team, const QString &member, const KUndo2MagicString& name ) : NamedCommand( name ), m_team( team ), m_member( member ) { } void AddResourceTeamCmd::execute() { m_team->addTeamMemberId( m_member ); } void AddResourceTeamCmd::unexecute() { m_team->removeTeamMemberId( m_member ); } RemoveResourceTeamCmd::RemoveResourceTeamCmd( Resource *team, const QString &member, const KUndo2MagicString& name ) : NamedCommand( name ), m_team( team ), m_member( member ) { } void RemoveResourceTeamCmd::execute() { m_team->removeTeamMemberId( m_member ); } void RemoveResourceTeamCmd::unexecute() { m_team->addTeamMemberId( m_member ); } RemoveResourceGroupCmd::RemoveResourceGroupCmd( Project *project, ResourceGroup *group, const KUndo2MagicString& name ) : NamedCommand( name ), m_group( group ), m_project( project ), m_cmd( 0 ) { m_index = project->indexOf( group ); m_mine = false; if ( !m_group->requests().isEmpty() ) { m_cmd = new MacroCommand(KUndo2MagicString()); foreach( ResourceGroupRequest * r, m_group->requests() ) { m_cmd->addCommand( new RemoveResourceGroupRequestCmd( r ) ); } } } RemoveResourceGroupCmd::~RemoveResourceGroupCmd() { delete m_cmd; if ( m_mine ) delete m_group; } void RemoveResourceGroupCmd::execute() { // remove all requests to this group if ( m_cmd ) { m_cmd->execute(); } if ( m_project ) m_project->takeResourceGroup( m_group ); m_mine = true; } void RemoveResourceGroupCmd::unexecute() { if ( m_project ) m_project->addResourceGroup( m_group, m_index ); m_mine = false; // add all requests if ( m_cmd ) { m_cmd->unexecute(); } } AddResourceGroupCmd::AddResourceGroupCmd( Project *project, ResourceGroup *group, const KUndo2MagicString& name ) : RemoveResourceGroupCmd( project, group, name ) { m_mine = true; } void AddResourceGroupCmd::execute() { RemoveResourceGroupCmd::unexecute(); } void AddResourceGroupCmd::unexecute() { RemoveResourceGroupCmd::execute(); } ModifyResourceGroupNameCmd::ModifyResourceGroupNameCmd( ResourceGroup *group, const QString& value, const KUndo2MagicString& name ) : NamedCommand( name ), m_group( group ), m_newvalue( value ) { m_oldvalue = group->name(); } void ModifyResourceGroupNameCmd::execute() { m_group->setName( m_newvalue ); } void ModifyResourceGroupNameCmd::unexecute() { m_group->setName( m_oldvalue ); } ModifyResourceGroupTypeCmd::ModifyResourceGroupTypeCmd( ResourceGroup *group, int value, const KUndo2MagicString& name ) : NamedCommand( name ), m_group( group ), m_newvalue( value ) { m_oldvalue = group->type(); } void ModifyResourceGroupTypeCmd::execute() { m_group->setType( static_cast( m_newvalue) ); } void ModifyResourceGroupTypeCmd::unexecute() { m_group->setType( static_cast( m_oldvalue ) ); } ModifyCompletionEntrymodeCmd::ModifyCompletionEntrymodeCmd( Completion &completion, Completion::Entrymode value, const KUndo2MagicString& name ) : NamedCommand( name ), m_completion( completion ), oldvalue( m_completion.entrymode() ), newvalue( value ) { } void ModifyCompletionEntrymodeCmd::execute() { m_completion.setEntrymode( newvalue ); } void ModifyCompletionEntrymodeCmd::unexecute() { m_completion.setEntrymode( oldvalue ); } ModifyCompletionPercentFinishedCmd::ModifyCompletionPercentFinishedCmd( Completion &completion, const QDate &date, int value, const KUndo2MagicString& name ) : NamedCommand( name ), m_completion( completion ), m_date( date ), m_newvalue( value ), m_oldvalue( completion.percentFinished( date ) ) { if ( ! completion.entries().contains( date ) ) { Completion::Entry *e = new Completion::Entry(); Completion::Entry *latest = completion.entry( completion.entryDate() ); if ( latest ) { *e = *latest; } cmd.addCommand( new AddCompletionEntryCmd( completion, date, e ) ); } } void ModifyCompletionPercentFinishedCmd::execute() { cmd.execute(); m_completion.setPercentFinished( m_date, m_newvalue ); } void ModifyCompletionPercentFinishedCmd::unexecute() { m_completion.setPercentFinished( m_date, m_oldvalue ); cmd.unexecute(); } ModifyCompletionRemainingEffortCmd::ModifyCompletionRemainingEffortCmd( Completion &completion, const QDate &date, const Duration &value, const KUndo2MagicString &name ) : NamedCommand( name ), m_completion( completion ), m_date( date ), m_newvalue( value ), m_oldvalue( completion.remainingEffort( date ) ) { if ( ! completion.entries().contains( date ) ) { Completion::Entry *e = new Completion::Entry(); Completion::Entry *latest = completion.entry( completion.entryDate() ); if ( latest ) { *e = *latest; } cmd.addCommand( new AddCompletionEntryCmd( completion, date, e ) ); } } void ModifyCompletionRemainingEffortCmd::execute() { cmd.execute(); m_completion.setRemainingEffort( m_date, m_newvalue ); } void ModifyCompletionRemainingEffortCmd::unexecute() { m_completion.setRemainingEffort( m_date, m_oldvalue ); cmd.unexecute(); } ModifyCompletionActualEffortCmd::ModifyCompletionActualEffortCmd( Completion &completion, const QDate &date, const Duration &value, const KUndo2MagicString &name ) : NamedCommand( name ), m_completion( completion ), m_date( date ), m_newvalue( value ), m_oldvalue( completion.actualEffort( date ) ) { if ( ! completion.entries().contains( date ) ) { Completion::Entry *e = new Completion::Entry(); Completion::Entry *latest = completion.entry( completion.entryDate() ); if ( latest ) { *e = *latest; } cmd.addCommand( new AddCompletionEntryCmd( completion, date, e ) ); } } void ModifyCompletionActualEffortCmd::execute() { cmd.execute(); m_completion.setActualEffort( m_date, m_newvalue ); } void ModifyCompletionActualEffortCmd::unexecute() { m_completion.setActualEffort( m_date, m_oldvalue ); cmd.unexecute(); } ModifyCompletionStartedCmd::ModifyCompletionStartedCmd( Completion &completion, bool value, const KUndo2MagicString& name ) : NamedCommand( name ), m_completion( completion ), oldvalue( m_completion.isStarted() ), newvalue( value ) { } void ModifyCompletionStartedCmd::execute() { m_completion.setStarted( newvalue ); } void ModifyCompletionStartedCmd::unexecute() { m_completion.setStarted( oldvalue ); } ModifyCompletionFinishedCmd::ModifyCompletionFinishedCmd( Completion &completion, bool value, const KUndo2MagicString& name ) : NamedCommand( name ), m_completion( completion ), oldvalue( m_completion.isFinished() ), newvalue( value ) { } void ModifyCompletionFinishedCmd::execute() { m_completion.setFinished( newvalue ); } void ModifyCompletionFinishedCmd::unexecute() { m_completion.setFinished( oldvalue ); } ModifyCompletionStartTimeCmd::ModifyCompletionStartTimeCmd( Completion &completion, const QDateTime &value, const KUndo2MagicString& name ) : NamedCommand( name ), m_completion( completion ), oldvalue( m_completion.startTime() ), newvalue( value ) { m_timeZone = static_cast( completion.node()->projectNode() )->timeZone(); } void ModifyCompletionStartTimeCmd::execute() { m_completion.setStartTime( DateTime( newvalue, m_timeZone ) ); } void ModifyCompletionStartTimeCmd::unexecute() { m_completion.setStartTime( oldvalue ); } ModifyCompletionFinishTimeCmd::ModifyCompletionFinishTimeCmd( Completion &completion, const QDateTime &value, const KUndo2MagicString& name ) : NamedCommand( name ), m_completion( completion ), oldvalue( m_completion.finishTime() ), newvalue( value ) { m_timeZone = static_cast( completion.node()->projectNode() )->timeZone(); } void ModifyCompletionFinishTimeCmd::execute() { m_completion.setFinishTime( DateTime( newvalue, m_timeZone ) ); } void ModifyCompletionFinishTimeCmd::unexecute() { m_completion.setFinishTime( oldvalue ); } AddCompletionEntryCmd::AddCompletionEntryCmd( Completion &completion, const QDate &date, Completion::Entry *value, const KUndo2MagicString& name ) : NamedCommand( name ), m_completion( completion ), m_date( date ), newvalue( value ), m_newmine( true ) { } AddCompletionEntryCmd::~AddCompletionEntryCmd() { if ( m_newmine ) delete newvalue; } void AddCompletionEntryCmd::execute() { Q_ASSERT( ! m_completion.entries().contains( m_date ) ); m_completion.addEntry( m_date, newvalue ); m_newmine = false; } void AddCompletionEntryCmd::unexecute() { m_completion.takeEntry( m_date ); m_newmine = true; } RemoveCompletionEntryCmd::RemoveCompletionEntryCmd( Completion &completion, const QDate &date, const KUndo2MagicString& name ) : NamedCommand( name ), m_completion( completion ), m_date( date ), m_mine( false ) { value = m_completion.entry( date ); } RemoveCompletionEntryCmd::~RemoveCompletionEntryCmd() { debugPlan<addCommand( new RemoveCompletionEntryCmd( completion, date ) ); cmd->addCommand( new AddCompletionEntryCmd( completion, date, value ) ); } ModifyCompletionEntryCmd::~ModifyCompletionEntryCmd() { delete cmd; } void ModifyCompletionEntryCmd::execute() { cmd->execute(); } void ModifyCompletionEntryCmd::unexecute() { cmd->unexecute(); } AddCompletionUsedEffortCmd::AddCompletionUsedEffortCmd( Completion &completion, const Resource *resource, Completion::UsedEffort *value, const KUndo2MagicString& name ) : NamedCommand( name ), m_completion( completion ), m_resource( resource ), newvalue( value ), m_newmine( true ), m_oldmine( false) { oldvalue = m_completion.usedEffort( resource ); } AddCompletionUsedEffortCmd::~AddCompletionUsedEffortCmd() { if ( m_oldmine ) delete oldvalue; if ( m_newmine ) delete newvalue; } void AddCompletionUsedEffortCmd::execute() { if ( oldvalue ) { m_completion.takeUsedEffort( m_resource ); m_oldmine = true; } m_completion.addUsedEffort( m_resource, newvalue ); m_newmine = false; } void AddCompletionUsedEffortCmd::unexecute() { m_completion.takeUsedEffort( m_resource ); if ( oldvalue ) { m_completion.addUsedEffort( m_resource, oldvalue ); } m_newmine = true; m_oldmine = false; } AddCompletionActualEffortCmd::AddCompletionActualEffortCmd( Completion::UsedEffort &ue, const QDate &date, const Completion::UsedEffort::ActualEffort &value, const KUndo2MagicString& name ) : NamedCommand( name ), m_usedEffort( ue ), m_date( date ), newvalue( value ) { oldvalue = ue.effort( date ); } AddCompletionActualEffortCmd::~AddCompletionActualEffortCmd() { } void AddCompletionActualEffortCmd::execute() { m_usedEffort.takeEffort( m_date ); if ( newvalue.effort() > 0 ) { m_usedEffort.setEffort( m_date, newvalue ); } } void AddCompletionActualEffortCmd::unexecute() { m_usedEffort.takeEffort( m_date ); if ( oldvalue.effort() > 0 ) { m_usedEffort.setEffort( m_date, oldvalue ); } } AddAccountCmd::AddAccountCmd( Project &project, Account *account, const QString& parent, int index, const KUndo2MagicString& name ) : NamedCommand( name ), m_project( project ), m_account( account ), m_parent( 0 ), m_index( index ), m_parentName( parent ) { m_mine = true; } AddAccountCmd::AddAccountCmd( Project &project, Account *account, Account *parent, int index, const KUndo2MagicString& name ) : NamedCommand( name ), m_project( project ), m_account( account ), m_parent( parent ), m_index( index ) { m_mine = true; } AddAccountCmd::~AddAccountCmd() { if ( m_mine ) delete m_account; } void AddAccountCmd::execute() { if ( m_parent == 0 && !m_parentName.isEmpty() ) { m_parent = m_project.accounts().findAccount( m_parentName ); } m_project.accounts().insert( m_account, m_parent, m_index ); m_mine = false; } void AddAccountCmd::unexecute() { m_project.accounts().take( m_account ); m_mine = true; } RemoveAccountCmd::RemoveAccountCmd( Project &project, Account *account, const KUndo2MagicString& name ) - : NamedCommand( name ), - m_project( project ), - m_account( account ), - m_parent( account->parent() ) + : NamedCommand( name ), + m_project( project ), + m_account( account ), + m_parent( account->parent() ) { if ( m_parent ) { m_index = m_parent->accountList().indexOf( account ); } else { m_index = project.accounts().accountList().indexOf( account ); } m_mine = false; m_isDefault = account == project.accounts().defaultAccount(); + + for (Account::CostPlace *cp : m_account->costPlaces()) { + if (cp->node()) { + if (cp->running()) { + m_cmd.addCommand(new NodeModifyRunningAccountCmd(*cp->node(), cp->node()->runningAccount(), 0)); + } + if (cp->startup()) { + m_cmd.addCommand(new NodeModifyStartupAccountCmd(*cp->node(), cp->node()->startupAccount(), 0)); + } + if (cp->shutdown()) { + m_cmd.addCommand(new NodeModifyShutdownAccountCmd(*cp->node(), cp->node()->shutdownAccount(), 0)); + } + } else if (cp->resource()) { + m_cmd.addCommand(new ResourceModifyAccountCmd(*cp->resource(), cp->resource()->account(), 0)); + } + } + for (int i = account->accountList().count()-1; i >= 0; --i) { + m_cmd.addCommand(new RemoveAccountCmd(project, account->accountList().at(i))); + } } RemoveAccountCmd::~RemoveAccountCmd() { if ( m_mine ) delete m_account; } void RemoveAccountCmd::execute() { if ( m_isDefault ) { m_project.accounts().setDefaultAccount( 0 ); } - m_project.accounts().take( m_account ); + m_cmd.execute(); // remove costplaces and children + m_project.accounts().take( m_account ); m_mine = true; } void RemoveAccountCmd::unexecute() { m_project.accounts().insert( m_account, m_parent, m_index ); + + m_cmd.unexecute(); // add costplaces && children + if ( m_isDefault ) { m_project.accounts().setDefaultAccount( m_account ); } m_mine = false; } RenameAccountCmd::RenameAccountCmd( Account *account, const QString& value, const KUndo2MagicString& name ) : NamedCommand( name ), m_account( account ) { m_oldvalue = account->name(); m_newvalue = value; } void RenameAccountCmd::execute() { m_account->setName( m_newvalue ); } void RenameAccountCmd::unexecute() { m_account->setName( m_oldvalue ); } ModifyAccountDescriptionCmd::ModifyAccountDescriptionCmd( Account *account, const QString& value, const KUndo2MagicString& name ) : NamedCommand( name ), m_account( account ) { m_oldvalue = account->description(); m_newvalue = value; } void ModifyAccountDescriptionCmd::execute() { m_account->setDescription( m_newvalue ); } void ModifyAccountDescriptionCmd::unexecute() { m_account->setDescription( m_oldvalue ); } NodeModifyStartupCostCmd::NodeModifyStartupCostCmd( Node &node, double value, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( node ) { m_oldvalue = node.startupCost(); m_newvalue = value; } void NodeModifyStartupCostCmd::execute() { m_node.setStartupCost( m_newvalue ); } void NodeModifyStartupCostCmd::unexecute() { m_node.setStartupCost( m_oldvalue ); } NodeModifyShutdownCostCmd::NodeModifyShutdownCostCmd( Node &node, double value, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( node ) { m_oldvalue = node.shutdownCost(); m_newvalue = value; } void NodeModifyShutdownCostCmd::execute() { m_node.setShutdownCost( m_newvalue ); } void NodeModifyShutdownCostCmd::unexecute() { m_node.setShutdownCost( m_oldvalue ); } NodeModifyRunningAccountCmd::NodeModifyRunningAccountCmd( Node &node, Account *oldvalue, Account *newvalue, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( node ) { m_oldvalue = oldvalue; m_newvalue = newvalue; //debugPlan; } void NodeModifyRunningAccountCmd::execute() { //debugPlan; if ( m_oldvalue ) { m_oldvalue->removeRunning( m_node ); } if ( m_newvalue ) { m_newvalue->addRunning( m_node ); } } void NodeModifyRunningAccountCmd::unexecute() { //debugPlan; if ( m_newvalue ) { m_newvalue->removeRunning( m_node ); } if ( m_oldvalue ) { m_oldvalue->addRunning( m_node ); } } NodeModifyStartupAccountCmd::NodeModifyStartupAccountCmd( Node &node, Account *oldvalue, Account *newvalue, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( node ) { m_oldvalue = oldvalue; m_newvalue = newvalue; //debugPlan; } void NodeModifyStartupAccountCmd::execute() { //debugPlan; if ( m_oldvalue ) { m_oldvalue->removeStartup( m_node ); } if ( m_newvalue ) { m_newvalue->addStartup( m_node ); } } void NodeModifyStartupAccountCmd::unexecute() { //debugPlan; if ( m_newvalue ) { m_newvalue->removeStartup( m_node ); } if ( m_oldvalue ) { m_oldvalue->addStartup( m_node ); } } NodeModifyShutdownAccountCmd::NodeModifyShutdownAccountCmd( Node &node, Account *oldvalue, Account *newvalue, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( node ) { m_oldvalue = oldvalue; m_newvalue = newvalue; //debugPlan; } void NodeModifyShutdownAccountCmd::execute() { //debugPlan; if ( m_oldvalue ) { m_oldvalue->removeShutdown( m_node ); } if ( m_newvalue ) { m_newvalue->addShutdown( m_node ); } } void NodeModifyShutdownAccountCmd::unexecute() { //debugPlan; if ( m_newvalue ) { m_newvalue->removeShutdown( m_node ); } if ( m_oldvalue ) { m_oldvalue->addShutdown( m_node ); } } ModifyDefaultAccountCmd::ModifyDefaultAccountCmd( Accounts &acc, Account *oldvalue, Account *newvalue, const KUndo2MagicString& name ) : NamedCommand( name ), m_accounts( acc ) { m_oldvalue = oldvalue; m_newvalue = newvalue; //debugPlan; } void ModifyDefaultAccountCmd::execute() { //debugPlan; m_accounts.setDefaultAccount( m_newvalue ); } void ModifyDefaultAccountCmd::unexecute() { //debugPlan; m_accounts.setDefaultAccount( m_oldvalue ); } ResourceModifyAccountCmd::ResourceModifyAccountCmd( Resource &resource, Account *oldvalue, Account *newvalue, const KUndo2MagicString& name ) : NamedCommand( name ), m_resource( resource ) { m_oldvalue = oldvalue; m_newvalue = newvalue; } void ResourceModifyAccountCmd::execute() { //debugPlan; if ( m_oldvalue ) { m_oldvalue->removeRunning( m_resource ); } if ( m_newvalue ) { m_newvalue->addRunning( m_resource ); } } void ResourceModifyAccountCmd::unexecute() { //debugPlan; if ( m_newvalue ) { m_newvalue->removeRunning( m_resource ); } if ( m_oldvalue ) { m_oldvalue->addRunning( m_resource ); } } ProjectModifyConstraintCmd::ProjectModifyConstraintCmd( Project &node, Node::ConstraintType c, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( node ), newConstraint( c ), oldConstraint( static_cast( node.constraint() ) ) { } void ProjectModifyConstraintCmd::execute() { m_node.setConstraint( newConstraint ); } void ProjectModifyConstraintCmd::unexecute() { m_node.setConstraint( oldConstraint ); } ProjectModifyStartTimeCmd::ProjectModifyStartTimeCmd( Project &node, const QDateTime& dt, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( node ), newTime( dt ), oldTime( node.startTime() ) { m_timeZone = node.timeZone(); } void ProjectModifyStartTimeCmd::execute() { m_node.setConstraintStartTime( DateTime( newTime, m_timeZone ) ); } void ProjectModifyStartTimeCmd::unexecute() { m_node.setConstraintStartTime( oldTime ); } ProjectModifyEndTimeCmd::ProjectModifyEndTimeCmd( Project &node, const QDateTime& dt, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( node ), newTime( dt ), oldTime( node.endTime() ) { m_timeZone = node.timeZone(); } void ProjectModifyEndTimeCmd::execute() { m_node.setEndTime( DateTime( newTime, m_timeZone ) ); m_node.setConstraintEndTime( DateTime( newTime, m_timeZone ) ); } void ProjectModifyEndTimeCmd::unexecute() { m_node.setConstraintEndTime( oldTime ); } //---------------------------- AddScheduleManagerCmd::AddScheduleManagerCmd( Project &node, ScheduleManager *sm, int index, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( node ), m_parent( sm->parentManager() ), m_sm( sm ), m_index( index ), m_exp( sm->expected() ), m_mine( true) { } AddScheduleManagerCmd::AddScheduleManagerCmd( ScheduleManager *parent, ScheduleManager *sm, int index, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( parent->project() ), m_parent( parent ), m_sm( sm ), m_index( index ), m_exp( sm->expected() ), m_mine( true) { } AddScheduleManagerCmd::~AddScheduleManagerCmd() { if ( m_mine ) { m_sm->setParentManager( 0 ); delete m_sm; } } void AddScheduleManagerCmd::execute() { m_node.addScheduleManager( m_sm, m_parent, m_index ); m_sm->setExpected( m_exp ); m_mine = false; } void AddScheduleManagerCmd::unexecute() { m_node.takeScheduleManager( m_sm ); m_sm->setExpected( 0 ); m_mine = true; } DeleteScheduleManagerCmd::DeleteScheduleManagerCmd( Project &node, ScheduleManager *sm, const KUndo2MagicString& name ) : AddScheduleManagerCmd( node, sm, -1, name ) { m_mine = false; m_index = m_parent ? m_parent->indexOf( sm ) : node.indexOf( sm ); foreach ( ScheduleManager *s, sm->children() ) { cmd.addCommand( new DeleteScheduleManagerCmd( node, s ) ); } } void DeleteScheduleManagerCmd::execute() { cmd.execute(); AddScheduleManagerCmd::unexecute(); } void DeleteScheduleManagerCmd::unexecute() { AddScheduleManagerCmd::execute(); cmd.unexecute(); } MoveScheduleManagerCmd::MoveScheduleManagerCmd( ScheduleManager *sm, ScheduleManager *newparent, int newindex, const KUndo2MagicString& name ) : NamedCommand( name ), m_sm( sm ), m_oldparent( sm->parentManager() ), m_newparent( newparent ), m_newindex( newindex ) { m_oldindex = sm->parentManager() ? sm->parentManager()->indexOf( sm ) : sm->project().indexOf( sm ); } void MoveScheduleManagerCmd::execute() { m_sm->project().moveScheduleManager( m_sm, m_newparent, m_newindex ); } void MoveScheduleManagerCmd::unexecute() { m_sm->project().moveScheduleManager( m_sm, m_oldparent, m_oldindex ); } ModifyScheduleManagerNameCmd::ModifyScheduleManagerNameCmd( ScheduleManager &sm, const QString& value, const KUndo2MagicString& name ) : NamedCommand( name ), m_sm( sm ), oldvalue( sm.name() ), newvalue( value ) { } void ModifyScheduleManagerNameCmd::execute() { m_sm.setName( newvalue ); } void ModifyScheduleManagerNameCmd::unexecute() { m_sm.setName( oldvalue ); } ModifyScheduleManagerAllowOverbookingCmd::ModifyScheduleManagerAllowOverbookingCmd( ScheduleManager &sm, bool value, const KUndo2MagicString& name ) : NamedCommand( name ), m_sm( sm ), oldvalue( sm.allowOverbooking() ), newvalue( value ) { } void ModifyScheduleManagerAllowOverbookingCmd::execute() { m_sm.setAllowOverbooking( newvalue ); } void ModifyScheduleManagerAllowOverbookingCmd::unexecute() { m_sm.setAllowOverbooking( oldvalue ); } ModifyScheduleManagerDistributionCmd::ModifyScheduleManagerDistributionCmd( ScheduleManager &sm, bool value, const KUndo2MagicString& name ) : NamedCommand( name ), m_sm( sm ), oldvalue( sm.usePert() ), newvalue( value ) { } void ModifyScheduleManagerDistributionCmd::execute() { m_sm.setUsePert( newvalue ); } void ModifyScheduleManagerDistributionCmd::unexecute() { m_sm.setUsePert( oldvalue ); } ModifyScheduleManagerSchedulingDirectionCmd::ModifyScheduleManagerSchedulingDirectionCmd( ScheduleManager &sm, bool value, const KUndo2MagicString& name ) : NamedCommand( name ), m_sm( sm ), oldvalue( sm.schedulingDirection() ), newvalue( value ) { } void ModifyScheduleManagerSchedulingDirectionCmd::execute() { m_sm.setSchedulingDirection( newvalue ); } void ModifyScheduleManagerSchedulingDirectionCmd::unexecute() { m_sm.setSchedulingDirection( oldvalue ); } ModifyScheduleManagerSchedulerCmd::ModifyScheduleManagerSchedulerCmd( ScheduleManager &sm, int value, const KUndo2MagicString& name ) : NamedCommand( name ), m_sm( sm ), oldvalue( sm.schedulerPluginIndex() ), newvalue( value ) { } void ModifyScheduleManagerSchedulerCmd::execute() { m_sm.setSchedulerPlugin( newvalue ); } void ModifyScheduleManagerSchedulerCmd::unexecute() { m_sm.setSchedulerPlugin( oldvalue ); } ModifyScheduleManagerSchedulingGranularityCmd::ModifyScheduleManagerSchedulingGranularityCmd( ScheduleManager &sm, int value, const KUndo2MagicString& name ) : NamedCommand( name ), m_sm( sm ), oldvalue( sm.granularity() ), newvalue( value ) { } void ModifyScheduleManagerSchedulingGranularityCmd::execute() { m_sm.setGranularity( newvalue ); } void ModifyScheduleManagerSchedulingGranularityCmd::unexecute() { m_sm.setGranularity( oldvalue ); } CalculateScheduleCmd::CalculateScheduleCmd( Project &node, ScheduleManager *sm, const KUndo2MagicString& name ) : NamedCommand( name ), m_node( node ), m_sm( sm ), m_first( true ), m_oldexpected( m_sm->expected() ), m_newexpected( 0 ) { } void CalculateScheduleCmd::execute() { Q_ASSERT( m_sm ); if ( m_first ) { m_sm->calculateSchedule(); if ( m_sm->calculationResult() != ScheduleManager::CalculationCanceled ) { m_first = false; } m_newexpected = m_sm->expected(); } else { m_sm->setExpected( m_newexpected ); } } void CalculateScheduleCmd::unexecute() { if ( m_sm->scheduling() ) { // terminate scheduling QApplication::setOverrideCursor( Qt::WaitCursor ); m_sm->haltCalculation(); m_first = true; QApplication::restoreOverrideCursor(); } m_sm->setExpected( m_oldexpected ); } //------------------------ BaselineScheduleCmd::BaselineScheduleCmd( ScheduleManager &sm, const KUndo2MagicString& name ) : NamedCommand( name ), m_sm( sm ) { } void BaselineScheduleCmd::execute() { m_sm.setBaselined( true ); } void BaselineScheduleCmd::unexecute() { m_sm.setBaselined( false ); } ResetBaselineScheduleCmd::ResetBaselineScheduleCmd( ScheduleManager &sm, const KUndo2MagicString& name ) : NamedCommand( name ), m_sm( sm ) { } void ResetBaselineScheduleCmd::execute() { m_sm.setBaselined( false ); } void ResetBaselineScheduleCmd::unexecute() { m_sm.setBaselined( true ); } //------------------------ ModifyStandardWorktimeYearCmd::ModifyStandardWorktimeYearCmd( StandardWorktime *wt, double oldvalue, double newvalue, const KUndo2MagicString& name ) : NamedCommand( name ), swt( wt ), m_oldvalue( oldvalue ), m_newvalue( newvalue ) { } void ModifyStandardWorktimeYearCmd::execute() { swt->setYear( m_newvalue ); } void ModifyStandardWorktimeYearCmd::unexecute() { swt->setYear( m_oldvalue ); } ModifyStandardWorktimeMonthCmd::ModifyStandardWorktimeMonthCmd( StandardWorktime *wt, double oldvalue, double newvalue, const KUndo2MagicString& name ) : NamedCommand( name ), swt( wt ), m_oldvalue( oldvalue ), m_newvalue( newvalue ) { } void ModifyStandardWorktimeMonthCmd::execute() { swt->setMonth( m_newvalue ); } void ModifyStandardWorktimeMonthCmd::unexecute() { swt->setMonth( m_oldvalue ); } ModifyStandardWorktimeWeekCmd::ModifyStandardWorktimeWeekCmd( StandardWorktime *wt, double oldvalue, double newvalue, const KUndo2MagicString& name ) : NamedCommand( name ), swt( wt ), m_oldvalue( oldvalue ), m_newvalue( newvalue ) { } void ModifyStandardWorktimeWeekCmd::execute() { swt->setWeek( m_newvalue ); } void ModifyStandardWorktimeWeekCmd::unexecute() { swt->setWeek( m_oldvalue ); } ModifyStandardWorktimeDayCmd::ModifyStandardWorktimeDayCmd( StandardWorktime *wt, double oldvalue, double newvalue, const KUndo2MagicString& name ) : NamedCommand( name ), swt( wt ), m_oldvalue( oldvalue ), m_newvalue( newvalue ) { } void ModifyStandardWorktimeDayCmd::execute() { swt->setDay( m_newvalue ); } void ModifyStandardWorktimeDayCmd::unexecute() { swt->setDay( m_oldvalue ); } //---------------- DocumentAddCmd::DocumentAddCmd( Documents &docs, Document *value, const KUndo2MagicString& name ) : NamedCommand( name ), m_docs( docs ), m_mine( true ) { Q_ASSERT( value ); m_value = value; } DocumentAddCmd::~DocumentAddCmd() { //debugPlan; if ( m_mine ) delete m_value; } void DocumentAddCmd::execute() { m_docs.addDocument( m_value ); m_mine = false; } void DocumentAddCmd::unexecute() { m_docs.takeDocument( m_value ); m_mine = true; } //---------------- DocumentRemoveCmd::DocumentRemoveCmd( Documents &docs, Document *value, const KUndo2MagicString& name ) : NamedCommand( name ), m_docs( docs ), m_mine( false ) { Q_ASSERT( value ); m_value = value; } DocumentRemoveCmd::~DocumentRemoveCmd() { //debugPlan; if ( m_mine ) delete m_value; } void DocumentRemoveCmd::execute() { m_docs.takeDocument( m_value ); m_mine = true; } void DocumentRemoveCmd::unexecute() { m_docs.addDocument( m_value ); m_mine = false; } //---------------- DocumentModifyUrlCmd::DocumentModifyUrlCmd( Document *doc, const QUrl &value, const KUndo2MagicString& name ) : NamedCommand( name ), m_doc( doc ) { Q_ASSERT( doc ); m_value = value; m_oldvalue = doc->url(); } void DocumentModifyUrlCmd::execute() { m_doc->setUrl( m_value ); } void DocumentModifyUrlCmd::unexecute() { m_doc->setUrl( m_oldvalue ); } //---------------- DocumentModifyNameCmd::DocumentModifyNameCmd( Document *doc, const QString &value, const KUndo2MagicString& name ) : NamedCommand( name ), m_doc( doc ) { Q_ASSERT( doc ); m_value = value; m_oldvalue = doc->name(); } void DocumentModifyNameCmd::execute() { m_doc->setName( m_value ); } void DocumentModifyNameCmd::unexecute() { m_doc->setName( m_oldvalue ); } //---------------- DocumentModifyTypeCmd::DocumentModifyTypeCmd( Document *doc, Document::Type value, const KUndo2MagicString& name ) : NamedCommand( name ), m_doc( doc ) { Q_ASSERT( doc ); m_value = value; m_oldvalue = doc->type(); } void DocumentModifyTypeCmd::execute() { m_doc->setType( m_value ); } void DocumentModifyTypeCmd::unexecute() { m_doc->setType( m_oldvalue ); } //---------------- DocumentModifyStatusCmd::DocumentModifyStatusCmd( Document *doc, const QString &value, const KUndo2MagicString& name ) : NamedCommand( name ), m_doc( doc ) { Q_ASSERT( doc ); m_value = value; m_oldvalue = doc->type(); } void DocumentModifyStatusCmd::execute() { m_doc->setStatus( m_value ); } void DocumentModifyStatusCmd::unexecute() { m_doc->setStatus( m_oldvalue ); } //---------------- DocumentModifySendAsCmd::DocumentModifySendAsCmd( Document *doc, const Document::SendAs value, const KUndo2MagicString& name ) : NamedCommand( name ), m_doc( doc ) { Q_ASSERT( doc ); m_value = value; m_oldvalue = doc->sendAs(); } void DocumentModifySendAsCmd::execute() { m_doc->setSendAs( m_value ); } void DocumentModifySendAsCmd::unexecute() { m_doc->setSendAs( m_oldvalue ); } //---------------- WBSDefinitionModifyCmd::WBSDefinitionModifyCmd( Project &project, const WBSDefinition value, const KUndo2MagicString& name ) : NamedCommand( name ), m_project( project ) { m_newvalue = value; m_oldvalue = m_project.wbsDefinition(); } void WBSDefinitionModifyCmd::execute() { m_project.setWbsDefinition( m_newvalue ); } void WBSDefinitionModifyCmd::unexecute() { m_project.setWbsDefinition( m_oldvalue ); } //---------------- InsertProjectCmd::InsertProjectCmd( Project &project, Node *parent, Node *after, const KUndo2MagicString& name ) : MacroCommand( name ), m_project( static_cast( parent->projectNode() ) ), m_parent( parent ) { Q_ASSERT( &project != m_project ); if ( m_project->defaultCalendar() ) { project.setDefaultCalendar( 0 ); // or else m_project default calendar may be overwitten } QString defaultAccount; if ( ! m_project->accounts().defaultAccount() && project.accounts().defaultAccount() ) { defaultAccount = project.accounts().defaultAccount()->name(); } QMap startupaccountmap; QMap shutdownaccountmap; QMap runningaccountmap; QMap nodecalendarmap; // remove unhandled info in tasks and get accounts and calendars foreach ( Node *n, project.allNodes() ) { if ( n->type() == Node::Type_Task ) { Task *t = static_cast( n ); t->workPackage().clear(); while ( ! t->workPackageLog().isEmpty() ) { WorkPackage *wp = t->workPackageLog().at( 0 ); t->removeWorkPackage( wp ); delete wp; } } if ( n->startupAccount() ) { startupaccountmap.insert( n, n->startupAccount()->name() ); n->setStartupAccount( 0 ); } if ( n->shutdownAccount() ) { shutdownaccountmap.insert( n, n->shutdownAccount()->name() ); n->setShutdownAccount( 0 ); } if ( n->runningAccount() ) { runningaccountmap.insert( n, n->runningAccount()->name() ); n->setRunningAccount( 0 ); } if ( n->estimate()->calendar() ) { nodecalendarmap.insert( n, n->estimate()->calendar()->id() ); n->estimate()->setCalendar( 0 ); } } // get resources pointing to calendars and accounts QMap resaccountmap; QMap rescalendarmap; foreach ( Resource *r, project.resourceList() ) { if ( r->account() ) { resaccountmap.insert( r, r->account()->name() ); r->setAccount( 0 ); } if ( r->calendar() ) { rescalendarmap.insert( r, r->calendar()->id() ); r->setCalendar( 0 ); } } // create add account commands and keep track of used and unused accounts QList unusedAccounts; QMap accountsmap; foreach ( Account *a, m_project->accounts().allAccounts() ) { accountsmap.insert( a->name(), a ); } foreach ( Account *a, project.accounts().accountList() ) { addAccounts( a, 0, unusedAccounts, accountsmap ); } // create add calendar commands and keep track of used and unused calendars QList unusedCalendars; QMap calendarsmap; foreach ( Calendar *c, m_project->allCalendars() ) { calendarsmap.insert( c->id(), c ); } foreach ( Calendar *c, project.calendars() ) { addCalendars( c, 0, unusedCalendars, calendarsmap ); } // get all requests before resources are merged QMap > greqs; QMap > rreqs; foreach ( Node *n, project.allNodes() ) { QList resReq; if ( n->type() != (int)Node::Type_Task || n->requests().isEmpty() ) { continue; } while ( ResourceGroupRequest *gr = n->requests().requests().value( 0 ) ) { while ( ResourceRequest *rr = gr->resourceRequests( false ).value( 0 ) ) { debugPlanInsertProject<<"Get resource request:"<( rr, rr->resource() ) ); // all resource requests shall be reinserted rr->unregisterRequest(); gr->takeResourceRequest( rr ); } // all group requests shall be reinserted greqs[ gr ] = QPair( n, gr->group() ); gr->group()->unregisterRequest( gr ); int i = n->requests().takeRequest( gr ); Q_ASSERT( i >= 0 ); #ifdef NDEBUG Q_UNUSED(i); #endif } } QList allGroups; QList allResources; QList newResources; QMap existingGroups; QMap existingResources; foreach ( ResourceGroup *g, project.resourceGroups() ) { ResourceGroup *gr = m_project->findResourceGroup( g->id() ); if ( gr == 0 ) { addCommand( new AddResourceGroupCmd( m_project, g, kundo2_noi18n("ResourceGroup") ) ); gr = g; debugPlanInsertProject<<"AddResourceGroupCmd:"<name(); } else { existingGroups[ gr ] = g; } allGroups << gr; foreach ( Resource *r, g->resources() ) { while ( Schedule *s = r->schedules().values().value( 0 ) ) { r->deleteSchedule( s ); // schedules not handled } Resource *res = m_project->findResource( r->id() ); if ( res == 0 ) { addCommand( new AddResourceCmd( gr, r, kundo2_noi18n("Resource") ) ); allResources << r; newResources << r; debugPlanInsertProject<<"AddResourceCmd:"<name()<name(); } else { existingResources[ res ] = r; allResources << res; } } } // Update resource account {QMap::const_iterator it = resaccountmap.constBegin(); QMap::const_iterator end = resaccountmap.constEnd(); for ( ; it != end; ++it ) { Resource *r = it.key(); if ( newResources.contains( r ) ) { Q_ASSERT( allResources.contains( r ) ); addCommand( new ResourceModifyAccountCmd( *r, 0, accountsmap.value( it.value() ) ) ); } }} // Update resource calendar {QMap::const_iterator it = rescalendarmap.constBegin(); QMap::const_iterator end = rescalendarmap.constEnd(); for ( ; it != end; ++it ) { Resource *r = it.key(); if ( newResources.contains( r ) ) { Q_ASSERT( allResources.contains( r ) ); addCommand( new ModifyResourceCalendarCmd( r, calendarsmap.value( it.value() ) ) ); } }} // Requests: clean up requests to resources already in m_project int gi = 0; int ri = 0; foreach ( ResourceGroupRequest *gr, greqs.keys() ) { QPair pair = greqs[ gr ]; Node *n = pair.first; ResourceGroup *newGroup = pair.second; if ( existingGroups.values().contains( newGroup ) ) { newGroup = existingGroups.key( newGroup ); } Q_ASSERT( allGroups.contains( newGroup ) ); gr->setGroup( newGroup ); addCommand( new AddResourceGroupRequestCmd( static_cast( *n ), gr, kundo2_noi18n("Group %1", ++gi) ) ); debugPlanInsertProject<<"Add resource group request:"<name()<<":"<name(); QMap >::const_iterator i = rreqs.constFind( gr ); for ( ; i != rreqs.constEnd() && i.key() == gr; ++i ) { ResourceRequest *rr = i.value().first; Resource *newRes = i.value().second; if ( existingResources.values().contains( newRes ) ) { newRes = existingResources.key( newRes ); } debugPlanInsertProject<<"Add resource request:"<name()<<":"<name()<<":"<name(); if ( ! rr->requiredResources().isEmpty() ) { // the resource request may have required resources that needs mapping QList required; foreach ( Resource *r, rr->requiredResources() ) { if ( newResources.contains( r ) ) { required << r; debugPlanInsertProject<<"Request: required (new)"<name(); continue; } Resource *r2 = existingResources.key( r ); Q_ASSERT( allResources.contains( r2 ) ); if ( r2 ) { debugPlanInsertProject<<"Request: required (existing)"<name(); required << r2; } } rr->setRequiredResources( required ); } Q_ASSERT( allResources.contains( newRes ) ); // all resource requests shall be reinserted rr->setResource( newRes ); addCommand( new AddResourceRequestCmd( gr, rr, kundo2_noi18n("Resource %1", ++ri) ) ); } } // Add nodes ( ids are unique, no need to check ) Node *node_after = after; for ( int i = 0; i < project.numChildren(); ++i ) { Node *n = project.childNode( i ); Q_ASSERT( n ); while ( Schedule *s = n->schedules().values().value( 0 ) ) { n->takeSchedule( s ); // schedules not handled delete s; } n->setParentNode( 0 ); if ( node_after ) { addCommand( new TaskAddCmd( m_project, n, node_after, kundo2_noi18n("Task") ) ); node_after = n; } else { addCommand( new SubtaskAddCmd( m_project, n, parent, kundo2_noi18n("Subtask") ) ); } addChildNodes( n ); } // Dependencies: foreach ( Node *n, project.allNodes() ) { while ( n->numDependChildNodes() > 0 ) { Relation *r = n->dependChildNodes().at( 0 ); n->takeDependChildNode( r ); r->child()->takeDependParentNode( r ); addCommand( new AddRelationCmd( *m_project, r ) ); } } // node calendar {QMap::const_iterator it = nodecalendarmap.constBegin(); QMap::const_iterator end = nodecalendarmap.constEnd(); for ( ; it != end; ++it ) { addCommand( new ModifyEstimateCalendarCmd( *(it.key()), 0, calendarsmap.value( it.value() ) ) ); }} // node startup account {QMap::const_iterator it = startupaccountmap.constBegin(); QMap::const_iterator end = startupaccountmap.constEnd(); for ( ; it != end; ++it ) { addCommand( new NodeModifyStartupAccountCmd( *(it.key()), 0, accountsmap.value( it.value() ) ) ); }} // node shutdown account {QMap::const_iterator it = shutdownaccountmap.constBegin(); QMap::const_iterator end = shutdownaccountmap.constEnd(); for ( ; it != end; ++it ) { addCommand( new NodeModifyShutdownAccountCmd( *(it.key()), 0, accountsmap.value( it.value() ) ) ); }} // node running account {QMap::const_iterator it = runningaccountmap.constBegin(); QMap::const_iterator end = runningaccountmap.constEnd(); for ( ; it != end; ++it ) { addCommand( new NodeModifyRunningAccountCmd( *(it.key()), 0, accountsmap.value( it.value() ) ) ); }} if ( ! defaultAccount.isEmpty() ) { Account *a = accountsmap.value( defaultAccount ); if ( a && a->list() ) { addCommand( new ModifyDefaultAccountCmd( m_project->accounts(), 0, a ) ); } } // Cleanup // Remove nodes from project so they are not deleted while ( Node *ch = project.childNode( 0 ) ) { project.takeChildNode( ch ); } foreach ( Node *n, project.allNodes() ) { project.removeId( n->id() ); } // Remove calendars from project while ( project.calendarCount() > 0 ) { project.takeCalendar( project.calendarAt( 0 ) ); } qDeleteAll( unusedCalendars ); // Remove accounts from project while ( project.accounts().accountCount() > 0 ) { project.accounts().take( project.accounts().accountAt( 0 ) ); } qDeleteAll( unusedAccounts ); while ( project.numResourceGroups() > 0 ) { ResourceGroup *g = project.resourceGroupAt( 0 ); while ( g->numResources() > 0 ) { g->takeResource( g->resourceAt( 0 ) ); } project.takeResourceGroup( g ); } qDeleteAll( existingResources ); // deletes unused resources qDeleteAll( existingGroups ); // deletes unused resource groups } void InsertProjectCmd::addCalendars( Calendar *calendar, Calendar *parent, QList &unused, QMap &calendarsmap ) { Calendar *par = 0; if ( parent ) { par = calendarsmap.value( parent->id() ); } if ( par == 0 ) { par = parent; } Calendar *cal = calendarsmap.value( calendar->id() ); if ( cal == 0 ) { calendarsmap.insert( calendar->id(), calendar ); addCommand( new CalendarAddCmd( m_project, calendar, -1, par ) ); } else { unused << calendar; } foreach ( Calendar *c, calendar->calendars() ) { addCalendars( c, calendar, unused, calendarsmap ); } } void InsertProjectCmd::addAccounts( Account *account, Account *parent, QList &unused, QMap &accountsmap ) { Account *par = 0; if ( parent ) { par = accountsmap.value( parent->name() ); } if ( par == 0 ) { par = parent; } Account *acc = accountsmap.value( account->name() ); if ( acc == 0 ) { debugPlanInsertProject<<"Move to new project:"<name(); accountsmap.insert( account->name(), account ); addCommand( new AddAccountCmd( *m_project, account, par, -1, kundo2_noi18n( "Add account %1", account->name() ) ) ); } else { debugPlanInsertProject<<"Already exists:"<name(); unused << account; } while ( ! account->accountList().isEmpty() ) { Account *a = account->accountList().first(); account->list()->take( a ); addAccounts( a, account, unused, accountsmap ); } } void InsertProjectCmd::addChildNodes( Node *node ) { // schedules not handled while ( Schedule *s = node->schedules().values().value( 0 ) ) { node->takeSchedule( s ); // schedules not handled delete s; } foreach ( Node *n, node->childNodeIterator() ) { n->setParentNode( 0 ); addCommand( new SubtaskAddCmd( m_project, n, node, kundo2_noi18n("Subtask") ) ); addChildNodes( n ); } // Remove child nodes so they are not added twice while ( Node *ch = node->childNode( 0 ) ) { node->takeChildNode( ch ); } } void InsertProjectCmd::execute() { QApplication::setOverrideCursor( Qt::WaitCursor ); MacroCommand::execute(); QApplication::restoreOverrideCursor(); } void InsertProjectCmd::unexecute() { QApplication::setOverrideCursor( Qt::WaitCursor ); MacroCommand::unexecute(); QApplication::restoreOverrideCursor(); } WorkPackageAddCmd::WorkPackageAddCmd( Project *project, Node *node, WorkPackage *value, const KUndo2MagicString& name ) : NamedCommand( name ), m_project( project ), m_node( node ), m_wp( value ), m_mine( true ) { } WorkPackageAddCmd::~WorkPackageAddCmd() { if ( m_mine ) { delete m_wp; } } void WorkPackageAddCmd::execute() { // FIXME use project //m_project->addWorkPackage( m_node, m_wp ); static_cast( m_node )->addWorkPackage( m_wp ); } void WorkPackageAddCmd::unexecute() { // FIXME use project //m_project->removeWorkPackage( m_node, m_wp ); static_cast( m_node )->removeWorkPackage( m_wp ); } ModifyProjectLocaleCmd::ModifyProjectLocaleCmd( Project &project, const KUndo2MagicString& name ) : MacroCommand( name ), m_project( project ) { }; void ModifyProjectLocaleCmd::execute() { MacroCommand::execute(); m_project.emitLocaleChanged(); } void ModifyProjectLocaleCmd::unexecute() { MacroCommand::unexecute(); m_project.emitLocaleChanged(); } ModifyCurrencySymolCmd::ModifyCurrencySymolCmd( Locale *locale, const QString &value, const KUndo2MagicString& name ) : NamedCommand( name ), m_locale( locale ), m_newvalue( value ), m_oldvalue( locale->currencySymbol() ) { }; void ModifyCurrencySymolCmd::execute() { m_locale->setCurrencySymbol( m_newvalue ); } void ModifyCurrencySymolCmd::unexecute() { m_locale->setCurrencySymbol( m_oldvalue ); } ModifyCurrencyFractionalDigitsCmd::ModifyCurrencyFractionalDigitsCmd( Locale *locale, int value, const KUndo2MagicString& name ) : NamedCommand( name ), m_locale( locale ), m_newvalue( value ), m_oldvalue(locale->monetaryDecimalPlaces()) { }; void ModifyCurrencyFractionalDigitsCmd::execute() { m_locale->setMonetaryDecimalPlaces(m_newvalue); } void ModifyCurrencyFractionalDigitsCmd::unexecute() { m_locale->setMonetaryDecimalPlaces(m_oldvalue); } AddExternalAppointmentCmd::AddExternalAppointmentCmd( Resource *resource, const QString &pid, const QString &pname, const QDateTime &start, const QDateTime &end, double load, const KUndo2MagicString& name ) : NamedCommand( name ), m_resource( resource ), m_pid( pid ), m_pname( pname ), m_start( start ), m_end( end ), m_load( load ) { } void AddExternalAppointmentCmd::execute() { m_resource->addExternalAppointment( m_pid, m_pname, m_start, m_end, m_load ); } void AddExternalAppointmentCmd::unexecute() { m_resource->subtractExternalAppointment( m_pid, m_start, m_end, m_load ); // FIXME do this smarter if ( ! m_resource->externalAppointments( m_pid ).isEmpty() ) { m_resource->takeExternalAppointment( m_pid ); } } ClearExternalAppointmentCmd::ClearExternalAppointmentCmd( Resource *resource, const QString &pid, const KUndo2MagicString &name ) : NamedCommand( name ), m_resource( resource ), m_pid( pid ), m_appointments( 0 ) { } ClearExternalAppointmentCmd::~ClearExternalAppointmentCmd() { delete m_appointments; } void ClearExternalAppointmentCmd::execute() { // debugPlan<name()<takeExternalAppointment( m_pid ); } void ClearExternalAppointmentCmd::unexecute() { // debugPlan<name()<addExternalAppointment( m_pid, m_appointments ); } m_appointments = 0; } ClearAllExternalAppointmentsCmd::ClearAllExternalAppointmentsCmd( Project *project, const KUndo2MagicString &name ) : NamedCommand( name ), m_project( project ) { foreach ( Resource *r, project->resourceList() ) { foreach ( const QString &id, r->externalProjects().keys() ) { m_cmd.addCommand( new ClearExternalAppointmentCmd( r, id ) ); } } } void ClearAllExternalAppointmentsCmd::execute() { m_cmd.redo(); } void ClearAllExternalAppointmentsCmd::unexecute() { m_cmd.undo(); } SharedResourcesFileCmd::SharedResourcesFileCmd(Project *project, const QString &newValue, const KUndo2MagicString& name) : NamedCommand(name) , m_project(project) , m_oldValue(project->sharedResourcesFile()) , m_newValue(newValue) { } void SharedResourcesFileCmd::execute() { m_project->setSharedResourcesFile(m_newValue); } void SharedResourcesFileCmd::unexecute() { m_project->setSharedResourcesFile(m_oldValue); } UseSharedResourcesCmd::UseSharedResourcesCmd(Project *project, bool newValue, const KUndo2MagicString& name) : NamedCommand(name) , m_project(project) , m_oldValue(project->useSharedResources()) , m_newValue(newValue) { } void UseSharedResourcesCmd::execute() { m_project->setUseSharedResources(m_newValue); } void UseSharedResourcesCmd::unexecute() { m_project->setUseSharedResources(m_oldValue); } SharedProjectsUrlCmd::SharedProjectsUrlCmd(Project *project, const QUrl &newValue, const KUndo2MagicString& name) : NamedCommand(name) , m_project(project) , m_oldValue(project->sharedProjectsUrl()) , m_newValue(newValue) { } void SharedProjectsUrlCmd::execute() { m_project->setSharedProjectsUrl(m_newValue); } void SharedProjectsUrlCmd::unexecute() { m_project->setSharedProjectsUrl(m_oldValue); } +LoadProjectsAtStartupCmd::LoadProjectsAtStartupCmd(Project *project, bool newValue, const KUndo2MagicString& name) + : NamedCommand(name) + , m_project(project) + , m_oldValue(project->loadProjectsAtStartup()) + , m_newValue(newValue) +{ +} + +void LoadProjectsAtStartupCmd::execute() +{ + m_project->setLoadProjectsAtStartup(m_newValue); +} + +void LoadProjectsAtStartupCmd::unexecute() +{ + m_project->setLoadProjectsAtStartup(m_oldValue); +} + } //KPlato namespace diff --git a/plan/libs/kernel/kptcommand.h b/plan/libs/kernel/kptcommand.h index 9cb80fb8feb..3bcb4de2f5b 100644 --- a/plan/libs/kernel/kptcommand.h +++ b/plan/libs/kernel/kptcommand.h @@ -1,1975 +1,1988 @@ /* This file is part of the KDE project Copyright (C) 2004-2007 Dag Andersen Copyright (C) 2011 Dag Andersen Copyright (C) 2016 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 KPTCOMMAND_H #define KPTCOMMAND_H #include "kplatokernel_export.h" #include #include #include "kptappointment.h" #include "kptnode.h" #include "kptduration.h" #include "kpttask.h" #include "kptwbsdefinition.h" class QString; /** * @file * This file includes undo/redo commands for kernel data structures */ /// The main namespace namespace KPlato { class Locale; class Account; class Accounts; class Project; class Task; class Calendar; class CalendarDay; class Relation; class ResourceGroupRequest; class ResourceRequest; class ResourceGroup; class Resource; class Schedule; class StandardWorktime; class KPLATOKERNEL_EXPORT NamedCommand : public KUndo2Command { public: explicit NamedCommand( const KUndo2MagicString& name ) : KUndo2Command( name ) {} virtual void redo() { execute(); } virtual void undo() { unexecute(); } virtual void execute() = 0; virtual void unexecute() = 0; protected: /// Set all scheduled in the m_schedules map to their original scheduled state void setSchScheduled(); /// Set all schedules in the m_schedules map to scheduled state @p state void setSchScheduled( bool state ); /// Add a schedule to the m_schedules map along with its current scheduled state void addSchScheduled( Schedule *sch ); QMap m_schedules; }; class KPLATOKERNEL_EXPORT MacroCommand : public KUndo2Command { public: explicit MacroCommand( const KUndo2MagicString& name = KUndo2MagicString() ) : KUndo2Command( name ) {} ~MacroCommand(); void addCommand( KUndo2Command *cmd ); virtual void redo() { execute(); } virtual void undo() { unexecute(); } virtual void execute(); virtual void unexecute(); bool isEmpty() const { return cmds.isEmpty(); } protected: QList cmds; }; class KPLATOKERNEL_EXPORT CalendarAddCmd : public NamedCommand { public: CalendarAddCmd( Project *project, Calendar *cal, int pos, Calendar *parent, const KUndo2MagicString& name = KUndo2MagicString() ); ~CalendarAddCmd(); void execute(); void unexecute(); private: Project *m_project; Calendar *m_cal; int m_pos; Calendar *m_parent; bool m_mine; }; class KPLATOKERNEL_EXPORT CalendarRemoveCmd : public NamedCommand { public: CalendarRemoveCmd( Project *project, Calendar *cal, const KUndo2MagicString& name = KUndo2MagicString() ); ~CalendarRemoveCmd(); void execute(); void unexecute(); private: Project *m_project; Calendar *m_parent; Calendar *m_cal; int m_index; bool m_mine; MacroCommand *m_cmd; }; class KPLATOKERNEL_EXPORT CalendarMoveCmd : public NamedCommand { public: CalendarMoveCmd( Project *project, Calendar *cal, int position, Calendar *parent, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Project *m_project; Calendar *m_cal; int m_newpos; int m_oldpos; Calendar *m_newparent; Calendar *m_oldparent; }; class KPLATOKERNEL_EXPORT CalendarModifyNameCmd : public NamedCommand { public: CalendarModifyNameCmd( Calendar *cal, const QString& newvalue, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Calendar *m_cal; QString m_newvalue; QString m_oldvalue; }; class KPLATOKERNEL_EXPORT CalendarModifyParentCmd : public NamedCommand { public: CalendarModifyParentCmd( Project *project, Calendar *cal, Calendar *newvalue, const KUndo2MagicString& name = KUndo2MagicString() ); ~CalendarModifyParentCmd(); void execute(); void unexecute(); private: Project *m_project; Calendar *m_cal; Calendar *m_newvalue; Calendar *m_oldvalue; MacroCommand *m_cmd; int m_oldindex; int m_newindex; }; class KPLATOKERNEL_EXPORT CalendarModifyTimeZoneCmd : public NamedCommand { public: CalendarModifyTimeZoneCmd( Calendar *cal, const QTimeZone &value, const KUndo2MagicString& name = KUndo2MagicString() ); ~CalendarModifyTimeZoneCmd(); void execute(); void unexecute(); private: Calendar *m_cal; QTimeZone m_newvalue; QTimeZone m_oldvalue; MacroCommand *m_cmd; }; #ifdef HAVE_KHOLIDAYS class KPLATOKERNEL_EXPORT CalendarModifyHolidayRegionCmd : public NamedCommand { public: CalendarModifyHolidayRegionCmd( Calendar *cal, const QString &value, const KUndo2MagicString& name = KUndo2MagicString() ); ~CalendarModifyHolidayRegionCmd(); void execute(); void unexecute(); private: Calendar *m_cal; QString m_newvalue; QString m_oldvalue; }; #endif class KPLATOKERNEL_EXPORT CalendarAddDayCmd : public NamedCommand { public: CalendarAddDayCmd( Calendar *cal, CalendarDay *newvalue, const KUndo2MagicString& name = KUndo2MagicString() ); ~CalendarAddDayCmd(); void execute(); void unexecute(); protected: Calendar *m_cal; CalendarDay *m_newvalue; bool m_mine; }; class KPLATOKERNEL_EXPORT CalendarRemoveDayCmd : public NamedCommand { public: CalendarRemoveDayCmd( Calendar *cal, CalendarDay *day, const KUndo2MagicString& name = KUndo2MagicString() ); CalendarRemoveDayCmd( Calendar *cal, const QDate &day, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); protected: Calendar *m_cal; CalendarDay *m_value; bool m_mine; private: void init(); }; class KPLATOKERNEL_EXPORT CalendarModifyDayCmd : public NamedCommand { public: CalendarModifyDayCmd( Calendar *cal, CalendarDay *value, const KUndo2MagicString& name = KUndo2MagicString() ); ~CalendarModifyDayCmd(); void execute(); void unexecute(); private: Calendar *m_cal; CalendarDay *m_newvalue; CalendarDay *m_oldvalue; bool m_mine; }; class KPLATOKERNEL_EXPORT CalendarModifyStateCmd : public NamedCommand { public: CalendarModifyStateCmd( Calendar *calendar, CalendarDay *day, CalendarDay::State value, const KUndo2MagicString& name = KUndo2MagicString() ); ~CalendarModifyStateCmd(); void execute(); void unexecute(); private: Calendar *m_calendar; CalendarDay *m_day; CalendarDay::State m_newvalue; CalendarDay::State m_oldvalue; MacroCommand *m_cmd; }; class KPLATOKERNEL_EXPORT CalendarModifyTimeIntervalCmd : public NamedCommand { public: CalendarModifyTimeIntervalCmd( Calendar *calendar, TimeInterval &newvalue, TimeInterval *value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Calendar *m_calendar; TimeInterval *m_value; TimeInterval m_newvalue; TimeInterval m_oldvalue; }; class KPLATOKERNEL_EXPORT CalendarAddTimeIntervalCmd : public NamedCommand { public: CalendarAddTimeIntervalCmd( Calendar *calendar, CalendarDay *day, TimeInterval *value, const KUndo2MagicString& name = KUndo2MagicString() ); ~CalendarAddTimeIntervalCmd(); void execute(); void unexecute(); protected: Calendar *m_calendar; CalendarDay *m_day; TimeInterval *m_value; bool m_mine; }; class KPLATOKERNEL_EXPORT CalendarRemoveTimeIntervalCmd : public CalendarAddTimeIntervalCmd { public: CalendarRemoveTimeIntervalCmd( Calendar *calendar, CalendarDay *day, TimeInterval *value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); }; class KPLATOKERNEL_EXPORT CalendarModifyWeekdayCmd : public NamedCommand { public: CalendarModifyWeekdayCmd( Calendar *cal, int weekday, CalendarDay *value, const KUndo2MagicString& name = KUndo2MagicString() ); ~CalendarModifyWeekdayCmd(); void execute(); void unexecute(); private: int m_weekday; Calendar *m_cal; CalendarDay *m_value; CalendarDay m_orig; }; class KPLATOKERNEL_EXPORT CalendarModifyDateCmd : public NamedCommand { public: CalendarModifyDateCmd( Calendar *cal, CalendarDay *day, const QDate &value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Calendar *m_cal; CalendarDay *m_day; QDate m_newvalue, m_oldvalue; }; class KPLATOKERNEL_EXPORT ProjectModifyDefaultCalendarCmd : public NamedCommand { public: ProjectModifyDefaultCalendarCmd( Project *project, Calendar *cal, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Project *m_project; Calendar *m_newvalue, *m_oldvalue; }; class KPLATOKERNEL_EXPORT NodeDeleteCmd : public NamedCommand { public: explicit NodeDeleteCmd( Node *node, const KUndo2MagicString& name = KUndo2MagicString() ); ~NodeDeleteCmd(); void execute(); void unexecute(); private: Node *m_node; Node *m_parent; Project *m_project; int m_index; bool m_mine; QList m_appointments; MacroCommand *m_cmd; MacroCommand m_relCmd; }; class KPLATOKERNEL_EXPORT TaskAddCmd : public NamedCommand { public: TaskAddCmd( Project *project, Node *node, Node *after, const KUndo2MagicString& name = KUndo2MagicString() ); ~TaskAddCmd(); void execute(); void unexecute(); private: Project *m_project; Node *m_node; Node *m_after; bool m_added; }; class KPLATOKERNEL_EXPORT SubtaskAddCmd : public NamedCommand { public: SubtaskAddCmd( Project *project, Node *node, Node *parent, const KUndo2MagicString& name = KUndo2MagicString() ); ~SubtaskAddCmd(); void execute(); void unexecute(); private: Project *m_project; Node *m_node; Node *m_parent; bool m_added; MacroCommand *m_cmd; }; class KPLATOKERNEL_EXPORT NodeModifyNameCmd : public NamedCommand { public: NodeModifyNameCmd( Node &node, const QString& nodename, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Node &m_node; QString newName; QString oldName; }; class KPLATOKERNEL_EXPORT NodeModifyLeaderCmd : public NamedCommand { public: NodeModifyLeaderCmd( Node &node, const QString& leader, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Node &m_node; QString newLeader; QString oldLeader; }; class KPLATOKERNEL_EXPORT NodeModifyDescriptionCmd : public NamedCommand { public: NodeModifyDescriptionCmd( Node &node, const QString& description, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Node &m_node; QString newDescription; QString oldDescription; }; class KPLATOKERNEL_EXPORT NodeModifyConstraintCmd : public NamedCommand { public: NodeModifyConstraintCmd( Node &node, Node::ConstraintType c, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Node &m_node; Node::ConstraintType newConstraint; Node::ConstraintType oldConstraint; }; class KPLATOKERNEL_EXPORT NodeModifyConstraintStartTimeCmd : public NamedCommand { public: NodeModifyConstraintStartTimeCmd( Node &node, const QDateTime& dt, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Node &m_node; QDateTime newTime; DateTime oldTime; QTimeZone m_timeZone; }; class KPLATOKERNEL_EXPORT NodeModifyConstraintEndTimeCmd : public NamedCommand { public: NodeModifyConstraintEndTimeCmd( Node &node, const QDateTime& dt, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Node &m_node; QDateTime newTime; DateTime oldTime; QTimeZone m_timeZone; }; class KPLATOKERNEL_EXPORT NodeModifyStartTimeCmd : public NamedCommand { public: NodeModifyStartTimeCmd( Node &node, const QDateTime& dt, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Node &m_node; QDateTime newTime; DateTime oldTime; QTimeZone m_timeZone; }; class KPLATOKERNEL_EXPORT NodeModifyEndTimeCmd : public NamedCommand { public: NodeModifyEndTimeCmd( Node &node, const QDateTime& dt, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Node &m_node; QDateTime newTime; DateTime oldTime; QTimeZone m_timeZone; }; class KPLATOKERNEL_EXPORT NodeModifyIdCmd : public NamedCommand { public: NodeModifyIdCmd( Node &node, const QString& id, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Node &m_node; QString newId; QString oldId; }; class KPLATOKERNEL_EXPORT NodeIndentCmd : public NamedCommand { public: explicit NodeIndentCmd( Node &node, const KUndo2MagicString& name = KUndo2MagicString() ); ~NodeIndentCmd(); void execute(); void unexecute(); private: Node &m_node; Node *m_oldparent, *m_newparent; int m_oldindex, m_newindex; MacroCommand *m_cmd; }; class KPLATOKERNEL_EXPORT NodeUnindentCmd : public NamedCommand { public: explicit NodeUnindentCmd( Node &node, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Node &m_node; Node *m_oldparent, *m_newparent; int m_oldindex, m_newindex; }; class KPLATOKERNEL_EXPORT NodeMoveUpCmd : public NamedCommand { public: explicit NodeMoveUpCmd( Node &node, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Node &m_node; Project *m_project; bool m_moved; }; class KPLATOKERNEL_EXPORT NodeMoveDownCmd : public NamedCommand { public: explicit NodeMoveDownCmd( Node &node, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Node &m_node; Project *m_project; bool m_moved; }; class KPLATOKERNEL_EXPORT NodeMoveCmd : public NamedCommand { public: NodeMoveCmd( Project *project, Node *node, Node *newParent, int newPos, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Project *m_project; Node *m_node; Node *m_newparent; Node *m_oldparent; int m_newpos; int m_oldpos; bool m_moved; MacroCommand m_cmd; }; class KPLATOKERNEL_EXPORT AddRelationCmd : public NamedCommand { public: AddRelationCmd( Project &project, Relation *rel, const KUndo2MagicString& name = KUndo2MagicString() ); ~AddRelationCmd(); void execute(); void unexecute(); private: Relation *m_rel; Project &m_project; bool m_taken; }; class KPLATOKERNEL_EXPORT DeleteRelationCmd : public NamedCommand { public: DeleteRelationCmd( Project &project, Relation *rel, const KUndo2MagicString& name = KUndo2MagicString() ); ~DeleteRelationCmd(); void execute(); void unexecute(); private: Relation *m_rel; Project &m_project; bool m_taken; }; class KPLATOKERNEL_EXPORT ModifyRelationTypeCmd : public NamedCommand { public: ModifyRelationTypeCmd( Relation *rel, Relation::Type type, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Project *m_project; Relation *m_rel; Relation::Type m_newtype; Relation::Type m_oldtype; }; class KPLATOKERNEL_EXPORT ModifyRelationLagCmd : public NamedCommand { public: ModifyRelationLagCmd( Relation *rel, Duration lag, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Project *m_project; Relation *m_rel; Duration m_newlag; Duration m_oldlag; }; class KPLATOKERNEL_EXPORT AddResourceRequestCmd : public NamedCommand { public: AddResourceRequestCmd( ResourceGroupRequest *group, ResourceRequest *request, const KUndo2MagicString& name = KUndo2MagicString() ); ~AddResourceRequestCmd(); void execute(); void unexecute(); private: ResourceGroupRequest *m_group; ResourceRequest *m_request; bool m_mine; }; class KPLATOKERNEL_EXPORT RemoveResourceRequestCmd : public NamedCommand { public: RemoveResourceRequestCmd( ResourceGroupRequest *group, ResourceRequest *request, const KUndo2MagicString& name = KUndo2MagicString() ); ~RemoveResourceRequestCmd(); void execute(); void unexecute(); private: ResourceGroupRequest *m_group; ResourceRequest *m_request; bool m_mine; }; class KPLATOKERNEL_EXPORT ModifyResourceRequestUnitsCmd : public NamedCommand { public: ModifyResourceRequestUnitsCmd( ResourceRequest *request, int oldvalue, int newvalue, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: ResourceRequest *m_request; int m_oldvalue, m_newvalue; }; class KPLATOKERNEL_EXPORT ModifyResourceRequestRequiredCmd : public NamedCommand { public: ModifyResourceRequestRequiredCmd( ResourceRequest *request, const QList &value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: ResourceRequest *m_request; QList m_oldvalue, m_newvalue; }; class KPLATOKERNEL_EXPORT ModifyResourceGroupRequestUnitsCmd : public NamedCommand { public: ModifyResourceGroupRequestUnitsCmd( ResourceGroupRequest *request, int oldvalue, int newvalue, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: ResourceGroupRequest *m_request; int m_oldvalue, m_newvalue; }; class KPLATOKERNEL_EXPORT ModifyEstimateCmd : public NamedCommand { public: ModifyEstimateCmd( Node &node, double oldvalue, double newvalue, const KUndo2MagicString& name = KUndo2MagicString() ); ~ModifyEstimateCmd(); void execute(); void unexecute(); private: Estimate *m_estimate; double m_oldvalue, m_newvalue; int m_optimistic, m_pessimistic; MacroCommand *m_cmd; }; class KPLATOKERNEL_EXPORT EstimateModifyOptimisticRatioCmd : public NamedCommand { public: EstimateModifyOptimisticRatioCmd( Node &node, int oldvalue, int newvalue, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Estimate *m_estimate; int m_oldvalue, m_newvalue; }; class KPLATOKERNEL_EXPORT EstimateModifyPessimisticRatioCmd : public NamedCommand { public: EstimateModifyPessimisticRatioCmd( Node &node, int oldvalue, int newvalue, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Estimate *m_estimate; int m_oldvalue, m_newvalue; }; class KPLATOKERNEL_EXPORT ModifyEstimateTypeCmd : public NamedCommand { public: ModifyEstimateTypeCmd( Node &node, int oldvalue, int newvalue, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Estimate *m_estimate; int m_oldvalue, m_newvalue; }; class KPLATOKERNEL_EXPORT ModifyEstimateUnitCmd : public NamedCommand { public: ModifyEstimateUnitCmd( Node &node, Duration::Unit oldvalue, Duration::Unit newvalue, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Estimate *m_estimate; Duration::Unit m_oldvalue, m_newvalue; }; class KPLATOKERNEL_EXPORT EstimateModifyRiskCmd : public NamedCommand { public: EstimateModifyRiskCmd( Node &node, int oldvalue, int newvalue, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Estimate *m_estimate; int m_oldvalue, m_newvalue; }; class KPLATOKERNEL_EXPORT ModifyEstimateCalendarCmd : public NamedCommand { public: ModifyEstimateCalendarCmd( Node &node, Calendar *oldvalue, Calendar *newvalue, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Estimate *m_estimate; Calendar *m_oldvalue, *m_newvalue; }; class KPLATOKERNEL_EXPORT AddResourceGroupRequestCmd : public NamedCommand { public: AddResourceGroupRequestCmd( Task &task, ResourceGroupRequest *request, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Task &m_task; ResourceGroupRequest *m_request; bool m_mine; }; class KPLATOKERNEL_EXPORT RemoveResourceGroupRequestCmd : public NamedCommand { public: explicit RemoveResourceGroupRequestCmd( ResourceGroupRequest *request, const KUndo2MagicString& name = KUndo2MagicString() ); RemoveResourceGroupRequestCmd( Task &task, ResourceGroupRequest *request, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Task &m_task; ResourceGroupRequest *m_request; bool m_mine; }; class KPLATOKERNEL_EXPORT AddResourceCmd : public NamedCommand { public: AddResourceCmd( ResourceGroup *group, Resource *resource, const KUndo2MagicString& name = KUndo2MagicString() ); ~AddResourceCmd(); void execute(); void unexecute(); protected: ResourceGroup *m_group; Resource *m_resource; int m_index; bool m_mine; }; class KPLATOKERNEL_EXPORT RemoveResourceCmd : public AddResourceCmd { public: RemoveResourceCmd( ResourceGroup *group, Resource *resource, const KUndo2MagicString& name = KUndo2MagicString() ); ~RemoveResourceCmd(); void execute(); void unexecute(); private: QList m_requests; QList m_appointments; MacroCommand m_cmd; }; class KPLATOKERNEL_EXPORT MoveResourceCmd : public NamedCommand { public: MoveResourceCmd( ResourceGroup *group, Resource *resource, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Project &m_project; Resource *m_resource; ResourceGroup *m_oldvalue, *m_newvalue; MacroCommand cmd; }; class KPLATOKERNEL_EXPORT ModifyResourceNameCmd : public NamedCommand { public: ModifyResourceNameCmd( Resource *resource, const QString& value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Resource *m_resource; QString m_newvalue; QString m_oldvalue; }; class KPLATOKERNEL_EXPORT ModifyResourceInitialsCmd : public NamedCommand { public: ModifyResourceInitialsCmd( Resource *resource, const QString& value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Resource *m_resource; QString m_newvalue; QString m_oldvalue; }; class KPLATOKERNEL_EXPORT ModifyResourceEmailCmd : public NamedCommand { public: ModifyResourceEmailCmd( Resource *resource, const QString& value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Resource *m_resource; QString m_newvalue; QString m_oldvalue; }; class KPLATOKERNEL_EXPORT ModifyResourceAutoAllocateCmd : public NamedCommand { public: ModifyResourceAutoAllocateCmd( Resource *resource, bool value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Resource *m_resource; bool m_newvalue; bool m_oldvalue; }; class KPLATOKERNEL_EXPORT ModifyResourceTypeCmd : public NamedCommand { public: ModifyResourceTypeCmd( Resource *resource, int value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Resource *m_resource; int m_newvalue; int m_oldvalue; }; class KPLATOKERNEL_EXPORT ModifyResourceUnitsCmd : public NamedCommand { public: ModifyResourceUnitsCmd( Resource *resource, int value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Resource *m_resource; int m_newvalue; int m_oldvalue; }; class KPLATOKERNEL_EXPORT ModifyResourceAvailableFromCmd : public NamedCommand { public: ModifyResourceAvailableFromCmd( Resource *resource, const QDateTime& value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Resource *m_resource; QDateTime m_newvalue; DateTime m_oldvalue; QTimeZone m_timeZone; }; class KPLATOKERNEL_EXPORT ModifyResourceAvailableUntilCmd : public NamedCommand { public: ModifyResourceAvailableUntilCmd( Resource *resource, const QDateTime& value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Resource *m_resource; QDateTime m_newvalue; DateTime m_oldvalue; QTimeZone m_timeZone; }; class KPLATOKERNEL_EXPORT ModifyResourceNormalRateCmd : public NamedCommand { public: ModifyResourceNormalRateCmd( Resource *resource, double value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Resource *m_resource; double m_newvalue; double m_oldvalue; }; class KPLATOKERNEL_EXPORT ModifyResourceOvertimeRateCmd : public NamedCommand { public: ModifyResourceOvertimeRateCmd( Resource *resource, double value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Resource *m_resource; double m_newvalue; double m_oldvalue; }; class KPLATOKERNEL_EXPORT ModifyResourceCalendarCmd : public NamedCommand { public: ModifyResourceCalendarCmd( Resource *resource, Calendar *value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Resource *m_resource; Calendar *m_newvalue; Calendar *m_oldvalue; }; class KPLATOKERNEL_EXPORT ModifyRequiredResourcesCmd : public NamedCommand { public: ModifyRequiredResourcesCmd( Resource *resource, const QStringList &value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Resource *m_resource; QStringList m_newvalue; QStringList m_oldvalue; }; class KPLATOKERNEL_EXPORT ModifyResourceAccountCmd : public NamedCommand { public: ModifyResourceAccountCmd( Resource *resource, Account *account, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Resource *m_resource; Account *m_newvalue; Account *m_oldvalue; }; class KPLATOKERNEL_EXPORT AddResourceTeamCmd : public NamedCommand { public: AddResourceTeamCmd( Resource *team, const QString &member, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Resource *m_team; QString m_member; }; class KPLATOKERNEL_EXPORT RemoveResourceTeamCmd : public NamedCommand { public: RemoveResourceTeamCmd( Resource *team, const QString &member, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Resource *m_team; QString m_member; }; class KPLATOKERNEL_EXPORT RemoveResourceGroupCmd : public NamedCommand { public: RemoveResourceGroupCmd( Project *project, ResourceGroup *group, const KUndo2MagicString& name = KUndo2MagicString() ); ~RemoveResourceGroupCmd(); void execute(); void unexecute(); protected: ResourceGroup *m_group; Project *m_project; int m_index; bool m_mine; MacroCommand *m_cmd; }; class KPLATOKERNEL_EXPORT AddResourceGroupCmd : public RemoveResourceGroupCmd { public: AddResourceGroupCmd( Project *project, ResourceGroup *group, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); }; class KPLATOKERNEL_EXPORT ModifyResourceGroupNameCmd : public NamedCommand { public: ModifyResourceGroupNameCmd( ResourceGroup *group, const QString& value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: ResourceGroup *m_group; QString m_newvalue; QString m_oldvalue; }; class KPLATOKERNEL_EXPORT ModifyResourceGroupTypeCmd : public NamedCommand { public: ModifyResourceGroupTypeCmd( ResourceGroup *group, int value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: ResourceGroup *m_group; int m_newvalue; int m_oldvalue; }; class KPLATOKERNEL_EXPORT ModifyCompletionEntrymodeCmd : public NamedCommand { public: ModifyCompletionEntrymodeCmd( Completion &completion, Completion::Entrymode value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Completion &m_completion; Completion::Entrymode oldvalue; Completion::Entrymode newvalue; }; class KPLATOKERNEL_EXPORT ModifyCompletionStartedCmd : public NamedCommand { public: ModifyCompletionStartedCmd( Completion &completion, bool value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Completion &m_completion; bool oldvalue; bool newvalue; }; class KPLATOKERNEL_EXPORT ModifyCompletionFinishedCmd : public NamedCommand { public: ModifyCompletionFinishedCmd( Completion &completion, bool value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Completion &m_completion; bool oldvalue; bool newvalue; }; class KPLATOKERNEL_EXPORT ModifyCompletionStartTimeCmd : public NamedCommand { public: ModifyCompletionStartTimeCmd( Completion &completion, const QDateTime &value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Completion &m_completion; DateTime oldvalue; QDateTime newvalue; QTimeZone m_timeZone; }; class KPLATOKERNEL_EXPORT ModifyCompletionFinishTimeCmd : public NamedCommand { public: ModifyCompletionFinishTimeCmd( Completion &completion, const QDateTime &value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Completion &m_completion; DateTime oldvalue; QDateTime newvalue; QTimeZone m_timeZone; }; class KPLATOKERNEL_EXPORT AddCompletionEntryCmd : public NamedCommand { public: AddCompletionEntryCmd( Completion &completion, const QDate &date, Completion::Entry *value, const KUndo2MagicString& name = KUndo2MagicString() ); ~AddCompletionEntryCmd(); void execute(); void unexecute(); private: Completion &m_completion; QDate m_date; Completion::Entry *newvalue; bool m_newmine; }; class KPLATOKERNEL_EXPORT RemoveCompletionEntryCmd : public NamedCommand { public: RemoveCompletionEntryCmd( Completion &completion, const QDate& date, const KUndo2MagicString& name = KUndo2MagicString() ); ~RemoveCompletionEntryCmd(); void execute(); void unexecute(); private: Completion &m_completion; QDate m_date; Completion::Entry *value; bool m_mine; }; class KPLATOKERNEL_EXPORT ModifyCompletionEntryCmd : public NamedCommand { public: ModifyCompletionEntryCmd( Completion &completion, const QDate &date, Completion::Entry *value, const KUndo2MagicString& name = KUndo2MagicString() ); ~ModifyCompletionEntryCmd(); void execute(); void unexecute(); private: MacroCommand *cmd; }; class KPLATOKERNEL_EXPORT ModifyCompletionPercentFinishedCmd : public NamedCommand { public: ModifyCompletionPercentFinishedCmd( Completion &completion, const QDate &date, int value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Completion &m_completion; QDate m_date; int m_newvalue, m_oldvalue; MacroCommand cmd; }; class KPLATOKERNEL_EXPORT ModifyCompletionRemainingEffortCmd : public NamedCommand { public: ModifyCompletionRemainingEffortCmd( Completion &completion, const QDate &date, const Duration &value, const KUndo2MagicString &name = KUndo2MagicString() ); void execute(); void unexecute(); private: Completion &m_completion; QDate m_date; Duration m_newvalue, m_oldvalue; MacroCommand cmd; }; class KPLATOKERNEL_EXPORT ModifyCompletionActualEffortCmd : public NamedCommand { public: ModifyCompletionActualEffortCmd( Completion &completion, const QDate &date, const Duration &value, const KUndo2MagicString &name = KUndo2MagicString() ); void execute(); void unexecute(); private: Completion &m_completion; QDate m_date; Duration m_newvalue, m_oldvalue; MacroCommand cmd; }; /** * Add used effort for @p resource. * Note that the used effort definition in @p value must contain entries for *all* dates. * If used effort is already defined it will be replaced. */ class KPLATOKERNEL_EXPORT AddCompletionUsedEffortCmd : public NamedCommand { public: AddCompletionUsedEffortCmd( Completion &completion, const Resource *resource, Completion::UsedEffort *value, const KUndo2MagicString& name = KUndo2MagicString() ); ~AddCompletionUsedEffortCmd(); void execute(); void unexecute(); private: Completion &m_completion; const Resource *m_resource; Completion::UsedEffort *oldvalue; Completion::UsedEffort *newvalue; bool m_newmine, m_oldmine; }; class KPLATOKERNEL_EXPORT AddCompletionActualEffortCmd : public NamedCommand { public: AddCompletionActualEffortCmd( Completion::UsedEffort &ue, const QDate &date, const Completion::UsedEffort::ActualEffort &value, const KUndo2MagicString& name = KUndo2MagicString() ); ~AddCompletionActualEffortCmd(); void execute(); void unexecute(); private: Completion::UsedEffort &m_usedEffort; QDate m_date; Completion::UsedEffort::ActualEffort oldvalue; Completion::UsedEffort::ActualEffort newvalue; }; class KPLATOKERNEL_EXPORT AddAccountCmd : public NamedCommand { public: AddAccountCmd( Project &project, Account *account, Account *parent = 0, int index = -1, const KUndo2MagicString& name = KUndo2MagicString() ); AddAccountCmd( Project &project, Account *account, const QString& parent, int index = -1, const KUndo2MagicString& name = KUndo2MagicString() ); ~AddAccountCmd(); void execute(); void unexecute(); protected: bool m_mine; private: Project &m_project; Account *m_account; Account *m_parent; int m_index; QString m_parentName; }; class KPLATOKERNEL_EXPORT RemoveAccountCmd : public NamedCommand { public: RemoveAccountCmd( Project &project, Account *account, const KUndo2MagicString& name = KUndo2MagicString() ); ~RemoveAccountCmd(); void execute(); void unexecute(); private: Project &m_project; Account *m_account; Account *m_parent; int m_index; bool m_isDefault; bool m_mine; - + MacroCommand m_cmd; }; class KPLATOKERNEL_EXPORT RenameAccountCmd : public NamedCommand { public: RenameAccountCmd( Account *account, const QString& value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Account *m_account; QString m_oldvalue; QString m_newvalue; }; class KPLATOKERNEL_EXPORT ModifyAccountDescriptionCmd : public NamedCommand { public: ModifyAccountDescriptionCmd( Account *account, const QString& value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Account *m_account; QString m_oldvalue; QString m_newvalue; }; class KPLATOKERNEL_EXPORT NodeModifyStartupCostCmd : public NamedCommand { public: NodeModifyStartupCostCmd( Node &node, double value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Node &m_node; double m_oldvalue; double m_newvalue; }; class KPLATOKERNEL_EXPORT NodeModifyShutdownCostCmd : public NamedCommand { public: NodeModifyShutdownCostCmd( Node &node, double value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Node &m_node; double m_oldvalue; double m_newvalue; }; class KPLATOKERNEL_EXPORT NodeModifyRunningAccountCmd : public NamedCommand { public: NodeModifyRunningAccountCmd( Node &node, Account *oldvalue, Account *newvalue, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Node &m_node; Account *m_oldvalue; Account *m_newvalue; }; class KPLATOKERNEL_EXPORT NodeModifyStartupAccountCmd : public NamedCommand { public: NodeModifyStartupAccountCmd( Node &node, Account *oldvalue, Account *newvalue, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Node &m_node; Account *m_oldvalue; Account *m_newvalue; }; class KPLATOKERNEL_EXPORT NodeModifyShutdownAccountCmd : public NamedCommand { public: NodeModifyShutdownAccountCmd( Node &node, Account *oldvalue, Account *newvalue, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Node &m_node; Account *m_oldvalue; Account *m_newvalue; }; class KPLATOKERNEL_EXPORT ModifyDefaultAccountCmd : public NamedCommand { public: ModifyDefaultAccountCmd( Accounts &acc, Account *oldvalue, Account *newvalue, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Accounts &m_accounts; Account *m_oldvalue; Account *m_newvalue; }; class KPLATOKERNEL_EXPORT ResourceModifyAccountCmd : public NamedCommand { public: ResourceModifyAccountCmd( Resource &resource, Account *oldvalue, Account *newvalue, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Resource &m_resource; Account *m_oldvalue; Account *m_newvalue; }; class KPLATOKERNEL_EXPORT ProjectModifyConstraintCmd : public NamedCommand { public: ProjectModifyConstraintCmd( Project &node, Node::ConstraintType c, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Project &m_node; Node::ConstraintType newConstraint; Node::ConstraintType oldConstraint; }; class KPLATOKERNEL_EXPORT ProjectModifyStartTimeCmd : public NamedCommand { public: ProjectModifyStartTimeCmd( Project &node, const QDateTime& dt, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Project &m_node; QDateTime newTime; DateTime oldTime; QTimeZone m_timeZone; }; class KPLATOKERNEL_EXPORT ProjectModifyEndTimeCmd : public NamedCommand { public: ProjectModifyEndTimeCmd( Project &project, const QDateTime& dt, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Project &m_node; QDateTime newTime; DateTime oldTime; QTimeZone m_timeZone; }; class KPLATOKERNEL_EXPORT AddScheduleManagerCmd : public NamedCommand { public: AddScheduleManagerCmd( Project &project, ScheduleManager *sm, int index = -1, const KUndo2MagicString& name = KUndo2MagicString() ); AddScheduleManagerCmd( ScheduleManager *parent, ScheduleManager *sm, int index = -1, const KUndo2MagicString& name = KUndo2MagicString() ); ~AddScheduleManagerCmd(); void execute(); void unexecute(); protected: Project &m_node; ScheduleManager *m_parent; ScheduleManager *m_sm; int m_index; MainSchedule *m_exp; bool m_mine; }; class KPLATOKERNEL_EXPORT DeleteScheduleManagerCmd : public AddScheduleManagerCmd { public: DeleteScheduleManagerCmd( Project &project, ScheduleManager *sm, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: MacroCommand cmd; }; class KPLATOKERNEL_EXPORT MoveScheduleManagerCmd : public NamedCommand { public: MoveScheduleManagerCmd( ScheduleManager *sm, ScheduleManager *newparent, int newindex, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: ScheduleManager *m_sm; ScheduleManager *m_oldparent; int m_oldindex; ScheduleManager *m_newparent; int m_newindex; MacroCommand m_cmd; }; class KPLATOKERNEL_EXPORT ModifyScheduleManagerNameCmd : public NamedCommand { public: ModifyScheduleManagerNameCmd( ScheduleManager &sm, const QString& value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: ScheduleManager &m_sm; QString oldvalue, newvalue; }; class KPLATOKERNEL_EXPORT ModifyScheduleManagerAllowOverbookingCmd : public NamedCommand { public: ModifyScheduleManagerAllowOverbookingCmd( ScheduleManager &sm, bool value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: ScheduleManager &m_sm; bool oldvalue, newvalue; }; class KPLATOKERNEL_EXPORT ModifyScheduleManagerDistributionCmd : public NamedCommand { public: ModifyScheduleManagerDistributionCmd( ScheduleManager &sm, bool value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: ScheduleManager &m_sm; bool oldvalue, newvalue; }; class KPLATOKERNEL_EXPORT CalculateScheduleCmd : public NamedCommand { public: CalculateScheduleCmd( Project &project, ScheduleManager *sm, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Project &m_node; QPointer m_sm; bool m_first; MainSchedule *m_oldexpected; MainSchedule *m_newexpected; }; class KPLATOKERNEL_EXPORT BaselineScheduleCmd : public NamedCommand { public: explicit BaselineScheduleCmd( ScheduleManager &sm, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: ScheduleManager &m_sm; }; class KPLATOKERNEL_EXPORT ResetBaselineScheduleCmd : public NamedCommand { public: explicit ResetBaselineScheduleCmd( ScheduleManager &sm, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: ScheduleManager &m_sm; }; class KPLATOKERNEL_EXPORT ModifyScheduleManagerSchedulingDirectionCmd : public NamedCommand { public: ModifyScheduleManagerSchedulingDirectionCmd( ScheduleManager &sm, bool value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: ScheduleManager &m_sm; bool oldvalue, newvalue; }; class KPLATOKERNEL_EXPORT ModifyScheduleManagerSchedulerCmd : public NamedCommand { public: ModifyScheduleManagerSchedulerCmd( ScheduleManager &sm, int value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: ScheduleManager &m_sm; int oldvalue, newvalue; }; class KPLATOKERNEL_EXPORT ModifyScheduleManagerSchedulingGranularityCmd : public NamedCommand { public: ModifyScheduleManagerSchedulingGranularityCmd( ScheduleManager &sm, int value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: ScheduleManager &m_sm; int oldvalue, newvalue; }; class KPLATOKERNEL_EXPORT ModifyStandardWorktimeYearCmd : public NamedCommand { public: ModifyStandardWorktimeYearCmd( StandardWorktime *wt, double oldvalue, double newvalue, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: StandardWorktime *swt; double m_oldvalue; double m_newvalue; }; class KPLATOKERNEL_EXPORT ModifyStandardWorktimeMonthCmd : public NamedCommand { public: ModifyStandardWorktimeMonthCmd( StandardWorktime *wt, double oldvalue, double newvalue, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: StandardWorktime *swt; double m_oldvalue; double m_newvalue; }; class KPLATOKERNEL_EXPORT ModifyStandardWorktimeWeekCmd : public NamedCommand { public: ModifyStandardWorktimeWeekCmd( StandardWorktime *wt, double oldvalue, double newvalue, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: StandardWorktime *swt; double m_oldvalue; double m_newvalue; }; class KPLATOKERNEL_EXPORT ModifyStandardWorktimeDayCmd : public NamedCommand { public: ModifyStandardWorktimeDayCmd( StandardWorktime *wt, double oldvalue, double newvalue, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: StandardWorktime *swt; double m_oldvalue; double m_newvalue; }; class KPLATOKERNEL_EXPORT DocumentAddCmd : public NamedCommand { public: DocumentAddCmd( Documents& docs, Document *value, const KUndo2MagicString& name = KUndo2MagicString() ); ~DocumentAddCmd(); void execute(); void unexecute(); private: Documents& m_docs; Document *m_value; bool m_mine; }; class KPLATOKERNEL_EXPORT DocumentRemoveCmd : public NamedCommand { public: DocumentRemoveCmd( Documents& docs, Document *value, const KUndo2MagicString& name = KUndo2MagicString() ); ~DocumentRemoveCmd(); void execute(); void unexecute(); private: Documents& m_docs; Document *m_value; bool m_mine; }; class KPLATOKERNEL_EXPORT DocumentModifyUrlCmd : public NamedCommand { public: DocumentModifyUrlCmd( Document *doc, const QUrl &url, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Document *m_doc; QUrl m_value; QUrl m_oldvalue; }; class KPLATOKERNEL_EXPORT DocumentModifyNameCmd : public NamedCommand { public: DocumentModifyNameCmd( Document *doc, const QString &value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Document *m_doc; QString m_value; QString m_oldvalue; }; class KPLATOKERNEL_EXPORT DocumentModifyTypeCmd : public NamedCommand { public: DocumentModifyTypeCmd( Document *doc, Document::Type value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Document *m_doc; Document::Type m_value; Document::Type m_oldvalue; }; class KPLATOKERNEL_EXPORT DocumentModifyStatusCmd : public NamedCommand { public: DocumentModifyStatusCmd( Document *doc, const QString &value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Document *m_doc; QString m_value; QString m_oldvalue; }; class KPLATOKERNEL_EXPORT DocumentModifySendAsCmd : public NamedCommand { public: DocumentModifySendAsCmd( Document *doc, const Document::SendAs value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Document *m_doc; Document::SendAs m_value; Document::SendAs m_oldvalue; }; class KPLATOKERNEL_EXPORT WBSDefinitionModifyCmd : public NamedCommand { public: WBSDefinitionModifyCmd( Project &project, const WBSDefinition value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Project &m_project; WBSDefinition m_newvalue, m_oldvalue; }; class KPLATOKERNEL_EXPORT InsertProjectCmd : public MacroCommand { public: InsertProjectCmd( Project &project, Node *parent, Node *after, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); protected: void addAccounts( Account *account, Account *parent, QList &unused, QMap &all ); void addCalendars( Calendar *calendar, Calendar *parent, QList &unused, QMap &all ); void addChildNodes( Node *node ); private: Project *m_project; Node *m_parent; Node *m_after; }; class KPLATOKERNEL_EXPORT WorkPackageAddCmd : public NamedCommand { public: WorkPackageAddCmd( Project *project, Node *node, WorkPackage *wp, const KUndo2MagicString& name = KUndo2MagicString() ); ~WorkPackageAddCmd(); void execute(); void unexecute(); private: Project *m_project; Node *m_node; WorkPackage *m_wp; bool m_mine; }; class KPLATOKERNEL_EXPORT ModifyProjectLocaleCmd : public MacroCommand { public: ModifyProjectLocaleCmd( Project &project, const KUndo2MagicString &name ); void execute(); void unexecute(); private: Project &m_project; }; class KPLATOKERNEL_EXPORT ModifyCurrencySymolCmd : public NamedCommand { public: ModifyCurrencySymolCmd( Locale *locale, const QString &value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Locale *m_locale; QString m_newvalue; QString m_oldvalue; }; class KPLATOKERNEL_EXPORT ModifyCurrencyFractionalDigitsCmd : public NamedCommand { public: ModifyCurrencyFractionalDigitsCmd( Locale *locale, int value, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Locale *m_locale; int m_newvalue; int m_oldvalue; }; class KPLATOKERNEL_EXPORT AddExternalAppointmentCmd : public NamedCommand { public: AddExternalAppointmentCmd( Resource *resource, const QString &pid, const QString &pname, const QDateTime &start, const QDateTime &end, double load, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Resource *m_resource; QString m_pid; QString m_pname; QDateTime m_start; QDateTime m_end; double m_load; }; class KPLATOKERNEL_EXPORT ClearExternalAppointmentCmd : public NamedCommand { public: ClearExternalAppointmentCmd( Resource *resource, const QString &pid, const KUndo2MagicString& name = KUndo2MagicString() ); ~ClearExternalAppointmentCmd(); void execute(); void unexecute(); private: Resource *m_resource; QString m_pid; Appointment *m_appointments; }; class KPLATOKERNEL_EXPORT ClearAllExternalAppointmentsCmd : public NamedCommand { public: explicit ClearAllExternalAppointmentsCmd( Project *project, const KUndo2MagicString& name = KUndo2MagicString() ); void execute(); void unexecute(); private: Project *m_project; MacroCommand m_cmd; }; class KPLATOKERNEL_EXPORT SharedResourcesFileCmd : public NamedCommand { public: explicit SharedResourcesFileCmd(Project *project, const QString &newValue, const KUndo2MagicString& name = KUndo2MagicString()); void execute(); void unexecute(); private: Project *m_project; QString m_oldValue; QString m_newValue; }; class KPLATOKERNEL_EXPORT UseSharedResourcesCmd : public NamedCommand { public: explicit UseSharedResourcesCmd(Project *project, bool newValue, const KUndo2MagicString& name = KUndo2MagicString()); void execute(); void unexecute(); private: Project *m_project; bool m_oldValue; bool m_newValue; }; class KPLATOKERNEL_EXPORT SharedProjectsUrlCmd : public NamedCommand { public: explicit SharedProjectsUrlCmd(Project *project, const QUrl &newValue, const KUndo2MagicString& name = KUndo2MagicString()); void execute(); void unexecute(); private: Project *m_project; QUrl m_oldValue; QUrl m_newValue; }; +class KPLATOKERNEL_EXPORT LoadProjectsAtStartupCmd : public NamedCommand +{ +public: + explicit LoadProjectsAtStartupCmd(Project *project, bool newValue, const KUndo2MagicString& name = KUndo2MagicString()); + void execute(); + void unexecute(); + +private: + Project *m_project; + bool m_oldValue; + bool m_newValue; +}; + } //KPlato namespace #endif //COMMAND_H diff --git a/plan/libs/kernel/kptproject.cpp b/plan/libs/kernel/kptproject.cpp index bebb0628beb..1b7f539156f 100644 --- a/plan/libs/kernel/kptproject.cpp +++ b/plan/libs/kernel/kptproject.cpp @@ -1,2905 +1,2920 @@ /* This file is part of the KDE project Copyright (C) 2001 Thomas zander Copyright (C) 2004 - 2010, 2012 Dag Andersen Copyright (C) 2007 Florian Piquemal Copyright (C) 2007 Alexis Ménard 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 "kptproject.h" #include "kptlocale.h" #include "kptappointment.h" #include "kpttask.h" #include "kptdatetime.h" #include "kpteffortcostmap.h" #include "kptschedule.h" #include "kptwbsdefinition.h" #include "kptxmlloaderobject.h" #include "kptschedulerplugin.h" #include "kptdebug.h" #include #include #include #include #include #include namespace KPlato { Project::Project( Node *parent ) : Node( parent ), m_accounts( *this ), m_defaultCalendar( 0 ), m_config( &emptyConfig ), m_schedulerPlugins(), - m_sharedResourcesLoaded(false) + m_sharedResourcesLoaded(false), + m_loadProjectsAtStartup(false) { //debugPlan<<"("<setDefaultValues(*this); } void Project::deref() { --m_refCount; Q_ASSERT( m_refCount >= 0 ); if ( m_refCount <= 0 ) { emit aboutToBeDeleted(); deleteLater(); } } Project::~Project() { debugPlan<<"("<blockChanged(); } for (Resource *r : resourceIdDict) { r->blockChanged(); } for (ResourceGroup *g : resourceGroupIdDict) { g->blockChanged(); } delete m_standardWorktime; while ( !m_resourceGroups.isEmpty() ) delete m_resourceGroups.takeFirst(); while ( !m_calendars.isEmpty() ) delete m_calendars.takeFirst(); while ( !m_managers.isEmpty() ) delete m_managers.takeFirst(); m_config = 0; //not mine, don't delete } int Project::type() const { return Node::Type_Project; } void Project::generateUniqueNodeIds() { foreach ( Node *n, nodeIdDict ) { debugPlan<name()<<"old"<id(); QString uid = uniqueNodeId(); nodeIdDict.remove( n->id() ); n->setId( uid ); nodeIdDict[ uid ] = n; debugPlan<name()<<"new"<id(); } } void Project::generateUniqueIds() { generateUniqueNodeIds(); foreach ( ResourceGroup *g, resourceGroupIdDict ) { if (g->isShared()) { continue; } resourceGroupIdDict.remove( g->id() ); g->setId( uniqueResourceGroupId() ); resourceGroupIdDict[ g->id() ] = g; } foreach ( Resource *r, resourceIdDict ) { if (r->isShared()) { continue; } resourceIdDict.remove( r->id() ); r->setId( uniqueResourceId() ); resourceIdDict[ r->id() ] = r; } foreach ( Calendar *c, calendarIdDict ) { if (c->isShared()) { continue; } calendarIdDict.remove( c->id() ); c->setId( uniqueCalendarId() ); calendarIdDict[ c->id() ] = c; } } void Project::calculate( Schedule *schedule, const DateTime &dt ) { if ( schedule == 0 ) { errorPlan << "Schedule == 0, cannot calculate"; return ; } m_currentSchedule = schedule; calculate( dt ); } void Project::calculate( const DateTime &dt ) { if ( m_currentSchedule == 0 ) { errorPlan << "No current schedule to calculate"; return ; } stopcalculation = false; QLocale locale; DateTime time = dt.isValid() ? dt : DateTime( QDateTime::currentDateTime() ); MainSchedule *cs = static_cast( m_currentSchedule ); Estimate::Use estType = ( Estimate::Use ) cs->type(); if ( type() == Type_Project ) { cs->setPhaseName( 0, i18n( "Init" ) ); cs->logInfo( i18n( "Schedule project from: %1", locale.toString(dt, QLocale::ShortFormat) ), 0 ); initiateCalculation( *cs ); initiateCalculationLists( *cs ); // must be after initiateCalculation() !! propagateEarliestStart( time ); // Calculate lateFinish from time. If a task has started, remainingEffort is used. cs->setPhaseName( 1, i18nc( "Schedule project forward", "Forward" ) ); cs->logInfo( i18n( "Calculate finish" ), 1 ); cs->lateFinish = calculateForward( estType ); cs->lateFinish = checkEndConstraints( cs->lateFinish ); propagateLatestFinish( cs->lateFinish ); // Calculate earlyFinish. If a task has started, remainingEffort is used. cs->setPhaseName( 2, i18nc( "Schedule project backward","Backward" ) ); cs->logInfo( i18n( "Calculate start" ), 2 ); calculateBackward( estType ); // Schedule. If a task has started, remainingEffort is used and appointments are copied from parent cs->setPhaseName( 3, i18n( "Schedule" ) ); cs->logInfo( i18n( "Schedule tasks forward" ), 3 ); cs->endTime = scheduleForward( cs->startTime, estType ); cs->logInfo( i18n( "Scheduled finish: %1", locale.toString(cs->endTime, QLocale::ShortFormat) ), 3 ); if ( cs->endTime > m_constraintEndTime ) { cs->logError( i18n( "Could not finish project in time: %1", locale.toString(m_constraintEndTime, QLocale::ShortFormat) ), 3 ); } else if ( cs->endTime == m_constraintEndTime ) { cs->logWarning( i18n( "Finished project exactly on time: %1", locale.toString(m_constraintEndTime, QLocale::ShortFormat) ), 3 ); } else { cs->logInfo( i18n( "Finished project before time: %1", locale.toString(m_constraintEndTime, QLocale::ShortFormat) ), 3 ); } calcCriticalPath( false ); calcResourceOverbooked(); cs->notScheduled = false; calcFreeFloat(); emit scheduleChanged( cs ); emit projectChanged(); } else if ( type() == Type_Subproject ) { warnPlan << "Subprojects not implemented"; } else { errorPlan << "Illegal project type: " << type(); } } void Project::calculate( ScheduleManager &sm ) { emit sigCalculationStarted( this, &sm ); sm.setScheduling( true ); m_progress = 0; int nodes = 0; foreach ( Node *n, nodeIdDict ) { if ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) { nodes++; } } int maxprogress = nodes * 3; if ( sm.recalculate() ) { emit maxProgress( maxprogress ); sm.setMaxProgress( maxprogress ); incProgress(); if ( sm.parentManager() ) { sm.expected()->startTime = sm.parentManager()->expected()->startTime; sm.expected()->earlyStart = sm.parentManager()->expected()->earlyStart; } incProgress(); calculate( sm.expected(), sm.recalculateFrom() ); } else { emit maxProgress( maxprogress ); sm.setMaxProgress( maxprogress ); calculate( sm.expected() ); emit scheduleChanged( sm.expected() ); setCurrentSchedule( sm.expected()->id() ); } emit sigProgress( maxprogress ); emit sigCalculationFinished( this, &sm ); emit scheduleManagerChanged( &sm ); emit projectCalculated( &sm ); emit projectChanged(); sm.setScheduling( false ); } void Project::calculate( Schedule *schedule ) { if ( schedule == 0 ) { errorPlan << "Schedule == 0, cannot calculate"; return ; } m_currentSchedule = schedule; calculate(); } void Project::calculate() { if ( m_currentSchedule == 0 ) { errorPlan << "No current schedule to calculate"; return ; } stopcalculation = false; MainSchedule *cs = static_cast( m_currentSchedule ); bool backwards = false; if ( cs->manager() ) { backwards = cs->manager()->schedulingDirection(); } QLocale locale; Estimate::Use estType = ( Estimate::Use ) cs->type(); if ( type() == Type_Project ) { QTime timer; timer.start(); initiateCalculation( *cs ); initiateCalculationLists( *cs ); // must be after initiateCalculation() !! if ( ! backwards ) { cs->setPhaseName( 0, i18n( "Init" ) ); cs->logInfo( i18n( "Schedule project forward from: %1", locale.toString(m_constraintStartTime, QLocale::ShortFormat) ), 0 ); cs->startTime = m_constraintStartTime; cs->earlyStart = m_constraintStartTime; // Calculate from start time propagateEarliestStart( cs->earlyStart ); cs->setPhaseName( 1, i18nc( "Schedule project forward", "Forward" ) ); cs->logInfo( i18n( "Calculate late finish" ), 1 ); cs->lateFinish = calculateForward( estType ); // cs->lateFinish = checkEndConstraints( cs->lateFinish ); cs->logInfo( i18n( "Late finish calculated: %1", locale.toString(cs->lateFinish, QLocale::ShortFormat) ), 1 ); propagateLatestFinish( cs->lateFinish ); cs->setPhaseName( 2, i18nc( "Schedule project backward", "Backward" ) ); cs->logInfo( i18n( "Calculate early start" ), 2 ); calculateBackward( estType ); cs->setPhaseName( 3, i18n( "Schedule" ) ); cs->logInfo( i18n( "Schedule tasks forward" ), 3 ); cs->endTime = scheduleForward( cs->startTime, estType ); cs->duration = cs->endTime - cs->startTime; cs->logInfo( i18n( "Scheduled finish: %1", locale.toString(cs->endTime, QLocale::ShortFormat) ), 3 ); if ( cs->endTime > m_constraintEndTime ) { cs->constraintError = true; cs->logError( i18n( "Could not finish project in time: %1", locale.toString(m_constraintEndTime, QLocale::ShortFormat) ), 3 ); } else if ( cs->endTime == m_constraintEndTime ) { cs->logWarning( i18n( "Finished project exactly on time: %1", locale.toString(m_constraintEndTime, QLocale::ShortFormat) ), 3 ); } else { cs->logInfo( i18n( "Finished project before time: %1", locale.toString(m_constraintEndTime, QLocale::ShortFormat) ), 3 ); } calcCriticalPath( false ); } else { cs->setPhaseName( 0, i18n( "Init" ) ); cs->logInfo( i18n( "Schedule project backward from: %1", locale.toString(m_constraintEndTime, QLocale::ShortFormat) ), 0 ); // Calculate from end time propagateLatestFinish( m_constraintEndTime ); cs->setPhaseName( 1, i18nc( "Schedule project backward", "Backward" ) ); cs->logInfo( i18n( "Calculate early start" ), 1 ); cs->earlyStart = calculateBackward( estType ); // cs->earlyStart = checkStartConstraints( cs->earlyStart ); cs->logInfo( i18n( "Early start calculated: %1", locale.toString(cs->earlyStart, QLocale::ShortFormat) ), 1 ); propagateEarliestStart( cs->earlyStart ); cs->setPhaseName( 2, i18nc( "Schedule project forward", "Forward" ) ); cs->logInfo( i18n( "Calculate late finish" ), 2 ); cs->lateFinish = qMax( m_constraintEndTime, calculateForward( estType ) ); cs->logInfo( i18n( "Late finish calculated: %1", locale.toString(cs->lateFinish, QLocale::ShortFormat) ), 2 ); cs->setPhaseName( 3, i18n( "Schedule" ) ); cs->logInfo( i18n( "Schedule tasks backward" ), 3 ); cs->startTime = scheduleBackward( cs->lateFinish, estType ); cs->endTime = cs->startTime; foreach ( Node *n, allNodes() ) { if ( n->type() == Type_Task || n->type() == Type_Milestone ) { DateTime e = n->endTime( cs->id() ); if ( cs->endTime < e ) { cs->endTime = e; } } } if ( cs->endTime > m_constraintEndTime ) { cs->constraintError = true; cs->logError( i18n( "Failed to finish project within target time" ), 3 ); } cs->duration = cs->endTime - cs->startTime; cs->logInfo( i18n( "Scheduled start: %1, target time: %2", locale.toString(cs->startTime, QLocale::ShortFormat), locale.toString(m_constraintStartTime, QLocale::ShortFormat) ), 3 ); if ( cs->startTime < m_constraintStartTime ) { cs->constraintError = true; cs->logError( i18n( "Must start project early in order to finish in time: %1", locale.toString(m_constraintStartTime, QLocale::ShortFormat) ), 3 ); } else if ( cs->startTime == m_constraintStartTime ) { cs->logWarning( i18n( "Start project exactly on time: %1", locale.toString(m_constraintStartTime, QLocale::ShortFormat) ), 3 ); } else { cs->logInfo( i18n( "Can start project later than time: %1", locale.toString(m_constraintStartTime, QLocale::ShortFormat) ), 3 ); } calcCriticalPath( true ); } cs->logInfo( i18n( "Calculation took: %1", KFormat().formatDuration( timer.elapsed() ) ) ); // TODO: fix this uncertainty, manager should *always* be available if (cs->manager()) { finishCalculation(*(cs->manager())); } } else if ( type() == Type_Subproject ) { warnPlan << "Subprojects not implemented"; } else { errorPlan << "Illegal project type: " << type(); } } void Project::finishCalculation( ScheduleManager &sm ) { MainSchedule *cs = sm.expected(); if (nodeIdDict.count() > 1) { // calculate project duration cs->startTime = m_constraintEndTime; cs->endTime = m_constraintStartTime; for (const Node *n : nodeIdDict) { cs->startTime = qMin(cs->startTime, n->startTime(cs->id())); cs->endTime = qMax(cs->endTime, n->endTime(cs->id())); } cs->duration = cs->endTime - cs->startTime; } calcCriticalPath( false ); calcResourceOverbooked(); cs->notScheduled = false; calcFreeFloat(); emit scheduleChanged( cs ); emit projectChanged(); debugPlan<startTime<endTime<<"-------------------------"; } void Project::setProgress( int progress, ScheduleManager *sm ) { m_progress = progress; if ( sm ) { sm->setProgress( progress ); } emit sigProgress( progress ); } void Project::setMaxProgress( int max, ScheduleManager *sm ) { if ( sm ) { sm->setMaxProgress( max ); } emitMaxProgress( max ); } void Project::incProgress() { m_progress += 1; emit sigProgress( m_progress ); } void Project::emitMaxProgress( int value ) { emit maxProgress( value ); } bool Project::calcCriticalPath( bool fromEnd ) { //debugPlan; MainSchedule *cs = static_cast( m_currentSchedule ); if ( cs == 0 ) { return false; } if ( fromEnd ) { QListIterator startnodes = cs->startNodes(); while ( startnodes.hasNext() ) { startnodes.next() ->calcCriticalPath( fromEnd ); } } else { QListIterator endnodes = cs->endNodes(); while ( endnodes.hasNext() ) { endnodes.next() ->calcCriticalPath( fromEnd ); } } calcCriticalPathList( cs ); return false; } void Project::calcCriticalPathList( MainSchedule *cs ) { //debugPlan<name(); cs->clearCriticalPathList(); foreach ( Node *n, allNodes() ) { if ( n->numDependParentNodes() == 0 && n->inCriticalPath( cs->id() ) ) { cs->addCriticalPath(); cs->addCriticalPathNode( n ); calcCriticalPathList( cs, n ); } } cs->criticalPathListCached = true; //debugPlan<<*(criticalPathList( cs->id() )); } void Project::calcCriticalPathList( MainSchedule *cs, Node *node ) { //debugPlan<name()<<", "<id(); bool newPath = false; QList lst = *( cs->currentCriticalPath() ); foreach ( Relation *r, node->dependChildNodes() ) { if ( r->child()->inCriticalPath( cs->id() ) ) { if ( newPath ) { cs->addCriticalPath( &lst ); //debugPlan<name()<<" new path"; } cs->addCriticalPathNode( r->child() ); calcCriticalPathList( cs, r->child() ); newPath = true; } } } const QList< QList > *Project::criticalPathList( long id ) { Schedule *s = schedule( id ); if ( s == 0 ) { //debugPlan<<"No schedule with id="<( s ); if ( ! ms->criticalPathListCached ) { initiateCalculationLists( *ms ); calcCriticalPathList( ms ); } return ms->criticalPathList(); } QList Project::criticalPath( long id, int index ) { Schedule *s = schedule( id ); if ( s == 0 ) { //debugPlan<<"No schedule with id="<(); } MainSchedule *ms = static_cast( s ); if ( ! ms->criticalPathListCached ) { initiateCalculationLists( *ms ); calcCriticalPathList( ms ); } return ms->criticalPath( index ); } DateTime Project::startTime( long id ) const { Schedule *s = schedule( id ); return s ? s->startTime : m_constraintStartTime; } DateTime Project::endTime( long id ) const { Schedule *s = schedule( id ); return s ? s->endTime : m_constraintEndTime; } Duration Project::duration( long id ) const { Schedule *s = schedule( id ); return s ? s->duration : Duration::zeroDuration; } Duration *Project::getRandomDuration() { return 0L; } DateTime Project::checkStartConstraints( const DateTime &dt ) const { DateTime t = dt; foreach ( Node *n, nodeIdDict ) { if ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) { switch ( n->constraint() ) { case Node::FixedInterval: case Node::StartNotEarlier: case Node::MustStartOn: t = qMin( t, qMax( n->constraintStartTime(), m_constraintStartTime ) ); break; default: break; } } } return t; } DateTime Project::checkEndConstraints( const DateTime &dt ) const { DateTime t = dt; foreach ( Node *n, nodeIdDict ) { if ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) { switch ( n->constraint() ) { case Node::FixedInterval: case Node::FinishNotLater: case Node::MustFinishOn: t = qMax( t, qMin( n->constraintEndTime(), m_constraintEndTime ) ); break; default: break; } } } return t; } #ifndef PLAN_NLOGDEBUG bool Project::checkParent( Node *n, const QList &list, QList &checked ) { if ( n->isStartNode() ) { debugPlan< lst = list; lst << n; foreach ( Relation *r, n->dependParentNodes() ) { if ( checked.contains( r ) ) { debugPlan<<"Depend:"<parent()<<": checked"; continue; } checked << r; if ( ! checkParent( r->parent(), lst, checked ) ) { return false; } } Task *t = static_cast( n ); foreach ( Relation *r, t->parentProxyRelations() ) { if ( checked.contains( r ) ) { debugPlan<<"Depend:"<parent()<<": checked"; continue; } checked << r; debugPlan<<"Proxy:"<parent()<<":"<parent(), lst, checked ) ) { return false; } } return true; } bool Project::checkChildren( Node *n, const QList &list, QList &checked ) { if ( n->isEndNode() ) { debugPlan< lst = list; lst << n; foreach ( Relation *r, n->dependChildNodes() ) { if ( checked.contains( r ) ) { debugPlan<<"Depend:"<parent()<<": checked"; continue; } checked << r; if ( ! checkChildren( r->child(), lst, checked ) ) { return false; } } Task *t = static_cast( n ); foreach ( Relation *r, t->childProxyRelations() ) { if ( checked.contains( r ) ) { debugPlan<<"Depend:"<parent()<<": checked"; continue; } debugPlan<<"Proxy:"<parent()<<":"<child(), lst, checked ) ) { return false; } } return true; } #endif void Project::tasksForward() { m_hardConstraints.clear(); m_softConstraints.clear(); m_terminalNodes.clear(); foreach ( Task *t, allTasks() ) { switch ( t->constraint() ) { case Node::MustStartOn: case Node::MustFinishOn: case Node::FixedInterval: m_hardConstraints.append( t ); break; case Node::StartNotEarlier: case Node::FinishNotLater: m_softConstraints.append( t ); break; default: if ( t->isEndNode() ) { m_terminalNodes.append( t ); } break; } } #ifndef PLAN_NLOGDEBUG debugPlan<<"End nodes:"< lst; QList rel; Q_ASSERT( checkParent( n, lst, rel ) ); Q_UNUSED( n ); } #endif } void Project::tasksBackward() { m_hardConstraints.clear(); m_softConstraints.clear(); m_terminalNodes.clear(); foreach ( Task *t, allTasks() ) { switch ( t->constraint() ) { case Node::MustStartOn: case Node::MustFinishOn: case Node::FixedInterval: m_hardConstraints.append( t ); break; case Node::StartNotEarlier: case Node::FinishNotLater: m_softConstraints.append( t ); break; default: if ( t->isStartNode() ) { m_terminalNodes.append( t ); } break; } } #ifndef PLAN_NLOGDEBUG debugPlan<<"Start nodes:"< lst; QList rel; Q_ASSERT( checkChildren( n, lst, rel ) ); Q_UNUSED( n ); } #endif } DateTime Project::calculateForward( int use ) { //debugPlan<( m_currentSchedule ); if ( cs == 0 ) { return finish; } if ( type() == Node::Type_Project ) { QTime timer; timer.start(); cs->logInfo( i18n( "Start calculating forward" ) ); m_visitedForward = true; if ( ! m_visitedBackward ) { // setup tasks tasksForward(); // Do all hard constrained first foreach ( Node *n, m_hardConstraints ) { cs->logDebug( "Calculate task with hard constraint:" + n->name() + " : " + n->constraintToString() ); DateTime time = n->calculateEarlyFinish( use ); // do not do predeccessors if ( time > finish ) { finish = time; } } // do the predeccessors foreach ( Node *n, m_hardConstraints ) { cs->logDebug( "Calculate predeccessors to hard constrained task:" + n->name() + " : " + n->constraintToString() ); DateTime time = n->calculateForward( use ); if ( time > finish ) { finish = time; } } // now try to schedule soft constrained *with* predeccessors foreach ( Node *n, m_softConstraints ) { cs->logDebug( "Calculate task with soft constraint:" + n->name() + " : " + n->constraintToString() ); DateTime time = n->calculateForward( use ); if ( time > finish ) { finish = time; } } // and then the rest using the end nodes to calculate everything (remaining) foreach ( Task *n, m_terminalNodes ) { cs->logDebug( "Calculate using end task:" + n->name() + " : " + n->constraintToString() ); DateTime time = n->calculateForward( use ); if ( time > finish ) { finish = time; } } } else { // tasks have been calculated backwards in this order foreach ( Node *n, cs->backwardNodes() ) { DateTime time = n->calculateForward( use ); if ( time > finish ) { finish = time; } } } cs->logInfo( i18n( "Finished calculating forward: %1 ms", timer.elapsed() ) ); } else { //TODO: subproject } return finish; } DateTime Project::calculateBackward( int use ) { //debugPlan<( m_currentSchedule ); if ( cs == 0 ) { return start; } if ( type() == Node::Type_Project ) { QTime timer; timer.start(); cs->logInfo( i18n( "Start calculating backward" ) ); m_visitedBackward = true; if ( ! m_visitedForward ) { // setup tasks tasksBackward(); // Do all hard constrained first foreach ( Task *n, m_hardConstraints ) { cs->logDebug( "Calculate task with hard constraint:" + n->name() + " : " + n->constraintToString() ); DateTime time = n->calculateLateStart( use ); // do not do predeccessors if ( ! start.isValid() || time < start ) { start = time; } } // then do the predeccessors foreach ( Task *n, m_hardConstraints ) { cs->logDebug( "Calculate predeccessors to hard constrained task:" + n->name() + " : " + n->constraintToString() ); DateTime time = n->calculateBackward( use ); if ( ! start.isValid() || time < start ) { start = time; } } // now try to schedule soft constrained *with* predeccessors foreach ( Task *n, m_softConstraints ) { cs->logDebug( "Calculate task with soft constraint:" + n->name() + " : " + n->constraintToString() ); DateTime time = n->calculateBackward( use ); if ( ! start.isValid() || time < start ) { start = time; } } // and then the rest using the start nodes to calculate everything (remaining) foreach ( Task *n, m_terminalNodes ) { cs->logDebug( "Calculate using start task:" + n->name() + " : " + n->constraintToString() ); DateTime time = n->calculateBackward( use ); if ( ! start.isValid() || time < start ) { start = time; } } } else { // tasks have been calculated forwards in this order foreach ( Node *n, cs->forwardNodes() ) { DateTime time = n->calculateBackward( use ); if ( ! start.isValid() || time < start ) { start = time; } } } cs->logInfo( i18n( "Finished calculating backward: %1 ms", timer.elapsed() ) ); } else { //TODO: subproject } return start; } DateTime Project::scheduleForward( const DateTime &earliest, int use ) { DateTime end; MainSchedule *cs = static_cast( m_currentSchedule ); if ( cs == 0 || stopcalculation ) { return DateTime(); } QTime timer; timer.start(); cs->logInfo( i18n( "Start scheduling forward" ) ); resetVisited(); // Schedule in the same order as calculated forward // Do all hard constrained first foreach ( Node *n, m_hardConstraints ) { cs->logDebug( "Schedule task with hard constraint:" + n->name() + " : " + n->constraintToString() ); DateTime time = n->scheduleFromStartTime( use ); // do not do predeccessors if ( time > end ) { end = time; } } foreach ( Node *n, cs->forwardNodes() ) { cs->logDebug( "Schedule task:" + n->name() + " : " + n->constraintToString() ); DateTime time = n->scheduleForward( earliest, use ); if ( time > end ) { end = time; } } // Fix summarytasks adjustSummarytask(); cs->logInfo( i18n( "Finished scheduling forward: %1 ms", timer.elapsed() ) ); foreach ( Node *n, allNodes() ) { if ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) { Q_ASSERT( n->isScheduled() ); } } return end; } DateTime Project::scheduleBackward( const DateTime &latest, int use ) { DateTime start; MainSchedule *cs = static_cast( m_currentSchedule ); if ( cs == 0 || stopcalculation ) { return start; } QTime timer; timer.start(); cs->logInfo( i18n( "Start scheduling backward" ) ); resetVisited(); // Schedule in the same order as calculated backward // Do all hard constrained first foreach ( Node *n, m_hardConstraints ) { cs->logDebug( "Schedule task with hard constraint:" + n->name() + " : " + n->constraintToString() ); DateTime time = n->scheduleFromEndTime( use ); // do not do predeccessors if ( ! start.isValid() || time < start ) { start = time; } } foreach ( Node *n, cs->backwardNodes() ) { cs->logDebug( "Schedule task:" + n->name() + " : " + n->constraintToString() ); DateTime time = n->scheduleBackward( latest, use ); if ( ! start.isValid() || time < start ) { start = time; } } // Fix summarytasks adjustSummarytask(); cs->logInfo( i18n( "Finished scheduling backward: %1 ms", timer.elapsed() ) ); foreach ( Node *n, allNodes() ) { if ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) { Q_ASSERT( n->isScheduled() ); } } return start; } void Project::adjustSummarytask() { MainSchedule *cs = static_cast( m_currentSchedule ); if ( cs == 0 || stopcalculation ) { return; } QListIterator it( cs->summaryTasks() ); while ( it.hasNext() ) { it.next() ->adjustSummarytask(); } } void Project::initiateCalculation( MainSchedule &sch ) { //debugPlan< git( m_resourceGroups ); while ( git.hasNext() ) { git.next() ->initiateCalculation( sch ); } Node::initiateCalculation( sch ); } void Project::initiateCalculationLists( MainSchedule &sch ) { //debugPlan< it = childNodeIterator(); while ( it.hasNext() ) { it.next() ->initiateCalculationLists( sch ); } } else { //TODO: subproject } } bool Project::load( KoXmlElement &element, XMLLoaderObject &status ) { //debugPlan<<"--->"; m_useSharedResources = false; // default should off in case old project // load locale first KoXmlNode n = element.firstChild(); for ( ; ! n.isNull(); n = n.nextSibling() ) { if ( ! n.isElement() ) { continue; } KoXmlElement e = n.toElement(); if ( e.tagName() == "locale" ) { Locale *l = locale(); l->setCurrencySymbol(e.attribute( "currency-symbol", "")); if ( e.hasAttribute( "currency-digits" ) ) { l->setMonetaryDecimalPlaces(e.attribute("currency-digits").toInt()); } QLocale::Language language = QLocale::AnyLanguage; QLocale::Country country = QLocale::AnyCountry; if (e.hasAttribute("language")) { language = static_cast(e.attribute("language").toInt()); } if (e.hasAttribute("country")) { country = static_cast(e.attribute("country").toInt()); } l->setCurrencyLocale(language, country); } else if (e.tagName() == "shared-resources") { m_useSharedResources = e.attribute("use", "0").toInt(); m_sharedResourcesFile = e.attribute("file"); m_sharedProjectsUrl = QUrl(e.attribute("projects-url")); + m_loadProjectsAtStartup = (bool)e.attribute("projects-loadatstartup", "0").toInt(); } } QList cals; QString s; bool ok = false; setName( element.attribute( "name" ) ); removeId( m_id ); m_id = element.attribute( "id" ); registerNodeId( this ); m_leader = element.attribute( "leader" ); m_description = element.attribute( "description" ); QTimeZone tz( element.attribute( "timezone" ).toLatin1() ); if ( tz.isValid() ) { m_timeZone = tz; } else warnPlan<<"No timezone specified, using default (local)"; status.setProjectTimeZone( m_timeZone ); // Allow for both numeric and text s = element.attribute( "scheduling", "0" ); m_constraint = ( Node::ConstraintType ) s.toInt( &ok ); if ( !ok ) setConstraint( s ); if ( m_constraint != Node::MustStartOn && m_constraint != Node::MustFinishOn ) { errorPlan << "Illegal constraint: " << constraintToString(); setConstraint( Node::MustStartOn ); } s = element.attribute( "start-time" ); if ( !s.isEmpty() ) m_constraintStartTime = DateTime::fromString( s, m_timeZone ); s = element.attribute( "end-time" ); if ( !s.isEmpty() ) m_constraintEndTime = DateTime::fromString( s, m_timeZone ); status.setProgress( 10 ); // Load the project children // Do calendars first, they only reference other calendars //debugPlan<<"Calendars--->"; n = element.firstChild(); for ( ; ! n.isNull(); n = n.nextSibling() ) { if ( ! n.isElement() ) { continue; } KoXmlElement e = n.toElement(); if ( e.tagName() == "calendar" ) { // Load the calendar. // Referenced by resources Calendar * child = new Calendar(); child->setProject( this ); if ( child->load( e, status ) ) { cals.append( child ); // temporary, reorder later } else { // TODO: Complain about this errorPlan << "Failed to load calendar"; delete child; } } else if ( e.tagName() == "standard-worktime" ) { // Load standard worktime StandardWorktime * child = new StandardWorktime(); if ( child->load( e, status ) ) { setStandardWorktime( child ); } else { errorPlan << "Failed to load standard worktime"; delete child; } } } // calendars references calendars in arbritary saved order bool added = false; do { added = false; QList lst; while ( !cals.isEmpty() ) { Calendar *c = cals.takeFirst(); c->m_blockversion = true; if ( c->parentId().isEmpty() ) { addCalendar( c, status.baseCalendar() ); // handle pre 0.6 version added = true; //debugPlan<<"added to project:"<name(); } else { Calendar *par = calendar( c->parentId() ); if ( par ) { par->m_blockversion = true; addCalendar( c, par ); added = true; //debugPlan<<"added:"<name()<<" to parent:"<name(); par->m_blockversion = false; } else { lst.append( c ); // treat later //debugPlan<<"treat later:"<name(); } } c->m_blockversion = false; } cals = lst; } while ( added ); if ( ! cals.isEmpty() ) { errorPlan<<"All calendars not saved!"; } //debugPlan<<"Calendars<---"; status.setProgress( 15 ); // Resource groups and resources, can reference calendars n = element.firstChild(); for ( ; ! n.isNull(); n = n.nextSibling() ) { if ( ! n.isElement() ) { continue; } KoXmlElement e = n.toElement(); if ( e.tagName() == "resource-group" ) { // Load the resources // References calendars ResourceGroup * child = new ResourceGroup(); if ( child->load( e, status ) ) { addResourceGroup( child ); } else { // TODO: Complain about this delete child; } } } status.setProgress( 20 ); // The main stuff n = element.firstChild(); for ( ; ! n.isNull(); n = n.nextSibling() ) { if ( ! n.isElement() ) { continue; } KoXmlElement e = n.toElement(); if ( e.tagName() == "project" ) { //debugPlan<<"Sub project--->"; /* // Load the subproject Project * child = new Project( this ); if ( child->load( e ) ) { if ( !addTask( child, this ) ) { delete child; // TODO: Complain about this } } else { // TODO: Complain about this delete child; }*/ } else if ( e.tagName() == "task" ) { //debugPlan<<"Task--->"; // Load the task (and resourcerequests). // Depends on resources already loaded Task * child = new Task( this ); if ( child->load( e, status ) ) { if ( !addTask( child, this ) ) { delete child; // TODO: Complain about this } } else { // TODO: Complain about this delete child; } } } status.setProgress( 70 ); // These go last n = element.firstChild(); for ( ; ! n.isNull(); n = n.nextSibling() ) { debugPlan<"; // Load accounts // References tasks if ( !m_accounts.load( e, *this ) ) { errorPlan << "Failed to load accounts"; } } else if ( e.tagName() == "relation" ) { //debugPlan<<"Relation--->"; // Load the relation // References tasks Relation * child = new Relation(); if ( !child->load( e, *this ) ) { // TODO: Complain about this errorPlan << "Failed to load relation"; delete child; } //debugPlan<<"Relation<---"; } else if ( e.tagName() == "schedules" ) { //debugPlan<<"Project schedules & task appointments--->"; // References tasks and resources KoXmlNode sn = e.firstChild(); for ( ; ! sn.isNull(); sn = sn.nextSibling() ) { if ( ! sn.isElement() ) { continue; } KoXmlElement el = sn.toElement(); //debugPlan<loadXML( el, status ) ) { if ( add ) addScheduleManager( sm ); } else { errorPlan << "Failed to load schedule manager"; delete sm; } } else { debugPlan<<"No schedule manager ?!"; } } //debugPlan<<"Node schedules<---"; } else if ( e.tagName() == "resource-teams" ) { //debugPlan<<"Resource teams--->"; // References other resources KoXmlNode tn = e.firstChild(); for ( ; ! tn.isNull(); tn = tn.nextSibling() ) { if ( ! tn.isElement() ) { continue; } KoXmlElement el = tn.toElement(); if ( el.tagName() == "team" ) { Resource *r = findResource( el.attribute( "team-id" ) ); Resource *tm = findResource( el.attribute( "member-id" ) ); if ( r == 0 || tm == 0 ) { errorPlan<<"resource-teams: cannot find resources"; continue; } if ( r == tm ) { errorPlan<<"resource-teams: a team cannot be a member of itself"; continue; } r->addTeamMemberId( tm->id() ); } else { errorPlan<<"resource-teams: unhandled tag"<currencySymbolExplicit().isEmpty()) { loc.setAttribute("currency-symbol", l->currencySymbolExplicit()); } loc.setAttribute("currency-digits", l->monetaryDecimalPlaces()); loc.setAttribute("language", l->currencyLanguage()); loc.setAttribute("country", l->currencyCountry()); QDomElement share = me.ownerDocument().createElement( "shared-resources" ); me.appendChild(share); share.setAttribute("use", m_useSharedResources); share.setAttribute("file", m_sharedResourcesFile); share.setAttribute("projects-url", QString(m_sharedProjectsUrl.toEncoded())); + share.setAttribute("projects-loadatstartup", m_loadProjectsAtStartup); m_accounts.save( me ); // save calendars foreach ( Calendar *c, calendarIdDict ) { c->save( me ); } // save standard worktime if ( m_standardWorktime ) m_standardWorktime->save( me ); // save project resources, must be after calendars QListIterator git( m_resourceGroups ); while ( git.hasNext() ) { git.next() ->save( me ); } // Only save parent relations QListIterator it( m_dependParentNodes ); while ( it.hasNext() ) { it.next() ->save( me ); } for ( int i = 0; i < numChildren(); i++ ) // Save all children childNode( i ) ->save( me ); // Now we can save relations assuming no tasks have relations outside the project QListIterator nodes( m_nodes ); while ( nodes.hasNext() ) { nodes.next() ->saveRelations( me ); } if ( !m_managers.isEmpty() ) { QDomElement el = me.ownerDocument().createElement( "schedules" ); me.appendChild( el ); foreach ( ScheduleManager *sm, m_managers ) { sm->saveXML( el ); } } // save resource teams QDomElement el = me.ownerDocument().createElement( "resource-teams" ); me.appendChild( el ); foreach ( Resource *r, resourceIdDict ) { if ( r->type() != Resource::Type_Team ) { continue; } foreach ( const QString &id, r->teamMemberIds() ) { QDomElement e = el.ownerDocument().createElement( "team" ); el.appendChild( e ); e.setAttribute( "team-id", r->id() ); e.setAttribute( "member-id", id ); } } } void Project::saveWorkPackageXML( QDomElement &element, const Node *node, long id ) const { QDomElement me = element.ownerDocument().createElement( "project" ); element.appendChild( me ); me.setAttribute( "name", m_name ); me.setAttribute( "leader", m_leader ); me.setAttribute( "id", m_id ); me.setAttribute( "description", m_description ); me.setAttribute( "timezone", m_timeZone.isValid() ? QString::fromLatin1(m_timeZone.id()) : QString() ); me.setAttribute( "scheduling", constraintToString() ); me.setAttribute( "start-time", m_constraintStartTime.toString( Qt::ISODate ) ); me.setAttribute( "end-time", m_constraintEndTime.toString( Qt::ISODate ) ); QListIterator git( m_resourceGroups ); while ( git.hasNext() ) { git.next() ->saveWorkPackageXML( me, node->assignedResources( id ) ); } if ( node == 0 ) { return; } node->saveWorkPackageXML( me, id ); foreach ( ScheduleManager *sm, m_managerIdMap ) { if ( sm->scheduleId() == id ) { QDomElement el = me.ownerDocument().createElement( "schedules" ); me.appendChild( el ); sm->saveWorkPackageXML( el, *node ); break; } } } void Project::setParentSchedule( Schedule *sch ) { QListIterator it = m_nodes; while ( it.hasNext() ) { it.next() ->setParentSchedule( sch ); } } void Project::addResourceGroup( ResourceGroup *group, int index ) { int i = index == -1 ? m_resourceGroups.count() : index; emit resourceGroupToBeAdded( group, i ); m_resourceGroups.insert( i, group ); setResourceGroupId( group ); group->setProject( this ); foreach ( Resource *r, group->resources() ) { setResourceId( r ); r->setProject( this ); } emit resourceGroupAdded( group ); emit projectChanged(); } ResourceGroup *Project::takeResourceGroup( ResourceGroup *group ) { int i = m_resourceGroups.indexOf( group ); Q_ASSERT( i != -1 ); if ( i == -1 ) { return 0; } emit resourceGroupToBeRemoved( group ); ResourceGroup *g = m_resourceGroups.takeAt( i ); Q_ASSERT( group == g ); g->setProject( 0 ); removeResourceGroupId( g->id() ); foreach ( Resource *r, g->resources() ) { r->setProject( 0 ); removeResourceId( r->id() ); } emit resourceGroupRemoved( g ); emit projectChanged(); return g; } QList &Project::resourceGroups() { return m_resourceGroups; } void Project::addResource( ResourceGroup *group, Resource *resource, int index ) { int i = index == -1 ? group->numResources() : index; emit resourceToBeAdded( group, i ); group->addResource( i, resource, 0 ); setResourceId( resource ); emit resourceAdded( resource ); emit projectChanged(); } Resource *Project::takeResource( ResourceGroup *group, Resource *resource ) { emit resourceToBeRemoved( resource ); bool result = removeResourceId( resource->id() ); Q_ASSERT( result == true ); if (!result) { warnPlan << "Could not remove resource with id" << resource->id(); } resource->removeRequests(); // not valid anymore Resource *r = group->takeResource( resource ); Q_ASSERT( resource == r ); if (resource != r) { warnPlan << "Cound not take resource from group"; } emit resourceRemoved( resource ); emit projectChanged(); return r; } void Project::moveResource( ResourceGroup *group, Resource *resource ) { if ( group == resource->parentGroup() ) { return; } takeResource( resource->parentGroup(), resource ); addResource( group, resource ); return; } QMap< QString, QString > Project::externalProjects() const { QMap< QString, QString > map; foreach ( Resource *r, resourceList() ) { for( QMapIterator it( r->externalProjects() ); it.hasNext(); ) { it.next(); if ( ! map.contains( it.key() ) ) { map[ it.key() ] = it.value(); } } } return map; } bool Project::addTask( Node* task, Node* position ) { // we want to add a task at the given position. => the new node will // become next sibling right after position. if ( 0 == position ) { return addSubTask( task, this ); } //debugPlan<<"Add"<name()<<" after"<name(); // in case we want to add to the main project, we make it child element // of the root element. if ( Node::Type_Project == position->type() ) { return addSubTask( task, position ); } // find the position // we have to tell the parent that we want to delete one of its children Node* parentNode = position->parentNode(); if ( !parentNode ) { debugPlan <<"parent node not found???"; return false; } int index = parentNode->findChildNode( position ); if ( -1 == index ) { // ok, it does not exist debugPlan <<"Task not found???"; return false; } return addSubTask( task, index + 1, parentNode ); } bool Project::addSubTask( Node* task, Node* parent ) { // append task to parent return addSubTask( task, -1, parent ); } bool Project::addSubTask( Node* task, int index, Node* parent, bool emitSignal ) { // we want to add a subtask to the node "parent" at the given index. // If parent is 0, add to this Node *p = parent; if ( 0 == p ) { p = this; } if ( !registerNodeId( task ) ) { errorPlan << "Failed to register node id, can not add subtask: " << task->name(); return false; } int i = index == -1 ? p->numChildren() : index; if ( emitSignal ) emit nodeToBeAdded( p, i ); p->insertChildNode( i, task ); connect( this, SIGNAL(standardWorktimeChanged(StandardWorktime*)), task, SLOT(slotStandardWorktimeChanged(StandardWorktime*)) ); if ( emitSignal ) { emit nodeAdded( task ); emit projectChanged(); if ( p != this && p->numChildren() == 1 ) { emit nodeChanged( p ); } } return true; } void Project::takeTask( Node *node, bool emitSignal ) { //debugPlan<name(); Node * parent = node->parentNode(); if ( parent == 0 ) { debugPlan <<"Node must have a parent!"; return; } removeId( node->id() ); if ( emitSignal ) emit nodeToBeRemoved( node ); disconnect( this, SIGNAL(standardWorktimeChanged(StandardWorktime*)), node, SLOT(slotStandardWorktimeChanged(StandardWorktime*)) ); parent->takeChildNode( node ); if ( emitSignal ) { emit nodeRemoved( node ); emit projectChanged(); if ( parent != this && parent->type() != Node::Type_Summarytask ) { emit nodeChanged( parent ); } } } bool Project::canMoveTask( Node* node, Node *newParent ) { //debugPlan<name()<<" to"<name(); if ( node == this ) { return false; } Node *p = newParent; while ( p && p != this ) { if ( ! node->canMoveTo( p ) ) { return false; } p = p->parentNode(); } return true; } bool Project::moveTask( Node* node, Node *newParent, int newPos ) { //debugPlan<name()<<" to"<name()<<","<parentNode(); int oldPos = oldParent->indexOf( node ); int i = newPos < 0 ? newParent->numChildren() : newPos; if ( oldParent == newParent && i == oldPos ) { // no need to move to where it already is return false; } int newRow = i; if ( oldParent == newParent && newPos > oldPos ) { ++newRow; // itemmodels wants new row *before* node is removed from old position } debugPlan<name()<<"at"<indexOf( node )<<"to"<name()<numChildren() == 0 ) { emit nodeChanged( oldParent ); } if ( newParent != this && newParent->numChildren() == 1 ) { emit nodeChanged( newParent ); } return true; } bool Project::canIndentTask( Node* node ) { if ( 0 == node ) { // should always be != 0. At least we would get the Project, // but you never know who might change that, so better be careful return false; } if ( node->type() == Node::Type_Project ) { //debugPlan<<"The root node cannot be indented"; return false; } // we have to find the parent of task to manipulate its list of children Node* parentNode = node->parentNode(); if ( !parentNode ) { return false; } if ( parentNode->findChildNode( node ) == -1 ) { errorPlan << "Tasknot found???"; return false; } Node *sib = node->siblingBefore(); if ( !sib ) { //debugPlan<<"new parent node not found"; return false; } if ( node->findParentRelation( sib ) || node->findChildRelation( sib ) ) { //debugPlan<<"Cannot have relations to parent"; return false; } return true; } bool Project::indentTask( Node* node, int index ) { if ( canIndentTask( node ) ) { Node * newParent = node->siblingBefore(); int i = index == -1 ? newParent->numChildren() : index; moveTask( node, newParent, i ); //debugPlan; return true; } return false; } bool Project::canUnindentTask( Node* node ) { if ( 0 == node ) { // is always != 0. At least we would get the Project, but you // never know who might change that, so better be careful return false; } if ( Node::Type_Project == node->type() ) { //debugPlan<<"The root node cannot be unindented"; return false; } // we have to find the parent of task to manipulate its list of children // and we need the parent's parent too Node* parentNode = node->parentNode(); if ( !parentNode ) { return false; } Node* grandParentNode = parentNode->parentNode(); if ( !grandParentNode ) { //debugPlan<<"This node already is at the top level"; return false; } int index = parentNode->findChildNode( node ); if ( -1 == index ) { errorPlan << "Tasknot found???"; return false; } return true; } bool Project::unindentTask( Node* node ) { if ( canUnindentTask( node ) ) { Node * parentNode = node->parentNode(); Node *grandParentNode = parentNode->parentNode(); int i = grandParentNode->indexOf( parentNode ) + 1; if ( i == 0 ) { i = grandParentNode->numChildren(); } moveTask( node, grandParentNode, i ); //debugPlan; return true; } return false; } bool Project::canMoveTaskUp( Node* node ) { if ( node == 0 ) return false; // safety // we have to find the parent of task to manipulate its list of children Node* parentNode = node->parentNode(); if ( !parentNode ) { //debugPlan<<"No parent found"; return false; } if ( parentNode->findChildNode( node ) == -1 ) { errorPlan << "Tasknot found???"; return false; } if ( node->siblingBefore() ) { return true; } return false; } bool Project::moveTaskUp( Node* node ) { if ( canMoveTaskUp( node ) ) { moveTask( node, node->parentNode(), node->parentNode()->indexOf( node ) - 1 ); return true; } return false; } bool Project::canMoveTaskDown( Node* node ) { if ( node == 0 ) return false; // safety // we have to find the parent of task to manipulate its list of children Node* parentNode = node->parentNode(); if ( !parentNode ) { return false; } if ( parentNode->findChildNode( node ) == -1 ) { errorPlan << "Tasknot found???"; return false; } if ( node->siblingAfter() ) { return true; } return false; } bool Project::moveTaskDown( Node* node ) { if ( canMoveTaskDown( node ) ) { moveTask( node, node->parentNode(), node->parentNode()->indexOf( node ) + 1 ); return true; } return false; } Task *Project::createTask() { Task * node = new Task(); node->setId( uniqueNodeId() ); reserveId( node->id(), node ); return node; } Task *Project::createTask( const Task &def ) { Task * node = new Task( def ); node->setId( uniqueNodeId() ); reserveId( node->id(), node ); return node; } Node *Project::findNode( const QString &id ) const { if ( m_parent == 0 ) { if ( nodeIdDict.contains( id ) ) { return nodeIdDict[ id ]; } return 0; } return m_parent->findNode( id ); } bool Project::nodeIdentExists( const QString &id ) const { return nodeIdDict.contains( id ) || nodeIdReserved.contains( id ); } QString Project::uniqueNodeId( int seed ) const { Q_UNUSED(seed); QString s = QDateTime::currentDateTime().toString( Qt::ISODate ) + ' '; QString ident = s + KRandom::randomString( 10 ); // int i = seed; while ( nodeIdentExists( ident ) ) { ident = s + KRandom::randomString( 10 ); } return ident; } QString Project::uniqueNodeId( const QList &existingIds, int seed ) { QString id = uniqueNodeId( seed ); while ( existingIds.contains( id ) ) { id = uniqueNodeId( seed ); } return id; } bool Project::removeId( const QString &id ) { //debugPlan <<"id=" << id; if ( m_parent ) { return m_parent->removeId( id ); } //debugPlan << "id=" << id<< nodeIdDict.contains(id); return nodeIdDict.remove( id ); } void Project::reserveId( const QString &id, Node *node ) { //debugPlan <<"id=" << id << node->name(); nodeIdReserved.insert( id, node ); } bool Project::registerNodeId( Node *node ) { nodeIdReserved.remove( node->id() ); if ( node->id().isEmpty() ) { warnPlan << "Node id is empty, cannot register it"; return false; } Node *rn = findNode( node->id() ); if ( rn == 0 ) { //debugPlan <<"id=" << node->id() << node->name(); nodeIdDict.insert( node->id(), node ); return true; } if ( rn != node ) { errorPlan << "Id already exists for different task: " << node->id(); return false; } //debugPlan<<"Already exists" <<"id=" << node->id() << node->name(); return true; } QList Project::allNodes() const { QList lst = nodeIdDict.values(); int me = lst.indexOf( const_cast( this ) ); if ( me != -1 ) { lst.removeAt( me ); } return lst; } QList Project::allTasks( const Node *parent ) const { QList lst; const Node *p = parent ? parent : this; foreach ( Node *n, p->childNodeIterator() ) { if ( n->type() == Node::Type_Task || n->type() == Type_Milestone ) { lst << static_cast( n ); } lst += allTasks( n ); } return lst; } bool Project::setResourceGroupId( ResourceGroup *group ) { if ( group == 0 ) { return false; } if ( ! group->id().isEmpty() ) { ResourceGroup *g = findResourceGroup( group->id() ); if ( group == g ) { return true; } else if ( g == 0 ) { insertResourceGroupId( group->id(), group ); return true; } } QString id = uniqueResourceGroupId(); group->setId( id ); if ( id.isEmpty() ) { return false; } insertResourceGroupId( id, group ); return true; } QString Project::uniqueResourceGroupId() const { QString s = QDateTime::currentDateTime().toString( Qt::ISODate ) + ' '; QString id = s + KRandom::randomString( 10 ); while ( resourceGroupIdDict.contains( id ) ) { id = s + KRandom::randomString( 10 ); } return id; } ResourceGroup *Project::group( const QString& id ) { return findResourceGroup( id ); } ResourceGroup *Project::groupByName( const QString& name ) const { foreach ( ResourceGroup *g, resourceGroupIdDict ) { if ( g->name() == name ) { return g; } } return 0; } QList Project::autoAllocateResources() const { QList lst; foreach ( Resource *r, resourceIdDict ) { if ( r->autoAllocate() ) { lst << r; } } return lst; } void Project::insertResourceId( const QString &id, Resource *resource ) { resourceIdDict.insert( id, resource ); } bool Project::removeResourceId( const QString &id ) { return resourceIdDict.remove( id ); } bool Project::setResourceId( Resource *resource ) { if ( resource == 0 ) { return false; } if ( ! resource->id().isEmpty() ) { Resource *r = findResource( resource->id() ); if ( resource == r ) { return true; } else if ( r == 0 ) { insertResourceId( resource->id(), resource ); return true; } } QString id = uniqueResourceId(); resource->setId( id ); if ( id.isEmpty() ) { return false; } insertResourceId( id, resource ); return true; } QString Project::uniqueResourceId() const { QString s = QDateTime::currentDateTime().toString( Qt::ISODate ) + ' '; QString id = s + KRandom::randomString( 10 ); while ( resourceIdDict.contains( id ) ) { id = s + KRandom::randomString( 10 ); } return id; } Resource *Project::resource( const QString& id ) { return findResource( id ); } Resource *Project::resourceByName( const QString& name ) const { foreach ( const QString &k, resourceIdDict.keys() ) { Resource *r = resourceIdDict[ k ]; if ( r->name() == name ) { Q_ASSERT( k == r->id() ); return r; } } return 0; } QStringList Project::resourceNameList() const { QStringList lst; foreach ( Resource *r, resourceIdDict ) { lst << r->name(); } return lst; } EffortCostMap Project::plannedEffortCostPrDay( QDate start, QDate end, long id, EffortCostCalculationType typ ) const { //debugPlan< it( childNodeIterator() ); while ( it.hasNext() ) { ec += it.next() ->plannedEffortCostPrDay( start, end, id, typ ); } return ec; } EffortCostMap Project::plannedEffortCostPrDay( const Resource *resource, QDate start, QDate end, long id, EffortCostCalculationType typ ) const { //debugPlan< it( childNodeIterator() ); while ( it.hasNext() ) { ec += it.next() ->plannedEffortCostPrDay( resource, start, end, id, typ ); } return ec; } EffortCostMap Project::actualEffortCostPrDay( QDate start, QDate end, long id, EffortCostCalculationType typ ) const { //debugPlan< it( childNodeIterator() ); while ( it.hasNext() ) { ec += it.next() ->actualEffortCostPrDay( start, end, id, typ ); } return ec; } EffortCostMap Project::actualEffortCostPrDay( const Resource *resource, QDate start, QDate end, long id, EffortCostCalculationType typ ) const { //debugPlan< it( childNodeIterator() ); while ( it.hasNext() ) { ec += it.next() ->actualEffortCostPrDay( resource, start, end, id, typ ); } return ec; } // Returns the total planned effort for this project (or subproject) Duration Project::plannedEffort( long id, EffortCostCalculationType typ ) const { //debugPlan; Duration eff; QListIterator it( childNodeIterator() ); while ( it.hasNext() ) { eff += it.next() ->plannedEffort( id, typ ); } return eff; } // Returns the total planned effort for this project (or subproject) on date Duration Project::plannedEffort( QDate date, long id, EffortCostCalculationType typ ) const { //debugPlan; Duration eff; QListIterator it( childNodeIterator() ); while ( it.hasNext() ) { eff += it.next() ->plannedEffort( date, id, typ ); } return eff; } // Returns the total planned effort for this project (or subproject) upto and including date Duration Project::plannedEffortTo( QDate date, long id, EffortCostCalculationType typ ) const { //debugPlan; Duration eff; QListIterator it( childNodeIterator() ); while ( it.hasNext() ) { eff += it.next() ->plannedEffortTo( date, id, typ ); } return eff; } // Returns the total actual effort for this project (or subproject) upto and including date Duration Project::actualEffortTo( QDate date ) const { //debugPlan; Duration eff; QListIterator it( childNodeIterator() ); while ( it.hasNext() ) { eff += it.next() ->actualEffortTo( date ); } return eff; } // Returns the total planned effort for this project (or subproject) upto and including date double Project::plannedCostTo( QDate date, long id, EffortCostCalculationType typ ) const { //debugPlan; double c = 0; QListIterator it( childNodeIterator() ); while ( it.hasNext() ) { c += it.next() ->plannedCostTo( date, id, typ ); } return c; } // Returns the total actual cost for this project (or subproject) upto and including date EffortCost Project::actualCostTo( long int id, QDate date ) const { //debugPlan; EffortCost c; QListIterator it( childNodeIterator() ); while ( it.hasNext() ) { c += it.next() ->actualCostTo( id, date ); } return c; } Duration Project::budgetedWorkPerformed( QDate date, long id ) const { //debugPlan; Duration e; foreach (Node *n, childNodeIterator()) { e += n->budgetedWorkPerformed( date, id ); } return e; } double Project::budgetedCostPerformed( QDate date, long id ) const { //debugPlan; double c = 0.0; foreach (Node *n, childNodeIterator()) { c += n->budgetedCostPerformed( date, id ); } return c; } double Project::effortPerformanceIndex( QDate date, long id ) const { //debugPlan; debugPlan< 0.0 ) { r = p / s; } debugPlan< date ? end : date), id ); double budgetAtCompletion; double plannedCompleted; double budgetedCompleted; bool useEffort = false; //FIXME if ( useEffort ) { budgetAtCompletion = plan.totalEffort().toDouble( Duration::Unit_h ); plannedCompleted = plan.effortTo( date ).toDouble( Duration::Unit_h ); //actualCompleted = actual.effortTo( date ).toDouble( Duration::Unit_h ); budgetedCompleted = budgetedWorkPerformed( date, id ).toDouble( Duration::Unit_h ); } else { budgetAtCompletion = plan.totalCost(); plannedCompleted = plan.costTo( date ); budgetedCompleted = budgetedCostPerformed( date, id ); } double c = 0.0; if ( budgetAtCompletion > 0.0 ) { double percentageCompletion = budgetedCompleted / budgetAtCompletion; c = budgetAtCompletion * percentageCompletion; //?? debugPlan<name()<<","<<(parent?parent->name():"No parent"); int row = parent == 0 ? m_calendars.count() : parent->calendars().count(); if ( index >= 0 && index < row ) { row = index; } emit calendarToBeAdded( parent, row ); calendar->setProject( this ); if ( parent == 0 ) { calendar->setParentCal( 0 ); // in case m_calendars.insert( row, calendar ); } else { calendar->setParentCal( parent, row ); } if ( calendar->isDefault() ) { setDefaultCalendar( calendar ); } setCalendarId( calendar ); emit calendarAdded( calendar ); emit projectChanged(); } void Project::takeCalendar( Calendar *calendar ) { emit calendarToBeRemoved( calendar ); removeCalendarId( calendar->id() ); if ( calendar == m_defaultCalendar ) { m_defaultCalendar = 0; } if ( calendar->parentCal() == 0 ) { int i = indexOf( calendar ); if ( i != -1 ) { m_calendars.removeAt( i ); } } else { calendar->setParentCal( 0 ); } emit calendarRemoved( calendar ); calendar->setProject( 0 ); emit projectChanged(); } int Project::indexOf( const Calendar *calendar ) const { return m_calendars.indexOf( const_cast(calendar) ); } Calendar *Project::calendar( const QString& id ) const { return findCalendar( id ); } Calendar *Project::calendarByName( const QString& name ) const { foreach( Calendar *c, calendarIdDict ) { if ( c->name() == name ) { return c; } } return 0; } const QList &Project::calendars() const { return m_calendars; } QList Project::allCalendars() const { return calendarIdDict.values(); } QStringList Project::calendarNames() const { QStringList lst; foreach( Calendar *c, calendarIdDict ) { lst << c->name(); } return lst; } bool Project::setCalendarId( Calendar *calendar ) { if ( calendar == 0 ) { return false; } if ( ! calendar->id().isEmpty() ) { Calendar *c = findCalendar( calendar->id() ); if ( calendar == c ) { return true; } else if ( c == 0 ) { insertCalendarId( calendar->id(), calendar ); return true; } } QString id = uniqueCalendarId(); calendar->setId( id ); if ( id.isEmpty() ) { return false; } insertCalendarId( id, calendar ); return true; } QString Project::uniqueCalendarId() const { QString s = QDateTime::currentDateTime().toString( Qt::ISODate ) + ' '; QString id = s + KRandom::randomString( 10 ); while ( calendarIdDict.contains( id ) ) { id = s + KRandom::randomString( 10 ); } return id; } void Project::setDefaultCalendar( Calendar *cal ) { if ( m_defaultCalendar ) { m_defaultCalendar->setDefault( false ); } m_defaultCalendar = cal; if ( cal ) { cal->setDefault( true ); } emit defaultCalendarChanged( cal ); emit projectChanged(); } void Project::setStandardWorktime( StandardWorktime * worktime ) { if ( m_standardWorktime != worktime ) { delete m_standardWorktime; m_standardWorktime = worktime; m_standardWorktime->setProject( this ); emit standardWorktimeChanged( worktime ); } } void Project::emitDocumentAdded( Node *node , Document *doc , int index ) { emit documentAdded( node, doc, index ); } void Project::emitDocumentRemoved( Node *node , Document *doc , int index ) { emit documentRemoved( node, doc, index ); } void Project::emitDocumentChanged( Node *node , Document *doc , int index ) { emit documentChanged( node, doc, index ); } bool Project::linkExists( const Node *par, const Node *child ) const { if ( par == 0 || child == 0 || par == child || par->isDependChildOf( child ) ) { return false; } foreach ( Relation *r, par->dependChildNodes() ) { if ( r->child() == child ) { return true; } } return false; } bool Project::legalToLink( const Node *par, const Node *child ) const { //debugPlan<isDependChildOf( child ) ) { return false; } if ( linkExists( par, child ) ) { return false; } bool legal = true; // see if par/child is related if ( legal && ( par->isParentOf( child ) || child->isParentOf( par ) ) ) { legal = false; } if ( legal ) legal = legalChildren( par, child ); if ( legal ) legal = legalParents( par, child ); if ( legal ) { foreach ( Node *p, par->childNodeIterator() ) { if ( ! legalToLink( p, child ) ) { return false; } } } return legal; } bool Project::legalParents( const Node *par, const Node *child ) const { bool legal = true; //debugPlan<name()<<" ("<numDependParentNodes()<<" parents)"<name()<<" ("<numDependChildNodes()<<" children)"; for ( int i = 0; i < par->numDependParentNodes() && legal; ++i ) { Node *pNode = par->getDependParentNode( i ) ->parent(); if ( child->isParentOf( pNode ) || pNode->isParentOf( child ) ) { //debugPlan<<"Found:"<name()<<" is related to"<name(); legal = false; } else { legal = legalChildren( pNode, child ); } if ( legal ) legal = legalParents( pNode, child ); } return legal; } bool Project::legalChildren( const Node *par, const Node *child ) const { bool legal = true; //debugPlan<name()<<" ("<numDependParentNodes()<<" parents)"<name()<<" ("<numDependChildNodes()<<" children)"; for ( int j = 0; j < child->numDependChildNodes() && legal; ++j ) { Node *cNode = child->getDependChildNode( j ) ->child(); if ( par->isParentOf( cNode ) || cNode->isParentOf( par ) ) { //debugPlan<<"Found:"<name()<<" is related to"<name(); legal = false; } else { legal = legalChildren( par, cNode ); } } return legal; } WBSDefinition &Project::wbsDefinition() { return m_wbsDefinition; } void Project::setWbsDefinition( const WBSDefinition &def ) { //debugPlan; m_wbsDefinition = def; emit wbsDefinitionChanged(); emit projectChanged(); } QString Project::generateWBSCode( QList &indexes, bool sortable ) const { QString code = m_wbsDefinition.projectCode(); if (sortable) { int fw = (nodeIdDict.count() / 10) + 1; QLatin1Char fc('0'); foreach ( int index, indexes ) { code += ".%1"; code = code.arg(QString::number(index), fw, fc); } debugPlan< hash = resourceIdDict; foreach ( Resource * r, hash ) { r->setCurrentSchedule( id ); } emit currentScheduleChanged(); emit projectChanged(); } ScheduleManager *Project::scheduleManager( long id ) const { foreach ( ScheduleManager *sm, m_managers ) { if ( sm->scheduleId() == id ) { return sm; } } return 0; } ScheduleManager *Project::scheduleManager( const QString &id ) const { return m_managerIdMap.value( id ); } ScheduleManager *Project::findScheduleManagerByName( const QString &name ) const { //debugPlan; ScheduleManager *m = 0; foreach( ScheduleManager *sm, m_managers ) { m = sm->findManager( name ); if ( m ) { break; } } return m; } QList Project::allScheduleManagers() const { QList lst; foreach ( ScheduleManager *sm, m_managers ) { lst << sm; lst << sm->allChildren(); } return lst; } QString Project::uniqueScheduleName() const { //debugPlan; QString n = i18n( "Plan" ); bool unique = findScheduleManagerByName( n ) == 0; if ( unique ) { return n; } n += " %1"; int i = 1; for ( ; true; ++i ) { unique = findScheduleManagerByName( n.arg( i ) ) == 0; if ( unique ) { break; } } return n.arg( i ); } void Project::addScheduleManager( ScheduleManager *sm, ScheduleManager *parent, int index ) { int row = parent == 0 ? m_managers.count() : parent->childCount(); if ( index >= 0 && index < row ) { row = index; } if ( parent == 0 ) { emit scheduleManagerToBeAdded( parent, row ); m_managers.insert( row, sm ); } else { emit scheduleManagerToBeAdded( parent, row ); sm->setParentManager( parent, row ); } if ( sm->managerId().isEmpty() ) { sm->setManagerId( uniqueScheduleManagerId() ); } Q_ASSERT( ! m_managerIdMap.contains( sm->managerId() ) ); m_managerIdMap.insert( sm->managerId(), sm ); emit scheduleManagerAdded( sm ); emit projectChanged(); //debugPlan<<"Added:"<name()<<", now"<children() ) { takeScheduleManager( s ); } if ( sm->scheduling() ) { sm->stopCalculation(); } int index = -1; if ( sm->parentManager() ) { int index = sm->parentManager()->indexOf( sm ); if ( index >= 0 ) { emit scheduleManagerToBeRemoved( sm ); sm->setParentManager( 0 ); m_managerIdMap.remove( sm->managerId() ); emit scheduleManagerRemoved( sm ); emit projectChanged(); } } else { index = indexOf( sm ); if ( index >= 0 ) { emit scheduleManagerToBeRemoved( sm ); m_managers.removeAt( indexOf( sm ) ); m_managerIdMap.remove( sm->managerId() ); emit scheduleManagerRemoved( sm ); emit projectChanged(); } } return index; } void Project::moveScheduleManager( ScheduleManager *sm, ScheduleManager *newparent, int newindex ) { //debugPlan<name()<parentManager() ) { m_managers.removeAt( indexOf( sm ) ); } sm->setParentManager( newparent, newindex ); if ( ! newparent ) { m_managers.insert( newindex, sm ); } emit scheduleManagerMoved( sm, newindex ); } bool Project::isScheduleManager( void *ptr ) const { const ScheduleManager *sm = static_cast( ptr ); if ( indexOf( sm ) >= 0 ) { return true; } foreach ( ScheduleManager *p, m_managers ) { if ( p->isParentOf( sm ) ) { return true; } } return false; } ScheduleManager *Project::createScheduleManager( const QString &name ) { //debugPlan<isBaselined() ) { return true; } } return false; } Schedule *s = schedule( id ); return s == 0 ? false : s->isBaselined(); } MainSchedule *Project::createSchedule( const QString& name, Schedule::Type type ) { //debugPlan<<"No of schedules:"<setName( name ); sch->setType( type ); addMainSchedule( sch ); return sch; } void Project::addMainSchedule( MainSchedule *sch ) { if ( sch == 0 ) { return; } //debugPlan<<"No of schedules:"<setId( i ); sch->setNode( this ); addSchedule( sch ); } bool Project::removeCalendarId( const QString &id ) { //debugPlan <<"id=" << id; return calendarIdDict.remove( id ); } void Project::insertCalendarId( const QString &id, Calendar *calendar ) { //debugPlan <<"id=" << id <<":" << calendar->name(); calendarIdDict.insert( id, calendar ); } void Project::changed( Node *node, int property ) { if ( m_parent == 0 ) { Node::changed( node, property ); // reset cache if ( property != Node::Type ) { // add/remove node is handled elsewhere emit nodeChanged( node ); emit projectChanged(); } return; } Node::changed( node, property ); } void Project::changed( ResourceGroup *group ) { //debugPlan; emit resourceGroupChanged( group ); emit projectChanged(); } void Project::changed( ScheduleManager *sm ) { emit scheduleManagerChanged( sm ); emit projectChanged(); } void Project::changed( MainSchedule *sch ) { //debugPlan<id(); emit scheduleChanged( sch ); emit projectChanged(); } void Project::sendScheduleToBeAdded( const ScheduleManager *sm, int row ) { emit scheduleToBeAdded( sm, row ); } void Project::sendScheduleAdded( const MainSchedule *sch ) { //debugPlan<id(); emit scheduleAdded( sch ); emit projectChanged(); } void Project::sendScheduleToBeRemoved( const MainSchedule *sch ) { //debugPlan<id(); emit scheduleToBeRemoved( sch ); } void Project::sendScheduleRemoved( const MainSchedule *sch ) { //debugPlan<id(); emit scheduleRemoved( sch ); emit projectChanged(); } void Project::changed( Resource *resource ) { emit resourceChanged( resource ); emit projectChanged(); } void Project::changed( Calendar *cal ) { emit calendarChanged( cal ); emit projectChanged(); } void Project::changed( StandardWorktime *w ) { emit standardWorktimeChanged( w ); emit projectChanged(); } bool Project::addRelation( Relation *rel, bool check ) { if ( rel->parent() == 0 || rel->child() == 0 ) { return false; } if ( check && !legalToLink( rel->parent(), rel->child() ) ) { return false; } emit relationToBeAdded( rel, rel->parent()->numDependChildNodes(), rel->child()->numDependParentNodes() ); rel->parent()->addDependChildNode( rel ); rel->child()->addDependParentNode( rel ); emit relationAdded( rel ); emit projectChanged(); return true; } void Project::takeRelation( Relation *rel ) { emit relationToBeRemoved( rel ); rel->parent() ->takeDependChildNode( rel ); rel->child() ->takeDependParentNode( rel ); emit relationRemoved( rel ); emit projectChanged(); } void Project::setRelationType( Relation *rel, Relation::Type type ) { emit relationToBeModified( rel ); rel->setType( type ); emit relationModified( rel ); emit projectChanged(); } void Project::setRelationLag( Relation *rel, const Duration &lag ) { emit relationToBeModified( rel ); rel->setLag( lag ); emit relationModified( rel ); emit projectChanged(); } QList Project::flatNodeList( Node *parent ) { QList lst; Node *p = parent == 0 ? this : parent; //debugPlan<name()<childNodeIterator() ) { lst.append( n ); if ( n->numChildren() > 0 ) { lst += flatNodeList( n ); } } return lst; } void Project::setSchedulerPlugins( const QMap &plugins ) { m_schedulerPlugins = plugins; debugPlan< Copyright (C) 2007 Florian Piquemal Copyright (C) 2007 Alexis Ménard 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 KPTPROJECT_H #define KPTPROJECT_H #include "kplatokernel_export.h" #include "kptnode.h" #include "kptglobal.h" #include "kptaccount.h" #include "kptcalendar.h" #include "kptdatetime.h" #include "kptduration.h" #include "kptresource.h" #include "kptwbsdefinition.h" #include "kptconfigbase.h" #include #include #include #include #include /// The main namespace. namespace KPlato { class Locale; class Schedule; class StandardWorktime; class ScheduleManager; class XMLLoaderObject; class Task; class SchedulerPlugin; class KPlatoXmlLoaderBase; /** * Project is the main node in a project, it contains child nodes and * possibly sub-projects. A sub-project is just another instantion of this * node however. * * A note on timezones: * To be able to handle resources working in diffierent timezones and * to facilitate data exchange with other applications like PIMs or * and groupware servers, the project has a timezone that is used for * all datetimes in nodes and schedules. * By default the local timezone is used. * * A resources timezone is defined by the associated calendar. * * Note that a projects datetimes are always displayed/modified in the timezone * it was originally created, not necessarly in your current local timezone. */ class KPLATOKERNEL_EXPORT Project : public Node { Q_OBJECT public: explicit Project( Node *parent = 0 ); explicit Project( ConfigBase &config, Node *parent = 0 ); ~Project(); /// Reference this project. void ref() { ++m_refCount; } /// De-reference this project. Deletes project of ref count <= 0 void deref(); /// Returns the node type. Can be Type_Project or Type_Subproject. virtual int type() const; /** * Calculate the schedules managed by the schedule manager * * @param sm Schedule manager */ void calculate( ScheduleManager &sm ); /** * Re-calculate the schedules managed by the schedule manager * * @param sm Schedule manager * @param dt The datetime from when the schedule shall be re-calculated */ void calculate( ScheduleManager &sm, const DateTime &dt ); virtual DateTime startTime( long id = -1 ) const; virtual DateTime endTime( long id = -1 ) const; /// Returns the calculated duration for schedule @p id Duration duration( long id = -1 ) const; using Node::duration; /** * Instead of using the expected duration, generate a random value using * the Distribution of each Task. This can be used for Monte-Carlo * estimation of Project duration. */ Duration *getRandomDuration(); virtual bool load( KoXmlElement &element, XMLLoaderObject &status ); virtual void save( QDomElement &element ) const; using Node::saveWorkPackageXML; /// Save a workpackage document containing @node with schedule identity @p id void saveWorkPackageXML( QDomElement &element, const Node *node, long id ) const; /** * Add the node @p task to the project, after node @p position * If @p postition is zero or the project node, it will be added to this project. */ bool addTask( Node* task, Node* position ); /** * Add the node @p task to the @p parent */ bool addSubTask( Node* task, Node* parent ); /** * Add the node @p task to @p parent, in position @p index * If @p parent is zero, it will be added to this project. */ bool addSubTask( Node* task, int index, Node* parent, bool emitSignal = true ); /** * Remove the @p node. * The node is not deleted. */ void takeTask( Node *node, bool emitSignal = true ); bool canMoveTask( Node* node, Node *newParent ); bool moveTask( Node* node, Node *newParent, int newPos ); bool canIndentTask( Node* node ); bool indentTask( Node* node, int index = -1 ); bool canUnindentTask( Node* node ); bool unindentTask( Node* node ); bool canMoveTaskUp( Node* node ); bool moveTaskUp( Node* node ); bool canMoveTaskDown( Node* node ); bool moveTaskDown( Node* node ); /** * Create a task with a unique id. * The task is not added to the project. Do this with addSubTask(). */ Task *createTask(); /** * Create a copy of @p def with a unique id. * The task is not added to the project. Do this with addSubTask(). */ Task *createTask( const Task &def ); int resourceGroupCount() const { return m_resourceGroups.count(); } QList &resourceGroups(); /// Adds the resource group to the project. virtual void addResourceGroup( ResourceGroup *resource, int index = -1 ); /** * Removes the resource group @p resource from the project. * The resource group is not deleted. */ ResourceGroup *takeResourceGroup( ResourceGroup *resource ); int indexOf( ResourceGroup *resource ) const { return m_resourceGroups.indexOf( resource ); } ResourceGroup *resourceGroupAt( int pos ) const { return m_resourceGroups.value( pos ); } int numResourceGroups() const { return m_resourceGroups.count(); } /// Returns the resourcegroup with identity id. ResourceGroup *group( const QString& id ); /// Returns the resource group with the matching name, 0 if no match is found. ResourceGroup *groupByName( const QString& name ) const; /** * Adds the resource to the project and resource group. * Always use this to add resources. */ void addResource( ResourceGroup *group, Resource *resource, int index = -1 ); /** * Removes the resource from the project and resource group. * The resource is not deleted. * Always use this to remove resources. */ Resource *takeResource( ResourceGroup *group, Resource *resource ); /// Move @p resource to the new @p group. Requests are removed. void moveResource( ResourceGroup *group, Resource *resource ); /// Returns the resource with identity id. Resource *resource( const QString& id ); /// Returns the resource with matching name, 0 if no match is found. Resource *resourceByName( const QString& name ) const; QStringList resourceNameList() const; /// Returns a list of all resources QList resourceList() const { return resourceIdDict.values(); } virtual EffortCostMap plannedEffortCostPrDay( QDate start, QDate end, long id = CURRENTSCHEDULE, EffortCostCalculationType = ECCT_All ) const; virtual EffortCostMap plannedEffortCostPrDay(const Resource *resource, QDate start, QDate end, long id = CURRENTSCHEDULE, EffortCostCalculationType = ECCT_All ) const; using Node::plannedEffort; /// Returns the total planned effort for this project (or subproject) virtual Duration plannedEffort( long id = CURRENTSCHEDULE, EffortCostCalculationType = ECCT_All ) const; /// Returns the total planned effort for this project (or subproject) on date virtual Duration plannedEffort( QDate date, long id = CURRENTSCHEDULE, EffortCostCalculationType = ECCT_All ) const; using Node::plannedEffortTo; /// Returns the planned effort up to and including date virtual Duration plannedEffortTo( QDate date, long id = CURRENTSCHEDULE, EffortCostCalculationType = ECCT_All ) const; /// Returns the actual effort up to and including @p date virtual Duration actualEffortTo( QDate date ) const; /** * Planned cost up to and including date * @param date The cost is calculated from the start of the project upto including date. * @param id Identity of the schedule to be used. */ virtual double plannedCostTo( QDate date, long id = CURRENTSCHEDULE, EffortCostCalculationType = ECCT_All ) const; /** * Actual cost up to and including @p date * @param date The cost is calculated from the start of the project upto including date. */ virtual EffortCost actualCostTo( long int id, QDate date ) const; virtual EffortCostMap actualEffortCostPrDay( QDate start, QDate end, long id = CURRENTSCHEDULE, EffortCostCalculationType = ECCT_All ) const; virtual EffortCostMap actualEffortCostPrDay( const Resource *resource, QDate start, QDate end, long id = CURRENTSCHEDULE, EffortCostCalculationType = ECCT_All ) const; double effortPerformanceIndex( QDate date, long id ) const; double schedulePerformanceIndex( QDate date, long id ) const; /// Returns the effort planned to be used to reach the actual percent finished virtual Duration budgetedWorkPerformed( QDate date, long id = CURRENTSCHEDULE ) const; /// Returns the cost planned to be used to reach the actual percent finished virtual double budgetedCostPerformed( QDate date, long id = CURRENTSCHEDULE ) const; /// Budgeted Cost of Work Scheduled ( up to @p date ) virtual double bcws( QDate date, long id = BASELINESCHEDULE ) const; /// Budgeted Cost of Work Performed virtual double bcwp( long id = BASELINESCHEDULE ) const; /// Budgeted Cost of Work Performed ( up to @p date ) virtual double bcwp( QDate date, long id = BASELINESCHEDULE ) const; Calendar *defaultCalendar() const { return m_defaultCalendar; } void setDefaultCalendar( Calendar *cal ); const QList &calendars() const; void addCalendar( Calendar *calendar, Calendar *parent = 0, int index = -1 ); void takeCalendar( Calendar *calendar ); int indexOf( const Calendar *calendar ) const; /// Returns the calendar with identity id. Calendar *calendar( const QString& id ) const; /// Returns a list of all calendars QStringList calendarNames() const; /// Find calendar by name Calendar *calendarByName( const QString &name ) const; void changed( Calendar *cal ); QList allCalendars() const; /// Return number of calendars int calendarCount() const { return m_calendars.count(); } /// Return the calendar at @p index, 0 if index out of bounds Calendar *calendarAt( int index ) const { return m_calendars.value( index ); } /** * Defines the length of days, weeks, months and years * and the standard working week. * Used for estimation and calculation of effort, * and presentation in gantt chart. */ StandardWorktime *standardWorktime() { return m_standardWorktime; } void setStandardWorktime( StandardWorktime * worktime ); void changed( StandardWorktime* ); /// Check if a link exists between node @p par and @p child. bool linkExists( const Node *par, const Node *child ) const; /// Check if node @p par can be linked to node @p child. bool legalToLink( const Node *par, const Node *child ) const; using Node::legalToLink; virtual const QHash &nodeDict() { return nodeIdDict; } /// Return a list of all nodes in the project (exluding myself) QList allNodes() const; /// Return the number of all nodes in the project (exluding myself) int nodeCount() const { return nodeIdDict.count() - 1; } /// Return a list of all tasks and milestones int the wbs order QList allTasks( const Node *parent = 0 ) const; using Node::findNode; /// Find the node with identity id virtual Node *findNode( const QString &id ) const; using Node::removeId; /// Remove the node with identity id from the registers virtual bool removeId( const QString &id ); /// Reserve @p id for the @p node virtual void reserveId( const QString &id, Node *node ); /// Register @p node. The nodes id must be unique and non-empty. bool registerNodeId( Node *node ); /// Create a unique id. QString uniqueNodeId( int seed = 1 ) const; /// Check if node @p id is used bool nodeIdentExists( const QString &id ) const; /// Create a unique id. QString uniqueNodeId( const QList &existingIds, int seed = 1 ); ResourceGroup *findResourceGroup( const QString &id ) const { if ( resourceGroupIdDict.contains( id ) ) return resourceGroupIdDict[ id ]; return 0; } /// Remove the resourcegroup with identity id from the register bool removeResourceGroupId( const QString &id ) { if ( resourceGroupIdDict.contains( id ) ) return resourceGroupIdDict.remove( id ); return false; } /// Insert the resourcegroup with identity id void insertResourceGroupId( const QString &id, ResourceGroup* group ) { resourceGroupIdDict.insert( id, group ); } /// Generate, set and insert unique id bool setResourceGroupId( ResourceGroup *group); /// returns a unique resourcegroup id QString uniqueResourceGroupId() const; /// Return a list of resources that will be allocated to new tasks QList autoAllocateResources() const; Resource *findResource( const QString &id ) const { if ( resourceIdDict.contains( id ) ) return resourceIdDict[ id ]; return 0; } /// Remove the resource with identity id from the register bool removeResourceId( const QString &id ); /// Insert the resource with identity id void insertResourceId( const QString &id, Resource *resource ); /// Generate, set and insert unique id bool setResourceId( Resource *resource ); /// returns a unique resource id QString uniqueResourceId() const; /// Find the calendar with identity id virtual Calendar *findCalendar( const QString &id ) const { if ( id.isEmpty() || !calendarIdDict.contains( id ) ) return 0; return calendarIdDict[ id ]; } /// Remove the calendar with identity id from the register virtual bool removeCalendarId( const QString &id ); /// Insert the calendar with identity id virtual void insertCalendarId( const QString &id, Calendar *calendar ); /// Set and insert a unique id for calendar bool setCalendarId( Calendar *calendar ); /// returns a unique calendar id QString uniqueCalendarId() const; /// Return reference to WBS Definition WBSDefinition &wbsDefinition(); /// Set WBS Definition to @p def void setWbsDefinition( const WBSDefinition &def ); /// Generate WBS Code virtual QString generateWBSCode( QList &indexes, bool sortable = false ) const; Accounts &accounts() { return m_accounts; } const Accounts &accounts() const { return m_accounts; } /** * Set current schedule to the schedule with identity @p id, for me and my children * Note that this is used (and may be changed) when calculating schedules */ virtual void setCurrentSchedule( long id ); /// Create new schedule with unique name and id of type Expected. MainSchedule *createSchedule(); /// Create new schedule with unique id. MainSchedule *createSchedule( const QString& name, Schedule::Type type ); /// Add the schedule to the project. A fresh id will be generated for the schedule. void addMainSchedule( MainSchedule *schedule ); /// Set parent schedule for my children virtual void setParentSchedule( Schedule *sch ); /// Find the schedule manager that manages the Schedule with @p id ScheduleManager *scheduleManager( long id ) const; /// Find the schedule manager with @p id ScheduleManager *scheduleManager( const QString &id ) const; /// Create a unique schedule name (This may later be changed by the user) QString uniqueScheduleName() const; /// Create a unique schedule manager identity QString uniqueScheduleManagerId() const; ScheduleManager *createScheduleManager(); ScheduleManager *createScheduleManager( const QString &name ); /// Returns a list of all top level schedule managers QList scheduleManagers() const { return m_managers; } int numScheduleManagers() const { return m_managers.count(); } int indexOf( const ScheduleManager *sm ) const { return m_managers.indexOf( const_cast(sm) ); } bool isScheduleManager( void* ptr ) const; void addScheduleManager( ScheduleManager *sm, ScheduleManager *parent = 0, int index = -1 ); int takeScheduleManager( ScheduleManager *sm ); void moveScheduleManager( ScheduleManager *sm, ScheduleManager *newparent = 0, int newindex = -1 ); ScheduleManager *findScheduleManagerByName( const QString &name ) const; /// Returns a list of all schedule managers QList allScheduleManagers() const; /// Return true if schedule with identity @p id is baselined bool isBaselined( long id = ANYSCHEDULED ) const; void changed( ResourceGroup *group ); void changed( Resource *resource ); void changed( ScheduleManager *sm ); void changed( MainSchedule *sch ); void sendScheduleAdded( const MainSchedule *sch ); void sendScheduleToBeAdded( const ScheduleManager *manager, int row ); void sendScheduleRemoved( const MainSchedule *sch ); void sendScheduleToBeRemoved( const MainSchedule *sch ); /// Return the time zone used in this project QTimeZone timeZone() const { return m_timeZone; } /// Set the time zone to be used in this project void setTimeZone( const QTimeZone &tz ) { m_timeZone = tz; } /** * Add a relation between the nodes specified in the relation rel. * Emits signals relationToBeAdded() before the relation is added, * and relationAdded() after it has been added. * @param rel The relation to be added. * @param check If true, the relation is checked for validity * @return true if successful. */ bool addRelation( Relation *rel, bool check=true ); /** * Removes the relation @p rel without deleting it. * Emits signals relationToBeRemoved() before the relation is removed, * and relationRemoved() after it has been removed. */ void takeRelation( Relation *rel ); /** * Modify the @p type of the @p relation. */ void setRelationType( Relation *relation, Relation::Type type ); /** * Modify the @p lag of the @p relation. */ void setRelationLag( Relation *relation, const Duration &lag ); void calcCriticalPathList( MainSchedule *cs ); void calcCriticalPathList( MainSchedule *cs, Node *node ); /** * Returns the list of critical paths for schedule @p id */ const QList< QList > *criticalPathList( long id = CURRENTSCHEDULE ); QList criticalPath( long id = CURRENTSCHEDULE, int index = 0 ); /// Returns a flat list af all nodes QList flatNodeList( Node *parent = 0 ); void generateUniqueNodeIds(); void generateUniqueIds(); const ConfigBase &config() const { return m_config ? *m_config : emptyConfig; } /// Set configuration data void setConfig( ConfigBase *config ) { m_config = config; } const Task &taskDefaults() const { return config().taskDefaults(); } /// Return locale. (Used for currency, everything else is from KGlobal::locale) Locale *locale() { return const_cast(config()).locale(); } /// Return locale. (Used for currency, everything else is from KGlobal::locale) const Locale *locale() const { return config().locale(); } /// Signal that locale data has changed void emitLocaleChanged(); void setSchedulerPlugins( const QMap &plugins ); const QMap &schedulerPlugins() const { return m_schedulerPlugins; } void initiateCalculation( MainSchedule &sch ); void initiateCalculationLists( MainSchedule &sch ); void finishCalculation( ScheduleManager &sm ); void adjustSummarytask(); /// Increments progress and emits signal sigProgress() void incProgress(); /// Emits signal maxProgress() void emitMaxProgress( int value ); bool stopcalculation; /// return a map of all external projects QMap externalProjects() const; void emitDocumentAdded( Node*, Document*, int index ); void emitDocumentRemoved( Node*, Document*, int index ); void emitDocumentChanged( Node*, Document*, int index ); bool useSharedResources() const; void setUseSharedResources(bool on); bool isSharedResourcesLoaded() const; void setSharedResourcesLoaded(bool on); void setSharedResourcesFile(const QString &file); QString sharedResourcesFile() const; void setSharedProjectsUrl(const QUrl &url); QUrl sharedProjectsUrl() const; + void setLoadProjectsAtStartup(bool value); + bool loadProjectsAtStartup() const; public Q_SLOTS: /// Sets m_progress to @p progress and emits signal sigProgress() /// If @p sm is not 0, progress is also set for the schedule manager void setProgress( int progress, ScheduleManager *sm = 0 ); /// Sets m_maxprogress to @p max and emits signal maxProgress() /// If @p sm is not 0, max progress is also set for the schedule manager void setMaxProgress( int max, ScheduleManager *sm = 0 ); Q_SIGNALS: /// Emitted when the project is about to be deleted (The destroyed signal is disabled) void aboutToBeDeleted(); /// Emitted when anything in the project is changed (use with care) void projectChanged(); /// Emitted when the WBS code definition has changed. This may change all nodes. void wbsDefinitionChanged(); /// Emitted when a schedule has been calculated void projectCalculated( ScheduleManager *sm ); /// Emitted when the pointer to the current schedule has been changed void currentScheduleChanged(); /// Use to show progress during calculation void sigProgress( int ); /// Use to set the maximum progress (minimum always 0) void maxProgress( int ); /// Emitted when calculation starts void sigCalculationStarted( Project *project, ScheduleManager *sm ); /// Emitted when calculation is finished void sigCalculationFinished( Project *project, ScheduleManager *sm ); /// This signal is emitted when one of the nodes members is changed. void nodeChanged( Node* ); /// This signal is emitted when the node is to be added to the project. void nodeToBeAdded( Node*, int ); /// This signal is emitted when the node has been added to the project. void nodeAdded( Node* ); /// This signal is emitted when the node is to be removed from the project. void nodeToBeRemoved( Node* ); /// This signal is emitted when the node has been removed from the project. void nodeRemoved( Node* ); /// This signal is emitted when the node is to be moved up, moved down, indented or unindented. void nodeToBeMoved( Node* node, int pos, Node* newParent, int newPos ); /// This signal is emitted when the node has been moved up, moved down, indented or unindented. void nodeMoved( Node* ); /// This signal is emitted when a document is added void documentAdded( Node*, Document*, int index ); /// This signal is emitted when a document is removed void documentRemoved( Node*, Document*, int index ); /// This signal is emitted when a document is changed void documentChanged( Node*, Document*, int index ); void resourceGroupChanged( ResourceGroup *group ); void resourceGroupAdded( const ResourceGroup *group ); void resourceGroupToBeAdded( const ResourceGroup *group, int row ); void resourceGroupRemoved( const ResourceGroup *group ); void resourceGroupToBeRemoved( const ResourceGroup *group ); void resourceChanged( Resource *resource ); void resourceAdded( const Resource *resource ); void resourceToBeAdded( const ResourceGroup *group, int row ); void resourceRemoved( const Resource *resource ); void resourceToBeRemoved( const Resource *resource ); void scheduleManagerChanged( ScheduleManager *sch ); void scheduleManagerAdded( const ScheduleManager *sch ); void scheduleManagerToBeAdded( const ScheduleManager *sch, int row ); void scheduleManagerRemoved( const ScheduleManager *sch ); void scheduleManagerToBeRemoved( const ScheduleManager *sch ); void scheduleManagerMoved( const ScheduleManager *sch, int row ); void scheduleManagerToBeMoved( const ScheduleManager *sch ); void scheduleChanged( MainSchedule *sch ); void scheduleToBeAdded( const ScheduleManager *manager, int row ); void scheduleAdded( const MainSchedule *sch ); void scheduleToBeRemoved( const MainSchedule *sch ); void scheduleRemoved( const MainSchedule *sch ); // void currentViewScheduleIdChanged( long id ); void calendarChanged( Calendar *cal ); void calendarToBeAdded( const Calendar *cal, int row ); void calendarAdded( const Calendar *cal ); void calendarToBeRemoved( const Calendar *cal ); void calendarRemoved( const Calendar *cal ); /** * Emitted when the default calendar pointer has changed * @parem cal The new default calendar. May be 0. */ void defaultCalendarChanged( Calendar *cal ); /** * Emitted when the standard worktime has been changed. */ void standardWorktimeChanged( StandardWorktime* ); /// Emitted when the relation @p rel is about to be added. void relationToBeAdded( Relation *rel, int parentIndex, int childIndex ); /// Emitted when the relation @p rel has been added. void relationAdded( Relation *rel ); /// Emitted when the relation @p rel is about to be removed. void relationToBeRemoved( Relation *rel ); /// Emitted when the relation @p rel has been removed. void relationRemoved( Relation *rel ); /// Emitted when the relation @p rel shall be modified. void relationToBeModified( Relation *rel ); /// Emitted when the relation @p rel has been modified. void relationModified( Relation *rel ); /// Emitted when locale data has changed void localeChanged(); protected: /// Calculate the schedule. void calculate( Schedule *scedule ); /// Calculate current schedule void calculate(); /// Re-calculate the schedule from @p dt void calculate( Schedule *scedule, const DateTime &dt ); /// Calculate current schedule from @p dt (Always calculates forward) void calculate( const DateTime &dt ); /// Calculate critical path virtual bool calcCriticalPath( bool fromEnd ); /// Prepare task lists for scheduling void tasksForward(); /// Prepare task lists for scheduling void tasksBackward(); protected: friend class KPlatoXmlLoaderBase; using Node::changed; virtual void changed(Node *node, int property = -1); Accounts m_accounts; QList m_resourceGroups; QList m_calendars; Calendar * m_defaultCalendar; StandardWorktime *m_standardWorktime; DateTime calculateForward( int use ); DateTime calculateBackward( int use ); DateTime scheduleForward( const DateTime &earliest, int use ); DateTime scheduleBackward( const DateTime &latest, int use ); DateTime checkStartConstraints( const DateTime &dt ) const; DateTime checkEndConstraints( const DateTime &dt ) const; bool legalParents( const Node *par, const Node *child ) const; bool legalChildren( const Node *par, const Node *child ) const; #ifndef PLAN_NLOGDEBUG private: static bool checkParent( Node *n, const QList &list, QList &checked ); static bool checkChildren( Node *n, const QList &list, QList &checked ); #endif private: void init(); QHash resourceGroupIdDict; QHash resourceIdDict; QHash nodeIdDict; QMap nodeIdReserved; QMap calendarIdDict; QMap m_managerIdMap; QList m_managers; QTimeZone m_timeZone; WBSDefinition m_wbsDefinition; ConfigBase emptyConfig; QPointer m_config; // this one is not owned by me, don't delete int m_progress; QMap m_schedulerPlugins; int m_refCount; // make it possible to use the project by different threads QList m_hardConstraints; QList m_softConstraints; QList m_terminalNodes; bool m_useSharedResources; bool m_sharedResourcesLoaded; QString m_sharedResourcesFile; QUrl m_sharedProjectsUrl; + bool m_loadProjectsAtStartup; }; } //KPlato namespace #endif diff --git a/plan/libs/kernel/tests/AccountsCommandTester.cpp b/plan/libs/kernel/tests/AccountsCommandTester.cpp new file mode 100644 index 00000000000..26f45d4e848 --- /dev/null +++ b/plan/libs/kernel/tests/AccountsCommandTester.cpp @@ -0,0 +1,322 @@ +/* This file is part of the KDE project + Copyright (C) 2017 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 "AccountsCommandTester.h" + +#include "kptdatetime.h" +#include "kptcommand.h" +#include "kptproject.h" +#include "kptcalendar.h" +#include "kptresource.h" +#include "kptnode.h" +#include "kpttask.h" +#include "kptschedule.h" + +#include +#include + +namespace QTest +{ + template<> + char *toString(const KPlato::DateTime &dt) + { + return toString( dt.toString() ); + } +} + + +namespace KPlato +{ + +void AccountsCommandTester::printDebug( long id ) const { + Project *p = m_project; + Resource *r = m_resource; + qDebug()<<"Debug info -------------------------------------"; + qDebug()<<"project start time:"<startTime().toString(); + qDebug()<<"project end time :"<endTime().toString(); + + qDebug()<<"Resource start:"<startTime( id ).toString(); + qDebug()<<"Resource end :"<endTime( id ).toString(); + qDebug()<<"Appointments:"<numAppointments( id )<<"(internal)"; + foreach ( Appointment *a, r->appointments( id ) ) { + foreach ( const AppointmentInterval &i, a->intervals().map() ) { + qDebug()<<" "<numExternalAppointments()<<"(external)"; + foreach ( Appointment *a, r->externalAppointmentList() ) { + foreach ( const AppointmentInterval &i, a->intervals().map() ) { + qDebug()<<" "<logMessages() ) { + qDebug()<setName( "P1" ); + m_project->setId( m_project->uniqueNodeId() ); + m_project->registerNodeId( m_project ); + DateTime targetstart = DateTime( QDate::currentDate(), QTime(0,0,0) ); + DateTime targetend = DateTime( targetstart.addDays( 3 ) ); + m_project->setConstraintStartTime( targetstart ); + m_project->setConstraintEndTime( targetend); + + // standard worktime defines 8 hour day as default + QVERIFY( m_project->standardWorktime() ); + QCOMPARE( m_project->standardWorktime()->day(), 8.0 ); + m_calendar = new Calendar( "Test" ); + m_calendar->setDefault( true ); + QTime t1( 9, 0, 0 ); + QTime t2 ( 17, 0, 0 ); + int length = t1.msecsTo( t2 ); + for ( int i=1; i <= 7; ++i ) { + CalendarDay *d = m_calendar->weekday( i ); + d->setState( CalendarDay::Working ); + d->addInterval( t1, length ); + } + m_project->addCalendar( m_calendar ); + + + ResourceGroup *g = new ResourceGroup(); + g->setName( "G1" ); + m_project->addResourceGroup( g ); + m_resource = new Resource(); + m_resource->setName( "R1" ); + m_resource->setCalendar( m_calendar ); + m_project->addResource( g, m_resource ); + + m_task = m_project->createTask(); + m_task->setName( "T1" ); + m_project->addTask( m_task, m_project ); + m_task->estimate()->setUnit( Duration::Unit_h ); + m_task->estimate()->setExpectedEstimate( 8.0 ); + m_task->estimate()->setType( Estimate::Type_Effort ); +} + +void AccountsCommandTester::cleanup() +{ + delete m_project; +} + +void AccountsCommandTester::addAccount() +{ + Account *a1 = new Account(); + a1->setName("a1"); + AddAccountCmd *cmd1 = new AddAccountCmd(*m_project, a1); + cmd1->redo(); + + QCOMPARE(m_project->accounts().allAccounts().count(), 1); + + cmd1->undo(); + QCOMPARE(m_project->accounts().allAccounts().count(), 0); + + delete cmd1; + + a1 = new Account(); + a1->setName("a1"); + cmd1 = new AddAccountCmd(*m_project, a1); + cmd1->redo(); + + QCOMPARE(m_project->accounts().allAccounts().count(), 1); + + Account *a2 = new Account(); + a2->setName("a2"); + AddAccountCmd *cmd2 = new AddAccountCmd(*m_project, a2, a1); + cmd2->redo(); + + QCOMPARE(m_project->accounts().allAccounts().count(), 2); + + cmd2->undo(); + QCOMPARE(m_project->accounts().allAccounts().count(), 1); + cmd1->undo(); + QCOMPARE(m_project->accounts().allAccounts().count(), 0); + + delete cmd2; + delete cmd1; +} + +void AccountsCommandTester::removeAccount() +{ + Account *a1 = new Account(); + a1->setName("a1"); + m_project->accounts().insert(a1); + QCOMPARE(m_project->accounts().allAccounts().count(), 1); + + + + RemoveAccountCmd *cmd1 = new RemoveAccountCmd(*m_project, a1); + cmd1->redo(); + QCOMPARE(m_project->accounts().allAccounts().count(), 0); + + cmd1->undo(); + QCOMPARE(m_project->accounts().allAccounts().count(), 1); + + cmd1->redo(); + delete cmd1; + QCOMPARE(m_project->accounts().allAccounts().count(), 0); + + a1 = new Account(); + a1->setName("a1"); + m_project->accounts().insert(a1); + Account *a2 = new Account(); + a2->setName("a2"); + m_project->accounts().insert(a2, a1); + QCOMPARE(m_project->accounts().allAccounts().count(), 2); + + cmd1 = new RemoveAccountCmd(*m_project, a1); + cmd1->redo(); + QCOMPARE(m_project->accounts().allAccounts().count(), 0); + + cmd1->undo(); + QCOMPARE(m_project->accounts().allAccounts().count(), 2); + + RemoveAccountCmd *cmd2 = new RemoveAccountCmd(*m_project, a2); + cmd2->redo(); + QCOMPARE(m_project->accounts().allAccounts().count(), 1); + + cmd2->undo(); + QCOMPARE(m_project->accounts().allAccounts().count(), 2); + + cmd2->redo(); + QCOMPARE(m_project->accounts().allAccounts().count(), 1); + + delete cmd2; // should delete a2 + delete cmd1; // should not delete a1 +} + +void AccountsCommandTester::costPlace() +{ + KUndo2QStack cmds; + Account *a1 = new Account(); + a1->setName("a1"); + cmds.push(new AddAccountCmd(*m_project, a1)); + QCOMPARE(m_project->accounts().allAccounts().count(), 1); + + Account *a2 = new Account(); + a2->setName("a2"); + cmds.push(new AddAccountCmd(*m_project, a2)); + QCOMPARE(m_project->accounts().allAccounts().count(), 2); + + Account *a3 = new Account(); + a3->setName("a3"); + cmds.push(new AddAccountCmd(*m_project, a3)); + QCOMPARE(m_project->accounts().allAccounts().count(), 3); + + cmds.push(new NodeModifyRunningAccountCmd(*m_task, 0, a1)); + QCOMPARE(m_task->runningAccount(), a1); + cmds.push(new NodeModifyStartupAccountCmd(*m_task, 0, a2)); + QCOMPARE(m_task->startupAccount(), a2); + cmds.push(new NodeModifyShutdownAccountCmd(*m_task, 0, a3)); + QCOMPARE(m_task->shutdownAccount(), a3); + + cmds.push(new RemoveAccountCmd(*m_project, a1)); + QVERIFY(m_task->runningAccount() == 0); + QCOMPARE(m_task->startupAccount(), a2); + QCOMPARE(m_task->shutdownAccount(), a3); + cmds.undo(); + QCOMPARE(m_task->runningAccount(), a1); + QCOMPARE(m_task->startupAccount(), a2); + QCOMPARE(m_task->shutdownAccount(), a3); + + cmds.push(new RemoveAccountCmd(*m_project, a2)); + QVERIFY(m_task->startupAccount() == 0); + QCOMPARE(m_task->runningAccount(), a1); + QCOMPARE(m_task->shutdownAccount(), a3); + cmds.undo(); + QCOMPARE(m_task->runningAccount(), a1); + QCOMPARE(m_task->startupAccount(), a2); + QCOMPARE(m_task->shutdownAccount(), a3); + + cmds.push(new RemoveAccountCmd(*m_project, a3)); + QVERIFY(m_task->shutdownAccount() == 0); + QCOMPARE(m_task->runningAccount(), a1); + QCOMPARE(m_task->startupAccount(), a2); + cmds.undo(); + QCOMPARE(m_task->runningAccount(), a1); + QCOMPARE(m_task->startupAccount(), a2); + QCOMPARE(m_task->shutdownAccount(), a3); + + cmds.push(new ResourceModifyAccountCmd(*m_resource, 0, a1)); + QCOMPARE(m_resource->account(), a1); + + cmds.push(new RemoveAccountCmd(*m_project, a1)); + QVERIFY(m_task->runningAccount() == 0); + QVERIFY(m_resource->account() == 0); + cmds.undo(); + QCOMPARE(m_task->runningAccount(), a1); + QCOMPARE(m_resource->account(), a1); + + // test when same account is used for running/startup/shutdown + while (cmds.canUndo()) { + cmds.undo(); + } + a1 = new Account(); + a1->setName("a1"); + cmds.push(new AddAccountCmd(*m_project, a1)); + QCOMPARE(m_project->accounts().allAccounts().count(), 1); + + cmds.push(new NodeModifyRunningAccountCmd(*m_task, 0, a1)); + QCOMPARE(m_task->runningAccount(), a1); + cmds.push(new NodeModifyStartupAccountCmd(*m_task, 0, a1)); + QCOMPARE(m_task->startupAccount(), a1); + cmds.push(new NodeModifyShutdownAccountCmd(*m_task, 0, a1)); + QCOMPARE(m_task->shutdownAccount(), a1); + + cmds.undo(); + QCOMPARE(m_task->runningAccount(), a1); + QCOMPARE(m_task->startupAccount(), a1); + QVERIFY(m_task->shutdownAccount() == 0); + + cmds.undo(); + QCOMPARE(m_task->runningAccount(), a1); + QVERIFY(m_task->startupAccount() == 0); + QVERIFY(m_task->shutdownAccount() == 0); + + cmds.undo(); + QVERIFY(m_task->runningAccount() == 0); + QVERIFY(m_task->startupAccount() == 0); + QVERIFY(m_task->shutdownAccount() == 0); + + cmds.redo(); + QCOMPARE(m_task->runningAccount(), a1); + QVERIFY(m_task->startupAccount() == 0); + QVERIFY(m_task->shutdownAccount() == 0); + + cmds.redo(); + QCOMPARE(m_task->runningAccount(), a1); + QCOMPARE(m_task->startupAccount(), a1); + QVERIFY(m_task->shutdownAccount() == 0); + + cmds.redo(); + QCOMPARE(m_task->runningAccount(), a1); + QCOMPARE(m_task->startupAccount(), a1); + QCOMPARE(m_task->shutdownAccount(), a1); +} + +} //namespace KPlato + +QTEST_GUILESS_MAIN( KPlato::AccountsCommandTester ) diff --git a/plan/libs/kernel/tests/AccountsTester.h b/plan/libs/kernel/tests/AccountsCommandTester.h similarity index 62% copy from plan/libs/kernel/tests/AccountsTester.h copy to plan/libs/kernel/tests/AccountsCommandTester.h index b09cf21e490..fb970c7ccd1 100644 --- a/plan/libs/kernel/tests/AccountsTester.h +++ b/plan/libs/kernel/tests/AccountsCommandTester.h @@ -1,64 +1,58 @@ /* This file is part of the KDE project - Copyright (C) 2008 Dag Andersen + Copyright (C) 2017 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 KPlato_AccountsTester_h -#define KPlato_AccountsTester_h +#ifndef KPlato_AccountsCommandTester_h +#define KPlato_AccountsCommandTester_h -#include "kptproject.h" +#include namespace KPlato { class Task; +class Project; +class Resource; +class Calendar; +class ScheduleManager; -class AccountsTester : public QObject +class AccountsCommandTester : public QObject { Q_OBJECT private Q_SLOTS: void init(); void cleanup(); - void defaultAccount(); - void costPlaces(); - void startupDefault(); - void startupAccount(); - - void shutdownAccount(); - - void subaccounts(); + void addAccount(); + void removeAccount(); + void costPlace(); private: - Project *project; - Task *t; - Resource *r; - ScheduleManager *sm; - Account *topaccount; - - QDate today; - QDate tomorrow; - QDate yesterday; - QDate nextweek; - QTime t1; - QTime t2; - int length; + void printDebug( long id ) const; + void printSchedulingLog( const ScheduleManager &sm ) const; + + Project *m_project; + Calendar *m_calendar; + Task *m_task; + Resource *m_resource; + }; -} +} //namespace KPlato #endif diff --git a/plan/libs/kernel/tests/AccountsTester.cpp b/plan/libs/kernel/tests/AccountsTester.cpp index 0b6dc90f183..641abaecc16 100644 --- a/plan/libs/kernel/tests/AccountsTester.cpp +++ b/plan/libs/kernel/tests/AccountsTester.cpp @@ -1,579 +1,622 @@ /* This file is part of the KDE project Copyright (C) 2008 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 "AccountsTester.h" #include "kptaccount.h" #include "kptduration.h" #include "kptnode.h" #include "kpttask.h" #include "debug.cpp" #include namespace KPlato { void AccountsTester::init() { project = new Project(); project->setId( project->uniqueCalendarId() ); project->registerNodeId( project ); today = QDate::currentDate(); tomorrow = today.addDays( 1 ); yesterday = today.addDays( -1 ); nextweek = today.addDays( 7 ); t1 = QTime( 9, 0, 0 ); t2 = QTime( 17, 0, 0 ); length = t1.msecsTo( t2 ); t = project->createTask(); t->setName( "T1" ); project->addTask( t, project ); t->estimate()->setUnit( Duration::Unit_d ); t->estimate()->setExpectedEstimate( 1.0 ); sm = project->createScheduleManager( "Test Plan" ); project->addScheduleManager( sm ); // standard worktime defines 8 hour day as default Calendar *c = new Calendar(); c->setDefault( true ); for ( int i=1; i <= 7; ++i ) { CalendarDay *d = c->weekday( i ); d->setState( CalendarDay::Working ); d->addInterval( t1, length ); } project->addCalendar( c ); ResourceGroup *g = new ResourceGroup(); project->addResourceGroup( g ); r = new Resource(); r->setAvailableFrom( QDateTime( yesterday, QTime(), Qt::LocalTime ) ); r->setCalendar( c ); r->setNormalRate( 100.0 ); project->addResource( g, r ); ResourceGroupRequest *gr = new ResourceGroupRequest( g ); t->addRequest( gr ); ResourceRequest *rr = new ResourceRequest( r, 100 ); gr->addResourceRequest( rr ); t->estimate()->setType( Estimate::Type_Effort ); //qDebug()<<"Calculate forward, Task: ASAP -----------------------------------"; project->setConstraintStartTime( DateTime( today, QTime() ) ); project->setConstraintEndTime( DateTime( tomorrow, QTime() ) ); sm->createSchedules(); project->calculate( *sm ); QCOMPARE( t->earlyStart(), t->requests().workTimeAfter( project->startTime() ) ); QVERIFY( t->lateStart() >= t->earlyStart() ); QVERIFY( t->earlyFinish() <= t->endTime() ); QVERIFY( t->lateFinish() >= t->endTime() ); QCOMPARE( t->startTime(), DateTime( today, t1 ) ); QCOMPARE( t->endTime(), t->startTime() + Duration( 0, 8, 0 ) ); //### QVERIFY( t->schedulingError() == false ); sm->setBaselined( true ); } void AccountsTester::cleanup() { delete project; project = 0; t = 0; r = 0; sm = 0; topaccount = 0; } void AccountsTester::defaultAccount() { Account *a = new Account( "Default Account" ); project->accounts().insert( a ); project->accounts().setDefaultAccount( a ); EffortCostMap ec = project->accounts().plannedCost( *a, t->startTime().date(), t->endTime().date() ); qDebug()<startTime()<endTime()<accounts().actualCost( *a, t->startTime().date(), t->endTime().date() ); qDebug()<startTime()<endTime()<completion().setEntrymode( Completion::FollowPlan ); ec = project->accounts().actualCost( *a, t->startTime().date(), t->endTime().date() ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 8.0 ); QCOMPARE( ec.totalCost(), 800.0 ); t->completion().setEntrymode( Completion::EnterCompleted ); ec = project->accounts().actualCost( *a, t->startTime().date(), t->endTime().date() ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 0.0 ); t->completion().setEntrymode( Completion::EnterCompleted ); t->completion().setStarted( true ); t->completion().setStartTime( DateTime( tomorrow, QTime() ) ); t->completion().setPercentFinished( tomorrow, 50 ); ec = project->accounts().actualCost( *a, t->startTime().date(), tomorrow ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 0.0 ); t->completion().setEntrymode( Completion::EnterEffortPerTask ); t->completion().setActualEffort( tomorrow, Duration( 0, 4, 0 ) ); ec = project->accounts().actualCost( *a, t->startTime().date(), tomorrow ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 4.0 ); QCOMPARE( ec.totalCost(), 400.0 ); t->completion().setEntrymode( Completion::EnterEffortPerResource ); Completion::UsedEffort *ue = new Completion::UsedEffort(); Completion::UsedEffort::ActualEffort e( Duration( 0, 6, 0 ) ) ; ue->setEffort( tomorrow, e ); t->completion().addUsedEffort( r, ue ); ec = project->accounts().actualCost( *a, t->startTime().date(), tomorrow ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 6.0 ); QCOMPARE( ec.totalCost(), 600.0 ); } void AccountsTester::costPlaces() { EffortCostMap ec; Account *top = new Account( "Top account" ); project->accounts().insert( top ); Account *a = new Account( "Running account" ); project->accounts().insert( a, top ); a->addRunning( *t ); ec = a->plannedCost( sm->scheduleId() ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 8.0 ); QCOMPARE( ec.totalCost(), 800.0 ); a = new Account( "Startup account" ); project->accounts().insert( a, top ); a->addStartup( *t ); t->setStartupCost( 200.0 ); ec = a->plannedCost( sm->scheduleId() ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 200.0 ); a = new Account( "Shutdown cost" ); project->accounts().insert( a, top ); a->addShutdown( *t ); t->setShutdownCost( 300.0 ); ec = a->plannedCost( sm->scheduleId() ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 300.0 ); ec = top->plannedCost( sm->scheduleId() ); // Debug::print( top, sm->scheduleId(), "All planned cost in child accounts--------" ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 8.0 ); QCOMPARE( ec.totalCost(), 1300.0 ); a = new Account( "All cost in one account" ); project->accounts().insert( a ); a->addRunning( *t ); a->addStartup( *t ); a->addShutdown( *t ); ec = a->plannedCost( sm->scheduleId() ); // Debug::print( a, sm->scheduleId(), "All planned cost in one account-----------" ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 8.0 ); QCOMPARE( ec.totalCost(), 1300.0 ); } void AccountsTester::startupDefault() { Account *a = new Account( "Default Account" ); project->accounts().insert( a ); project->accounts().setDefaultAccount( a ); EffortCostMap ec = project->accounts().plannedCost( *a, t->startTime().date(), t->endTime().date() ); qDebug()<startTime()<endTime()<accounts().actualCost( *a, t->startTime().date(), t->endTime().date() ); qDebug()<startTime()<endTime()<setStartupCost( 25.0 ); ec = project->accounts().plannedCost( *a, t->startTime().date(), t->endTime().date() ); qDebug()<startTime()<endTime()<completion().entryModeToString(); ec = project->accounts().actualCost( *a, t->startTime().date(), t->endTime().date() ); qDebug()<startTime()<endTime()<completion().isStarted() ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 0.0 ); t->completion().setEntrymode( Completion::EnterCompleted ); t->completion().setStarted( true ); t->completion().setStartTime( DateTime( tomorrow, QTime() ) ); t->completion().setPercentFinished( tomorrow, 50 ); QVERIFY( t->completion().isStarted() ); qDebug()<completion().startTime()<<":"<startTime().date()<accounts().actualCost( *a, t->startTime().date(), tomorrow ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 25.0 ); ec = project->accounts().actualCost( *a, QDate(), QDate() ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 25.0 ); t->completion().setEntrymode( Completion::EnterEffortPerTask ); t->completion().setActualEffort( tomorrow, Duration( 0, 4, 0 ) ); ec = project->accounts().actualCost( *a, t->startTime().date(), tomorrow ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 4.0 ); QCOMPARE( ec.totalCost(), 425.0 ); ec = project->accounts().actualCost( *a, QDate(), QDate() ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 4.0 ); QCOMPARE( ec.totalCost(), 425.0 ); } void AccountsTester::startupAccount() { Account *a = new Account( "Account" ); project->accounts().insert( a ); a->addStartup( *t ); // planned wo startup cost EffortCostMap ec = project->accounts().plannedCost( *a, t->startTime().date(), t->endTime().date() ); qDebug()<startTime()<endTime()<accounts().actualCost( *a, t->startTime().date(), t->endTime().date() ); qDebug()<startTime()<endTime()<setStartupCost( 25.0 ); ec = project->accounts().plannedCost( *a, t->startTime().date(), t->endTime().date() ); qDebug()<startTime()<endTime()<accounts().actualCost( *a, t->startTime().date(), t->endTime().date() ); qDebug()<startTime()<endTime()<completion().isStarted() ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 0.0 ); // start task (tomorrow), no actual effort t->completion().setEntrymode( Completion::EnterCompleted ); t->completion().setStarted( true ); t->completion().setStartTime( DateTime( tomorrow, QTime() ) ); QVERIFY( t->completion().isStarted() ); ec = project->accounts().actualCost( *a, tomorrow, tomorrow ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 25.0 ); ec = project->accounts().actualCost( *a, QDate(), QDate() ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 25.0 ); // add actual effort, but no running cost t->completion().setEntrymode( Completion::EnterEffortPerTask ); t->completion().setActualEffort( tomorrow, Duration( 0, 4, 0 ) ); ec = project->accounts().actualCost( *a, t->startTime().date(), tomorrow ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 25.0 ); ec = project->accounts().actualCost( *a, QDate(), QDate() ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 25.0 ); // add running account a->addRunning( *t ); // planned wo startup cost t->completion().setStarted( false ); t->setStartupCost( 0.0 ); ec = project->accounts().plannedCost( *a, t->startTime().date(), t->endTime().date() ); qDebug()<startTime()<endTime()<accounts().actualCost( *a, t->startTime().date(), t->endTime().date() ); qDebug()<startTime()<endTime()<setStartupCost( 25.0 ); ec = project->accounts().plannedCost( *a, t->startTime().date(), t->endTime().date() ); qDebug()<startTime()<endTime()<accounts().actualCost( *a, t->startTime().date(), t->endTime().date() ); qDebug()<startTime()<endTime()<completion().isStarted() ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 0.0 ); // start task (tomorrow), 4h actual effort from before t->completion().setEntrymode( Completion::EnterCompleted ); t->completion().setStarted( true ); t->completion().setStartTime( DateTime( tomorrow, QTime() ) ); QVERIFY( t->completion().isStarted() ); Debug::print( t, "Started tomorrow, 4h actual effort" ); Debug::print( t->completion(), t->name() ); ec = project->accounts().actualCost( *a, tomorrow, tomorrow ); Debug::print( ec ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 4.0 ); QCOMPARE( ec.totalCost(), 425.0 ); ec = project->accounts().actualCost( *a, QDate(), QDate() ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 4.0 ); QCOMPARE( ec.totalCost(), 425.0 ); } void AccountsTester::shutdownAccount() { Account *a = new Account( "Account" ); project->accounts().insert( a ); a->addShutdown( *t ); t->completion().setStarted( true ); t->completion().setStartTime( t->startTime() ); // planned wo shutdown cost EffortCostMap ec = project->accounts().plannedCost( *a, t->startTime().date(), t->endTime().date() ); qDebug()<startTime()<endTime()<accounts().actualCost( *a, t->startTime().date(), t->endTime().date() ); qDebug()<startTime()<endTime()<setShutdownCost( 25.0 ); ec = project->accounts().plannedCost( *a, t->startTime().date(), t->endTime().date() ); qDebug()<startTime()<endTime()<accounts().actualCost( *a, t->startTime().date(), t->endTime().date() ); qDebug()<startTime()<endTime()<completion().isFinished() ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 0.0 ); // finish task (tomorrow), no actual effort t->completion().setEntrymode( Completion::EnterCompleted ); t->completion().setFinished( true ); t->completion().setFinishTime( DateTime( tomorrow, QTime() ) ); QVERIFY( t->completion().isFinished() ); ec = project->accounts().actualCost( *a, tomorrow, tomorrow ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 25.0 ); ec = project->accounts().actualCost( *a, QDate(), QDate() ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 25.0 ); // add actual effort, no running account t->completion().setEntrymode( Completion::EnterEffortPerTask ); t->completion().setActualEffort( tomorrow, Duration( 0, 4, 0 ) ); ec = project->accounts().actualCost( *a, t->startTime().date(), tomorrow ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 25.0 ); ec = project->accounts().actualCost( *a, QDate(), QDate() ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 25.0 ); // add running account a->addRunning( *t ); t->completion().setFinished( false ); t->setShutdownCost( 0.0 ); // planned wo finish cost ec = project->accounts().plannedCost( *a, t->startTime().date(), t->endTime().date() ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 8.0 ); QCOMPARE( ec.totalCost(), 800.0 ); ec = project->accounts().actualCost( *a, t->startTime().date(), t->endTime().date() ); Debug::print( t, "planned wo finish cost, with running", true ); Debug::print( t->completion(), t->name() ); Debug::print( ec ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 0.0 ); // planned with startup cost t->setShutdownCost( 25.0 ); ec = project->accounts().plannedCost( *a, t->startTime().date(), t->endTime().date() ); qDebug()<startTime()<endTime()<accounts().actualCost( *a, t->startTime().date(), t->endTime().date() ); qDebug()<startTime()<endTime()<completion().isFinished() ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 0.0 ); // finish task (tomorrow), 4h actual effort from before t->completion().setEntrymode( Completion::EnterCompleted ); t->completion().setFinished( true ); t->completion().setFinishTime( DateTime( tomorrow, QTime() ) ); QVERIFY( t->completion().isFinished() ); ec = project->accounts().actualCost( *a, tomorrow, tomorrow ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 4.0 ); QCOMPARE( ec.totalCost(), 425.0 ); ec = project->accounts().actualCost( *a, QDate(), QDate() ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 4.0 ); QCOMPARE( ec.totalCost(), 425.0 ); } void AccountsTester::subaccounts() { Account *a1 = new Account( "Account" ); project->accounts().insert( a1 ); Account *a2 = new Account( "Sub-Account" ); project->accounts().insert( a2, a1 ); project->accounts().setDefaultAccount( a2 ); EffortCostMap ec = project->accounts().plannedCost( *a2 ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 8.0 ); QCOMPARE( ec.totalCost(), 800.0 ); ec = project->accounts().plannedCost( *a1 ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 8.0 ); QCOMPARE( ec.totalCost(), 800.0 ); ec = project->accounts().actualCost( *a2 ); qDebug()<startTime()<endTime()<accounts().actualCost( *a1 ); qDebug()<startTime()<endTime()<completion().setEntrymode( Completion::FollowPlan ); ec = project->accounts().actualCost( *a2 ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 8.0 ); QCOMPARE( ec.totalCost(), 800.0 ); ec = project->accounts().actualCost( *a1 ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 8.0 ); QCOMPARE( ec.totalCost(), 800.0 ); t->completion().setEntrymode( Completion::EnterCompleted ); ec = project->accounts().actualCost( *a2 ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 0.0 ); ec = project->accounts().actualCost( *a1 ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 0.0 ); t->completion().setEntrymode( Completion::EnterEffortPerTask ); t->completion().setStarted( true ); t->completion().setStartTime( DateTime( tomorrow, QTime() ) ); t->completion().setPercentFinished( tomorrow, 50 ); t->completion().setActualEffort( tomorrow, Duration( 0, 4, 0 ) ); ec = project->accounts().actualCost( *a2 ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 4.0 ); QCOMPARE( ec.totalCost(), 400.0 ); ec = project->accounts().actualCost( *a1 ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 4.0 ); QCOMPARE( ec.totalCost(), 400.0 ); t->setStartupCost( 25.0 ); a1->addStartup( *t ); ec = project->accounts().actualCost( *a2 ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 4.0 ); QCOMPARE( ec.totalCost(), 400.0 ); ec = project->accounts().actualCost( *a1 ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 4.0 ); QCOMPARE( ec.totalCost(), 425.0 ); project->accounts().setDefaultAccount( a1 ); ec = project->accounts().plannedCost( *a2 ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 0.0 ); ec = project->accounts().plannedCost( *a1 ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 8.0 ); QCOMPARE( ec.totalCost(), 825.0 ); ec = project->accounts().actualCost( *a2 ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 0.0 ); ec = project->accounts().actualCost( *a1 ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 4.0 ); QCOMPARE( ec.totalCost(), 425.0 ); t->setShutdownCost( 1.0 ); a2->addShutdown( *t ); ec = project->accounts().plannedCost( *a2 ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 1.0 ); ec = project->accounts().plannedCost( *a1 ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 8.0 ); QCOMPARE( ec.totalCost(), 826.0 ); t->completion().setFinished( true ); t->completion().setFinishTime( DateTime( tomorrow, QTime() ) ); ec = project->accounts().actualCost( *a2 ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 0.0 ); QCOMPARE( ec.totalCost(), 1.0 ); ec = project->accounts().actualCost( *a1 ); QCOMPARE( ec.totalEffort().toDouble( Duration::Unit_h ), 4.0 ); QCOMPARE( ec.totalCost(), 426.0 ); } +void AccountsTester::deleteAccount() +{ + QVERIFY(project->accounts().allAccounts().isEmpty()); + + qInfo()<<"Add/delete one account"; + Account *a1 = new Account( "Account" ); + project->accounts().insert( a1 ); + + QCOMPARE(project->accounts().allAccounts().count(), 1); + QCOMPARE(project->accounts().allAccounts().first(), a1); + + delete a1; + QVERIFY(project->accounts().allAccounts().isEmpty()); + + qInfo()<<"Add/delete one account with one sub-account"; + a1 = new Account( "Account 1" ); + project->accounts().insert( a1 ); + Account *a2 = new Account( "Account 1.1" ); + project->accounts().insert(a2, a1); + QCOMPARE(project->accounts().allAccounts().count(), 2); + + qInfo()<<"Delete top account"; + delete a1; + QVERIFY(project->accounts().allAccounts().isEmpty()); + + qInfo()<<"Add/delete one account with one sub-account"; + a1 = new Account( "Account 1" ); + project->accounts().insert( a1 ); + a2 = new Account( "Account 1.1" ); + project->accounts().insert(a2, a1); + project->accounts().setDefaultAccount(a2); + QCOMPARE(project->accounts().allAccounts().count(), 2); + + qInfo()<<"Delete sub account"; + delete a2; + QVERIFY(project->accounts().defaultAccount() == 0); + QCOMPARE(project->accounts().allAccounts().count(), 1); + + qInfo()<<"Delete top account"; + delete a1; + QVERIFY(project->accounts().allAccounts().isEmpty()); +} + } //namespace KPlato QTEST_GUILESS_MAIN( KPlato::AccountsTester ) diff --git a/plan/libs/kernel/tests/AccountsTester.h b/plan/libs/kernel/tests/AccountsTester.h index b09cf21e490..74483f6d399 100644 --- a/plan/libs/kernel/tests/AccountsTester.h +++ b/plan/libs/kernel/tests/AccountsTester.h @@ -1,64 +1,66 @@ /* This file is part of the KDE project Copyright (C) 2008 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 KPlato_AccountsTester_h #define KPlato_AccountsTester_h #include "kptproject.h" namespace KPlato { class Task; class AccountsTester : public QObject { Q_OBJECT private Q_SLOTS: void init(); void cleanup(); void defaultAccount(); void costPlaces(); void startupDefault(); void startupAccount(); void shutdownAccount(); void subaccounts(); + void deleteAccount(); + private: Project *project; Task *t; Resource *r; ScheduleManager *sm; Account *topaccount; QDate today; QDate tomorrow; QDate yesterday; QDate nextweek; QTime t1; QTime t2; int length; }; } #endif diff --git a/plan/libs/kernel/tests/CMakeLists.txt b/plan/libs/kernel/tests/CMakeLists.txt index f31c72d52b7..1e4bd01889d 100644 --- a/plan/libs/kernel/tests/CMakeLists.txt +++ b/plan/libs/kernel/tests/CMakeLists.txt @@ -1,63 +1,67 @@ set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) include_directories( .. ${CMAKE_SOURCE_DIR}/libs/widgetutils ${KOODF_INCLUDES} ${KUNDO2_INCLUDES} ) # call: plankernel_add_unit_test( LINK_LIBRARIES [ [...]] [GUI]) macro(PLANKERNEL_ADD_UNIT_TEST _TEST_NAME) ecm_add_test( ${ARGN} TEST_NAME "${_TEST_NAME}" NAME_PREFIX "plan-kernel-" ) endmacro() ########### next target ############### plankernel_add_unit_test(DateTimeTester DateTimeTester.cpp LINK_LIBRARIES kplatokernel Qt5::Test) ########## next target ############### plankernel_add_unit_test(DurationTester DurationTester.cpp LINK_LIBRARIES kplatokernel Qt5::Test) ########## next target ############### plankernel_add_unit_test(AppointmentIntervalTester AppointmentIntervalTester.cpp LINK_LIBRARIES kplatokernel Qt5::Test) ########## next target ############### plankernel_add_unit_test(EstimateTester EstimateTester.cpp LINK_LIBRARIES kplatokernel Qt5::Test) ########### next target ############### plankernel_add_unit_test(CalendarTester CalendarTester.cpp LINK_LIBRARIES kplatokernel Qt5::Test) ########## next target ############### plankernel_add_unit_test(ResourceTester ResourceTester.cpp LINK_LIBRARIES kplatokernel kundo2 koodf Qt5::Test) ########### next target ############### plankernel_add_unit_test(ScheduleTester ScheduleTester.cpp LINK_LIBRARIES kplatokernel Qt5::Test) ########### next target ############### plankernel_add_unit_test(ProjectTester ProjectTester.cpp LINK_LIBRARIES planprivate kplatokernel Qt5::Test) ########### next target ############### plankernel_add_unit_test(AccountsTester AccountsTester.cpp LINK_LIBRARIES planprivate kplatokernel Qt5::Test) ########### next target ############### +plankernel_add_unit_test(AccountsCommandTester AccountsCommandTester.cpp LINK_LIBRARIES kplatokernel komain Qt5::Test) + +########### next target ############### + plankernel_add_unit_test(PerformanceTester PerformanceTester.cpp LINK_LIBRARIES planprivate kplatokernel Qt5::Test) ########### next target ############### plankernel_add_unit_test(CommandsTester CommandsTester.cpp LINK_LIBRARIES planprivate kplatokernel kundo2 Qt5::Test) ########### next target ############### plankernel_add_unit_test(WorkInfoCacheTester WorkInfoCacheTester.cpp LINK_LIBRARIES planprivate kplatokernel Qt5::Test) diff --git a/plan/libs/models/kptnodeitemmodel.cpp b/plan/libs/models/kptnodeitemmodel.cpp index 17c485dc0a6..9a202363346 100644 --- a/plan/libs/models/kptnodeitemmodel.cpp +++ b/plan/libs/models/kptnodeitemmodel.cpp @@ -1,5197 +1,5206 @@ /* This file is part of the KDE project Copyright (C) 2007 - 2009, 2012 Dag Andersen Copyright (C) 2016 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 "kptnodeitemmodel.h" #include "kptglobal.h" #include "kptlocale.h" #include "kptcommonstrings.h" #include "kptcommand.h" #include "kptduration.h" #include "kptproject.h" #include "kptnode.h" #include "kpttaskcompletedelegate.h" #include "kptxmlloaderobject.h" #include "kptdebug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KPlato { //-------------------------------------- NodeModel::NodeModel() : QObject(), m_project( 0 ), m_manager( 0 ), m_now( QDate::currentDate() ), m_prec( 1 ) { } const QMetaEnum NodeModel::columnMap() const { return metaObject()->enumerator( metaObject()->indexOfEnumerator("Properties") ); } void NodeModel::setProject( Project *project ) { debugPlan<"<"<name(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Qt::DecorationRole: if ( node->isBaselined() ) { return koIcon("view-time-schedule-baselined"); } break; case Role::Foreground: { if ( ! m_project ) { break; } switch ( node->type() ) { case Node::Type_Task: return static_cast( node )->completion().isFinished() ? m_project->config().taskFinishedColor() : m_project->config().taskNormalColor(); case Node::Type_Milestone: return static_cast( node )->completion().isFinished() ? m_project->config().milestoneFinishedColor() : m_project->config().milestoneNormalColor(); case Node::Type_Summarytask: return m_project->config().summaryTaskLevelColor( node->level() ); default: break; } break; } } return QVariant(); } QVariant NodeModel::leader( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: case Qt::ToolTipRole: return node->leader(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::allocation( const Node *node, int role ) const { if ( node->type() == Node::Type_Task ) { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return node->requests().requestNameList().join( "," ); case Qt::ToolTipRole: { QMap lst; foreach ( ResourceRequest *rr, node->requests().resourceRequests( false ) ) { QStringList sl; foreach( Resource *r, rr->requiredResources() ) { sl << r->name(); } lst.insert( rr->resource()->name(), sl ); } if ( lst.isEmpty() ) { return xi18nc( "@info:tooltip", "No resources has been allocated" ); } QStringList sl; for ( QMap::ConstIterator it = lst.constBegin(); it != lst.constEnd(); ++it ) { if ( it.value().isEmpty() ) { sl << it.key(); } else { sl << xi18nc( "@info:tooltip 1=resource name, 2=list of required resources", "%1 (%2)", it.key(), it.value().join(", ") ); } } if ( sl.count() == 1 ) { return xi18nc( "@info:tooltip 1=resource name", "Allocated resource:%1", sl.first() ); } return xi18nc( "@info:tooltip 1=list of resources", "Allocated resources:%1", sl.join( "" ) ); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } } return QVariant(); } QVariant NodeModel::description( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: { KRichTextWidget w( node->description(), 0 ); w.switchToPlainText(); QString s = w.textOrHtml(); int i = s.indexOf( '\n' ); s = s.left( i ); if ( i > 0 ) { s += "..."; } return s; } case Qt::ToolTipRole: { KRichTextWidget w( node->description(), 0 ); w.switchToPlainText(); if ( w.textOrHtml().isEmpty() ) { return QVariant(); } return node->description(); } case Qt::EditRole: return node->description(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::type( const Node *node, int role ) const { //debugPlan<name()<<", "<typeToString( true ); case Qt::EditRole: return node->type(); case Qt::TextAlignmentRole: return (int)(Qt::AlignLeft|Qt::AlignVCenter); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::constraint( const Node *node, int role ) const { if ( node->type() == Node::Type_Project ) { switch ( role ) { case Qt::DisplayRole: return i18n( "Target times" ); case Qt::ToolTipRole: return xi18nc( "@info:tooltip", "Earliest start and latest finish" ); case Role::EnumList: case Qt::EditRole: case Role::EnumListValue: return QVariant(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } } else if ( node->type() != Node::Type_Summarytask ) { switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: return node->constraintToString( true ); case Role::EnumList: return Node::constraintList( true ); case Qt::EditRole: return node->constraint(); case Role::EnumListValue: return (int)node->constraint(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } } return QVariant(); } QVariant NodeModel::constraintStartTime( const Node *node, int role ) const { if ( node->type() == Node::Type_Project ) { switch ( role ) { case Qt::DisplayRole: { return QLocale().toString( node->constraintStartTime(), QLocale::ShortFormat ); } case Qt::ToolTipRole: { return QLocale().toString( node->constraintStartTime(), QLocale::LongFormat ); } case Qt::EditRole: return node->constraintStartTime(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } else if ( node->type() != Node::Type_Summarytask ) { switch ( role ) { case Qt::DisplayRole: { QString s = QLocale().toString( node->constraintStartTime(), QLocale::ShortFormat ); switch ( node->constraint() ) { case Node::StartNotEarlier: case Node::MustStartOn: case Node::FixedInterval: return s; default: break; } return QString( "(%1)" ).arg( s ); } case Qt::ToolTipRole: { int c = node->constraint(); if ( c == Node::MustStartOn || c == Node::StartNotEarlier || c == Node::FixedInterval ) { return QLocale().toString( node->constraintStartTime(), QLocale::LongFormat ); } break; } case Qt::EditRole: return node->constraintStartTime(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } } return QVariant(); } QVariant NodeModel::constraintEndTime( const Node *node, int role ) const { if ( node->type() == Node::Type_Project ) { switch ( role ) { case Qt::DisplayRole: { return QLocale().toString( node->constraintEndTime(), QLocale::ShortFormat ); } case Qt::ToolTipRole: { return QLocale().toString( node->constraintEndTime(), QLocale::LongFormat ); } case Qt::EditRole: return node->constraintEndTime(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } else if ( node->type() != Node::Type_Summarytask ) { switch ( role ) { case Qt::DisplayRole: { QString s = QLocale().toString( node->constraintEndTime(), QLocale::ShortFormat ); switch ( node->constraint() ) { case Node::FinishNotLater: case Node::MustFinishOn: case Node::FixedInterval: return s; default: break; } return QString( "(%1)" ).arg( s ); } case Qt::ToolTipRole: { int c = node->constraint(); if ( c == Node::FinishNotLater || c == Node::MustFinishOn || c == Node::FixedInterval ) { return QLocale().toString( node->constraintEndTime(), QLocale::LongFormat ); } break; } case Qt::EditRole: return node->constraintEndTime(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } } return QVariant(); } QVariant NodeModel::estimateType( const Node *node, int role ) const { if ( node->estimate() == 0 ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: if ( node->type() == Node::Type_Task ) { return node->estimate()->typeToString( true ); } return QString(); case Role::EnumList: return Estimate::typeToStringList( true ); case Qt::EditRole: if ( node->type() == Node::Type_Task ) { return node->estimate()->typeToString(); } return QString(); case Role::EnumListValue: return (int)node->estimate()->type(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::estimateCalendar( const Node *node, int role ) const { if ( node->estimate() == 0 ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: if ( node->type() == Node::Type_Task ) { if ( node->estimate()->calendar() ) { return node->estimate()->calendar()->name(); } return i18n( "None" ); } return QString(); case Qt::ToolTipRole: if ( node->type() == Node::Type_Task ) { if ( node->estimate()->type() == Estimate::Type_Effort ) { return xi18nc( "@info:tooltip", "Not applicable, estimate type is Effort" ); } if ( node->estimate()->calendar() ) { return node->estimate()->calendar()->name(); } return QVariant(); } return QString(); case Role::EnumList: { QStringList lst; lst << i18n( "None" ); const Node *n = const_cast( node )->projectNode(); if ( n ) { lst += static_cast( n )->calendarNames(); } return lst; } case Qt::EditRole: if ( node->type() == Node::Type_Task ) { if ( node->estimate()->calendar() == 0 ) { return i18n( "None" ); } return node->estimate()->calendar()->name(); } return QString(); case Role::EnumListValue: { if ( node->estimate()->calendar() == 0 ) { return 0; } QStringList lst; const Node *n = const_cast( node )->projectNode(); if ( n ) { lst = static_cast( n )->calendarNames(); } return lst.indexOf( node->estimate()->calendar()->name() ) + 1; } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::estimate( const Node *node, int role ) const { if ( node->estimate() == 0 ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: if ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) { Duration::Unit unit = node->estimate()->unit(); QString s = QLocale().toString( node->estimate()->expectedEstimate(), 'f', m_prec ) + Duration::unitToString( unit, true ); if ( node->constraint() == Node::FixedInterval && node->estimate()->type() == Estimate::Type_Duration ) { s = '(' + s + ')'; } return s; } break; case Qt::ToolTipRole: if ( node->type() == Node::Type_Task ) { Duration::Unit unit = node->estimate()->unit(); QString s = QLocale().toString( node->estimate()->expectedEstimate(), 'f', m_prec ) + Duration::unitToString( unit, true ); Estimate::Type t = node->estimate()->type(); if ( node->constraint() == Node::FixedInterval && t == Estimate::Type_Duration ) { s = xi18nc( "@info:tooltip", "Not applicable, constraint is Fixed Interval" ); } else if ( t == Estimate::Type_Effort ) { s = xi18nc( "@info:tooltip", "Estimated effort: %1", s ); } else { s = xi18nc( "@info:tooltip", "Estimated duration: %1", s ); } return s; } break; case Qt::EditRole: return node->estimate()->expectedEstimate(); case Role::DurationUnit: return static_cast( node->estimate()->unit() ); case Role::Minimum: return m_project->config().minimumDurationUnit(); case Role::Maximum: return m_project->config().maximumDurationUnit(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::optimisticRatio( const Node *node, int role ) const { if ( node->estimate() == 0 || node->type() == Node::Type_Summarytask || node->type() == Node::Type_Milestone ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: if ( node->type() == Node::Type_Task && node->constraint() == Node::FixedInterval && node->estimate()->type() == Estimate::Type_Duration ) { QString s = QString::number( node->estimate()->optimisticRatio() ); s = '(' + s + ')'; return s; } if ( node->estimate() ) { return node->estimate()->optimisticRatio(); } break; case Qt::EditRole: if ( node->estimate() ) { return node->estimate()->optimisticRatio(); } break; case Qt::ToolTipRole: if ( node->type() == Node::Type_Task ) { Duration::Unit unit = node->estimate()->unit(); QString s = QLocale().toString( node->estimate()->optimisticEstimate(), 'f', m_prec ) + Duration::unitToString( unit, true ); Estimate::Type t = node->estimate()->type(); if ( node->constraint() == Node::FixedInterval && t == Estimate::Type_Duration ) { s = xi18nc( "@info:tooltip", "Not applicable, constraint is Fixed Interval" ); } else if ( t == Estimate::Type_Effort ) { s = xi18nc( "@info:tooltip", "Optimistic effort: %1", s ); } else { s = xi18nc( "@info:tooltip", "Optimistic duration: %1", s ); } return s; } break; case Role::Minimum: return -99; case Role::Maximum: return 0; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::pessimisticRatio( const Node *node, int role ) const { if ( node->estimate() == 0 || node->type() == Node::Type_Summarytask || node->type() == Node::Type_Milestone ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: if ( node->type() == Node::Type_Task && node->constraint() == Node::FixedInterval && node->estimate()->type() == Estimate::Type_Duration ) { QString s = QString::number( node->estimate()->pessimisticRatio() ); s = '(' + s + ')'; return s; } if ( node->estimate() ) { return node->estimate()->pessimisticRatio(); } break; case Qt::EditRole: if ( node->estimate() ) { return node->estimate()->pessimisticRatio(); } break; case Qt::ToolTipRole: if ( node->type() == Node::Type_Task ) { Duration::Unit unit = node->estimate()->unit(); QString s = QLocale().toString( node->estimate()->pessimisticEstimate(), 'f', m_prec ) + Duration::unitToString( unit, true ); Estimate::Type t = node->estimate()->type(); if ( node->constraint() == Node::FixedInterval && t == Estimate::Type_Duration ) { s = xi18nc( "@info:tooltip", "Not applicable, constraint is Fixed Interval" ); } else if ( t == Estimate::Type_Effort ) { s = xi18nc( "@info:tooltip", "Pessimistic effort: %1", s ); } else { s = xi18nc( "@info:tooltip", "Pessimistic duration: %1", s ); } return s; } break; case Role::Minimum: return 0; case Role::Maximum: return INT_MAX; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::riskType( const Node *node, int role ) const { if ( node->estimate() == 0 ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: if ( node->type() == Node::Type_Task ) { return node->estimate()->risktypeToString( true ); } return QString(); case Role::EnumList: return Estimate::risktypeToStringList( true ); case Qt::EditRole: if ( node->type() == Node::Type_Task ) { return node->estimate()->risktypeToString(); } return QString(); case Role::EnumListValue: return (int)node->estimate()->risktype(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::runningAccount( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( node->type() == Node::Type_Task ) { Account *a = node->runningAccount(); return a == 0 ? i18n( "None" ) : a->name(); } break; case Qt::ToolTipRole: if ( node->type() == Node::Type_Task ) { Account *a = node->runningAccount(); return a ? xi18nc( "@info:tooltip", "Account for resource cost: %1", a->name() ) : xi18nc( "@info:tooltip", "Account for resource cost" ); } break; case Role::EnumListValue: case Qt::EditRole: { Account *a = node->runningAccount(); return a == 0 ? 0 : ( m_project->accounts().costElements().indexOf( a->name() ) + 1 ); } case Role::EnumList: { QStringList lst; lst << i18n("None"); lst += m_project->accounts().costElements(); return lst; } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::startupAccount( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) { Account *a = node->startupAccount(); //debugPlan<name()<<": "<name(); } break; case Qt::ToolTipRole: if ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) { Account *a = node->startupAccount(); //debugPlan<name()<<": "<name() ) : xi18nc( "@info:tooltip", "Account for task startup cost" ); } break; case Role::EnumListValue: case Qt::EditRole: { Account *a = node->startupAccount(); return a == 0 ? 0 : ( m_project->accounts().costElements().indexOf( a->name() ) + 1 ); } case Role::EnumList: { QStringList lst; lst << i18n("None"); lst += m_project->accounts().costElements(); return lst; } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::startupCost( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: if ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) { return m_project->locale()->formatMoney( node->startupCost() ); } break; case Qt::EditRole: return node->startupCost(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::shutdownAccount( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) { Account *a = node->shutdownAccount(); return a == 0 ? i18n( "None" ) : a->name(); } break; case Qt::ToolTipRole: if ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) { Account *a = node->shutdownAccount(); return a ? xi18nc( "@info:tooltip", "Account for task shutdown cost: %1", a->name() ) : xi18nc( "@info:tooltip", "Account for task shutdown cost" ); } break; case Role::EnumListValue: case Qt::EditRole: { Account *a = node->shutdownAccount(); return a == 0 ? 0 : ( m_project->accounts().costElements().indexOf( a->name() ) + 1 ); } case Role::EnumList: { QStringList lst; lst << i18n("None"); lst += m_project->accounts().costElements(); return lst; } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::shutdownCost( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: if ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) { return m_project->locale()->formatMoney( node->shutdownCost() ); } break; case Qt::EditRole: return node->shutdownCost(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::startTime( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return QLocale().toString( node->startTime( id() ), QLocale::ShortFormat ); case Qt::ToolTipRole: //debugPlan<name()<<", "<startTime( id() ), QLocale::LongFormat ) ); case Qt::EditRole: return node->startTime( id() ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::endTime( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return QLocale().toString( node->endTime( id() ), QLocale::ShortFormat ); case Qt::ToolTipRole: //debugPlan<name()<<", "<endTime( id() ), QLocale::LongFormat ) ); case Qt::EditRole: return node->endTime( id() ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::duration( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( node->type() == Node::Type_Task ) { Duration::Unit unit = node->estimate()->unit(); double v = node->duration( id() ).toDouble( unit ); return QVariant(QLocale().toString( v, 'f', m_prec ) + Duration::unitToString( unit, true )); } else if ( node->type() == Node::Type_Project ) { Duration::Unit unit = Duration::Unit_d; double v = node->duration( id() ).toDouble( unit ); return QVariant(QLocale().toString( v, 'f', m_prec ) + Duration::unitToString( unit, true )); } break; case Qt::ToolTipRole: if ( node->type() == Node::Type_Task ) { Duration::Unit unit = node->estimate()->unit(); double v = node->duration( id() ).toDouble( unit ); return xi18nc( "@info:tooltip", "Scheduled duration: %1", QLocale().toString( v, 'f', m_prec ) + Duration::unitToString( unit, true ) ); } else if ( node->type() == Node::Type_Project ) { Duration::Unit unit = Duration::Unit_d; double v = node->duration( id() ).toDouble( unit ); return xi18nc( "@info:tooltip", "Scheduled duration: %1", QLocale().toString( v, 'f', m_prec ) + Duration::unitToString( unit, true ) ); } break; case Qt::EditRole: { return node->duration( id() ).toDouble( Duration::Unit_h ); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::varianceDuration( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( node->type() == Node::Type_Task ) { Duration::Unit unit = node->estimate()->unit(); double v = node->variance( id(), unit ); return QLocale().toString( v, 'f', 2 ); } break; case Qt::EditRole: if ( node->type() == Node::Type_Task ) { Duration::Unit unit = node->estimate()->unit(); return node->variance( id(), unit ); } return 0.0; case Qt::ToolTipRole: if ( node->type() == Node::Type_Task ) { Duration::Unit unit = node->estimate()->unit(); double v = node->variance( id(), unit ); return xi18nc( "@info:tooltip", "PERT duration variance: %1", QLocale().toString( v ,'f', 2 ) ); } break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::varianceEstimate( const Estimate *est, int role ) const { switch ( role ) { case Qt::DisplayRole: { if ( est == 0 ) { return QVariant(); } Duration::Unit unit = est->unit(); double v = est->variance( unit ); //debugPlan<name()<<": "<variance( est->unit() ); } case Qt::ToolTipRole: { if ( est == 0 ) { return QVariant(); } Duration::Unit unit = est->unit(); double v = est->variance( unit ); return xi18nc( "@info:tooltip", "PERT estimate variance: %1", QLocale().toString( v, 'f', 2 ) + Duration::unitToString( unit, true ) ); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::optimisticDuration( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: { if ( node->type() != Node::Type_Task ) { return QVariant(); } Duration d = node->duration( id() ); d = ( d * ( 100 + node->estimate()->optimisticRatio() ) ) / 100; Duration::Unit unit = node->estimate()->unit(); double v = d.toDouble( unit ); //debugPlan<name()<<": "<type() != Node::Type_Task ) { return 0.0; } Duration d = node->duration( id() ); d = ( d * ( 100 + node->estimate()->optimisticRatio() ) ) / 100; Duration::Unit unit = node->estimate()->unit(); return d.toDouble( unit ); } case Qt::ToolTipRole: { if ( node->type() != Node::Type_Task ) { return QVariant(); } Duration d = node->duration( id() ); d = ( d * ( 100 + node->estimate()->optimisticRatio() ) ) / 100; Duration::Unit unit = node->estimate()->unit(); double v = d.toDouble( unit ); //debugPlan<name()<<": "<unit(); return QVariant(QLocale().toString( est->optimisticEstimate(), 'f', m_prec ) + Duration::unitToString( unit, true )); break; } case Qt::EditRole: { if ( est == 0 ) { return 0.0; } return est->optimisticEstimate(); } case Qt::ToolTipRole: { if ( est == 0 ) { return QVariant(); } Duration::Unit unit = est->unit(); return xi18nc( "@info:tooltip", "Optimistic estimate: %1", QLocale().toString( est->optimisticEstimate(), 'f', m_prec ) + Duration::unitToString( unit, true ) ); break; } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::pertExpected( const Estimate *est, int role ) const { switch ( role ) { case Qt::DisplayRole: { if ( est == 0 ) { return QVariant(); } Duration::Unit unit = est->unit(); double v = Estimate::scale( est->pertExpected(), unit, est->scales() ); return QVariant(QLocale().toString( v, 'f', m_prec ) + Duration::unitToString( unit, true )); } case Qt::EditRole: { if ( est == 0 ) { return 0.0; } return Estimate::scale( est->pertExpected(), est->unit(), est->scales() ); } case Qt::ToolTipRole: { if ( est == 0 ) { return QVariant(); } Duration::Unit unit = est->unit(); double v = Estimate::scale( est->pertExpected(), unit, est->scales() ); return xi18nc( "@info:tooltip", "PERT expected estimate: %1", QLocale().toString( v, 'f', m_prec ) + Duration::unitToString( unit, true ) ); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::pessimisticDuration( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: { if ( node->type() != Node::Type_Task ) { return QVariant(); } Duration d = node->duration( id() ); d = ( d * ( 100 + node->estimate()->pessimisticRatio() ) ) / 100; Duration::Unit unit = node->estimate()->unit(); double v = d.toDouble( unit ); //debugPlan<name()<<": "<type() != Node::Type_Task ) { return 0.0; } Duration d = node->duration( id() ); d = ( d * ( 100 + node->estimate()->pessimisticRatio() ) ) / 100; return d.toDouble( node->estimate()->unit() ); } case Qt::ToolTipRole: { if ( node->type() != Node::Type_Task ) { return QVariant(); } Duration d = node->duration( id() ); d = ( d * ( 100 + node->estimate()->pessimisticRatio() ) ) / 100; Duration::Unit unit = node->estimate()->unit(); double v = d.toDouble( unit ); //debugPlan<name()<<": "<unit(); return QVariant(QLocale().toString( est->pessimisticEstimate(), 'f', m_prec ) + Duration::unitToString( unit, true )); break; } case Qt::EditRole: { if ( est == 0 ) { return 0.0; } return est->pessimisticEstimate(); } case Qt::ToolTipRole: { if ( est == 0 ) { return QVariant(); } Duration::Unit unit = est->unit(); return xi18nc( "@info:tooltip", "Pessimistic estimate: %1", QLocale().toString( est->pessimisticEstimate(), 'f', m_prec ) + Duration::unitToString( unit, true ) ); break; } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::earlyStart( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: return QLocale().toString( t->earlyStart( id() ), QLocale::ShortFormat ); case Qt::ToolTipRole: return QLocale().toString( t->earlyStart( id() ).date(), QLocale::ShortFormat ); case Qt::EditRole: return t->earlyStart( id() ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::earlyFinish( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: return QLocale().toString( t->earlyFinish( id() ), QLocale::ShortFormat ); case Qt::ToolTipRole: return QLocale().toString( t->earlyFinish( id() ).date(), QLocale::ShortFormat ); case Qt::EditRole: return t->earlyFinish( id() ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::lateStart( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: return QLocale().toString( t->lateStart( id() ), QLocale::ShortFormat ); case Qt::ToolTipRole: return QLocale().toString( t->lateStart( id() ).date(), QLocale::ShortFormat ); case Qt::EditRole: return t->lateStart( id() ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::lateFinish( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: return QLocale().toString( t->lateFinish( id() ), QLocale::ShortFormat ); case Qt::ToolTipRole: return QLocale().toString( t->lateFinish( id() ).date(), QLocale::ShortFormat ); case Qt::EditRole: return t->lateFinish( id() ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::positiveFloat( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: return t->positiveFloat( id() ).toString( Duration::Format_i18nHourFraction ); case Qt::ToolTipRole: return t->positiveFloat( id() ).toString( Duration::Format_i18nDayTime ); case Qt::EditRole: return t->positiveFloat( id() ).toDouble( Duration::Unit_h ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::freeFloat( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: return t->freeFloat( id() ).toString( Duration::Format_i18nHourFraction ); case Qt::ToolTipRole: return t->freeFloat( id() ).toString( Duration::Format_i18nDayTime ); case Qt::EditRole: return t->freeFloat( id() ).toDouble( Duration::Unit_h ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::negativeFloat( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: return t->negativeFloat( id() ).toString( Duration::Format_i18nHourFraction ); case Qt::ToolTipRole: return t->negativeFloat( id() ).toString( Duration::Format_i18nDayTime ); case Qt::EditRole: return t->negativeFloat( id() ).toDouble( Duration::Unit_h ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::startFloat( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: return t->startFloat( id() ).toString( Duration::Format_i18nHourFraction ); case Qt::ToolTipRole: return t->startFloat( id() ).toString( Duration::Format_i18nDayTime ); case Qt::EditRole: return t->startFloat( id() ).toDouble( Duration::Unit_h ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::finishFloat( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: return t->finishFloat( id() ).toString( Duration::Format_i18nHourFraction ); case Qt::ToolTipRole: return t->finishFloat( id() ).toString( Duration::Format_i18nDayTime ); case Qt::EditRole: return t->finishFloat( id() ).toDouble( Duration::Unit_h ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::assignedResources( const Node *node, int role ) const { if ( node->type() != Node::Type_Task ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return node->assignedNameList( id() ).join(","); case Qt::ToolTipRole: { QStringList lst = node->assignedNameList( id() ); if ( ! lst.isEmpty() ) { return xi18nc( "@info:tooltip 1=list of resources", "Assigned resources:%1", node->assignedNameList( id() ).join("") ); } break; } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::completed( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: return t->completion().percentFinished(); case Qt::EditRole: return t->completion().percentFinished(); case Qt::ToolTipRole: return xi18nc( "@info:tooltip", "Task is %1% completed", t->completion().percentFinished() ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::status( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: { int st = t->state( id() ); if ( st & Node::State_NotScheduled ) { return SchedulingState::notScheduled(); } if ( st & Node::State_Finished ) { if ( st & Node::State_FinishedLate ) { return i18n( "Finished late" ); } if ( st & Node::State_FinishedEarly ) { return i18n( "Finished early" ); } return i18n( "Finished" ); } if ( st & Node::State_Running ) { if ( st & Node::State_Late ) { return i18n( "Running late" ); } return i18n( "Running" ); } if ( st & Node::State_Started ) { if ( st & Node::State_StartedLate ) { return i18n( "Started late" ); } if ( st & Node::State_StartedEarly ) { return i18n( "Started early" ); } if ( st & Node::State_Late ) { return i18n( "Running late" ); } return i18n( "Started" ); } if ( st & Node::State_ReadyToStart ) { if ( st & Node::State_Late ) { return i18n( "Not started" ); } return i18n( "Can start" ); } if ( st & Node::State_NotReadyToStart ) { if ( st & Node::State_Late ) { return i18n( "Delayed" ); } return i18n( "Cannot start" ); } return i18n( "Not started" ); break; } case Qt::ToolTipRole: { int st = t->state( id() ); if ( st & Node::State_NotScheduled ) { return SchedulingState::notScheduled(); } if ( st & Node::State_Finished ) { if ( st & Node::State_FinishedLate ) { Duration d = t->completion().finishTime() - t->endTime( id() ); return xi18nc( "@info:tooltip", "Finished %1 late", d.toString( Duration::Format_i18nDay ) ); } if ( st & Node::State_FinishedEarly ) { Duration d = t->endTime( id() ) - t->completion().finishTime(); return xi18nc( "@info:tooltip", "Finished %1 early", d.toString( Duration::Format_i18nDay ) ); } return xi18nc( "@info:tooltip", "Finished" ); } if ( st & Node::State_Started ) { if ( st & Node::State_StartedLate ) { Duration d = t->completion().startTime() - t->startTime( id() ); return xi18nc( "@info:tooltip", "Started %1 late", d.toString( Duration::Format_i18nDay ) ); } if ( st & Node::State_StartedEarly ) { Duration d = t->startTime( id() ) - t->completion().startTime(); return xi18nc( "@info:tooltip", "Started %1 early", d.toString( Duration::Format_i18nDay ) ); } return xi18nc( "@info:tooltip", "Started" ); } if ( st & Node::State_Running ) { return xi18nc( "@info:tooltip", "Running" ); } if ( st & Node::State_ReadyToStart ) { return xi18nc( "@info:tooltip", "Can start" ); } if ( st & Node::State_NotReadyToStart ) { QStringList names; // TODO: proxy relations foreach ( Relation *r, node->dependParentNodes() ) { switch ( r->type() ) { case Relation::FinishFinish: case Relation::FinishStart: if ( ! static_cast( r->parent() )->completion().isFinished() ) { if ( ! names.contains( r->parent()->name() ) ) { names << r->parent()->name(); } } break; case Relation::StartStart: if ( ! static_cast( r->parent() )->completion().isStarted() ) { if ( ! names.contains( r->parent()->name() ) ) { names << r->parent()->name(); } } break; } } return names.isEmpty() ? xi18nc( "@info:tooltip", "Cannot start" ) : xi18nc( "@info:tooltip 1=list of task names", "Cannot start, waiting for:%1", names.join( "" ) ); } return xi18nc( "@info:tooltip", "Not started" ); break; } case Qt::EditRole: return t->state( id() ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::startedTime( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: if ( t->completion().isStarted() ) { return QLocale().toString( t->completion().startTime(), QLocale::ShortFormat ); } break; case Qt::ToolTipRole: if ( t->completion().isStarted() ) { return xi18nc( "@info:tooltip", "Actual start: %1", QLocale().toString( t->completion().startTime().date(), QLocale::LongFormat ) ); } break; case Qt::EditRole: if ( t->completion().isStarted() ) { return t->completion().startTime(); } return QDateTime::currentDateTime(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::isStarted( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return t->completion().isStarted(); case Qt::ToolTipRole: if ( t->completion().isStarted() ) { return xi18nc( "@info:tooltip", "The task started at: %1", QLocale().toString( t->completion().startTime().date(), QLocale::LongFormat ) ); } return xi18nc( "@info:tooltip", "The task is not started" ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::finishedTime( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: if ( t->completion().isFinished() ) { return QLocale().toString( t->completion().finishTime(), QLocale::ShortFormat ); } break; case Qt::ToolTipRole: if ( t->completion().isFinished() ) { return xi18nc( "@info:tooltip", "Actual finish: %1", QLocale().toString( t->completion().finishTime(), QLocale::LongFormat ) ); } break; case Qt::EditRole: if ( t->completion().isFinished() ) { return t->completion().finishTime(); } break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::isFinished( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return t->completion().isFinished(); case Qt::ToolTipRole: if ( t->completion().isFinished() ) { return xi18nc( "@info:tooltip", "The task finished at: %1", QLocale().toString( t->completion().finishTime().date(), QLocale::LongFormat ) ); } return xi18nc( "@info:tooltip", "The task is not finished" ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::plannedEffortTo( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return node->plannedEffortTo( m_now, id() ).format(); case Qt::ToolTipRole: return xi18nc( "@info:tooltip", "Planned effort until %1: %2", QLocale().toString( m_now, QLocale::ShortFormat ), node->plannedEffortTo( m_now, id() ).toString( Duration::Format_i18nHour ) ); case Qt::EditRole: return node->plannedEffortTo( m_now, id() ).toDouble( Duration::Unit_h ); case Role::DurationUnit: return static_cast( Duration::Unit_h ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::actualEffortTo( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return node->actualEffortTo( m_now ).format(); case Qt::ToolTipRole: //debugPlan<actualEffortTo( m_now ).toString( Duration::Format_i18nHour ) ); case Qt::EditRole: return node->actualEffortTo( m_now ).toDouble( Duration::Unit_h ); case Role::DurationUnit: return static_cast( Duration::Unit_h ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::remainingEffort( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: { const Task *t = dynamic_cast( node ); if ( t ) { return t->completion().remainingEffort().format(); } break; } case Qt::ToolTipRole: { const Task *t = dynamic_cast( node ); if ( t ) { return xi18nc( "@info:tooltip", "Remaining effort: %1", t->completion().remainingEffort().toString( Duration::Format_i18nHour ) ); } break; } case Qt::EditRole: { const Task *t = dynamic_cast( node ); if ( t == 0 ) { return QVariant(); } return t->completion().remainingEffort().toDouble( Duration::Unit_h ); } case Role::DurationUnit: return static_cast( Duration::Unit_h ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::plannedCostTo( const Node *node, int role ) const { Locale *l = m_project->locale(); switch ( role ) { case Qt::DisplayRole: return l->formatMoney( node->plannedCostTo( m_now, id() ) ); case Qt::ToolTipRole: return xi18nc( "@info:tooltip", "Planned cost until %1: %2", QLocale().toString( m_now, QLocale::ShortFormat ), l->formatMoney( node->plannedCostTo( m_now, id() ) ) ); case Qt::EditRole: return node->plannedCostTo( m_now ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::actualCostTo( const Node *node, int role ) const { Locale *l = m_project->locale(); switch ( role ) { case Qt::DisplayRole: return l->formatMoney( node->actualCostTo( id(), m_now ).cost() ); case Qt::ToolTipRole: return xi18nc( "@info:tooltip", "Actual cost until %1: %2", QLocale().toString( m_now, QLocale::ShortFormat ), l->formatMoney( node->actualCostTo( id(), m_now ).cost() ) ); case Qt::EditRole: return node->actualCostTo( id(), m_now ).cost(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::note( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: case Qt::ToolTipRole: if ( node->type() == Node::Type_Task ) { Node *n = const_cast( node ); return static_cast( n )->completion().note(); } break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::nodeSchedulingStatus( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return node->schedulingStatus( id(), true ).value( 0 ); case Qt::EditRole: return node->schedulingStatus( id(), false ).value( 0 ); case Qt::ToolTipRole: return node->schedulingStatus( id(), true ).join( "\n" ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::resourceIsMissing( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( node->resourceError( id() ) ) { return i18n( "Error" ); } break; case Qt::EditRole: return node->resourceError( id() ); case Qt::ToolTipRole: if ( node->resourceError( id() ) ) { return xi18nc( "@info:tooltip", "Resource allocation is expected when the task estimate type is Effort" ); } break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::Foreground: { if ( ! m_project ) { break; } switch ( node->type() ) { case Node::Type_Task: return m_project->config().taskErrorColor(); case Node::Type_Milestone: return m_project->config().milestoneErrorColor(); default: break; } } } return QVariant(); } QVariant NodeModel::resourceIsOverbooked( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( node->resourceOverbooked( id() ) ) { return i18n( "Error" ); } break; case Qt::EditRole: return node->resourceOverbooked( id() ); case Qt::ToolTipRole: if ( node->resourceOverbooked( id() ) ) { return xi18nc( "@info:tooltip", "A resource has been overbooked" ); } break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::Foreground: { if ( ! m_project ) { break; } switch ( node->type() ) { case Node::Type_Task: return m_project->config().taskErrorColor(); case Node::Type_Milestone: return m_project->config().milestoneErrorColor(); default: break; } } } return QVariant(); } QVariant NodeModel::resourceIsNotAvailable( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( node->resourceNotAvailable( id() ) ) { return i18n( "Error" ); } break; case Qt::EditRole: return node->resourceNotAvailable( id() ); case Qt::ToolTipRole: if ( node->resourceNotAvailable( id() ) ) { return xi18nc( "@info:tooltip", "No resource is available for this task" ); } break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::Foreground: { if ( ! m_project ) { break; } switch ( node->type() ) { case Node::Type_Task: return m_project->config().taskErrorColor(); case Node::Type_Milestone: return m_project->config().milestoneErrorColor(); default: break; } } } return QVariant(); } QVariant NodeModel::schedulingConstraintsError( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( node->constraintError( id() ) ) { return i18n( "Error" ); } break; case Qt::EditRole: return node->constraintError( id() ); case Qt::ToolTipRole: if ( node->constraintError( id() ) ) { return xi18nc( "@info:tooltip", "Failed to comply with a timing constraint" ); } break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::Foreground: { if ( ! m_project ) { break; } switch ( node->type() ) { case Node::Type_Task: return m_project->config().taskErrorColor(); case Node::Type_Milestone: return m_project->config().milestoneErrorColor(); default: break; } } } return QVariant(); } QVariant NodeModel::nodeIsNotScheduled( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( node->notScheduled( id() ) ) { return i18n( "Error" ); } break; case Qt::EditRole: return node->notScheduled( id() ); case Qt::ToolTipRole: if ( node->notScheduled( id() ) ) { return xi18nc( "@info:tooltip", "This task has not been scheduled" ); } break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::Foreground: { if ( ! m_project ) { break; } switch ( node->type() ) { case Node::Type_Task: return m_project->config().taskErrorColor(); case Node::Type_Milestone: return m_project->config().milestoneErrorColor(); default: break; } } } return QVariant(); } QVariant NodeModel::effortNotMet( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( node->effortMetError( id() ) ) { return i18n( "Error" ); } break; case Qt::EditRole: return node->effortMetError( id() ); case Qt::ToolTipRole: if ( node->effortMetError( id() ) ) { return xi18nc( "@info:tooltip", "The assigned resources cannot deliver the required estimated effort" ); } break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::Foreground: { if ( ! m_project ) { break; } switch ( node->type() ) { case Node::Type_Task: return m_project->config().taskErrorColor(); case Node::Type_Milestone: return m_project->config().milestoneErrorColor(); default: break; } } } return QVariant(); } QVariant NodeModel::schedulingError( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( node->schedulingError( id() ) ) { return i18n( "Error" ); } break; case Qt::EditRole: return node->schedulingError( id() ); case Qt::ToolTipRole: if ( node->schedulingError( id() ) ) { return xi18nc( "@info:tooltip", "Scheduling error" ); } break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::Foreground: { if ( ! m_project ) { break; } switch ( node->type() ) { case Node::Type_Task: return m_project->config().taskErrorColor(); case Node::Type_Milestone: return m_project->config().milestoneErrorColor(); default: break; } } } return QVariant(); } QVariant NodeModel::wbsCode( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return node->wbsCode(); case Qt::ToolTipRole: return xi18nc( "@info:tooltip", "Work breakdown structure code: %1", node->wbsCode() ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case SortableRole: return node->wbsCode(true); } return QVariant(); } QVariant NodeModel::nodeLevel( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return node->level(); case Qt::ToolTipRole: return xi18nc( "@info:tooltip", "Task level: %1", node->level() ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::nodeBCWS( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return m_project->locale()->formatMoney( node->bcws( m_now, id() ), QString(), 0 ); case Qt::EditRole: return node->bcws( m_now, id() ); case Qt::ToolTipRole: return xi18nc( "@info:tooltip", "Budgeted Cost of Work Scheduled at %1: %2", QLocale().toString( m_now, QLocale::ShortFormat ), m_project->locale()->formatMoney( node->bcws( m_now, id() ), QString(), 0 ) ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::nodeBCWP( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return m_project->locale()->formatMoney( node->bcwp( id() ), QString(), 0 ); case Qt::EditRole: return node->bcwp( id() ); case Qt::ToolTipRole: return xi18nc( "@info:tooltip", "Budgeted Cost of Work Performed at %1: %2", QLocale().toString( m_now, QLocale::ShortFormat ), m_project->locale()->formatMoney( node->bcwp( id() ), QString(), 0 ) ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::nodeACWP( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return m_project->locale()->formatMoney( node->acwp( m_now, id() ).cost(), QString(), 0 ); case Qt::EditRole: return node->acwp( m_now, id() ).cost(); case Qt::ToolTipRole: return xi18nc( "@info:tooltip", "Actual Cost of Work Performed at %1: %2", QLocale().toString( m_now, QLocale::ShortFormat ), m_project->locale()->formatMoney( node->acwp( m_now, id() ).cost() ) ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::nodePerformanceIndex( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return QLocale().toString( node->schedulePerformanceIndex( m_now, id() ), 'f', 2 ); case Qt::EditRole: return node->schedulePerformanceIndex( m_now, id() ); case Qt::ToolTipRole: return xi18nc( "@info:tooltip", "Schedule Performance Index at %1: %2", m_now.toString(), QLocale().toString( node->schedulePerformanceIndex( m_now, id() ), 'f', 2 ) ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Qt::ForegroundRole: return QColor(node->schedulePerformanceIndex( m_now, id() ) < 1.0 ? Qt::red : Qt::black); } return QVariant(); } QVariant NodeModel::nodeIsCritical( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return node->isCritical( id() ); case Qt::ToolTipRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::Foreground: { if ( ! m_project ) { break; } switch ( node->type() ) { case Node::Type_Task: return m_project->config().taskNormalColor(); case Node::Type_Milestone: return m_project->config().milestoneNormalColor(); default: break; } } } return QVariant(); } QVariant NodeModel::nodeInCriticalPath( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return node->inCriticalPath( id() ); case Qt::ToolTipRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::Foreground: { if ( ! m_project ) { break; } switch ( node->type() ) { case Node::Type_Task: return m_project->config().taskNormalColor(); case Node::Type_Milestone: return m_project->config().milestoneNormalColor(); default: break; } } } return QVariant(); } QVariant NodeModel::wpOwnerName( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: { const Task *t = dynamic_cast( node ); if ( t == 0 ) { return QVariant(); } if ( t->wpTransmitionStatus() == WorkPackage::TS_None ) { return xi18nc( "Not available", "NA" ); } return t->wpOwnerName(); } case Qt::ToolTipRole: { const Task *task = dynamic_cast( node ); if ( task == 0 ) { return QVariant(); } int sts = task->wpTransmitionStatus(); QString t = wpTransmitionTime( node, Qt::DisplayRole ).toString(); if ( sts == WorkPackage::TS_Send ) { return xi18nc( "@info:tooltip", "Latest work package sent to %1 at %2", static_cast( node )->wpOwnerName(), t ); } if ( sts == WorkPackage::TS_Receive ) { return xi18nc( "@info:tooltip", "Latest work package received from %1 at %2", static_cast( node )->wpOwnerName(), t ); } return xi18nc( "@info:tooltip", "Not available" ); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::wpTransmitionStatus( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: { const Task *t = dynamic_cast( node ); if ( t == 0 ) { return QVariant(); } if ( t->wpTransmitionStatus() == WorkPackage::TS_None ) { return xi18nc( "Not available", "NA" ); } return WorkPackage::transmitionStatusToString( t->wpTransmitionStatus(), true ); } case Qt::EditRole: { const Task *t = dynamic_cast( node ); if ( t == 0 ) { return QVariant(); } return WorkPackage::transmitionStatusToString( t->wpTransmitionStatus(), false ); } case Qt::ToolTipRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::wpTransmitionTime( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: { const Task *t = dynamic_cast( node ); if ( t == 0 ) { return QVariant(); } if ( t->wpTransmitionStatus() == WorkPackage::TS_None ) { return xi18nc( "Not available", "NA" ); } return QLocale().toString( t->wpTransmitionTime(), QLocale::ShortFormat ); } case Qt::ToolTipRole: { const Task *task = dynamic_cast( node ); if ( task == 0 ) { return QVariant(); } int sts = task->wpTransmitionStatus(); QString t = wpTransmitionTime( node, Qt::DisplayRole ).toString(); if ( sts == WorkPackage::TS_Send ) { return xi18nc( "@info:tooltip", "Latest work package sent: %1", t ); } if ( sts == WorkPackage::TS_Receive ) { return xi18nc( "@info:tooltip", "Latest work package received: %1", t ); } return xi18nc( "@info:tooltip", "Not available" ); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::data( const Node *n, int property, int role ) const { QVariant result; switch ( property ) { // Edited by user case NodeName: result = name( n, role ); break; case NodeType: result = type( n, role ); break; case NodeResponsible: result = leader( n, role ); break; case NodeAllocation: result = allocation( n, role ); break; case NodeEstimateType: result = estimateType( n, role ); break; case NodeEstimateCalendar: result = estimateCalendar( n, role ); break; case NodeEstimate: result = estimate( n, role ); break; case NodeOptimisticRatio: result = optimisticRatio( n, role ); break; case NodePessimisticRatio: result = pessimisticRatio( n, role ); break; case NodeRisk: result = riskType( n, role ); break; case NodeConstraint: result = constraint( n, role ); break; case NodeConstraintStart: result = constraintStartTime( n, role ); break; case NodeConstraintEnd: result = constraintEndTime( n, role ); break; case NodeRunningAccount: result = runningAccount( n, role ); break; case NodeStartupAccount: result = startupAccount( n, role ); break; case NodeStartupCost: result = startupCost( n, role ); break; case NodeShutdownAccount: result = shutdownAccount( n, role ); break; case NodeShutdownCost: result = shutdownCost( n, role ); break; case NodeDescription: result = description( n, role ); break; // Based on edited values case NodeExpected: result = pertExpected( n->estimate(), role ); break; case NodeVarianceEstimate: result = varianceEstimate( n->estimate(), role ); break; case NodeOptimistic: result = optimisticEstimate( n->estimate(), role ); break; case NodePessimistic: result = pessimisticEstimate( n->estimate(), role ); break; // After scheduling case NodeStartTime: result = startTime( n, role ); break; case NodeEndTime: result = endTime( n, role ); break; case NodeEarlyStart: result = earlyStart( n, role ); break; case NodeEarlyFinish: result = earlyFinish( n, role ); break; case NodeLateStart: result = lateStart( n, role ); break; case NodeLateFinish: result = lateFinish( n, role ); break; case NodePositiveFloat: result = positiveFloat( n, role ); break; case NodeFreeFloat: result = freeFloat( n, role ); break; case NodeNegativeFloat: result = negativeFloat( n, role ); break; case NodeStartFloat: result = startFloat( n, role ); break; case NodeFinishFloat: result = finishFloat( n, role ); break; case NodeAssignments: result = assignedResources( n, role ); break; // Based on scheduled values case NodeDuration: result = duration( n, role ); break; case NodeVarianceDuration: result = varianceDuration( n, role ); break; case NodeOptimisticDuration: result = optimisticDuration( n, role ); break; case NodePessimisticDuration: result = pessimisticDuration( n, role ); break; // Completion case NodeStatus: result = status( n, role ); break; case NodeCompleted: result = completed( n, role ); break; case NodePlannedEffort: result = plannedEffortTo( n, role ); break; case NodeActualEffort: result = actualEffortTo( n, role ); break; case NodeRemainingEffort: result = remainingEffort( n, role ); break; case NodePlannedCost: result = plannedCostTo( n, role ); break; case NodeActualCost: result = actualCostTo( n, role ); break; case NodeActualStart: result = startedTime( n, role ); break; case NodeStarted: result = isStarted( n, role ); break; case NodeActualFinish: result = finishedTime( n, role ); break; case NodeFinished: result = isFinished( n, role ); break; case NodeStatusNote: result = note( n, role ); break; // Scheduling errors case NodeSchedulingStatus: result = nodeSchedulingStatus( n, role ); break; case NodeNotScheduled: result = nodeIsNotScheduled( n, role ); break; case NodeAssignmentMissing: result = resourceIsMissing( n, role ); break; case NodeResourceOverbooked: result = resourceIsOverbooked( n, role ); break; case NodeResourceUnavailable: result = resourceIsNotAvailable( n, role ); break; case NodeConstraintsError: result = schedulingConstraintsError( n, role ); break; case NodeEffortNotMet: result = effortNotMet( n, role ); break; case NodeSchedulingError: result = schedulingError( n, role ); break; case NodeWBSCode: result = wbsCode( n, role ); break; case NodeLevel: result = nodeLevel( n, role ); break; // Performance case NodeBCWS: result = nodeBCWS( n, role ); break; case NodeBCWP: result = nodeBCWP( n, role ); break; case NodeACWP: result = nodeACWP( n, role ); break; case NodePerformanceIndex: result = nodePerformanceIndex( n, role ); break; case NodeCritical: result = nodeIsCritical( n, role ); break; case NodeCriticalPath: result = nodeInCriticalPath( n, role ); break; case WPOwnerName: result = wpOwnerName( n, role ); break; case WPTransmitionStatus: result = wpTransmitionStatus( n, role ); break; case WPTransmitionTime: result = wpTransmitionTime( n, role ); break; default: //debugPlan<<"Invalid property number: "<name() ) { return 0; } KUndo2MagicString s = kundo2_i18n( "Modify name" ); switch ( node->type() ) { case Node::Type_Task: s = kundo2_i18n( "Modify task name" ); break; case Node::Type_Milestone: s = kundo2_i18n( "Modify milestone name" ); break; case Node::Type_Summarytask: s = kundo2_i18n( "Modify summarytask name" ); break; case Node::Type_Project: s = kundo2_i18n( "Modify project name" ); break; } return new NodeModifyNameCmd( *node, value.toString(), s ); } } return 0; } KUndo2Command *NodeModel::setLeader( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { if ( value.toString() != node->leader() ) { return new NodeModifyLeaderCmd( *node, value.toString(), kundo2_i18n( "Modify responsible" ) ); } break; } default: break; } return 0; } KUndo2Command *NodeModel::setAllocation( Node */*node*/, const QVariant &/*value*/, int /*role*/ ) { return 0; } KUndo2Command *NodeModel::setDescription( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: if ( value.toString() == node->description() ) { return 0; } return new NodeModifyDescriptionCmd( *node, value.toString(), kundo2_i18n( "Modify task description" ) ); } return 0; } KUndo2Command *NodeModel::setType( Node *, const QVariant &, int ) { return 0; } KUndo2Command *NodeModel::setConstraint( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { Node::ConstraintType v; QStringList lst = node->constraintList( false ); if ( lst.contains( value.toString() ) ) { v = Node::ConstraintType( lst.indexOf( value.toString() ) ); } else { v = Node::ConstraintType( value.toInt() ); } //debugPlan<constraint() ) { return new NodeModifyConstraintCmd( *node, v, kundo2_i18n( "Modify constraint type" ) ); } break; } default: break; } return 0; } KUndo2Command *NodeModel::setConstraintStartTime( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { QDateTime dt = value.toDateTime(); dt.setTime( QTime( dt.time().hour(), dt.time().minute(), 0 ) ); // reset possible secs/msecs if ( dt != node->constraintStartTime() ) { return new NodeModifyConstraintStartTimeCmd( *node, dt, kundo2_i18n( "Modify constraint start time" ) ); } break; } default: break; } return 0; } KUndo2Command *NodeModel::setConstraintEndTime( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { QDateTime dt = value.toDateTime(); dt.setTime( QTime( dt.time().hour(), dt.time().minute(), 0 ) ); // reset possible secs/msecs if ( dt != node->constraintEndTime() ) { return new NodeModifyConstraintEndTimeCmd( *node, dt, kundo2_i18n( "Modify constraint end time" ) ); } break; } default: break; } return 0; } KUndo2Command *NodeModel::setEstimateType( Node *node, const QVariant &value, int role ) { if ( node->estimate() == 0 ) { return 0; } switch ( role ) { case Qt::EditRole: { Estimate::Type v; QStringList lst = node->estimate()->typeToStringList( false ); if ( lst.contains( value.toString() ) ) { v = Estimate::Type( lst.indexOf( value.toString() ) ); } else { v = Estimate::Type( value.toInt() ); } if ( v != node->estimate()->type() ) { return new ModifyEstimateTypeCmd( *node, node->estimate()->type(), v, kundo2_i18n( "Modify estimate type" ) ); } break; } default: break; } return 0; } KUndo2Command *NodeModel::setEstimateCalendar( Node *node, const QVariant &value, int role ) { if ( node->estimate() == 0 ) { return 0; } switch ( role ) { case Qt::EditRole: { Calendar *c = 0; Calendar *old = node->estimate()->calendar(); if ( value.toInt() > 0 ) { QStringList lst = estimateCalendar( node, Role::EnumList ).toStringList(); if ( value.toInt() < lst.count() ) { c = m_project->calendarByName( lst.at( value.toInt() ) ); } } if ( c != old ) { return new ModifyEstimateCalendarCmd( *node, old, c, kundo2_i18n( "Modify estimate calendar" ) ); } break; } default: break; } return 0; } KUndo2Command *NodeModel::setEstimate( Node *node, const QVariant &value, int role ) { if ( node->estimate() == 0 ) { return 0; } switch ( role ) { case Qt::EditRole: { double d; Duration::Unit unit; if ( value.toList().count() == 2 ) { d = value.toList()[0].toDouble(); unit = static_cast( value.toList()[1].toInt() ); } else if ( value.canConvert() ) { bool ok = Duration::valueFromString( value.toString(), d, unit ); if ( ! ok ) { return 0; } } else { return 0; } //debugPlan<"<estimate()->expectedEstimate() ) { if ( cmd == 0 ) cmd = new MacroCommand( kundo2_i18n( "Modify estimate" ) ); cmd->addCommand( new ModifyEstimateCmd( *node, node->estimate()->expectedEstimate(), d ) ); } if ( unit != node->estimate()->unit() ) { if ( cmd == 0 ) cmd = new MacroCommand( kundo2_i18n( "Modify estimate" ) ); cmd->addCommand( new ModifyEstimateUnitCmd( *node, node->estimate()->unit(), unit ) ); } if ( cmd ) { return cmd; } break; } default: break; } return 0; } KUndo2Command *NodeModel::setOptimisticRatio( Node *node, const QVariant &value, int role ) { if ( node->estimate() == 0 ) { return 0; } switch ( role ) { case Qt::EditRole: if ( value.toInt() != node->estimate()->optimisticRatio() ) { return new EstimateModifyOptimisticRatioCmd( *node, node->estimate()->optimisticRatio(), value.toInt(), kundo2_i18n( "Modify optimistic estimate" ) ); } break; default: break; } return 0; } KUndo2Command *NodeModel::setPessimisticRatio( Node *node, const QVariant &value, int role ) { if ( node->estimate() == 0 ) { return 0; } switch ( role ) { case Qt::EditRole: if ( value.toInt() != node->estimate()->pessimisticRatio() ) { return new EstimateModifyPessimisticRatioCmd( *node, node->estimate()->pessimisticRatio(), value.toInt(), kundo2_i18n( "Modify pessimistic estimate" ) ); } default: break; } return 0; } KUndo2Command *NodeModel::setRiskType( Node *node, const QVariant &value, int role ) { if ( node->estimate() == 0 ) { return 0; } switch ( role ) { case Qt::EditRole: { int val = 0; QStringList lst = node->estimate()->risktypeToStringList( false ); if ( lst.contains( value.toString() ) ) { val = lst.indexOf( value.toString() ); } else { val = value.toInt(); } if ( val != node->estimate()->risktype() ) { Estimate::Risktype v = Estimate::Risktype( val ); return new EstimateModifyRiskCmd( *node, node->estimate()->risktype(), v, kundo2_i18n( "Modify risk type" ) ); } break; } default: break; } return 0; } KUndo2Command *NodeModel::setRunningAccount( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { //debugPlan<name(); QStringList lst = runningAccount( node, Role::EnumList ).toStringList(); if ( value.toInt() < lst.count() ) { Account *a = m_project->accounts().findAccount( lst.at( value.toInt() ) ); Account *old = node->runningAccount(); if ( old != a ) { return new NodeModifyRunningAccountCmd( *node, old, a, kundo2_i18n( "Modify running account" ) ); } } break; } default: break; } return 0; } KUndo2Command *NodeModel::setStartupAccount( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { //debugPlan<name(); QStringList lst = startupAccount( node, Role::EnumList ).toStringList(); if ( value.toInt() < lst.count() ) { Account *a = m_project->accounts().findAccount( lst.at( value.toInt() ) ); Account *old = node->startupAccount(); //debugPlan<<(value.toInt())<<";"<<(lst.at( value.toInt()))<<":"<startupCost() ) { return new NodeModifyStartupCostCmd( *node, v, kundo2_i18n( "Modify startup cost" ) ); } break; } default: break; } return 0; } KUndo2Command *NodeModel::setShutdownAccount( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { //debugPlan<name(); QStringList lst = shutdownAccount( node, Role::EnumList ).toStringList(); if ( value.toInt() < lst.count() ) { Account *a = m_project->accounts().findAccount( lst.at( value.toInt() ) ); Account *old = node->shutdownAccount(); if ( old != a ) { return new NodeModifyShutdownAccountCmd( *node, old, a, kundo2_i18n( "Modify shutdown account" ) ); } } break; } default: break; } return 0; } KUndo2Command *NodeModel::setShutdownCost( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { double v = value.toDouble(); if ( v != node->shutdownCost() ) { return new NodeModifyShutdownCostCmd( *node, v, kundo2_i18n( "Modify shutdown cost" ) ); } break; } default: break; } return 0; } KUndo2Command *NodeModel::setCompletion( Node */*node*/, const QVariant &/*value*/, int /*role*/ ) { return 0; } KUndo2Command *NodeModel::setRemainingEffort( Node *node, const QVariant &value, int role ) { if ( role == Qt::EditRole && node->type() == Node::Type_Task ) { Task *t = static_cast( node ); double d( value.toList()[0].toDouble() ); Duration::Unit unit = static_cast( value.toList()[1].toInt() ); Duration dur( d, unit ); return new ModifyCompletionRemainingEffortCmd( t->completion(), QDate::currentDate(), dur, kundo2_i18n( "Modify remaining effort" ) ); } return 0; } KUndo2Command *NodeModel::setActualEffort( Node *node, const QVariant &value, int role ) { if ( role == Qt::EditRole && node->type() == Node::Type_Task ) { Task *t = static_cast( node ); double d( value.toList()[0].toDouble() ); Duration::Unit unit = static_cast( value.toList()[1].toInt() ); Duration dur( d, unit ); return new ModifyCompletionActualEffortCmd( t->completion(), QDate::currentDate(), dur, kundo2_i18n( "Modify actual effort" ) ); } return 0; } KUndo2Command *NodeModel::setStartedTime( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { Task *t = qobject_cast( node ); if ( t == 0 ) { return 0; } MacroCommand *m = new MacroCommand( kundo2_i18n( "Modify actual start time" ) ); if ( ! t->completion().isStarted() ) { m->addCommand( new ModifyCompletionStartedCmd( t->completion(), true ) ); } m->addCommand( new ModifyCompletionStartTimeCmd( t->completion(), value.toDateTime() ) ); if ( t->type() == Node::Type_Milestone ) { m->addCommand( new ModifyCompletionFinishedCmd( t->completion(), true ) ); m->addCommand( new ModifyCompletionFinishTimeCmd( t->completion(), value.toDateTime() ) ); if ( t->completion().percentFinished() < 100 ) { Completion::Entry *e = new Completion::Entry( 100, Duration::zeroDuration, Duration::zeroDuration ); m->addCommand( new AddCompletionEntryCmd( t->completion(), value.toDate(), e ) ); } } return m; } default: break; } return 0; } KUndo2Command *NodeModel::setFinishedTime( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { Task *t = qobject_cast( node ); if ( t == 0 ) { return 0; } MacroCommand *m = new MacroCommand( kundo2_i18n( "Modify actual finish time" ) ); if ( ! t->completion().isFinished() ) { m->addCommand( new ModifyCompletionFinishedCmd( t->completion(), true ) ); if ( t->completion().percentFinished() < 100 ) { Completion::Entry *e = new Completion::Entry( 100, Duration::zeroDuration, Duration::zeroDuration ); m->addCommand( new AddCompletionEntryCmd( t->completion(), value.toDate(), e ) ); } } m->addCommand( new ModifyCompletionFinishTimeCmd( t->completion(), value.toDateTime() ) ); if ( t->type() == Node::Type_Milestone ) { m->addCommand( new ModifyCompletionStartedCmd( t->completion(), true ) ); m->addCommand( new ModifyCompletionStartTimeCmd( t->completion(), value.toDateTime() ) ); } return m; } default: break; } return 0; } //---------------------------- NodeItemModel::NodeItemModel( QObject *parent ) : ItemModelBase( parent ), m_node( 0 ), m_projectshown( false ) { setReadOnly( NodeModel::NodeDescription, true ); } NodeItemModel::~NodeItemModel() { } void NodeItemModel::setShowProject( bool on ) { m_projectshown = on; reset(); emit projectShownChanged( on ); } void NodeItemModel::slotNodeToBeInserted( Node *parent, int row ) { //debugPlan<name()<<"; "<parentNode()->name()<<"-->"<name(); Q_ASSERT( node->parentNode() == m_node ); endInsertRows(); m_node = 0; emit nodeInserted( node ); } void NodeItemModel::slotNodeToBeRemoved( Node *node ) { //debugPlan<name(); Q_ASSERT( m_node == 0 ); m_node = node; int row = index( node ).row(); beginRemoveRows( index( node->parentNode() ), row, row ); } void NodeItemModel::slotNodeRemoved( Node *node ) { //debugPlan<name(); Q_ASSERT( node == m_node ); #ifdef NDEBUG Q_UNUSED(node) #endif endRemoveRows(); m_node = 0; } void NodeItemModel::slotNodeToBeMoved( Node *node, int pos, Node *newParent, int newPos ) { //debugPlan<parentNode()->name()<name()<parentNode() ), pos, pos, index( newParent ), newPos ); } void NodeItemModel::slotNodeMoved( Node *node ) { Q_UNUSED( node ); //debugPlan<parentNode()->name()<parentNode()->indexOf( node ); endMoveRows(); } void NodeItemModel::slotLayoutChanged() { //debugPlan<name(); emit layoutAboutToBeChanged(); emit layoutChanged(); } void NodeItemModel::slotProjectCalculated(ScheduleManager *sm) { debugPlan<allNodes() ) { int row = n->parentNode()->indexOf( n ); QModelIndex idx = createIndex( row, NodeModel::NodeWBSCode, n ); emit dataChanged( idx, idx ); } } void NodeItemModel::setProject( Project *project ) { if ( m_project ) { disconnect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); disconnect( m_project, SIGNAL(localeChanged()), this, SLOT(slotLayoutChanged()) ); disconnect( m_project, SIGNAL(wbsDefinitionChanged()), this, SLOT(slotWbsDefinitionChanged()) ); disconnect( m_project, SIGNAL(nodeChanged(Node*)), this, SLOT(slotNodeChanged(Node*)) ); disconnect( m_project, SIGNAL(nodeToBeAdded(Node*,int)), this, SLOT(slotNodeToBeInserted(Node*,int)) ); disconnect( m_project, SIGNAL(nodeToBeRemoved(Node*)), this, SLOT(slotNodeToBeRemoved(Node*)) ); disconnect( m_project, SIGNAL(nodeToBeMoved(Node*,int,Node*,int)), this, SLOT(slotNodeToBeMoved(Node*,int,Node*,int)) ); disconnect( m_project, SIGNAL(nodeMoved(Node*)), this, SLOT(slotNodeMoved(Node*)) ); disconnect( m_project, SIGNAL(nodeAdded(Node*)), this, SLOT(slotNodeInserted(Node*)) ); disconnect( m_project, SIGNAL(nodeRemoved(Node*)), this, SLOT(slotNodeRemoved(Node*)) ); disconnect( m_project, SIGNAL(projectCalculated(ScheduleManager*)), this, SLOT(slotProjectCalculated(ScheduleManager*))); } m_project = project; debugPlan<"<isBaselined(); flags |= Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; switch ( index.column() ) { case NodeModel::NodeName: // name flags |= Qt::ItemIsEditable; break; case NodeModel::NodeType: break; // Node type case NodeModel::NodeResponsible: // Responsible flags |= Qt::ItemIsEditable; break; case NodeModel::NodeAllocation: // allocation if ( n->type() == Node::Type_Task ) { flags |= Qt::ItemIsEditable; } break; case NodeModel::NodeEstimateType: // estimateType { if ( ! baselined && ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) ) { flags |= Qt::ItemIsEditable; } break; } case NodeModel::NodeEstimate: // estimate { if ( ! baselined && ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) ) { flags |= Qt::ItemIsEditable; } break; } case NodeModel::NodeOptimisticRatio: // optimisticRatio case NodeModel::NodePessimisticRatio: // pessimisticRatio { if ( ! baselined && n->type() == Node::Type_Task ) { flags |= Qt::ItemIsEditable; } break; } case NodeModel::NodeEstimateCalendar: { if ( ! baselined && n->type() == Node::Type_Task ) { flags |= Qt::ItemIsEditable; } break; } case NodeModel::NodeRisk: // risktype { if ( ! baselined && n->type() == Node::Type_Task ) { flags |= Qt::ItemIsEditable; } break; } case NodeModel::NodeConstraint: // constraint type if ( ! baselined && ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) ) { flags |= Qt::ItemIsEditable; } break; case NodeModel::NodeConstraintStart: { // constraint start if ( ! baselined && n->type() == Node::Type_Project ) { flags |= Qt::ItemIsEditable; break; } if ( ! baselined && ! ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) ) { break; } flags |= Qt::ItemIsEditable; break; } case NodeModel::NodeConstraintEnd: { // constraint end if ( ! baselined && n->type() == Node::Type_Project ) { flags |= Qt::ItemIsEditable; break; } if ( ! baselined && ! ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) ) { break; } flags |= Qt::ItemIsEditable; break; } case NodeModel::NodeRunningAccount: // running account if ( ! baselined && n->type() == Node::Type_Task ) { flags |= Qt::ItemIsEditable; } break; case NodeModel::NodeStartupAccount: // startup account case NodeModel::NodeStartupCost: // startup cost case NodeModel::NodeShutdownAccount: // shutdown account case NodeModel::NodeShutdownCost: { // shutdown cost if ( ! baselined && ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) ) { flags |= Qt::ItemIsEditable; } break; } case NodeModel::NodeDescription: // description flags |= Qt::ItemIsEditable; break; default: break; } Task *t = static_cast( n ); if ( manager() && t->isScheduled( id() ) ) { if ( ! t->completion().isStarted() ) { switch ( index.column() ) { case NodeModel::NodeActualStart: flags |= Qt::ItemIsEditable; break; case NodeModel::NodeActualFinish: if ( t->type() == Node::Type_Milestone ) { flags |= Qt::ItemIsEditable; } break; case NodeModel::NodeCompleted: if ( t->state() & Node::State_ReadyToStart ) { flags |= Qt::ItemIsEditable; } break; default: break; } } else if ( ! t->completion().isFinished() ) { switch ( index.column() ) { case NodeModel::NodeActualFinish: case NodeModel::NodeCompleted: case NodeModel::NodeRemainingEffort: flags |= Qt::ItemIsEditable; break; case NodeModel::NodeActualEffort: if ( t->completion().entrymode() == Completion::EnterEffortPerTask || t->completion().entrymode() == Completion::EnterEffortPerResource ) { flags |= Qt::ItemIsEditable; } break; default: break; } } } } return flags; } QModelIndex NodeItemModel::parent( const QModelIndex &index ) const { if ( ! index.isValid() ) { return QModelIndex(); } Node *n = node( index ); if ( n == 0 || n == m_project ) { return QModelIndex(); } Node *p = n->parentNode(); if ( p == m_project ) { return m_projectshown ? createIndex( 0, 0, p ) : QModelIndex(); } int row = p->parentNode()->indexOf( p ); if ( row == -1 ) { return QModelIndex(); } return createIndex( row, 0, p ); } QModelIndex NodeItemModel::index( int row, int column, const QModelIndex &parent ) const { if ( parent.isValid() ) { Q_ASSERT( parent.model() == this ); } //debugPlan<= columnCount() || row < 0 ) { //debugPlan<= p->numChildren() ) { errorPlan<name()<<" row too high"<childNode( row ); QModelIndex idx = createIndex(row, column, n); //debugPlan<parentNode(); if ( par ) { //debugPlan<"<indexOf( node ), column, const_cast(node) ); } if ( m_projectshown && node == m_project ) { return createIndex( 0, column, m_project ); } //debugPlan<( node ); if ( task == 0 ) { return false; } switch ( role ) { case Qt::EditRole: { MacroCommand *cmd = 0; QStringList res = m_project->resourceNameList(); QStringList req = node->requestNameList(); QStringList alloc; foreach ( const QString &s, value.toString().split( QRegExp(" *, *"), QString::SkipEmptyParts ) ) { alloc << s.trimmed(); } // first add all new resources (to "default" group) ResourceGroup *pargr = m_project->groupByName( i18n( "Resources" ) ); foreach ( const QString &s, alloc ) { Resource *r = m_project->resourceByName( s.trimmed() ); if ( r != 0 ) { continue; } if ( cmd == 0 ) cmd = new MacroCommand( kundo2_i18n( "Add resource" ) ); if ( pargr == 0 ) { pargr = new ResourceGroup(); pargr->setName( i18n( "Resources" ) ); cmd->addCommand( new AddResourceGroupCmd( m_project, pargr ) ); //debugPlan<<"add group:"<name(); } r = new Resource(); r->setName( s.trimmed() ); cmd->addCommand( new AddResourceCmd( pargr, r ) ); //debugPlan<<"add resource:"<name(); emit executeCommand( cmd ); cmd = 0; } KUndo2MagicString c = kundo2_i18n( "Modify resource allocations" ); // Handle deleted requests foreach ( const QString &s, req ) { // if a request is not in alloc, it must have been be removed by the user if ( alloc.indexOf( s ) == -1 ) { // remove removed resource request ResourceRequest *r = node->resourceRequest( s ); if ( r ) { if ( cmd == 0 ) cmd = new MacroCommand( c ); //debugPlan<<"delete request:"<resource()->name()<<" group:"<parent()->group()->name(); cmd->addCommand( new RemoveResourceRequestCmd( r->parent(), r ) ); } } } // Handle new requests QMap groupmap; foreach ( const QString &s, alloc ) { // if an allocation is not in req, it must be added if ( req.indexOf( s ) == -1 ) { ResourceGroup *pargr = 0; Resource *r = m_project->resourceByName( s ); if ( r == 0 ) { // Handle request to non exixting resource pargr = m_project->groupByName( i18n( "Resources" ) ); if ( pargr == 0 ) { pargr = new ResourceGroup(); pargr->setName( i18n( "Resources" ) ); cmd->addCommand( new AddResourceGroupCmd( m_project, pargr ) ); //debugPlan<<"add group:"<name(); } r = new Resource(); r->setName( s ); cmd->addCommand( new AddResourceCmd( pargr, r ) ); //debugPlan<<"add resource:"<name(); emit executeCommand( cmd ); cmd = 0; } else { pargr = r->parentGroup(); //debugPlan<<"add '"<name()<<"' to group:"<resourceGroupRequest( pargr ); if ( g == 0 ) { g = groupmap.value( pargr ); } if ( g == 0 ) { // create a group request if ( cmd == 0 ) cmd = new MacroCommand( c ); g = new ResourceGroupRequest( pargr ); cmd->addCommand( new AddResourceGroupRequestCmd( *task, g ) ); groupmap.insert( pargr, g ); //debugPlan<<"add group request:"<addCommand( new AddResourceRequestCmd( g, new ResourceRequest( r, r->units() ) ) ); //debugPlan<<"add request:"<name()<<" group:"<name()<type() == Node::Type_Task ) { Completion &c = static_cast( node )->completion(); QDateTime dt = QDateTime::currentDateTime(); QDate date = dt.date(); MacroCommand *m = new MacroCommand( kundo2_i18n( "Modify completion" ) ); if ( ! c.isStarted() ) { m->addCommand( new ModifyCompletionStartTimeCmd( c, dt ) ); m->addCommand( new ModifyCompletionStartedCmd( c, true ) ); } m->addCommand( new ModifyCompletionPercentFinishedCmd( c, date, value.toInt() ) ); if ( value.toInt() == 100 ) { m->addCommand( new ModifyCompletionFinishTimeCmd( c, dt ) ); m->addCommand( new ModifyCompletionFinishedCmd( c, true ) ); } emit executeCommand( m ); // also adds a new entry if necessary if ( c.entrymode() == Completion::EnterCompleted ) { Duration planned = static_cast( node )->plannedEffort( m_nodemodel.id() ); Duration actual = ( planned * value.toInt() ) / 100; debugPlan<execute(); m->addCommand( cmd ); cmd = new ModifyCompletionRemainingEffortCmd( c, date, planned - actual ); cmd->execute(); m->addCommand( cmd ); } return true; } if ( node->type() == Node::Type_Milestone ) { Completion &c = static_cast( node )->completion(); if ( value.toInt() > 0 ) { QDateTime dt = QDateTime::currentDateTime(); QDate date = dt.date(); MacroCommand *m = new MacroCommand( kundo2_i18n( "Set finished" ) ); m->addCommand( new ModifyCompletionStartTimeCmd( c, dt ) ); m->addCommand( new ModifyCompletionStartedCmd( c, true ) ); m->addCommand( new ModifyCompletionFinishTimeCmd( c, dt ) ); m->addCommand( new ModifyCompletionFinishedCmd( c, true ) ); m->addCommand( new ModifyCompletionPercentFinishedCmd( c, date, 100 ) ); emit executeCommand( m ); // also adds a new entry if necessary return true; } return false; } return false; } QVariant NodeItemModel::data( const QModelIndex &index, int role ) const { if ( role == Qt::TextAlignmentRole ) { return headerData( index.column(), Qt::Horizontal, role ); } Node *n = node( index ); if ( role == Role::Object ) { return n ? QVariant::fromValue( static_cast( n ) ) : QVariant(); } QVariant result; if ( n != 0 ) { result = m_nodemodel.data( n, index.column(), role ); //debugPlan<name()<<": "<numChildren(); } Qt::DropActions NodeItemModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } QStringList NodeItemModel::mimeTypes() const { return QStringList() << "application/x-vnd.kde.plan.nodeitemmodel.internal" << "application/x-vnd.kde.plan.resourceitemmodel.internal" << "application/x-vnd.kde.plan.project" << "text/uri-list"; } QMimeData *NodeItemModel::mimeData( const QModelIndexList & indexes ) const { QMimeData *m = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); QList rows; foreach (const QModelIndex &index, indexes) { if ( index.isValid() && !rows.contains( index.row() ) ) { //debugPlan<id(); } } } m->setData("application/x-vnd.kde.plan.nodeitemmodel.internal", encodedData); return m; } bool NodeItemModel::dropAllowed( const QModelIndex &index, int dropIndicatorPosition, const QMimeData *data ) { debugPlan; if ( m_projectshown && ! index.isValid() ) { return false; } Node *dn = node( index ); // returns project if ! index.isValid() if ( dn == 0 ) { errorPlan<<"no node (or project) to drop on!"; return false; // hmmm } if ( data->hasFormat("application/x-vnd.kde.plan.resourceitemmodel.internal") ) { switch ( dropIndicatorPosition ) { case ItemModelBase::OnItem: if ( index.column() == NodeModel::NodeAllocation ) { debugPlan<<"resource:"<type() == Node::Type_Task); return dn->type() == Node::Type_Task; } else if ( index.column() == NodeModel::NodeResponsible ) { debugPlan<<"resource:"<hasFormat( "application/x-vnd.kde.plan.nodeitemmodel.internal") || data->hasFormat( "application/x-vnd.kde.plan.project" ) || data->hasUrls() ) { switch ( dropIndicatorPosition ) { case ItemModelBase::AboveItem: case ItemModelBase::BelowItem: // dn == sibling, if not project if ( dn == m_project ) { return dropAllowed( dn, data ); } return dropAllowed( dn->parentNode(), data ); case ItemModelBase::OnItem: // dn == new parent return dropAllowed( dn, data ); default: break; } } else { debugPlan<<"Unknown mimetype"; } return false; } QList NodeItemModel::resourceList( QDataStream &stream ) { QList lst; while (!stream.atEnd()) { QString id; stream >> id; debugPlan<<"id"<findResource( id ); if ( r ) { lst << r; } } debugPlan<isBaselined() && on->type() != Node::Type_Summarytask ) { return false; } if ( data->hasFormat( "application/x-vnd.kde.plan.nodeitemmodel.internal" ) ) { QByteArray encodedData = data->data( "application/x-vnd.kde.plan.nodeitemmodel.internal" ); QDataStream stream(&encodedData, QIODevice::ReadOnly); QList lst = nodeList( stream ); foreach ( Node *n, lst ) { if ( n->type() == Node::Type_Project || on == n || on->isChildOf( n ) ) { return false; } } lst = removeChildNodes( lst ); foreach ( Node *n, lst ) { if ( ! m_project->canMoveTask( n, on ) ) { return false; } } } return true; } QList NodeItemModel::nodeList( QDataStream &stream ) { QList lst; while (!stream.atEnd()) { QString id; stream >> id; Node *node = m_project->findNode( id ); if ( node ) { lst << node; } } return lst; } QList NodeItemModel::removeChildNodes( const QList &nodes ) { QList lst; foreach ( Node *node, nodes ) { bool ins = true; foreach ( Node *n, lst ) { if ( node->isChildOf( n ) ) { //debugPlan<name()<<" is child of"<name(); ins = false; break; } } if ( ins ) { //debugPlan<<" insert"<name(); lst << node; } } QList nl = lst; QList nlst = lst; foreach ( Node *node, nl ) { foreach ( Node *n, nlst ) { if ( n->isChildOf( node ) ) { //debugPlan<name()<<" is child of"<name(); int i = nodes.indexOf( n ); lst.removeAt( i ); } } } return lst; } bool NodeItemModel::dropResourceMimeData( const QMimeData *data, Qt::DropAction action, int /*row*/, int /*column*/, const QModelIndex &parent ) { QByteArray encodedData = data->data( "application/x-vnd.kde.plan.resourceitemmodel.internal" ); QDataStream stream(&encodedData, QIODevice::ReadOnly); Node *n = node( parent ); debugPlan<name(); if ( parent.column() == NodeModel::NodeResponsible ) { QString s; foreach ( Resource *r, resourceList( stream ) ) { s += r->name(); } if ( ! s.isEmpty() ) { if ( action == Qt::CopyAction && ! n->leader().isEmpty() ) { s += ',' + n->leader(); } KUndo2Command *cmd = m_nodemodel.setLeader( n, s, Qt::EditRole ); if ( cmd ) { emit executeCommand( cmd ); } debugPlan<type() == Node::Type_Task ) { QList lst = resourceList( stream ); if ( action == Qt::CopyAction ) { lst += static_cast( n )->requestedResources(); } KUndo2Command *cmd = createAllocationCommand( static_cast( *n ), lst ); if ( cmd ) { emit executeCommand( cmd ); } return true; } return true; } bool NodeItemModel::dropProjectMimeData( const QMimeData *data, Qt::DropAction action, int row, int /*column*/, const QModelIndex &parent ) { Node *n = node( parent ); if ( n == 0 ) { n = m_project; } debugPlan<data( "application/x-vnd.kde.plan.project" ) ); KoXmlElement element = doc.documentElement().namedItem( "project" ).toElement(); Project project; XMLLoaderObject status; status.setVersion( doc.documentElement().attribute( "version", PLAN_FILE_SYNTAX_VERSION ) ); status.setProject( &project ); if ( ! project.load( element, status ) ) { debugPlan<<"Failed to load project"; return false; } project.generateUniqueNodeIds(); KUndo2Command *cmd = new InsertProjectCmd( project, n, n->childNode( row - 1 ), kundo2_i18nc("1=project or task name", "Insert %1", project.name() ) ); emit executeCommand( cmd ); return true; } bool NodeItemModel::dropUrlMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent ) { if ( data->hasUrls() ) { QList urls = data->urls(); debugPlan<bad() ) { // d->lastErrorMessage = i18n( "Not a valid Calligra file: %1", file ); debugPlan<<"bad store"<open( "root" ) ) { // maindoc.xml debugPlan<<"No root"<device() ); KoXmlElement element = doc.documentElement().namedItem( "project" ).toElement(); Project project; XMLLoaderObject status; status.setVersion( doc.documentElement().attribute( "version", PLAN_FILE_SYNTAX_VERSION ) ); status.setProject( &project ); if ( ! project.load( element, status ) ) { debugPlan<<"Failed to load project from:"<childNode( row - 1 ), kundo2_i18n( "Insert %1", url.fileName() ) ); emit executeCommand( cmd ); return true; } KUndo2Command *NodeItemModel::createAllocationCommand( Task &task, const QList &lst ) { MacroCommand *cmd = new MacroCommand( kundo2_i18n( "Modify resource allocations" ) ); QMap groups; foreach ( Resource *r, lst ) { if ( ! groups.contains( r->parentGroup() ) && task.resourceGroupRequest( r->parentGroup() ) == 0 ) { ResourceGroupRequest *gr = new ResourceGroupRequest( r->parentGroup() ); groups[ r->parentGroup() ] = gr; cmd->addCommand( new AddResourceGroupRequestCmd( task, gr ) ); } } QList resources = task.requestedResources(); foreach ( Resource *r, lst ) { if ( resources.contains( r ) ) { continue; } ResourceGroupRequest *gr = groups.value( r->parentGroup() ); if ( gr == 0 ) { gr = task.resourceGroupRequest( r->parentGroup() ); } if ( gr == 0 ) { errorPlan<<"No group request found, cannot add resource request:"<name(); continue; } cmd->addCommand( new AddResourceRequestCmd( gr, new ResourceRequest( r, 100 ) ) ); } foreach ( Resource *r, resources ) { if ( ! lst.contains( r ) ) { ResourceGroupRequest *gr = task.resourceGroupRequest( r->parentGroup() ); ResourceRequest *rr = task.requests().find( r ); if ( gr && rr ) { cmd->addCommand( new RemoveResourceRequestCmd( gr, rr ) ); } } } if ( cmd->isEmpty() ) { delete cmd; return 0; } return cmd; } bool NodeItemModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent ) { debugPlan<hasFormat( "application/x-vnd.kde.plan.resourceitemmodel.internal" ) ) { return dropResourceMimeData( data, action, row, column, parent ); } if ( data->hasFormat( "application/x-vnd.kde.plan.nodeitemmodel.internal" ) ) { if ( action == Qt::MoveAction ) { //debugPlan<<"MoveAction"; QByteArray encodedData = data->data( "application/x-vnd.kde.plan.nodeitemmodel.internal" ); QDataStream stream(&encodedData, QIODevice::ReadOnly); Node *par = 0; if ( parent.isValid() ) { par = node( parent ); } else { par = m_project; } QList lst = nodeList( stream ); QList nodes = removeChildNodes( lst ); // children goes with their parent foreach ( Node *n, nodes ) { if ( ! m_project->canMoveTask( n, par ) ) { //debugPlan<<"Can't move task:"<name(); return false; } } int offset = 0; MacroCommand *cmd = 0; foreach ( Node *n, nodes ) { if ( cmd == 0 ) cmd = new MacroCommand( kundo2_i18n( "Move tasks" ) ); // append nodes if dropped *on* another node, insert if dropped *after* int pos = row == -1 ? -1 : row + offset; if ( pos >= 0 && n->parentNode() == par && par->indexOf( n ) < pos ) { --pos; } if ( n->parentNode() == par ) { // avoid drop into the same position, QAbstractItemModel does not like it int crow = par->indexOf( n ); if ( ( ( pos == -1 ) && ( crow == par->numChildren() - 1 ) ) || ( pos == crow ) ) { delete cmd; cmd = 0; continue; } } cmd->addCommand( new NodeMoveCmd( m_project, n, par, pos ) ); offset++; } if ( cmd ) { emit executeCommand( cmd ); } //debugPlan<name(); return true; } } if ( data->hasFormat( "application/x-vnd.kde.plan.project" ) ) { debugPlan; return dropProjectMimeData( data, action, row, column, parent ); } if ( data->hasUrls() ) { return dropUrlMimeData( data, action, row, column, parent ); } return false; } Node *NodeItemModel::node( const QModelIndex &index ) const { Node *n = m_project; if ( index.isValid() ) { //debugPlan<( index.internalPointer() ); Q_ASSERT( n ); } return n; } void NodeItemModel::slotNodeChanged( Node *node ) { if ( node == 0 || ( ! m_projectshown && node->type() == Node::Type_Project ) ) { return; } if ( node->type() == Node::Type_Project ) { emit dataChanged( createIndex( 0, 0, node ), createIndex( 0, columnCount()-1, node ) ); return; } int row = node->parentNode()->findChildNode( node ); Q_ASSERT( row >= 0 ); emit dataChanged( createIndex( row, 0, node ), createIndex( row, columnCount()-1, node ) ); } QModelIndex NodeItemModel::insertTask( Node *node, Node *after ) { MacroCommand *cmd = new MacroCommand( kundo2_i18n( "Add task" ) ); cmd->addCommand( new TaskAddCmd( m_project, node, after ) ); if ( m_project && node->type() == Node::Type_Task ) { QMap groups; foreach ( Resource *r, m_project->autoAllocateResources() ) { if ( ! groups.contains( r->parentGroup() ) ) { ResourceGroupRequest *gr = new ResourceGroupRequest( r->parentGroup() ); cmd->addCommand( new AddResourceGroupRequestCmd( static_cast(*node), gr ) ); groups[ r->parentGroup() ] = gr; } ResourceRequest *rr = new ResourceRequest( r, 100 ); cmd->addCommand( new AddResourceRequestCmd( groups[ r->parentGroup() ], rr ) ); } } emit executeCommand( cmd ); int row = -1; if ( node->parentNode() ) { row = node->parentNode()->indexOf( node ); } if ( row != -1 ) { //debugPlan<<"Inserted: "<name()<<"; "<name(); return QModelIndex(); } QModelIndex NodeItemModel::insertSubtask( Node *node, Node *parent ) { emit executeCommand( new SubtaskAddCmd( m_project, node, parent, kundo2_i18n( "Add sub-task" ) ) ); int row = -1; if ( node->parentNode() ) { row = node->parentNode()->indexOf( node ); } if ( row != -1 ) { //debugPlan<parentNode()<<" inserted: "<name()<<"; "<name(); return QModelIndex(); } int NodeItemModel::sortRole( int column ) const { int v = Qt::DisplayRole; switch ( column ) { case NodeModel::NodeStartTime: case NodeModel::NodeEndTime: case NodeModel::NodeActualStart: case NodeModel::NodeActualFinish: case NodeModel::NodeEarlyStart: case NodeModel::NodeEarlyFinish: case NodeModel::NodeLateStart: case NodeModel::NodeLateFinish: case NodeModel::NodeConstraintStart: case NodeModel::NodeConstraintEnd: v = Qt::EditRole; break; case NodeModel::NodeWBSCode: v = NodeModel::SortableRole; break; default: break; } debugPlan< lst = parentmap.values(); while ( ! lst.isEmpty() ) delete (int*)(lst.takeFirst()); } int GanttItemModel::rowCount( const QModelIndex &parent ) const { if ( m_showSpecial ) { if ( parentmap.values().contains( parent.internalPointer() ) ) { return 0; } Node *n = node( parent ); if ( n && n->type() == Node::Type_Task ) { return 5; // the task + early start + late finish ++ } } return NodeItemModel::rowCount( parent ); } QModelIndex GanttItemModel::index( int row, int column, const QModelIndex &parent ) const { if ( m_showSpecial && parent.isValid() ) { Node *p = node( parent ); if ( p->type() == Node::Type_Task ) { void *v = 0; foreach ( void *i, parentmap.values( p ) ) { if ( *( (int*)( i ) ) == row ) { v = i; break; } } if ( v == 0 ) { v = new int( row ); const_cast( this )->parentmap.insertMulti( p, v ); } return createIndex( row, column, v ); } } return NodeItemModel::index( row, column, parent ); } QModelIndex GanttItemModel::parent( const QModelIndex &idx ) const { if ( m_showSpecial ) { QList lst = parentmap.keys( idx.internalPointer() ); if ( ! lst.isEmpty() ) { Q_ASSERT( lst.count() == 1 ); return index( lst.first() ); } } return NodeItemModel::parent( idx ); } QVariant GanttItemModel::data( const QModelIndex &index, int role ) const { if ( ! index.isValid() ) { return QVariant(); } if ( role == Qt::TextAlignmentRole ) { return headerData( index.column(), Qt::Horizontal, role ); } QModelIndex idx = index; QList lst; if ( m_showSpecial ) { lst = parentmap.keys( idx.internalPointer() ); } if ( ! lst.isEmpty() ) { Q_ASSERT( lst.count() == 1 ); int row = *((int*)(idx.internalPointer())); Node *n = lst.first(); if ( role == SpecialItemTypeRole ) { return row; // 0=task, 1=early start, 2=late finish... } switch ( row ) { case 0: // the task if ( idx.column() == NodeModel::NodeType && role == KGantt::ItemTypeRole ) { switch ( n->type() ) { case Node::Type_Task: return KGantt::TypeTask; default: break; } } break; case 1: { // early start if ( role != Qt::DisplayRole && role != Qt::EditRole && role != KGantt::ItemTypeRole ) { return QVariant(); } switch ( idx.column() ) { case NodeModel::NodeName: return "Early Start"; case NodeModel::NodeType: return KGantt::TypeEvent; case NodeModel::NodeStartTime: case NodeModel::NodeEndTime: return n->earlyStart( id() ); default: break; } } case 2: { // late finish if ( role != Qt::DisplayRole && role != Qt::EditRole && role != KGantt::ItemTypeRole ) { return QVariant(); } switch ( idx.column() ) { case NodeModel::NodeName: return "Late Finish"; case NodeModel::NodeType: return KGantt::TypeEvent; case NodeModel::NodeStartTime: case NodeModel::NodeEndTime: return n->lateFinish( id() ); default: break; } } case 3: { // late start if ( role != Qt::DisplayRole && role != Qt::EditRole && role != KGantt::ItemTypeRole ) { return QVariant(); } switch ( idx.column() ) { case NodeModel::NodeName: return "Late Start"; case NodeModel::NodeType: return KGantt::TypeEvent; case NodeModel::NodeStartTime: case NodeModel::NodeEndTime: return n->lateStart( id() ); default: break; } } case 4: { // early finish if ( role != Qt::DisplayRole && role != Qt::EditRole && role != KGantt::ItemTypeRole ) { return QVariant(); } switch ( idx.column() ) { case NodeModel::NodeName: return "Early Finish"; case NodeModel::NodeType: return KGantt::TypeEvent; case NodeModel::NodeStartTime: case NodeModel::NodeEndTime: return n->earlyFinish( id() ); default: break; } } default: return QVariant(); } idx = createIndex( idx.row(), idx.column(), n ); } else { if ( role == SpecialItemTypeRole ) { return 0; // task of some type } if ( idx.column() == NodeModel::NodeType && role == KGantt::ItemTypeRole ) { QVariant result = NodeItemModel::data( idx, Qt::EditRole ); switch ( result.toInt() ) { case Node::Type_Project: return KGantt::TypeSummary; case Node::Type_Summarytask: return KGantt::TypeSummary; case Node::Type_Milestone: return KGantt::TypeEvent; default: return m_showSpecial ? KGantt::TypeMulti : KGantt::TypeTask; } } } return NodeItemModel::data( idx, role ); } //---------------------------- MilestoneItemModel::MilestoneItemModel( QObject *parent ) : ItemModelBase( parent ) { } MilestoneItemModel::~MilestoneItemModel() { } QList MilestoneItemModel::mileStones() const { QList lst; foreach( Node* n, m_nodemap ) { if ( n->type() == Node::Type_Milestone ) { lst << n; } } return lst; } void MilestoneItemModel::slotNodeToBeInserted( Node *parent, int row ) { Q_UNUSED(parent); Q_UNUSED(row); } void MilestoneItemModel::slotNodeInserted( Node *node ) { Q_UNUSED(node); resetModel(); } void MilestoneItemModel::slotNodeToBeRemoved( Node *node ) { Q_UNUSED(node); //debugPlan<name(); /* int row = m_nodemap.values().indexOf( node ); if ( row != -1 ) { Q_ASSERT( m_nodemap.contains( node->wbsCode() ) ); Q_ASSERT( m_nodemap.keys().indexOf( node->wbsCode() ) == row ); beginRemoveRows( QModelIndex(), row, row ); m_nodemap.remove( node->wbsCode() ); endRemoveRows(); }*/ } void MilestoneItemModel::slotNodeRemoved( Node *node ) { Q_UNUSED(node); resetModel(); //endRemoveRows(); } void MilestoneItemModel::slotLayoutChanged() { //debugPlan<name(); emit layoutAboutToBeChanged(); emit layoutChanged(); } void MilestoneItemModel::slotNodeToBeMoved( Node *node, int pos, Node *newParent, int newPos ) { Q_UNUSED( node ); Q_UNUSED( pos ); Q_UNUSED( newParent ); Q_UNUSED( newPos ); } void MilestoneItemModel::slotNodeMoved( Node *node ) { Q_UNUSED( node ); resetModel(); } void MilestoneItemModel::setProject( Project *project ) { if ( m_project ) { disconnect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); disconnect( m_project, SIGNAL(localeChanged()), this, SLOT(slotLayoutChanged()) ); disconnect( m_project, SIGNAL(wbsDefinitionChanged()), this, SLOT(slotWbsDefinitionChanged()) ); disconnect( m_project, SIGNAL(nodeChanged(Node*)), this, SLOT(slotNodeChanged(Node*)) ); disconnect( m_project, SIGNAL(nodeToBeAdded(Node*,int)), this, SLOT(slotNodeToBeInserted(Node*,int)) ); disconnect( m_project, SIGNAL(nodeToBeRemoved(Node*)), this, SLOT(slotNodeToBeRemoved(Node*)) ); disconnect(m_project, SIGNAL(nodeToBeMoved(Node*,int,Node*,int)), this, SLOT(slotNodeToBeMoved(Node*,int,Node*,int))); disconnect(m_project, SIGNAL(nodeMoved(Node*)), this, SLOT(slotNodeMoved(Node*))); disconnect( m_project, SIGNAL(nodeAdded(Node*)), this, SLOT(slotNodeInserted(Node*)) ); disconnect( m_project, SIGNAL(nodeRemoved(Node*)), this, SLOT(slotNodeRemoved(Node*)) ); } m_project = project; //debugPlan<"<allNodes() ) { m_nodemap.insert( n->wbsCode(true), n ); } } return cnt != m_nodemap.count(); } void MilestoneItemModel::resetModel() { resetData(); reset(); } Qt::ItemFlags MilestoneItemModel::flags( const QModelIndex &index ) const { Qt::ItemFlags flags = QAbstractItemModel::flags( index ); if ( !index.isValid() ) { if ( m_readWrite ) { flags |= Qt::ItemIsDropEnabled; } return flags; } if ( m_readWrite ) { flags |= Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; switch ( index.column() ) { case NodeModel::NodeName: // name flags |= Qt::ItemIsEditable; break; case NodeModel::NodeType: break; // Node type case NodeModel::NodeResponsible: // Responsible flags |= Qt::ItemIsEditable; break; case NodeModel::NodeConstraint: // constraint type flags |= Qt::ItemIsEditable; break; case NodeModel::NodeConstraintStart: { // constraint start Node *n = node( index ); if ( n == 0 ) break; int c = n->constraint(); if ( c == Node::MustStartOn || c == Node::StartNotEarlier || c == Node::FixedInterval ) { flags |= Qt::ItemIsEditable; } break; } case NodeModel::NodeConstraintEnd: { // constraint end Node *n = node( index ); if ( n == 0 ) break; int c = n->constraint(); if ( c == Node::MustFinishOn || c == Node::FinishNotLater || c == Node::FixedInterval ) { flags |= Qt::ItemIsEditable; } break; } case NodeModel::NodeStartupAccount: // startup account case NodeModel::NodeStartupCost: // startup cost case NodeModel::NodeShutdownAccount: // shutdown account case NodeModel::NodeShutdownCost: { // shutdown cost Node *n = node( index ); if ( n && (n->type() == Node::Type_Task || n->type() == Node::Type_Milestone) ) { flags |= Qt::ItemIsEditable; } break; } case NodeModel::NodeDescription: // description break; default: flags &= ~Qt::ItemIsEditable; } } return flags; } QModelIndex MilestoneItemModel::parent( const QModelIndex &index ) const { Q_UNUSED(index); return QModelIndex(); } QModelIndex MilestoneItemModel::index( int row, int column, const QModelIndex &parent ) const { //debugPlan<= m_nodemap.count() ) { //debugPlan<<"No index for"<( node ) ), 0, const_cast(node) ); } QVariant MilestoneItemModel::data( const QModelIndex &index, int role ) const { QVariant result; if ( role == Qt::TextAlignmentRole ) { return headerData( index.column(), Qt::Horizontal, role ); } Node *n = node( index ); if ( n != 0 ) { if ( index.column() == NodeModel::NodeType && role == KGantt::ItemTypeRole ) { result = m_nodemodel.data( n, index.column(), Qt::EditRole ); switch ( result.toInt() ) { case Node::Type_Summarytask: return KGantt::TypeSummary; case Node::Type_Milestone: return KGantt::TypeEvent; default: return KGantt::TypeTask; } return result; } } result = m_nodemodel.data( n, index.column(), role ); return result; } bool MilestoneItemModel::setData( const QModelIndex &index, const QVariant &/*value*/, int role ) { if ( ( flags(index) &Qt::ItemIsEditable ) == 0 || role != Qt::EditRole ) { return false; } // Node *n = node( index ); switch (index.column()) { default: qWarning("data: invalid display value column %d", index.column()); return false; } return false; } QVariant MilestoneItemModel::headerData( int section, Qt::Orientation orientation, int role ) const { if ( orientation == Qt::Horizontal ) { if (role == Qt::DisplayRole || role == Qt::TextAlignmentRole || role == Qt::EditRole) { return m_nodemodel.headerData(section, role); } } if ( role == Qt::ToolTipRole ) { return NodeModel::headerData( section, role ); } return ItemModelBase::headerData(section, orientation, role); } QAbstractItemDelegate *MilestoneItemModel::createDelegate( int column, QWidget *parent ) const { switch ( column ) { case NodeModel::NodeEstimateType: return new EnumDelegate( parent ); case NodeModel::NodeEstimateCalendar: return new EnumDelegate( parent ); case NodeModel::NodeEstimate: return new DurationSpinBoxDelegate( parent ); case NodeModel::NodeOptimisticRatio: return new SpinBoxDelegate( parent ); case NodeModel::NodePessimisticRatio: return new SpinBoxDelegate( parent ); case NodeModel::NodeRisk: return new EnumDelegate( parent ); case NodeModel::NodeConstraint: return new EnumDelegate( parent ); case NodeModel::NodeRunningAccount: return new EnumDelegate( parent ); case NodeModel::NodeStartupAccount: return new EnumDelegate( parent ); case NodeModel::NodeStartupCost: return new MoneyDelegate( parent ); case NodeModel::NodeShutdownAccount: return new EnumDelegate( parent ); case NodeModel::NodeShutdownCost: return new MoneyDelegate( parent ); case NodeModel::NodeCompleted: return new TaskCompleteDelegate( parent ); case NodeModel::NodeRemainingEffort: return new DurationSpinBoxDelegate( parent ); case NodeModel::NodeActualEffort: return new DurationSpinBoxDelegate( parent ); default: return 0; } return 0; } int MilestoneItemModel::columnCount( const QModelIndex &/*parent*/ ) const { return m_nodemodel.propertyCount(); } int MilestoneItemModel::rowCount( const QModelIndex &parent ) const { //debugPlan< rows; foreach (const QModelIndex &index, indexes) { if ( index.isValid() && !rows.contains( index.row() ) ) { //debugPlan<id(); } } } m->setData("application/x-vnd.kde.plan.nodeitemmodel.internal", encodedData); return m; } bool MilestoneItemModel::dropAllowed( const QModelIndex &index, int dropIndicatorPosition, const QMimeData *data ) { //debugPlan; Node *dn = node( index ); if ( dn == 0 ) { errorPlan<<"no node to drop on!"; return false; // hmmm } switch ( dropIndicatorPosition ) { case ItemModelBase::AboveItem: case ItemModelBase::BelowItem: // dn == sibling return dropAllowed( dn->parentNode(), data ); case ItemModelBase::OnItem: // dn == new parent return dropAllowed( dn, data ); default: break; } return false; } bool MilestoneItemModel::dropAllowed( Node *on, const QMimeData *data ) { if ( !data->hasFormat("application/x-vnd.kde.plan.nodeitemmodel.internal") ) { return false; } if ( on == m_project ) { return true; } QByteArray encodedData = data->data( "application/x-vnd.kde.plan.nodeitemmodel.internal" ); QDataStream stream(&encodedData, QIODevice::ReadOnly); QList lst = nodeList( stream ); foreach ( Node *n, lst ) { if ( on == n || on->isChildOf( n ) ) { return false; } } lst = removeChildNodes( lst ); foreach ( Node *n, lst ) { if ( ! m_project->canMoveTask( n, on ) ) { return false; } } return true; } QList MilestoneItemModel::nodeList( QDataStream &stream ) { QList lst; while (!stream.atEnd()) { QString id; stream >> id; Node *node = m_project->findNode( id ); if ( node ) { lst << node; } } return lst; } QList MilestoneItemModel::removeChildNodes( const QList &nodes ) { QList lst; foreach ( Node *node, nodes ) { bool ins = true; foreach ( Node *n, lst ) { if ( node->isChildOf( n ) ) { //debugPlan<name()<<" is child of"<name(); ins = false; break; } } if ( ins ) { //debugPlan<<" insert"<name(); lst << node; } } QList nl = lst; QList nlst = lst; foreach ( Node *node, nl ) { foreach ( Node *n, nlst ) { if ( n->isChildOf( node ) ) { //debugPlan<name()<<" is child of"<name(); int i = nodes.indexOf( n ); lst.removeAt( i ); } } } return lst; } bool MilestoneItemModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int /*column*/, const QModelIndex &parent ) { //debugPlan<hasFormat( "application/x-vnd.kde.plan.nodeitemmodel.internal" ) ) { return false; } if ( action == Qt::MoveAction ) { //debugPlan<<"MoveAction"; QByteArray encodedData = data->data( "application/x-vnd.kde.plan.nodeitemmodel.internal" ); QDataStream stream(&encodedData, QIODevice::ReadOnly); Node *par = 0; if ( parent.isValid() ) { par = node( parent ); } else { par = m_project; } QList lst = nodeList( stream ); QList nodes = removeChildNodes( lst ); // children goes with their parent foreach ( Node *n, nodes ) { if ( ! m_project->canMoveTask( n, par ) ) { //debugPlan<<"Can't move task:"<name(); return false; } } int offset = 0; MacroCommand *cmd = 0; foreach ( Node *n, nodes ) { if ( cmd == 0 ) cmd = new MacroCommand( kundo2_i18n( "Move tasks" ) ); // append nodes if dropped *on* another node, insert if dropped *after* int pos = row == -1 ? -1 : row + offset; cmd->addCommand( new NodeMoveCmd( m_project, n, par, pos ) ); offset++; } if ( cmd ) { emit executeCommand( cmd ); } //debugPlan<name(); return true; } return false; } Node *MilestoneItemModel::node( const QModelIndex &index ) const { Node *n = 0; if ( index.isValid() ) { //debugPlan<( index.internalPointer() ); } return n; } void MilestoneItemModel::slotNodeChanged( Node *node ) { //debugPlan<name(); if ( node == 0 ) { return; } // if ( ! m_nodemap.contains( node->wbsCode() ) || m_nodemap.value( node->wbsCode() ) != node ) { emit layoutAboutToBeChanged(); if ( resetData() ) { reset(); } else { emit layoutChanged(); } return; /* } int row = m_nodemap.values().indexOf( node ); debugPlan<name()<<": "<typeToString()<( sourceModel() ); } void NodeSortFilterProxyModel::setFilterUnscheduled( bool on ) { m_filterUnscheduled = on; invalidateFilter(); } bool NodeSortFilterProxyModel::filterAcceptsRow ( int row, const QModelIndex & parent ) const { //debugPlan<project() == 0 ) { //debugPlan<project(); return false; } if ( m_filterUnscheduled ) { QString s = sourceModel()->data( sourceModel()->index( row, NodeModel::NodeNotScheduled, parent ), Qt::EditRole ).toString(); if ( s == "true" ) { //debugPlan<<"Filtered unscheduled:"<index( row, 0, parent ); return false; } } bool accepted = QSortFilterProxyModel::filterAcceptsRow( row, parent ); //debugPlan<index( row, 0, parent )<<"accepted ="<sortRole(column)); QSortFilterProxyModel::sort(column, order); } //------------------ TaskModuleModel::TaskModuleModel( QObject *parent ) : QAbstractItemModel( parent ) { } -void TaskModuleModel::addTaskModule( Project *project ) +void TaskModuleModel::addTaskModule( Project *project, const QUrl &url ) { beginInsertRows( QModelIndex(), m_modules.count(), m_modules.count() ); m_modules << project; + m_urls << url; endInsertRows(); } Qt::ItemFlags TaskModuleModel::flags( const QModelIndex &idx ) const { Qt::ItemFlags f = QAbstractItemModel::flags( idx ) | Qt::ItemIsDropEnabled; if ( idx.isValid() ) { f |= Qt::ItemIsDragEnabled; } return f; } int TaskModuleModel::columnCount (const QModelIndex &/*idx*/ ) const { return 1; } int TaskModuleModel::rowCount( const QModelIndex &idx ) const { return idx.isValid() ? 0 : m_modules.count(); } QVariant TaskModuleModel::data( const QModelIndex& idx, int role ) const { + if (!idx.isValid() || idx.row() >= m_modules.count()) { + return QVariant(); + } switch ( role ) { case Qt::DisplayRole: return m_modules.value( idx.row() )->name(); case Qt::ToolTipRole: return m_modules.value( idx.row() )->description(); case Qt::WhatsThisRole: return m_modules.value( idx.row() )->description(); + case Qt::UserRole: return m_urls.value(idx.row()); default: break; } return QVariant(); } QVariant TaskModuleModel::headerData( int /*section*/, Qt::Orientation orientation , int role ) const { if ( orientation == Qt::Horizontal ) { switch ( role ) { case Qt::DisplayRole: return xi18nc( "@title:column", "Name" ); default: break; } } return QVariant(); } QModelIndex TaskModuleModel::parent( const QModelIndex& /*idx*/ ) const { return QModelIndex(); } QModelIndex TaskModuleModel::index( int row, int column, const QModelIndex &parent ) const { if ( parent.isValid() ) { return QModelIndex(); } return createIndex( row, column, m_modules.value( row ) ); } QStringList TaskModuleModel::mimeTypes() const { return QStringList() << "application/x-vnd.kde.plan" << "text/uri-list"; } bool TaskModuleModel::dropMimeData( const QMimeData *data, Qt::DropAction /*action*/, int /*row*/, int /*column*/, const QModelIndex &/*parent*/ ) { if ( data->hasUrls() ) { QList urls = data->urls(); debugPlan<bad() ) { // d->lastErrorMessage = i18n( "Not a valid Calligra file: %1", file ); debugPlan<<"bad store"<open( "root" ) ) { // maindoc.xml debugPlan<<"No root"<device() ); KoXmlElement element = doc.documentElement().namedItem( "project" ).toElement(); Project *project = new Project(); XMLLoaderObject status; status.setVersion( doc.documentElement().attribute( "version", PLAN_FILE_SYNTAX_VERSION ) ); status.setProject( project ); if ( project->load( element, status ) ) { stripProject( project ); - addTaskModule( project ); + addTaskModule( project, url ); if ( emitsignal ) { // FIXME: save destroys the project, so give it a copy (see kptview.cpp) Project p; status.setProject( &p ); p.load( element, status ); emit saveTaskModule( url, &p ); } } else { debugPlan<<"Failed to load project from:"<save( doc ); mime->setData( "application/x-vnd.kde.plan.project", document.toByteArray() ); } } return mime; } void TaskModuleModel::stripProject( Project *project ) const { foreach ( ScheduleManager *sm, project->scheduleManagers() ) { DeleteScheduleManagerCmd c( *project, sm ); } } void TaskModuleModel::loadTaskModules( const QStringList &files ) { debugPlan< 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 NODEITEMMODEL_H #define NODEITEMMODEL_H #include "kptitemmodelbase.h" #include "kptschedule.h" #include "kptworkpackagemodel.h" #include #include #include +#include -class QUrl; class QMimeData; class KUndo2Command; class KoXmlWriter; class KoStore; class KoOdfWriteStore; namespace KPlato { class Project; class Node; class Estimate; class KPLATOMODELS_EXPORT NodeModel : public QObject { Q_OBJECT Q_ENUMS( Properties ) public: NodeModel(); ~NodeModel() {} enum SpecialRoles { SortableRole = Qt::UserRole + 5024 // unlikely high number }; enum Properties { NodeName = 0, NodeType, NodeResponsible, NodeAllocation, NodeEstimateType, NodeEstimateCalendar, NodeEstimate, NodeOptimisticRatio, NodePessimisticRatio, NodeRisk, NodeConstraint, NodeConstraintStart, NodeConstraintEnd, NodeRunningAccount, NodeStartupAccount, NodeStartupCost, NodeShutdownAccount, NodeShutdownCost, NodeDescription, // Based on edited values NodeExpected, NodeVarianceEstimate, NodeOptimistic, NodePessimistic, // After scheduling NodeStartTime, NodeEndTime, NodeEarlyStart, NodeEarlyFinish, NodeLateStart, NodeLateFinish, NodePositiveFloat, NodeFreeFloat, NodeNegativeFloat, NodeStartFloat, NodeFinishFloat, NodeAssignments, // Based on scheduled values NodeDuration, NodeVarianceDuration, NodeOptimisticDuration, NodePessimisticDuration, // Completion NodeStatus, NodeCompleted, NodePlannedEffort, NodeActualEffort, NodeRemainingEffort, NodePlannedCost, NodeActualCost, NodeActualStart, NodeStarted, NodeActualFinish, NodeFinished, NodeStatusNote, // Scheduling errors NodeSchedulingStatus, NodeNotScheduled, NodeAssignmentMissing, NodeResourceOverbooked, NodeResourceUnavailable, NodeConstraintsError, NodeEffortNotMet, NodeSchedulingError, NodeWBSCode, NodeLevel, // Performance NodeBCWS, NodeBCWP, NodeACWP, NodePerformanceIndex, // NodeCritical, NodeCriticalPath, // Info from latest work package transmission WPOwnerName, WPTransmitionStatus, WPTransmitionTime }; const QMetaEnum columnMap() const; void setProject( Project *project ); void setManager( ScheduleManager *sm ); Project *project() const { return m_project; } ScheduleManager *manager() const { return m_manager; } long id() const { return m_manager == 0 ? -1 : m_manager->scheduleId(); } QVariant data( const Node *node, int property, int role = Qt::DisplayRole ) const; KUndo2Command *setData( Node *node, int property, const QVariant & value, int role = Qt::EditRole ); static QVariant headerData( int section, int role = Qt::DisplayRole ); int propertyCount() const; void setNow( const QDate &now ) { m_now = now; } QDate now() const { return m_now; } QVariant name( const Node *node, int role ) const; QVariant leader( const Node *node, int role ) const; QVariant allocation( const Node *node, int role ) const; QVariant description( const Node *node, int role ) const; QVariant type( const Node *node, int role ) const; QVariant constraint( const Node *node, int role ) const; QVariant constraintStartTime( const Node *node, int role ) const; QVariant constraintEndTime( const Node *node, int role ) const; QVariant estimateType( const Node *node, int role ) const; QVariant estimateCalendar( const Node *node, int role ) const; QVariant estimate( const Node *node, int role ) const; QVariant optimisticRatio( const Node *node, int role ) const; QVariant pessimisticRatio( const Node *node, int role ) const; QVariant riskType( const Node *node, int role ) const; QVariant runningAccount( const Node *node, int role ) const; QVariant startupAccount( const Node *node, int role ) const; QVariant startupCost( const Node *node, int role ) const; QVariant shutdownAccount( const Node *node, int role ) const; QVariant shutdownCost( const Node *node, int role ) const; QVariant startTime( const Node *node, int role ) const; QVariant endTime( const Node *node, int role ) const; QVariant duration( const Node *node, int role ) const; QVariant varianceDuration( const Node *node, int role ) const; QVariant varianceEstimate( const Estimate *est, int role ) const; QVariant optimisticDuration( const Node *node, int role ) const; QVariant optimisticEstimate( const Estimate *est, int role ) const; QVariant pertExpected( const Estimate *est, int role ) const; QVariant pessimisticDuration( const Node *node, int role ) const; QVariant pessimisticEstimate( const Estimate *est, int role ) const; QVariant earlyStart( const Node *node, int role ) const; QVariant earlyFinish( const Node *node, int role ) const; QVariant lateStart( const Node *node, int role ) const; QVariant lateFinish( const Node *node, int role ) const; QVariant positiveFloat( const Node *node, int role ) const; QVariant freeFloat( const Node *node, int role ) const; QVariant negativeFloat( const Node *node, int role ) const; QVariant startFloat( const Node *node, int role ) const; QVariant finishFloat( const Node *node, int role ) const; QVariant assignedResources( const Node *node, int role ) const; QVariant status( const Node *node, int role ) const; QVariant completed( const Node *node, int role ) const; QVariant startedTime( const Node *node, int role ) const; QVariant isStarted( const Node *node, int role ) const; QVariant finishedTime( const Node *node, int role ) const; QVariant isFinished( const Node *node, int role ) const; QVariant plannedEffortTo( const Node *node, int role ) const; QVariant actualEffortTo( const Node *node, int role ) const; QVariant remainingEffort( const Node *node, int role ) const; QVariant plannedCostTo( const Node *node, int role ) const; QVariant actualCostTo( const Node *node, int role ) const; QVariant note( const Node *node, int role ) const; /// The nodes scheduling status QVariant nodeSchedulingStatus( const Node *node, int role ) const; /// Set if the node has not been scheduled QVariant nodeIsNotScheduled( const Node *node, int role ) const; /// Set if EffortType == Effort, but no resource is requested QVariant resourceIsMissing( const Node *node, int role ) const; /// Set if the assigned resource is overbooked QVariant resourceIsOverbooked( const Node *node, int role ) const; /// Set if the requested resource is not available QVariant resourceIsNotAvailable( const Node *node, int role ) const; /// Set if the task cannot be scheduled to fullfil all the constraints QVariant schedulingConstraintsError( const Node *node, int role ) const; /// Resources could not fullfil estimate QVariant effortNotMet( const Node *node, int role ) const; /// Other scheduling error occurred QVariant schedulingError( const Node *node, int role ) const; QVariant wbsCode( const Node *node, int role ) const; QVariant nodeLevel( const Node *node, int role ) const; QVariant nodeBCWS( const Node *node, int role ) const; QVariant nodeBCWP( const Node *node, int role ) const; QVariant nodeACWP( const Node *node, int role ) const; QVariant nodePerformanceIndex( const Node *node, int role ) const; QVariant nodeIsCritical( const Node *node, int role ) const; QVariant nodeInCriticalPath( const Node *node, int role ) const; QVariant wpOwnerName( const Node *node, int role ) const; QVariant wpTransmitionStatus( const Node *node, int role ) const; QVariant wpTransmitionTime( const Node *node, int role ) const; KUndo2Command *setName( Node *node, const QVariant &value, int role ); KUndo2Command *setLeader( Node *node, const QVariant &value, int role ); KUndo2Command *setAllocation( Node *node, const QVariant &value, int role ); KUndo2Command *setDescription( Node *node, const QVariant &value, int role ); KUndo2Command *setType( Node *node, const QVariant &value, int role ); KUndo2Command *setConstraint( Node *node, const QVariant &value, int role ); KUndo2Command *setConstraintStartTime( Node *node, const QVariant &value, int role ); KUndo2Command *setConstraintEndTime( Node *node, const QVariant &value, int role ); KUndo2Command *setEstimateType( Node *node, const QVariant &value, int role ); KUndo2Command *setEstimateCalendar( Node *node, const QVariant &value, int role ); KUndo2Command *setEstimate( Node *node, const QVariant &value, int role ); KUndo2Command *setOptimisticRatio( Node *node, const QVariant &value, int role ); KUndo2Command *setPessimisticRatio( Node *node, const QVariant &value, int role ); KUndo2Command *setRiskType( Node *node, const QVariant &value, int role ); KUndo2Command *setRunningAccount( Node *node, const QVariant &value, int role ); KUndo2Command *setStartupAccount( Node *node, const QVariant &value, int role ); KUndo2Command *setStartupCost( Node *node, const QVariant &value, int role ); KUndo2Command *setShutdownAccount( Node *node, const QVariant &value, int role ); KUndo2Command *setShutdownCost( Node *node, const QVariant &value, int role ); KUndo2Command *setCompletion( Node *node, const QVariant &value, int role ); KUndo2Command *setActualEffort( Node *node, const QVariant &value, int role ); KUndo2Command *setRemainingEffort( Node *node, const QVariant &value, int role ); KUndo2Command *setStartedTime( Node *node, const QVariant &value, int role ); KUndo2Command *setFinishedTime( Node *node, const QVariant &value, int role ); private: Project *m_project; ScheduleManager *m_manager; QDate m_now; int m_prec; }; class KPLATOMODELS_EXPORT NodeItemModel : public ItemModelBase { Q_OBJECT public: explicit NodeItemModel( QObject *parent = 0 ); ~NodeItemModel(); /// Returns a column number/- name map for this model virtual const QMetaEnum columnMap() const { return m_nodemodel.columnMap(); } ScheduleManager *manager() const { return m_nodemodel.manager(); } long id() const { return m_nodemodel.id(); } virtual Qt::ItemFlags flags( const QModelIndex & index ) const; virtual QModelIndex parent( const QModelIndex & index ) const; virtual QModelIndex index( int row, int column, const QModelIndex & parent = QModelIndex() ) const; virtual QModelIndex index( const Node *node, int column = 0 ) const; virtual int columnCount( const QModelIndex & parent = QModelIndex() ) const; virtual int rowCount( const QModelIndex & parent = QModelIndex() ) const; virtual QVariant data( const QModelIndex & index, int role = Qt::DisplayRole ) const; virtual bool setData( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole ); virtual QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; virtual QMimeData * mimeData( const QModelIndexList & indexes ) const; virtual QStringList mimeTypes () const; virtual Qt::DropActions supportedDropActions() const; virtual bool dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent ); Node *node( const QModelIndex &index ) const; QAbstractItemDelegate *createDelegate( int column, QWidget *parent ) const; QModelIndex insertTask( Node *node, Node *after ); QModelIndex insertSubtask( Node *node, Node *parent ); QList nodeList( QDataStream &stream ); QList resourceList( QDataStream &stream ); static QList removeChildNodes( const QList &nodes ); bool dropAllowed( Node *on, const QMimeData *data ); virtual bool dropAllowed( const QModelIndex &index, int dropIndicatorPosition, const QMimeData *data ); bool projectShown() const { return m_projectshown; } /// Return the sortorder to be used for @p column virtual int sortRole( int column ) const; Q_SIGNALS: void nodeInserted( Node *node ); void projectShownChanged( bool ); public Q_SLOTS: virtual void setProject( Project *project ); virtual void setScheduleManager( ScheduleManager *sm ); void setShowProject( bool on ); protected Q_SLOTS: virtual void slotWbsDefinitionChanged(); virtual void slotNodeChanged( Node* ); virtual void slotNodeToBeInserted( Node *node, int row ); virtual void slotNodeInserted( Node *node ); virtual void slotNodeToBeRemoved( Node *node ); virtual void slotNodeRemoved( Node *node ); virtual void slotNodeToBeMoved( Node *node, int pos, Node *newParent, int newPos ); virtual void slotNodeMoved( Node *node ); virtual void slotLayoutChanged(); virtual void slotProjectCalculated( ScheduleManager *sm ); protected: virtual bool setType( Node *node, const QVariant &value, int role ); bool setCompletion( Node *node, const QVariant &value, int role ); bool setAllocation( Node *node, const QVariant &value, int role ); bool dropResourceMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent ); bool dropProjectMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent ); KUndo2Command *createAllocationCommand( Task &task, const QList &lst ); bool dropUrlMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent ); bool importProjectFile( const QUrl &url, Qt::DropAction action, int row, int column, const QModelIndex &parent ); protected: Node *m_node; // for sanety check NodeModel m_nodemodel; bool m_projectshown; }; //-------------------------------------- class KPLATOMODELS_EXPORT GanttItemModel : public NodeItemModel { Q_OBJECT public: enum GanttModelRoles { SpecialItemTypeRole = Qt::UserRole + 123 }; //FIXME explicit GanttItemModel(QObject *parent = 0); ~GanttItemModel(); virtual int rowCount( const QModelIndex &parent ) const; using NodeItemModel::index; virtual QModelIndex index( int row, int column, const QModelIndex &parent ) const; QModelIndex parent( const QModelIndex &idx ) const; virtual QVariant data( const QModelIndex & index, int role = Qt::DisplayRole ) const; void setShowSpecial( bool on ) { m_showSpecial = on; } bool showSpecial() const { return m_showSpecial; } private: bool m_showSpecial; QMap parentmap; }; // TODO: Rename, this is now a flat node item model class KPLATOMODELS_EXPORT MilestoneItemModel : public ItemModelBase { Q_OBJECT public: explicit MilestoneItemModel( QObject *parent = 0 ); ~MilestoneItemModel(); /// Returns a column number/- name map for this model virtual const QMetaEnum columnMap() const { return m_nodemodel.columnMap(); } ScheduleManager *manager() const { return m_nodemodel.manager(); } long id() const { return m_nodemodel.id(); } virtual Qt::ItemFlags flags( const QModelIndex & index ) const; virtual QModelIndex parent( const QModelIndex & index ) const; virtual QModelIndex index( int row, int column, const QModelIndex & parent = QModelIndex() ) const; virtual QModelIndex index( const Node *node ) const; virtual int columnCount( const QModelIndex & parent = QModelIndex() ) const; virtual int rowCount( const QModelIndex & parent = QModelIndex() ) const; virtual QVariant data( const QModelIndex & index, int role = Qt::DisplayRole ) const; virtual bool setData( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole ); virtual QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; virtual QMimeData * mimeData( const QModelIndexList & indexes ) const; virtual QStringList mimeTypes () const; virtual Qt::DropActions supportedDropActions() const; virtual bool dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent ); Node *node( const QModelIndex &index ) const; virtual QAbstractItemDelegate *createDelegate( int column, QWidget *parent ) const; QModelIndex insertTask( Node *node, Node *after ); QModelIndex insertSubtask( Node *node, Node *parent ); QList nodeList( QDataStream &stream ); static QList removeChildNodes( const QList &nodes ); bool dropAllowed( Node *on, const QMimeData *data ); virtual bool dropAllowed( const QModelIndex &index, int dropIndicatorPosition, const QMimeData *data ); QList mileStones() const; int sortRole(int column) const; public Q_SLOTS: virtual void setProject( Project *project ); virtual void setScheduleManager( ScheduleManager *sm ); protected Q_SLOTS: void slotNodeChanged( Node* ); void slotNodeToBeInserted( Node *node, int row ); void slotNodeInserted( Node *node ); void slotNodeToBeRemoved( Node *node ); void slotNodeRemoved( Node *node ); void slotNodeToBeMoved( Node *node, int pos, Node *newParent, int newPos ); void slotNodeMoved( Node *node ); void slotLayoutChanged(); void slotWbsDefinitionChanged(); protected: bool resetData(); void resetModel(); private: NodeModel m_nodemodel; QMap m_nodemap; }; class KPLATOMODELS_EXPORT NodeSortFilterProxyModel : public QSortFilterProxyModel { Q_OBJECT public: NodeSortFilterProxyModel( ItemModelBase* model, QObject *parent, bool filterUnscheduled = true ); ItemModelBase *itemModel() const; void setFilterUnscheduled( bool on ); bool filterUnscheduled() const { return m_filterUnscheduled; } void sort(int column, Qt::SortOrder order = Qt::AscendingOrder); protected: bool filterAcceptsRow ( int source_row, const QModelIndex & source_parent ) const; private: NodeItemModel *m_model; bool m_filterUnscheduled; }; class KPLATOMODELS_EXPORT TaskModuleModel : public QAbstractItemModel { Q_OBJECT public: explicit TaskModuleModel(QObject *parent = 0); - void addTaskModule( Project *project ); + void addTaskModule(Project *project , const QUrl &url); Qt::ItemFlags flags( const QModelIndex &idx ) const; int columnCount( const QModelIndex &idx = QModelIndex() ) const; int rowCount( const QModelIndex &idx = QModelIndex() ) const; QVariant data( const QModelIndex &idx, int role = Qt::DisplayRole ) const; QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; QModelIndex parent( const QModelIndex &idx ) const; QModelIndex index( int row, int column, const QModelIndex &parent ) const; QStringList mimeTypes() const; bool dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent ); QMimeData *mimeData( const QModelIndexList &idx ) const; bool importProject( const QUrl &url, bool emitsignal = true ); public Q_SLOTS: void loadTaskModules( const QStringList &files ); Q_SIGNALS: void executeCommand( KUndo2Command *cmd ); void saveTaskModule( const QUrl &url, Project *project ); void removeTaskModule( const QUrl &url ); protected: void stripProject( Project *project ) const; private: QList m_modules; + QList m_urls; }; } //namespace KPlato #endif //NODEITEMMODEL_H diff --git a/plan/libs/ui/CMakeLists.txt b/plan/libs/ui/CMakeLists.txt index 62ceb99be5c..62850335595 100644 --- a/plan/libs/ui/CMakeLists.txt +++ b/plan/libs/ui/CMakeLists.txt @@ -1,179 +1,181 @@ include_directories( ${CMAKE_SOURCE_DIR}/plan/libs/kernel ${CMAKE_SOURCE_DIR}/plan/libs/models ${CMAKE_BINARY_DIR}/plan/libs/models ${CMAKE_BINARY_DIR}/plan/libs/ui ${KOMAIN_INCLUDES} ${KDEPIMLIBS_INCLUDE_DIR} ) #add_subdirectory( tests ) ########### KPlato private library ############### if (PLAN_BUILD_REPORTS) message(STATUS "-- Building plan with reports capability") add_subdirectory(reports/items) set(planreports_LIB_SRC reports/reportview.cpp reports/reportdata.cpp reports/reportsourceeditor.cpp reports/reportscripts.cpp ) set(planreports_ui_LIB_SRCS reports/reportsourceeditor.ui reports/reportnavigator.ui reports/reportsectionswidget.ui reports/reportgroupsectionswidget.ui reports/reporttoolswidget.ui ) endif() set(kplatoui_LIB_SRCS ${planreports_LIB_SRC} + WhatsThis.cpp + TasksEditController.cpp TasksEditDialog.cpp welcome/WelcomeView.cpp reportsgenerator/ReportsGeneratorView.cpp kptganttitemdelegate.cpp kptworkpackagesendpanel.cpp kptworkpackagesenddialog.cpp kptdocumentseditor.cpp kptdocumentspanel.cpp kptitemviewsettup.cpp kptsplitterview.cpp kptrelationeditor.cpp kptdependencyeditor.cpp kptusedefforteditor.cpp kpttaskstatusview.cpp kptcalendareditor.cpp kptviewbase.cpp kptaccountseditor.cpp kptperteditor.cpp kptpertresult.cpp kpttaskeditor.cpp kptresourceeditor.cpp kptscheduleeditor.cpp kptsummarytaskdialog.cpp kptsummarytaskgeneralpanel.cpp kptresourceappointmentsview.cpp kptaccountsviewconfigdialog.cpp kptaccountsview.cpp kpttaskcostpanel.cpp kptmilestoneprogresspanel.cpp kptmilestoneprogressdialog.cpp kpttaskdialog.cpp kptmainprojectdialog.cpp kptmainprojectpanel.cpp kptganttview.cpp kptrelationdialog.cpp kptrequestresourcespanel.cpp kptresourcedialog.cpp kptstandardworktimedialog.cpp kptintervaledit.cpp kpttaskgeneralpanel.cpp kpttaskprogresspanel.cpp kpttaskprogressdialog.cpp kpttaskdescriptiondialog.cpp kptwbsdefinitiondialog.cpp kptwbsdefinitionpanel.cpp kptresourceassignmentview.cpp kptperformancetablewidget.cpp kptresourceallocationeditor.cpp kptworkpackagemergedialog.cpp kptrecalculatedialog.cpp kpthtmlview.cpp locale/localemon.cpp kptlocaleconfigmoneydialog.cpp ResourceAllocationView.cpp ) ki18n_wrap_ui(kplatoui_LIB_SRCS ${planreports_ui_LIB_SRCS} welcome/WelcomeView.ui kptresourceappointmentsdisplayoptions.ui kptganttchartdisplayoptions.ui kptprintingheaderfooter.ui kptganttprintingoptions.ui kptworkpackagesendpanel.ui kptdocumentspanel.ui kptperformancestatus.ui kptcpmwidget.ui kptitemviewsettings.ui kptpertresult.ui standardworktimedialogbase.ui kptwbsdefinitionpanelbase.ui kptaccountsviewconfigurepanelbase.ui kptintervaleditbase.ui kpttaskcostpanelbase.ui kpttaskdescriptionpanelbase.ui kptsummarytaskgeneralpanelbase.ui kptmilestoneprogresspanelbase.ui resourcedialogbase.ui kptmainprojectpanelbase.ui relationpanel.ui kpttaskgeneralpanelbase.ui kpttaskprogresspanelbase.ui kptperteditor.ui kptresourceassignmentview.ui kpttaskstatusviewsettingspanel.ui kptperformancestatusviewsettingspanel.ui kptworkpackagemergepanel.ui kptrecalculatedialog.ui kptscheduleeditor.ui locale/localemon.ui ) add_library(kplatoui SHARED ${kplatoui_LIB_SRCS}) generate_export_header(kplatoui) target_link_libraries(kplatoui PUBLIC komain kplatokernel kplatomodels KGantt KF5::KHtml PRIVATE KChart KF5::ItemViews KF5::IconThemes KF5::Archive Qt5::Sql ) if (PLAN_BUILD_REPORTS) target_link_libraries(kplatoui PUBLIC KReport PRIVATE KPropertyWidgets) endif() if(KF5AkonadiContact_FOUND) target_link_libraries(kplatoui PRIVATE KF5::AkonadiContact) endif() set_target_properties(kplatoui PROPERTIES VERSION ${GENERIC_CALLIGRA_LIB_VERSION} SOVERSION ${GENERIC_CALLIGRA_LIB_SOVERSION} ) install(TARGETS kplatoui ${INSTALL_TARGETS_DEFAULT_ARGS}) # diff --git a/plan/libs/ui/WhatsThis.cpp b/plan/libs/ui/WhatsThis.cpp new file mode 100644 index 00000000000..50fec598ca8 --- /dev/null +++ b/plan/libs/ui/WhatsThis.cpp @@ -0,0 +1,61 @@ +/* This file is part of the KDE project + Copyright (C) 2017 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 "WhatsThis.h" + +#include +#include +#include +#include +#include + +namespace KPlato +{ + +namespace WhatsThis { + +void add(QWidget *widget, const QString &text) +{ + widget->installEventFilter(new WhatsThisClickedEventHandler(widget)); + widget->setWhatsThis(text); +} + +WhatsThisClickedEventHandler::WhatsThisClickedEventHandler(QObject *parent) + : QObject(parent) +{ + +} + +bool WhatsThisClickedEventHandler::eventFilter(QObject *object, QEvent *event) +{ + Q_UNUSED(object); + if (event->type() == QEvent::WhatsThisClicked) { + QWhatsThisClickedEvent *e = static_cast(event); + QUrl url(e->href()); + if (url.isValid()) { + QDesktopServices::openUrl(url); + } + return true; + } + return false; +} + +} + +} // namespace KPlato diff --git a/plan/libs/ui/WhatsThis.h b/plan/libs/ui/WhatsThis.h new file mode 100644 index 00000000000..00d27faa40e --- /dev/null +++ b/plan/libs/ui/WhatsThis.h @@ -0,0 +1,44 @@ +/* This file is part of the KDE project + Copyright (C) 2017 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 "kplatoui_export.h" + +#include + +class QEvent; + +namespace KPlato +{ +namespace WhatsThis +{ + KPLATOUI_EXPORT void add(QWidget *widget, const QString &text); + +class KPLATOUI_EXPORT WhatsThisClickedEventHandler : public QObject +{ + Q_OBJECT +public: + WhatsThisClickedEventHandler(QObject *parent=0); + + bool eventFilter(QObject *object, QEvent *event); + +}; + +} // namespace WhatsThis + +} // namespace KPlato diff --git a/plan/libs/ui/kptmainprojectdialog.cpp b/plan/libs/ui/kptmainprojectdialog.cpp index 01a278742bb..f534b8e7b82 100644 --- a/plan/libs/ui/kptmainprojectdialog.cpp +++ b/plan/libs/ui/kptmainprojectdialog.cpp @@ -1,86 +1,91 @@ /* This file is part of the KDE project Copyright (C) 2003 - 2007 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 "kptmainprojectdialog.h" #include "kptproject.h" #include "kptmainprojectpanel.h" #include "kptcommand.h" #include namespace KPlato { -MainProjectDialog::MainProjectDialog(Project &p, QWidget *parent, const char */*name*/) +MainProjectDialog::MainProjectDialog(Project &p, QWidget *parent, bool edit) : KoDialog( parent), project(p) { setWindowTitle( i18n("Project Settings") ); setButtons( Ok|Cancel ); setDefaultButton( Ok ); showButtonSeparator( true ); panel = new MainProjectPanel(project, this); + panel->projectsLoadBtn->setVisible(edit); + panel->projectsClearBtn->setVisible(edit); setMainWidget(panel); enableButtonOk(false); resize( QSize(500, 410).expandedTo(minimumSizeHint())); connect(this, SIGNAL(rejected()), SLOT(slotRejected())); connect(this, SIGNAL(accepted()), SLOT(slotOk())); connect(panel, SIGNAL(obligatedFieldsFilled(bool)), SLOT(enableButtonOk(bool))); + + connect(panel, SIGNAL(loadResourceAssignments(QUrl)), this, SIGNAL(loadResourceAssignments(QUrl))); + connect(panel, SIGNAL(clearResourceAssignments()), this, SIGNAL(clearResourceAssignments())); } void MainProjectDialog::slotRejected() { emit dialogFinished(QDialog::Rejected); } void MainProjectDialog::slotOk() { if (!panel->ok()) { return; } if (panel->loadSharedResources()) { QString file = panel->resourcesFile->text(); if (file.startsWith('/')) { file.prepend("file:/"); } QString place = panel->projectsPlace->text(); if (panel->projectsType->currentIndex() == 0 /*dir*/ && !place.isEmpty() && !place.endsWith('/')) { place.append('/'); } QUrl url(place); - emit sigLoadSharedResources(file, url); + emit sigLoadSharedResources(file, url, panel->projectsLoadAtStartup->isChecked()); } emit dialogFinished(QDialog::Accepted); } MacroCommand *MainProjectDialog::buildCommand() { MacroCommand *m = 0; KUndo2MagicString c = kundo2_i18n("Modify main project"); MacroCommand *cmd = panel->buildCommand(); if (cmd) { if (!m) m = new MacroCommand(c); m->addCommand(cmd); } return m; } } //KPlato namespace diff --git a/plan/libs/ui/kptmainprojectdialog.h b/plan/libs/ui/kptmainprojectdialog.h index 21b0b29c873..cf19eaba6d2 100644 --- a/plan/libs/ui/kptmainprojectdialog.h +++ b/plan/libs/ui/kptmainprojectdialog.h @@ -1,60 +1,62 @@ /* This file is part of the KDE project Copyright (C) 2003 - 2007 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 KPTMAINPROJECTDIALOG_H #define KPTMAINPROJECTDIALOG_H #include "kplatoui_export.h" #include namespace KPlato { class Project; class MainProjectPanel; class MacroCommand; class KPLATOUI_EXPORT MainProjectDialog : public KoDialog { Q_OBJECT public: - explicit MainProjectDialog(Project &project, QWidget *parent=0, const char *name=0); + explicit MainProjectDialog(Project &project, QWidget *parent=0, bool edit=true); MacroCommand *buildCommand(); bool loadSharedResources(); Q_SIGNALS: void dialogFinished(int); - void sigLoadSharedResources(const QString &file, const QUrl &projects); + void sigLoadSharedResources(const QString &file, const QUrl &projects, bool loadProjects=false); + void loadResourceAssignments(QUrl url); + void clearResourceAssignments(); protected Q_SLOTS: void slotRejected(); void slotOk(); private: Project &project; MainProjectPanel *panel; }; } //KPlato namespace #endif // MAINPROJECTDIALOG_H diff --git a/plan/libs/ui/kptmainprojectpanel.cpp b/plan/libs/ui/kptmainprojectpanel.cpp index a7bf0b868a9..9ed2eb9b17a 100644 --- a/plan/libs/ui/kptmainprojectpanel.cpp +++ b/plan/libs/ui/kptmainprojectpanel.cpp @@ -1,278 +1,306 @@ /* This file is part of the KDE project Copyright (C) 2004-2007, 2011, 2012 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 "kptmainprojectpanel.h" #include "kptdebug.h" #include #ifdef PLAN_KDEPIMLIBS_FOUND #include #include #include #endif #include "kptproject.h" #include "kptcommand.h" #include "kptschedule.h" #include "kpttaskdescriptiondialog.h" #include namespace KPlato { MainProjectPanel::MainProjectPanel(Project &p, QWidget *parent) : QWidget(parent), project(p) { setupUi(this); #ifndef PLAN_KDEPIMLIBS_FOUND chooseLeader->hide(); #endif // FIXME // [Bug 311940] New: Plan crashes when typing a text in the filter textbox before the textbook is fully loaded when selecting a contact from the adressbook chooseLeader->hide(); QString s = i18n( "The Work Breakdown Structure introduces numbering for all tasks in the project, according to the task structure.\nThe WBS code is auto-generated.\nYou can define the WBS code pattern using the Define WBS Pattern command in the Tools menu." ); wbslabel->setWhatsThis( s ); wbs->setWhatsThis( s ); namefield->setText(project.name()); leaderfield->setText(project.leader()); // useSharedResources->setEnabled(!project.isSharedResourcesLoaded()); useSharedResources->setChecked(project.useSharedResources()); resourcesFile->setText(project.sharedResourcesFile()); projectsPlace->setText(project.sharedProjectsUrl().toDisplayString()); qInfo()<widget(1) ); m_description->namefield->hide(); m_description->namelabel->hide(); wbs->setText(project.wbsCode()); if ( wbs->text().isEmpty() ) { wbslabel->hide(); wbs->hide(); } DateTime st = project.constraintStartTime(); DateTime et = project.constraintEndTime(); startDate->setDate(st.date()); startTime->setTime( QTime( st.time().hour(), st.time().minute(), 0 ) ); endDate->setDate(et.date()); endTime->setTime( QTime( et.time().hour(), et.time().minute(), 0 ) ); enableDateTime(); namefield->setFocus(); useSharedResources->setToolTip(xi18nc("@info:tooltip", "Enables sharing resources with other projects")); useSharedResources->setWhatsThis(xi18nc("@info:whatsthis", "Shared resources" "Resources can be shared between projects" " to avoid overbooking resources across projects." " Shared resources must be defined in a separate file," " and you must have at least read access to it." " The projects that share the resources must also be" " accessible by you." )); s = xi18nc("@info:tooltip", "File where shared resources are defined"); resourcesLabel->setToolTip(s); resourcesType->setToolTip(s); resourcesFile->setToolTip(s); s = xi18nc("@info:tooltip", "Directory where all the projects that share resources can be found"); projectsLabel->setToolTip(s); projectsType->setToolTip(s); projectsPlace->setToolTip(s); + projectsLoadAtStartup->setChecked(project.loadProjectsAtStartup()); + projectsLoadAtStartup->setToolTip(xi18nc("@info:tooltip", "Load shared resource assignments at startup")); + + projectsLoadBtn->setToolTip(xi18nc("@info:tooltip", "Load (or re-load) shared resource assignments")); + projectsClearBtn->setToolTip(xi18nc("@info:tooltip", "Clear shared resource assignments")); + // signals and slots connections connect( m_description, SIGNAL(textChanged(bool)), this, SLOT(slotCheckAllFieldsFilled()) ); connect( endDate, SIGNAL(dateChanged(QDate)), this, SLOT(slotCheckAllFieldsFilled()) ); connect( endTime, SIGNAL(timeChanged(QTime)), this, SLOT(slotCheckAllFieldsFilled()) ); connect( startDate, SIGNAL(dateChanged(QDate)), this, SLOT(slotCheckAllFieldsFilled()) ); connect( startTime, SIGNAL(timeChanged(QTime)), this, SLOT(slotCheckAllFieldsFilled()) ); connect( namefield, SIGNAL(textChanged(QString)), this, SLOT(slotCheckAllFieldsFilled()) ); connect( leaderfield, SIGNAL(textChanged(QString)), this, SLOT(slotCheckAllFieldsFilled()) ); connect( useSharedResources, SIGNAL(toggled(bool)), this, SLOT(slotCheckAllFieldsFilled()) ); connect( resourcesFile, SIGNAL(textChanged(const QString&)), this, SLOT(slotCheckAllFieldsFilled()) ); connect( projectsPlace, SIGNAL(textChanged(const QString&)), this, SLOT(slotCheckAllFieldsFilled()) ); + connect(projectsLoadAtStartup, SIGNAL(toggled(bool)), this, SLOT(slotCheckAllFieldsFilled())); connect( chooseLeader, SIGNAL(clicked()), this, SLOT(slotChooseLeader()) ); connect(resourcesBrowseBtn, SIGNAL(clicked()), this, SLOT(openResourcesFile())); connect(projectsBrowseBtn, SIGNAL(clicked()), this, SLOT(openProjectsPlace())); + connect(projectsLoadBtn, SIGNAL(clicked()), this, SLOT(loadProjects())); + connect(projectsClearBtn, SIGNAL(clicked()), this, SLOT(clearProjects())); } bool MainProjectPanel::ok() { if (useSharedResources->isChecked() && resourcesFile->text().isEmpty()) { return false; } return true; } MacroCommand *MainProjectPanel::buildCommand() { MacroCommand *m = 0; KUndo2MagicString c = kundo2_i18n("Modify main project"); if (project.name() != namefield->text()) { if (!m) m = new MacroCommand(c); m->addCommand(new NodeModifyNameCmd(project, namefield->text())); } if (project.leader() != leaderfield->text()) { if (!m) m = new MacroCommand(c); m->addCommand(new NodeModifyLeaderCmd(project, leaderfield->text())); } if (startDateTime() != project.constraintStartTime()) { if (!m) m = new MacroCommand(c); m->addCommand(new ProjectModifyStartTimeCmd(project, startDateTime())); } if (endDateTime() != project.constraintEndTime()) { if (!m) m = new MacroCommand(c); m->addCommand(new ProjectModifyEndTimeCmd(project, endDateTime())); } if (project.useSharedResources() != useSharedResources->isChecked()) { if (!m) m = new MacroCommand(c); m->addCommand(new UseSharedResourcesCmd(&project, useSharedResources->isChecked())); } if (project.sharedResourcesFile() != resourcesFile->text()) { if (!m) m = new MacroCommand(c); m->addCommand(new SharedResourcesFileCmd( &project, resourcesFile->text())); } QString place = projectsPlace->text(); if (projectsType->currentIndex() == 0 /*dir*/ && !place.isEmpty() && !place.endsWith('/')) { place.append('/'); } QUrl sharedProjectsUrl(place); if (project.sharedProjectsUrl() != sharedProjectsUrl) { if (!m) m = new MacroCommand(c); m->addCommand(new SharedProjectsUrlCmd( &project, sharedProjectsUrl)); } + if (project.loadProjectsAtStartup() != projectsLoadAtStartup->isChecked()) { + if (!m) m = new MacroCommand(c); + m->addCommand(new LoadProjectsAtStartupCmd( &project, projectsLoadAtStartup->isChecked())); + } MacroCommand *cmd = m_description->buildCommand(); if ( cmd ) { if (!m) m = new MacroCommand(c); m->addCommand( cmd ); } return m; } void MainProjectPanel::slotCheckAllFieldsFilled() { emit changed(); bool state = !namefield->text().isEmpty(); if (!project.isSharedResourcesLoaded()) { state = !useSharedResources->isChecked() || !resourcesFile->text().isEmpty(); } emit obligatedFieldsFilled(state); } void MainProjectPanel::slotChooseLeader() { #ifdef PLAN_KDEPIMLIBS_FOUND QPointer dlg = new Akonadi::EmailAddressSelectionDialog( this ); if ( dlg->exec() && dlg ) { QStringList names; const Akonadi::EmailAddressSelection::List selections = dlg->selectedAddresses(); foreach ( const Akonadi::EmailAddressSelection &selection, selections ) { QString s = selection.name(); if ( ! selection.email().isEmpty() ) { if ( ! selection.name().isEmpty() ) { s += " <"; } s += selection.email(); if ( ! selection.name().isEmpty() ) { s += '>'; } if ( ! s.isEmpty() ) { names << s; } } } if ( ! names.isEmpty() ) { leaderfield->setText( names.join( ", " ) ); } } #endif } void MainProjectPanel::slotStartDateClicked() { enableDateTime(); } void MainProjectPanel::slotEndDateClicked() { enableDateTime(); } void MainProjectPanel::enableDateTime() { debugPlan; startTime->setEnabled(true); startDate->setEnabled(true); endTime->setEnabled(true); endDate->setEnabled(true); } QDateTime MainProjectPanel::startDateTime() { return QDateTime(startDate->date(), startTime->time(), Qt::LocalTime); } QDateTime MainProjectPanel::endDateTime() { return QDateTime(endDate->date(), endTime->time(), Qt::LocalTime); } void MainProjectPanel::openResourcesFile() { QString fileName = QFileDialog::getOpenFileName(this, tr("Open Resources"), "", tr("Resources file (*.plan)")); resourcesFile->setText(fileName); } void MainProjectPanel::openProjectsPlace() { if (projectsType->currentIndex() == 0 /*Directory*/) { qInfo()<setText(dirName); return; } if (projectsType->currentIndex() == 1 /*File*/) { QString fileName = QFileDialog::getOpenFileName(this, tr("Open Projects"), "", tr("Projects file (*)")); projectsPlace->setText(fileName); return; } Q_ASSERT(false); // Unimplemented projects type } bool MainProjectPanel::loadSharedResources() const { return useSharedResources->isChecked(); } +void MainProjectPanel::loadProjects() +{ + QString place = projectsPlace->text(); + if (projectsType->currentIndex() == 0 /*dir*/ && !place.isEmpty() && !place.endsWith('/')) { + place.append('/'); + } + QUrl url(place); + emit loadResourceAssignments(url); +} + +void MainProjectPanel::clearProjects() +{ + emit clearResourceAssignments(); +} + } //KPlato namespace diff --git a/plan/libs/ui/kptmainprojectpanel.h b/plan/libs/ui/kptmainprojectpanel.h index 81f26a691f2..ff81f7727eb 100644 --- a/plan/libs/ui/kptmainprojectpanel.h +++ b/plan/libs/ui/kptmainprojectpanel.h @@ -1,75 +1,79 @@ /* This file is part of the KDE project Copyright (C) 2004-2007 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 KPTMAINPROJECTPANEL_H #define KPTMAINPROJECTPANEL_H #include "kplatoui_export.h" #include "ui_kptmainprojectpanelbase.h" #include class QDateTime; namespace KPlato { class Project; class MacroCommand; class TaskDescriptionPanel; class MainProjectPanel : public QWidget, public Ui_MainProjectPanelBase { Q_OBJECT public: explicit MainProjectPanel(Project &project, QWidget *parent=0); virtual QDateTime startDateTime(); virtual QDateTime endDateTime(); MacroCommand *buildCommand(); bool ok(); bool loadSharedResources() const; public Q_SLOTS: virtual void slotCheckAllFieldsFilled(); virtual void slotChooseLeader(); virtual void slotStartDateClicked(); virtual void slotEndDateClicked(); virtual void enableDateTime(); private Q_SLOTS: void openResourcesFile(); void openProjectsPlace(); + void loadProjects(); + void clearProjects(); Q_SIGNALS: void obligatedFieldsFilled(bool); void changed(); + void loadResourceAssignments(QUrl url); + void clearResourceAssignments(); private: TaskDescriptionPanel *m_description; Project &project; }; } //KPlato namespace #endif // MAINPROJECTPANEL_H diff --git a/plan/libs/ui/kptmainprojectpanelbase.ui b/plan/libs/ui/kptmainprojectpanelbase.ui index 56f41037976..324ba58cd17 100644 --- a/plan/libs/ui/kptmainprojectpanelbase.ui +++ b/plan/libs/ui/kptmainprojectpanelbase.ui @@ -1,374 +1,405 @@ Dag Andersen <danders@get2net.dk> KPlato::MainProjectPanelBase 0 0 - 387 - 460 + 489 + 520 0 0 0 0 0 General WBS: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 20 0 QFrame::StyledPanel QFrame::Sunken false The project name. &Name: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false namefield 0 0 The project name. The project leader. &Manager: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false leaderfield 0 0 The project leader. Choose a project leader from your address book. &Choose... Scheduling Range Earliest start: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Latest finish: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Qt::Horizontal 40 20 &Use shared resources true false Resources: File Browse... .. + + + + Projects: + + + Directory Browse... .. - - - - Projects: - - + + + + + + Load resource assignments at startup + + + + + + + Load + + + + + + + + + + Clear + + + + + + + Description 0 0 0 0 Qt::Vertical 20 18 KLineEdit QLineEdit
klineedit.h
1
namefield leaderfield chooseLeader startDate startTime endDate endTime useSharedResources toggled(bool) resourcesWidget setEnabled(bool) 242 330 242 344
diff --git a/plan/libs/ui/kpttaskeditor.cpp b/plan/libs/ui/kpttaskeditor.cpp index 5ecbd340760..ba3eb3debef 100644 --- a/plan/libs/ui/kpttaskeditor.cpp +++ b/plan/libs/ui/kpttaskeditor.cpp @@ -1,1674 +1,1687 @@ /* This file is part of the KDE project Copyright (C) 2006 - 2010, 2012 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 "kpttaskeditor.h" #include "kptglobal.h" #include "kptcommonstrings.h" #include "kptnodeitemmodel.h" #include "kptcommand.h" #include "kptproject.h" #include "kptitemviewsettup.h" #include "kptworkpackagesenddialog.h" #include "kptworkpackagesendpanel.h" #include "kptdatetime.h" #include "kptdebug.h" #include "kptresourcemodel.h" #include "kptresourceallocationmodel.h" #include "ResourceAllocationView.h" #include "kpttaskdialog.h" #include "TasksEditController.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KPlato { //-------------------- TaskEditorItemModel::TaskEditorItemModel( QObject *parent ) : NodeItemModel( parent ) { } Qt::ItemFlags TaskEditorItemModel::flags( const QModelIndex &index ) const { if ( index.column() == NodeModel::NodeType ) { if ( ! m_readWrite || isColumnReadOnly( index.column() ) ) { return QAbstractItemModel::flags( index ); } Node *n = node( index ); bool baselined = n ? n->isBaselined() : false; if ( n && ! baselined && ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) ) { return QAbstractItemModel::flags( index ) | Qt::ItemIsEditable | Qt::ItemIsDropEnabled; } return QAbstractItemModel::flags( index ) | Qt::ItemIsDropEnabled; } return NodeItemModel::flags( index ); } QVariant TaskEditorItemModel::headerData( int section, Qt::Orientation orientation, int role ) const { if ( orientation == Qt::Horizontal && section == NodeModel::NodeType ) { if ( role == Qt::ToolTipRole ) { return xi18nc( "@info:tooltip", "The type of task or the estimate type of the task" ); } else if ( role == Qt::WhatsThisRole ) { return xi18nc( "@info:whatsthis", "

Indicates the type of task or the estimate type of the task.

" "The type can be set to Milestone, Effort or Duration." "If the type is Summary or Project the type is not editable."); } } return NodeItemModel::headerData(section, orientation, role); } QVariant TaskEditorItemModel::data( const QModelIndex &index, int role ) const { if ( role == Qt::TextAlignmentRole ) { return NodeItemModel::data( index, role ); } Node *n = node( index ); if ( n != 0 && index.column() == NodeModel::NodeType ) { return type( n, role ); } return NodeItemModel::data( index, role ); } bool TaskEditorItemModel::setData( const QModelIndex &index, const QVariant &value, int role ) { Node *n = node( index ); if ( n != 0 && role == Qt::EditRole && index.column() == NodeModel::NodeType ) { return setType( n, value, role ); } return NodeItemModel::setData( index, value, role ); } QVariant TaskEditorItemModel::type( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: { if ( node->type() == Node::Type_Task ) { return node->estimate()->typeToString( true ); } return node->typeToString( true ); } case Qt::EditRole: return node->type(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::ToolTipRole: { if ( node->type() == Node::Type_Task ) { return xi18nc( "@info:tooltip", "Task with estimate type: %1", node->estimate()->typeToString( true ) ); } return xi18nc( "@info:tooltip", "Task type: %1", node->typeToString( true ) ); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::EnumListValue: { if ( node->type() == Node::Type_Milestone ) { return 0; } if ( node->type() == Node::Type_Task ) { return node->estimate()->type() + 1; } return -1; } case Role::EnumList: { QStringList lst; lst << Node::typeToString( Node::Type_Milestone, true ); lst += Estimate::typeToStringList( true ); return lst; } } return QVariant(); } bool TaskEditorItemModel::setType( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { if ( node->type() == Node::Type_Summarytask ) { return false; } int v = value.toInt(); switch ( v ) { case 0: { // Milestone NamedCommand *cmd = 0; if ( node->constraint() == Node::FixedInterval ) { cmd = new NodeModifyConstraintEndTimeCmd( *node, node->constraintStartTime(), kundo2_i18n( "Set type to Milestone" ) ); } else { cmd = new ModifyEstimateCmd( *node, node->estimate()->expectedEstimate(), 0.0, kundo2_i18n( "Set type to Milestone" ) ); } emit executeCommand( cmd ); return true; } default: { // Estimate --v; MacroCommand *m = new MacroCommand( kundo2_i18n( "Set type to %1", Estimate::typeToString( (Estimate::Type)v, true ) ) ); m->addCommand( new ModifyEstimateTypeCmd( *node, node->estimate()->type(), v ) ); if ( node->type() == Node::Type_Milestone ) { if ( node->constraint() == Node::FixedInterval ) { m->addCommand( new NodeModifyConstraintEndTimeCmd( *node, node->constraintStartTime().addDays( 1 ) ) ); } else { m->addCommand( new ModifyEstimateUnitCmd( *node, node->estimate()->unit(), Duration::Unit_d ) ); m->addCommand( new ModifyEstimateCmd( *node, node->estimate()->expectedEstimate(), 1.0 ) ); } } emit executeCommand( m ); return true; } } break; } default: break; } return false; } //-------------------- TaskEditorTreeView::TaskEditorTreeView( QWidget *parent ) : DoubleTreeViewBase( parent ) { TaskEditorItemModel *m = new TaskEditorItemModel( this ); setModel( m ); //setSelectionBehavior( QAbstractItemView::SelectItems ); setSelectionMode( QAbstractItemView::ExtendedSelection ); setSelectionBehavior( QAbstractItemView::SelectRows ); createItemDelegates( m ); setItemDelegateForColumn( NodeModel::NodeType, new EnumDelegate( this ) ); connect( this, SIGNAL(dropAllowed(QModelIndex,int,QDragMoveEvent*)), SLOT(slotDropAllowed(QModelIndex,int,QDragMoveEvent*)) ); } NodeItemModel *TaskEditorTreeView::baseModel() const { NodeSortFilterProxyModel *pr = proxyModel(); if ( pr ) { return static_cast( pr->sourceModel() ); } return static_cast( model() ); } void TaskEditorTreeView::slotDropAllowed( const QModelIndex &index, int dropIndicatorPosition, QDragMoveEvent *event ) { QModelIndex idx = index; NodeSortFilterProxyModel *pr = proxyModel(); if ( pr ) { idx = pr->mapToSource( index ); } event->ignore(); if ( baseModel()->dropAllowed( idx, dropIndicatorPosition, event->mimeData() ) ) { event->accept(); } } //-------------------- NodeTreeView::NodeTreeView( QWidget *parent ) : DoubleTreeViewBase( parent ) { NodeItemModel *m = new NodeItemModel( this ); setModel( m ); //setSelectionBehavior( QAbstractItemView::SelectItems ); setSelectionMode( QAbstractItemView::ExtendedSelection ); setSelectionBehavior( QAbstractItemView::SelectRows ); createItemDelegates( m ); connect( this, SIGNAL(dropAllowed(QModelIndex,int,QDragMoveEvent*)), SLOT(slotDropAllowed(QModelIndex,int,QDragMoveEvent*)) ); } NodeItemModel *NodeTreeView::baseModel() const { NodeSortFilterProxyModel *pr = proxyModel(); if ( pr ) { return static_cast( pr->sourceModel() ); } return static_cast( model() ); } void NodeTreeView::slotDropAllowed( const QModelIndex &index, int dropIndicatorPosition, QDragMoveEvent *event ) { QModelIndex idx = index; NodeSortFilterProxyModel *pr = proxyModel(); if ( pr ) { idx = pr->mapToSource( index ); } event->ignore(); if ( baseModel()->dropAllowed( idx, dropIndicatorPosition, event->mimeData() ) ) { event->accept(); } } //----------------------------------- TaskEditor::TaskEditor(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent ) { debugPlan<<"----------------- Create TaskEditor ----------------------"; QVBoxLayout * l = new QVBoxLayout( this ); l->setMargin( 0 ); m_view = new TaskEditorTreeView( this ); connect(this, SIGNAL(expandAll()), m_view, SLOT(slotExpand())); connect(this, SIGNAL(collapseAll()), m_view, SLOT(slotCollapse())); l->addWidget( m_view ); debugPlan<actionSplitView(); setupGui(); m_view->setEditTriggers( m_view->editTriggers() | QAbstractItemView::EditKeyPressed ); m_view->setDragDropMode( QAbstractItemView::DragDrop ); m_view->setDropIndicatorShown( true ); m_view->setDragEnabled ( true ); m_view->setAcceptDrops( true ); m_view->setAcceptDropsOnView( true ); QList lst1; lst1 << 1 << -1; // only display column 0 (NodeName) in left view QList show; show << NodeModel::NodeResponsible << NodeModel::NodeAllocation << NodeModel::NodeType << NodeModel::NodeEstimateCalendar << NodeModel::NodeEstimate << NodeModel::NodeOptimisticRatio << NodeModel::NodePessimisticRatio << NodeModel::NodeRisk << NodeModel::NodeConstraint << NodeModel::NodeConstraintStart << NodeModel::NodeConstraintEnd << NodeModel::NodeRunningAccount << NodeModel::NodeStartupAccount << NodeModel::NodeStartupCost << NodeModel::NodeShutdownAccount << NodeModel::NodeShutdownCost << NodeModel::NodeDescription; QList lst2; for ( int i = 0; i < model()->columnCount(); ++i ) { if ( ! show.contains( i ) ) { lst2 << i; } } for ( int i = 0; i < show.count(); ++i ) { int sec = m_view->slaveView()->header()->visualIndex( show[ i ] ); //debugPlan<<"move section:"<slaveView()->header()->moveSection( sec, i ); } } m_view->hideColumns( lst1, lst2 ); m_view->masterView()->setDefaultColumns( QList() << NodeModel::NodeName ); m_view->slaveView()->setDefaultColumns( show ); connect( model(), SIGNAL(executeCommand(KUndo2Command*)), doc, SLOT(addCommand(KUndo2Command*)) ); connect( m_view, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex)) ); connect( m_view, SIGNAL(selectionChanged(QModelIndexList)), this, SLOT(slotSelectionChanged(QModelIndexList)) ); connect( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SLOT(slotContextMenuRequested(QModelIndex,QPoint,QModelIndexList)) ); connect( m_view, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); connect(baseModel(), SIGNAL(projectShownChanged(bool)), SLOT(slotProjectShown(bool))); connect(model(), SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), this, SLOT(slotEnableActions())); } void TaskEditor::slotProjectShown( bool on ) { debugPlan<rowCount() > 0 ) { idx = proxyModel()->index( 0, 0 ); m_view->selectionModel()->setCurrentIndex( idx, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows ); } } else if ( baseModel() && baseModel()->rowCount() > 0 ) { idx = baseModel()->index( 0, 0 ); m_view->selectionModel()->setCurrentIndex( idx, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows ); } if ( on && idx.isValid() ) { m_view->masterView()->expand( idx ); } slotEnableActions(); } void TaskEditor::updateReadWrite( bool rw ) { m_view->setReadWrite( rw ); ViewBase::updateReadWrite( rw ); } void TaskEditor::setProject( Project *project ) { debugPlan<setProject( project ); ViewBase::setProject( project ); } void TaskEditor::createDockers() { // Add dockers DockWidget *ds = 0; { ds = new DockWidget( this, "Allocations", xi18nc( "@title resource allocations", "Allocations" ) ); QTreeView *x = new QTreeView( ds ); AllocatedResourceItemModel *m1 = new AllocatedResourceItemModel( x ); x->setModel( m1 ); m1->setProject( project() ); // x->setHeaderHidden( true ); x->setSelectionBehavior( QAbstractItemView::SelectRows ); x->setSelectionMode( QAbstractItemView::ExtendedSelection ); x->expandAll(); x->resizeColumnToContents( 0 ); x->setDragDropMode( QAbstractItemView::DragOnly ); x->setDragEnabled ( true ); ds->setWidget( x ); connect(this, SIGNAL(projectChanged(Project*)), m1, SLOT(setProject(Project*))); connect(this, SIGNAL(taskSelected(Task*)), m1, SLOT(setTask(Task*))); connect(m1, SIGNAL(expandAll()), x, SLOT(expandAll())); connect(m1, SIGNAL(resizeColumnToContents(int)), x, SLOT(resizeColumnToContents(int))); addDocker( ds ); } { ds = new DockWidget( this, "Resources", xi18nc( "@title", "Resources" ) ); ds->setToolTip( xi18nc( "@info:tooltip", "Drag resources into the Task Editor" " and drop into the allocations- or responsible column" ) ); ResourceAllocationView *e = new ResourceAllocationView(part(), ds ); ResourceItemModel *m = new ResourceItemModel( e ); e->setModel( m ); m->setProject( project() ); m->setReadWrite( isReadWrite() ); QList show; show << ResourceModel::ResourceName; for ( int i = m->columnCount() - 1; i >= 0; --i ) { e->setColumnHidden( i, ! show.contains( i ) ); } e->setHeaderHidden( true ); e->setSelectionBehavior( QAbstractItemView::SelectRows ); e->setSelectionMode( QAbstractItemView::ExtendedSelection ); e->expandAll(); e->resizeColumnToContents( ResourceModel::ResourceName ); e->setDragDropMode( QAbstractItemView::DragOnly ); e->setDragEnabled ( true ); ds->setWidget( e ); connect(m_view->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), e, SLOT(setSelectedTasks(const QItemSelection&, const QItemSelection&))); connect(this, SIGNAL(projectChanged(Project*)), m, SLOT(setProject(Project*))); connect(this, SIGNAL(readWriteChanged(bool)), m, SLOT(setReadWrite(bool))); connect(m, SIGNAL(executeCommand(KUndo2Command*)), part(), SLOT(addCommand(KUndo2Command*))); addDocker( ds ); } { ds = new DockWidget( this, "Taskmodules", xi18nc( "@title", "Task Modules" ) ); ds->setToolTip( xi18nc( "@info:tooltip", "Drag a task module into the Task Editor to add it to the project" ) ); ds->setLocation( Qt::LeftDockWidgetArea ); QTreeView *e = new QTreeView( ds ); - TaskModuleModel *m = new TaskModuleModel( e ); - e->setModel( m ); + QSortFilterProxyModel *sf = new QSortFilterProxyModel(e); + TaskModuleModel *m = new TaskModuleModel(sf); + sf->setSourceModel(m); + e->setModel(sf); + e->sortByColumn(0, Qt::AscendingOrder); + e->setSortingEnabled(true); e->setHeaderHidden( true ); e->setRootIsDecorated( false ); e->setSelectionBehavior( QAbstractItemView::SelectRows ); e->setSelectionMode( QAbstractItemView::SingleSelection ); // e->resizeColumnToContents( 0 ); e->setDragDropMode( QAbstractItemView::DragDrop ); e->setAcceptDrops( true ); e->setDragEnabled ( true ); ds->setWidget( e ); + connect(e, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(taskModuleDoubleClicked(QModelIndex))); connect(this, SIGNAL(loadTaskModules(QStringList)), m, SLOT(loadTaskModules(QStringList))); connect(m, SIGNAL(saveTaskModule(QUrl,Project*)), this, SIGNAL(saveTaskModule(QUrl,Project*))); connect(m, SIGNAL(removeTaskModule(QUrl)), this, SIGNAL(removeTaskModule(QUrl))); addDocker( ds ); } } +void TaskEditor::taskModuleDoubleClicked(QModelIndex idx) +{ + QUrl url = idx.data(Qt::UserRole).toUrl(); + if (url.isValid()) { + emit openDocument(url); + } +} + void TaskEditor::setTaskModules(const QStringList& files) { emit loadTaskModules( files ); } void TaskEditor::setGuiActive( bool activate ) { debugPlan<selectionModel()->currentIndex().isValid() && m_view->model()->rowCount() > 0 ) { m_view->selectionModel()->setCurrentIndex(m_view->model()->index( 0, 0 ), QItemSelectionModel::NoUpdate); } } void TaskEditor::slotCurrentChanged( const QModelIndex &curr, const QModelIndex & ) { debugPlan<( selectedNode() ) ); } QModelIndexList TaskEditor::selectedRows() const { #if 0 // Qt bug? return m_view->selectionModel()->selectedRows(); #else QModelIndexList lst; foreach ( QModelIndex i, m_view->selectionModel()->selectedIndexes() ) { if ( i.column() == 0 ) { lst << i; } } return lst; #endif } int TaskEditor::selectedRowCount() const { return selectedRows().count(); } QList TaskEditor::selectedNodes() const { QList lst; foreach ( const QModelIndex &i, selectedRows() ) { Node * n = m_view->baseModel()->node( i ); if ( n != 0 && n->type() != Node::Type_Project ) { lst.append( n ); } } return lst; } Node *TaskEditor::selectedNode() const { QList lst = selectedNodes(); if ( lst.count() != 1 ) { return 0; } return lst.first(); } Node *TaskEditor::currentNode() const { Node * n = m_view->baseModel()->node( m_view->selectionModel()->currentIndex() ); if ( n == 0 || n->type() == Node::Type_Project ) { return 0; } return n; } void TaskEditor::slotContextMenuRequested( const QModelIndex& index, const QPoint& pos, const QModelIndexList &rows ) { QString name; if (rows.count() > 1) { debugPlan< summarytasks; QList tasks; QList milestones; for (const QModelIndex &idx : rows) { Node *node = m_view->baseModel()->node( idx ); if (node) { switch ( node->type() ) { case Node::Type_Task: tasks << static_cast(node); break; case Node::Type_Milestone: milestones << static_cast(node); break; case Node::Type_Summarytask: summarytasks << static_cast(node); break; default: break; } } } if (!tasks.isEmpty()) { editTasks(tasks, pos); return; } return; } Node *node = m_view->baseModel()->node( index ); if ( node == 0 ) { return; } debugPlan<name()<<" :"<type() ) { case Node::Type_Project: name = "task_edit_popup"; break; case Node::Type_Task: name = node->isScheduled( baseModel()->id() ) ? "task_popup" : "task_edit_popup"; break; case Node::Type_Milestone: name = node->isScheduled( baseModel()->id() ) ? "taskeditor_milestone_popup" : "task_edit_popup"; break; case Node::Type_Summarytask: name = "summarytask_popup"; break; default: name = "node_popup"; break; } m_view->setContextMenuIndex(index); if ( name.isEmpty() ) { slotHeaderContextMenuRequested( pos ); m_view->setContextMenuIndex(QModelIndex()); return; } debugPlan<setContextMenuIndex(QModelIndex()); } void TaskEditor::editTasks(const QList &tasks, const QPoint &pos) { QList lst; QAction tasksEdit("Edit..."); if (!tasks.isEmpty()) { TasksEditController *ted = new TasksEditController(*project(), tasks, this); connect(&tasksEdit, SIGNAL(triggered(bool)), ted, SLOT(activate())); connect(ted, SIGNAL(addCommand(KUndo2Command*)), koDocument(), SLOT(addCommand(KUndo2Command*))); lst << &tasksEdit; } lst += contextActionList(); if (!lst.isEmpty()) { QMenu::exec( lst, pos, lst.first() ); } } void TaskEditor::setScheduleManager( ScheduleManager *sm ) { if (!sm && scheduleManager()) { // we should only get here if the only schedule manager is scheduled, // or when last schedule manager is deleted m_domdoc.clear(); QDomElement element = m_domdoc.createElement("expanded"); m_domdoc.appendChild(element); m_view->masterView()->saveExpanded(element); } bool tryexpand = sm && !scheduleManager(); QDomDocument doc; bool expand = sm && scheduleManager(); if (expand) { m_view->masterView()->setObjectName("TaskEditor"); QDomElement element = doc.createElement("expanded"); doc.appendChild(element); m_view->masterView()->saveExpanded(element); } ViewBase::setScheduleManager(sm); m_view->baseModel()->setScheduleManager( sm ); if (expand) { m_view->masterView()->doExpand(doc); } else if (tryexpand) { m_view->masterView()->doExpand(m_domdoc); } } void TaskEditor::slotEnableActions() { updateActionsEnabled( isReadWrite() ); } void TaskEditor::updateActionsEnabled( bool on ) { // debugPlan<setEnabled( false ); actionAddTask->setEnabled( false ); actionAddMilestone->setEnabled( false ); menuAddSubTask->setEnabled( false ); actionAddSubtask->setEnabled( false ); actionAddSubMilestone->setEnabled( false ); actionDeleteTask->setEnabled( false ); actionMoveTaskUp->setEnabled( false ); actionMoveTaskDown->setEnabled( false ); actionIndentTask->setEnabled( false ); actionUnindentTask->setEnabled( false ); return; } int selCount = selectedRowCount(); if ( selCount == 0 ) { if ( currentNode() ) { // there are tasks but none is selected menuAddTask->setEnabled( false ); actionAddTask->setEnabled( false ); actionAddMilestone->setEnabled( false ); menuAddSubTask->setEnabled( false ); actionAddSubtask->setEnabled( false ); actionAddSubMilestone->setEnabled( false ); actionDeleteTask->setEnabled( false ); actionMoveTaskUp->setEnabled( false ); actionMoveTaskDown->setEnabled( false ); actionIndentTask->setEnabled( false ); actionUnindentTask->setEnabled( false ); } else { // we need to be able to add the first task menuAddTask->setEnabled( true ); actionAddTask->setEnabled( true ); actionAddMilestone->setEnabled( true ); menuAddSubTask->setEnabled( false ); actionAddSubtask->setEnabled( false ); actionAddSubMilestone->setEnabled( false ); actionDeleteTask->setEnabled( false ); actionMoveTaskUp->setEnabled( false ); actionMoveTaskDown->setEnabled( false ); actionIndentTask->setEnabled( false ); actionUnindentTask->setEnabled( false ); } return; } Node *n = selectedNode(); // 0 if not a single task, summarytask or milestone if ( selCount == 1 && n == 0 ) { // only project selected menuAddTask->setEnabled( true ); actionAddTask->setEnabled( true ); actionAddMilestone->setEnabled( true ); menuAddSubTask->setEnabled( true ); actionAddSubtask->setEnabled( true ); actionAddSubMilestone->setEnabled( true ); actionDeleteTask->setEnabled( false ); actionMoveTaskUp->setEnabled( false ); actionMoveTaskDown->setEnabled( false ); actionIndentTask->setEnabled( false ); actionUnindentTask->setEnabled( false ); return; } if ( selCount == 1 && n != currentNode() ) { // multi selection in progress menuAddTask->setEnabled( false ); actionAddTask->setEnabled( false ); actionAddMilestone->setEnabled( false ); menuAddSubTask->setEnabled( false ); actionAddSubtask->setEnabled( false ); actionAddSubMilestone->setEnabled( false ); actionDeleteTask->setEnabled( false ); actionMoveTaskUp->setEnabled( false ); actionMoveTaskDown->setEnabled( false ); actionIndentTask->setEnabled( false ); actionUnindentTask->setEnabled( false ); return; } bool baselined = false; Project *p = m_view->project(); if ( p && p->isBaselined() ) { foreach ( Node *n, selectedNodes() ) { if ( n->isBaselined() ) { baselined = true; break; } } } if ( selCount == 1 ) { menuAddTask->setEnabled( true ); actionAddTask->setEnabled( true ); actionAddMilestone->setEnabled( true ); menuAddSubTask->setEnabled( ! baselined || n->type() == Node::Type_Summarytask ); actionAddSubtask->setEnabled( ! baselined || n->type() == Node::Type_Summarytask ); actionAddSubMilestone->setEnabled( ! baselined || n->type() == Node::Type_Summarytask ); actionDeleteTask->setEnabled( ! baselined ); Node *s = n->siblingBefore(); actionMoveTaskUp->setEnabled( s ); actionMoveTaskDown->setEnabled( n->siblingAfter() ); s = n->siblingBefore(); actionIndentTask->setEnabled( ! baselined && s && ! s->isBaselined() ); actionUnindentTask->setEnabled( ! baselined && n->level() > 1 ); return; } // selCount > 1 menuAddTask->setEnabled( false ); actionAddTask->setEnabled( false ); actionAddMilestone->setEnabled( false ); menuAddSubTask->setEnabled( false ); actionAddSubtask->setEnabled( false ); actionAddSubMilestone->setEnabled( false ); actionDeleteTask->setEnabled( ! baselined ); actionMoveTaskUp->setEnabled( false ); actionMoveTaskDown->setEnabled( false ); actionIndentTask->setEnabled( false ); actionUnindentTask->setEnabled( false ); } void TaskEditor::setupGui() { QString name = "taskeditor_add_list"; menuAddTask = new KActionMenu(koIcon("view-task-add"), i18n("Add Task"), this); actionCollection()->addAction("add_task", menuAddTask ); connect( menuAddTask, SIGNAL(triggered(bool)), SLOT(slotAddTask()) ); addAction( name, menuAddTask ); actionAddTask = new QAction( i18n( "Add Task" ), this); actionAddTask->setShortcut( Qt::CTRL + Qt::Key_I ); connect( actionAddTask, SIGNAL(triggered(bool)), SLOT(slotAddTask()) ); menuAddTask->addAction( actionAddTask ); actionAddMilestone = new QAction( i18n( "Add Milestone" ), this ); actionAddMilestone->setShortcut( Qt::CTRL + Qt::ALT + Qt::Key_I ); connect( actionAddMilestone, SIGNAL(triggered(bool)), SLOT(slotAddMilestone()) ); menuAddTask->addAction( actionAddMilestone ); menuAddSubTask = new KActionMenu(koIcon("view-task-child-add"), i18n("Add Sub-Task"), this); actionCollection()->addAction("add_subtask", menuAddTask ); connect( menuAddSubTask, SIGNAL(triggered(bool)), SLOT(slotAddSubtask()) ); addAction( name, menuAddSubTask ); actionAddSubtask = new QAction( i18n( "Add Sub-Task" ), this ); actionAddSubtask->setShortcut( Qt::CTRL + Qt::SHIFT + Qt::Key_I ); connect( actionAddSubtask, SIGNAL(triggered(bool)), SLOT(slotAddSubtask()) ); menuAddSubTask->addAction( actionAddSubtask ); actionAddSubMilestone = new QAction( i18n( "Add Sub-Milestone" ), this ); actionAddSubMilestone->setShortcut( Qt::CTRL + Qt::SHIFT + Qt::ALT + Qt::Key_I ); connect( actionAddSubMilestone, SIGNAL(triggered(bool)), SLOT(slotAddSubMilestone()) ); menuAddSubTask->addAction( actionAddSubMilestone ); actionDeleteTask = new QAction(koIcon("edit-delete"), xi18nc("@action", "Delete"), this); actionCollection()->setDefaultShortcut( actionDeleteTask, Qt::Key_Delete ); actionCollection()->addAction("delete_task", actionDeleteTask ); connect( actionDeleteTask, SIGNAL(triggered(bool)), SLOT(slotDeleteTask()) ); addAction( name, actionDeleteTask ); name = "taskeditor_move_list"; actionIndentTask = new QAction(koIcon("format-indent-more"), i18n("Indent Task"), this); actionCollection()->addAction("indent_task", actionIndentTask ); connect(actionIndentTask, SIGNAL(triggered(bool)), SLOT(slotIndentTask())); addAction( name, actionIndentTask ); actionUnindentTask = new QAction(koIcon("format-indent-less"), i18n("Unindent Task"), this); actionCollection()->addAction("unindent_task", actionUnindentTask ); connect(actionUnindentTask, SIGNAL(triggered(bool)), SLOT(slotUnindentTask())); addAction( name, actionUnindentTask ); actionMoveTaskUp = new QAction(koIcon("arrow-up"), i18n("Move Up"), this); actionCollection()->addAction("move_task_up", actionMoveTaskUp ); connect(actionMoveTaskUp, SIGNAL(triggered(bool)), SLOT(slotMoveTaskUp())); addAction( name, actionMoveTaskUp ); actionMoveTaskDown = new QAction(koIcon("arrow-down"), i18n("Move Down"), this); actionCollection()->addAction("move_task_down", actionMoveTaskDown ); connect(actionMoveTaskDown, SIGNAL(triggered(bool)), SLOT(slotMoveTaskDown())); addAction( name, actionMoveTaskDown ); // Add the context menu actions for the view options actionShowProject = new KToggleAction( i18n( "Show Project" ), this ); connect(actionShowProject, SIGNAL(triggered(bool)), baseModel(), SLOT(setShowProject(bool))); addContextAction( actionShowProject ); connect(m_view->actionSplitView(), SIGNAL(triggered(bool)), SLOT(slotSplitView())); addContextAction( m_view->actionSplitView() ); createOptionAction(); createDockers(); } void TaskEditor::slotSplitView() { debugPlan; m_view->setViewSplitMode( ! m_view->isViewSplit() ); emit optionsModified(); } void TaskEditor::slotOptions() { debugPlan; SplitItemViewSettupDialog *dlg = new SplitItemViewSettupDialog( this, m_view, this ); dlg->addPrintingOptions(); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } void TaskEditor::slotAddTask() { debugPlan; if ( selectedRowCount() == 0 || ( selectedRowCount() == 1 && selectedNode() == 0 ) ) { m_view->closePersistentEditor( m_view->selectionModel()->currentIndex() ); Task *t = m_view->project()->createTask( m_view->project()->taskDefaults() ); QModelIndex idx = m_view->baseModel()->insertSubtask( t, m_view->project() ); Q_ASSERT( idx.isValid() ); edit( idx ); return; } Node *sib = selectedNode(); if ( sib == 0 ) { return; } m_view->closePersistentEditor( m_view->selectionModel()->currentIndex() ); Task *t = m_view->project()->createTask( m_view->project()->taskDefaults() ); QModelIndex idx = m_view->baseModel()->insertTask( t, sib ); Q_ASSERT( idx.isValid() ); edit( idx ); } void TaskEditor::slotAddMilestone() { debugPlan; if ( selectedRowCount() == 0 || ( selectedRowCount() == 1 && selectedNode() == 0 ) ) { // None selected or only project selected: insert under main project m_view->closePersistentEditor( m_view->selectionModel()->currentIndex() ); Task *t = m_view->project()->createTask(); t->estimate()->clear(); QModelIndex idx = m_view->baseModel()->insertSubtask( t, m_view->project() ); Q_ASSERT( idx.isValid() ); edit( idx ); return; } Node *sib = selectedNode(); // sibling if ( sib == 0 ) { return; } m_view->closePersistentEditor( m_view->selectionModel()->currentIndex() ); Task *t = m_view->project()->createTask(); t->estimate()->clear(); QModelIndex idx = m_view->baseModel()->insertTask( t, sib ); Q_ASSERT( idx.isValid() ); edit( idx ); } void TaskEditor::slotAddSubMilestone() { debugPlan; Node *parent = selectedNode(); if ( parent == 0 && selectedRowCount() == 1 ) { // project selected parent = m_view->project(); } if ( parent == 0 ) { return; } m_view->closePersistentEditor( m_view->selectionModel()->currentIndex() ); Task *t = m_view->project()->createTask( m_view->project()->taskDefaults() ); t->estimate()->clear(); QModelIndex idx = m_view->baseModel()->insertSubtask( t, parent ); Q_ASSERT( idx.isValid() ); edit( idx ); } void TaskEditor::slotAddSubtask() { debugPlan; Node *parent = selectedNode(); if ( parent == 0 && selectedRowCount() == 1 ) { // project selected parent = m_view->project(); } if ( parent == 0 ) { return; } m_view->closePersistentEditor( m_view->selectionModel()->currentIndex() ); Task *t = m_view->project()->createTask( m_view->project()->taskDefaults() ); QModelIndex idx = m_view->baseModel()->insertSubtask( t, parent ); Q_ASSERT( idx.isValid() ); edit( idx ); } void TaskEditor::edit( const QModelIndex &i ) { if ( i.isValid() ) { m_view->selectionModel()->setCurrentIndex( i, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect ); m_view->setParentsExpanded( i, true ); // in case treeview does not have focus m_view->edit( i ); } } void TaskEditor::slotDeleteTask() { //debugPlan; QList lst = selectedNodes(); while ( true ) { // remove children of selected tasks, as parents delete their children Node *ch = 0; foreach ( Node *n1, lst ) { foreach ( Node *n2, lst ) { if ( n2->isChildOf( n1 ) ) { ch = n2; break; } } if ( ch != 0 ) { break; } } if ( ch == 0 ) { break; } lst.removeAt( lst.indexOf( ch ) ); } //foreach ( Node* n, lst ) { debugPlan<name(); } emit deleteTaskList( lst ); QModelIndex i = m_view->selectionModel()->currentIndex(); if ( i.isValid() ) { m_view->selectionModel()->select( i, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect ); m_view->selectionModel()->setCurrentIndex( i, QItemSelectionModel::NoUpdate ); } } void TaskEditor::slotIndentTask() { debugPlan; Node *n = selectedNode(); if ( n ) { emit indentTask(); QModelIndex i = baseModel()->index( n ); m_view->selectionModel()->select( i, QItemSelectionModel::Rows | QItemSelectionModel::Current | QItemSelectionModel::ClearAndSelect ); m_view->selectionModel()->setCurrentIndex( i, QItemSelectionModel::NoUpdate ); m_view->setParentsExpanded( i, true ); } } void TaskEditor::slotUnindentTask() { debugPlan; Node *n = selectedNode(); if ( n ) { emit unindentTask(); QModelIndex i = baseModel()->index( n ); m_view->selectionModel()->select( i, QItemSelectionModel::Rows | QItemSelectionModel::Current | QItemSelectionModel::ClearAndSelect ); m_view->selectionModel()->setCurrentIndex( i, QItemSelectionModel::NoUpdate ); } } void TaskEditor::slotMoveTaskUp() { debugPlan; Node *n = selectedNode(); if ( n ) { emit moveTaskUp(); QModelIndex i = baseModel()->index( n ); m_view->selectionModel()->select( i, QItemSelectionModel::Rows | QItemSelectionModel::Current | QItemSelectionModel::ClearAndSelect ); m_view->selectionModel()->setCurrentIndex( i, QItemSelectionModel::NoUpdate ); } } void TaskEditor::slotMoveTaskDown() { debugPlan; Node *n = selectedNode(); if ( n ) { emit moveTaskDown(); QModelIndex i = baseModel()->index( n ); m_view->selectionModel()->select( i, QItemSelectionModel::Rows | QItemSelectionModel::Current | QItemSelectionModel::ClearAndSelect ); m_view->selectionModel()->setCurrentIndex( i, QItemSelectionModel::NoUpdate ); } } bool TaskEditor::loadContext( const KoXmlElement &context ) { ViewBase::loadContext( context ); bool show = (bool)(context.attribute( "show-project", "0" ).toInt() ); actionShowProject->setChecked( show ); baseModel()->setShowProject( show ); // why is this not called by the action? bool res = m_view->loadContext( baseModel()->columnMap(), context ); return res; } void TaskEditor::saveContext( QDomElement &context ) const { ViewBase::saveContext( context ); context.setAttribute( "show-project", QString::number(baseModel()->projectShown()) ); m_view->saveContext( baseModel()->columnMap(), context ); } KoPrintJob *TaskEditor::createPrintJob() { return m_view->createPrintJob( this ); } //----------------------------------- TaskView::TaskView(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent) { QVBoxLayout * l = new QVBoxLayout( this ); l->setMargin( 0 ); m_view = new NodeTreeView( this ); connect(this, SIGNAL(expandAll()), m_view, SLOT(slotExpand())); connect(this, SIGNAL(collapseAll()), m_view, SLOT(slotCollapse())); NodeSortFilterProxyModel *p = new NodeSortFilterProxyModel( m_view->baseModel(), m_view ); m_view->setModel( p ); l->addWidget( m_view ); setupGui(); //m_view->setEditTriggers( m_view->editTriggers() | QAbstractItemView::EditKeyPressed ); m_view->setDragDropMode( QAbstractItemView::InternalMove ); m_view->setDropIndicatorShown( false ); m_view->setDragEnabled ( true ); m_view->setAcceptDrops( false ); m_view->setAcceptDropsOnView( false ); QList readonly; readonly << NodeModel::NodeName << NodeModel::NodeResponsible << NodeModel::NodeAllocation << NodeModel::NodeEstimateType << NodeModel::NodeEstimateCalendar << NodeModel::NodeEstimate << NodeModel::NodeOptimisticRatio << NodeModel::NodePessimisticRatio << NodeModel::NodeRisk << NodeModel::NodeConstraint << NodeModel::NodeConstraintStart << NodeModel::NodeConstraintEnd << NodeModel::NodeRunningAccount << NodeModel::NodeStartupAccount << NodeModel::NodeStartupCost << NodeModel::NodeShutdownAccount << NodeModel::NodeShutdownCost << NodeModel::NodeDescription; foreach ( int c, readonly ) { m_view->baseModel()->setReadOnly( c, true ); } QList lst1; lst1 << 1 << -1; QList show; show << NodeModel::NodeStatus << NodeModel::NodeCompleted << NodeModel::NodeResponsible << NodeModel::NodeAssignments << NodeModel::NodePerformanceIndex << NodeModel::NodeBCWS << NodeModel::NodeBCWP << NodeModel::NodeACWP << NodeModel::NodeDescription; for ( int s = 0; s < show.count(); ++s ) { m_view->slaveView()->mapToSection( show[s], s ); } QList lst2; for ( int i = 0; i < m_view->model()->columnCount(); ++i ) { if ( ! show.contains( i ) ) { lst2 << i; } } m_view->hideColumns( lst1, lst2 ); m_view->masterView()->setDefaultColumns( QList() << 0 ); m_view->slaveView()->setDefaultColumns( show ); connect( m_view->baseModel(), SIGNAL(executeCommand(KUndo2Command*)), doc, SLOT(addCommand(KUndo2Command*)) ); connect( m_view, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex)) ); connect( m_view, SIGNAL(selectionChanged(QModelIndexList)), this, SLOT(slotSelectionChanged(QModelIndexList)) ); connect( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); connect( m_view, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); } void TaskView::updateReadWrite( bool rw ) { m_view->setReadWrite( rw ); ViewBase::updateReadWrite( rw ); } void TaskView::draw( Project &project ) { m_view->setProject( &project ); } void TaskView::draw() { } void TaskView::setGuiActive( bool activate ) { debugPlan<selectionModel()->currentIndex().isValid() && m_view->model()->rowCount() > 0 ) { m_view->selectionModel()->setCurrentIndex(m_view->model()->index( 0, 0 ), QItemSelectionModel::NoUpdate); } } void TaskView::slotCurrentChanged( const QModelIndex &curr, const QModelIndex & ) { debugPlan<selectionModel(); return sm->selectedRows().count(); } QList TaskView::selectedNodes() const { QList lst; QItemSelectionModel* sm = m_view->selectionModel(); if ( sm == 0 ) { return lst; } foreach ( const QModelIndex &i, sm->selectedRows() ) { Node * n = m_view->baseModel()->node( proxyModel()->mapToSource( i ) ); if ( n != 0 && n->type() != Node::Type_Project ) { lst.append( n ); } } return lst; } Node *TaskView::selectedNode() const { QList lst = selectedNodes(); if ( lst.count() != 1 ) { return 0; } return lst.first(); } Node *TaskView::currentNode() const { Node * n = m_view->baseModel()->node( proxyModel()->mapToSource( m_view->selectionModel()->currentIndex() ) ); if ( n == 0 || n->type() == Node::Type_Project ) { return 0; } return n; } void TaskView::slotContextMenuRequested( const QModelIndex& index, const QPoint& pos ) { QString name; Node *node = m_view->baseModel()->node( proxyModel()->mapToSource( index ) ); if ( node ) { switch ( node->type() ) { case Node::Type_Task: name = "taskview_popup"; break; case Node::Type_Milestone: name = "taskview_milestone_popup"; break; case Node::Type_Summarytask: name = "taskview_summary_popup"; break; default: break; } } else debugPlan<<"No node: "<setContextMenuIndex(index); emit requestPopupMenu( name, pos ); m_view->setContextMenuIndex(QModelIndex()); } void TaskView::setScheduleManager( ScheduleManager *sm ) { //debugPlan<masterView()->saveExpanded(element); } bool tryexpand = sm && !scheduleManager(); QDomDocument doc; bool expand = sm && scheduleManager() && sm != scheduleManager(); if (expand) { m_view->masterView()->setObjectName("TaskEditor"); QDomElement element = doc.createElement("expanded"); doc.appendChild(element); m_view->masterView()->saveExpanded(element); } ViewBase::setScheduleManager(sm); m_view->baseModel()->setScheduleManager( sm ); if (expand) { m_view->masterView()->doExpand(doc); } else if (tryexpand) { m_view->masterView()->doExpand(m_domdoc); } } void TaskView::slotEnableActions() { updateActionsEnabled( true ); } void TaskView::updateActionsEnabled( bool /*on*/ ) { } void TaskView::setupGui() { // KActionCollection *coll = actionCollection(); // Add the context menu actions for the view options actionShowProject = new KToggleAction( i18n( "Show Project" ), this ); connect(actionShowProject, SIGNAL(triggered(bool)), baseModel(), SLOT(setShowProject(bool))); addContextAction( actionShowProject ); connect(m_view->actionSplitView(), SIGNAL(triggered(bool)), SLOT(slotSplitView())); addContextAction( m_view->actionSplitView() ); createOptionAction(); } void TaskView::slotSplitView() { debugPlan; m_view->setViewSplitMode( ! m_view->isViewSplit() ); emit optionsModified(); } void TaskView::slotOptions() { debugPlan; SplitItemViewSettupDialog *dlg = new SplitItemViewSettupDialog( this, m_view, this ); dlg->addPrintingOptions(); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } bool TaskView::loadContext( const KoXmlElement &context ) { ViewBase::loadContext( context ); bool show = (bool)(context.attribute( "show-project", "0" ).toInt() ); actionShowProject->setChecked( show ); baseModel()->setShowProject( show ); // why is this not called by the action? return m_view->loadContext( m_view->baseModel()->columnMap(), context ); } void TaskView::saveContext( QDomElement &context ) const { ViewBase::saveContext( context ); context.setAttribute( "show-project", QString::number(baseModel()->projectShown()) ); m_view->saveContext( m_view->baseModel()->columnMap(), context ); } KoPrintJob *TaskView::createPrintJob() { return m_view->createPrintJob( this ); } //--------------------------------- WorkPackageTreeView::WorkPackageTreeView( QWidget *parent ) : DoubleTreeViewBase( parent ) { debugPlan<<"----------"<baseModel(); } void WorkPackageTreeView::slotDropAllowed( const QModelIndex &index, int dropIndicatorPosition, QDragMoveEvent *event ) { Q_UNUSED(index); Q_UNUSED(dropIndicatorPosition); Q_UNUSED(event); /* QModelIndex idx = index; NodeSortFilterProxyModel *pr = proxyModel(); if ( pr ) { idx = pr->mapToSource( index ); } event->ignore(); if ( baseModel()->dropAllowed( idx, dropIndicatorPosition, event->mimeData() ) ) { event->accept(); }*/ } //-------------------------------- TaskWorkPackageView::TaskWorkPackageView(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent ), m_cmd( 0 ) { QVBoxLayout * l = new QVBoxLayout( this ); l->setMargin( 0 ); m_view = new WorkPackageTreeView( this ); connect(this, SIGNAL(expandAll()), m_view, SLOT(slotExpand())); connect(this, SIGNAL(collapseAll()), m_view, SLOT(slotCollapse())); l->addWidget( m_view ); setupGui(); //m_view->setEditTriggers( m_view->editTriggers() | QAbstractItemView::EditKeyPressed ); m_view->setDragDropMode( QAbstractItemView::InternalMove ); m_view->setDropIndicatorShown( false ); m_view->setDragEnabled ( true ); m_view->setAcceptDrops( false ); m_view->setAcceptDropsOnView( false ); QList readonly; readonly << NodeModel::NodeName << NodeModel::NodeResponsible << NodeModel::NodeAllocation << NodeModel::NodeEstimateType << NodeModel::NodeEstimateCalendar << NodeModel::NodeEstimate << NodeModel::NodeOptimisticRatio << NodeModel::NodePessimisticRatio << NodeModel::NodeRisk << NodeModel::NodeConstraint << NodeModel::NodeConstraintStart << NodeModel::NodeConstraintEnd << NodeModel::NodeRunningAccount << NodeModel::NodeStartupAccount << NodeModel::NodeStartupCost << NodeModel::NodeShutdownAccount << NodeModel::NodeShutdownCost << NodeModel::NodeDescription; foreach ( int c, readonly ) { m_view->baseModel()->setReadOnly( c, true ); } QList lst1; lst1 << 1 << -1; QList show; show << NodeModel::NodeStatus << NodeModel::NodeCompleted << NodeModel::NodeResponsible << NodeModel::NodeAssignments << NodeModel::NodeDescription; for ( int s = 0; s < show.count(); ++s ) { m_view->slaveView()->mapToSection( show[s], s ); } QList lst2; for ( int i = 0; i < m_view->model()->columnCount(); ++i ) { if ( ! show.contains( i ) ) { lst2 << i; } } m_view->hideColumns( lst1, lst2 ); m_view->masterView()->setDefaultColumns( QList() << 0 ); m_view->slaveView()->setDefaultColumns( show ); connect( m_view->baseModel(), SIGNAL(executeCommand(KUndo2Command*)), doc, SLOT(addCommand(KUndo2Command*)) ); connect( m_view, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex)) ); connect( m_view, SIGNAL(selectionChanged(QModelIndexList)), this, SLOT(slotSelectionChanged(QModelIndexList)) ); connect( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); connect( m_view, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); } Project *TaskWorkPackageView::project() const { return m_view->project(); } void TaskWorkPackageView::setProject( Project *project ) { m_view->setProject( project ); } WorkPackageProxyModel *TaskWorkPackageView::proxyModel() const { return m_view->proxyModel(); } void TaskWorkPackageView::updateReadWrite( bool rw ) { m_view->setReadWrite( rw ); ViewBase::updateReadWrite( rw ); } void TaskWorkPackageView::setGuiActive( bool activate ) { debugPlan<selectionModel()->currentIndex().isValid() && m_view->model()->rowCount() > 0 ) { m_view->selectionModel()->setCurrentIndex(m_view->model()->index( 0, 0 ), QItemSelectionModel::NoUpdate); } } void TaskWorkPackageView::slotRefreshView() { emit checkForWorkPackages(); } void TaskWorkPackageView::slotCurrentChanged( const QModelIndex &curr, const QModelIndex & ) { debugPlan<selectionModel(); return sm->selectedRows().count(); } QList TaskWorkPackageView::selectedNodes() const { QList lst; QItemSelectionModel* sm = m_view->selectionModel(); if ( sm == 0 ) { return lst; } foreach ( const QModelIndex &i, sm->selectedRows() ) { Node * n = proxyModel()->taskFromIndex( i ); if ( n != 0 && n->type() != Node::Type_Project ) { lst.append( n ); } } return lst; } Node *TaskWorkPackageView::selectedNode() const { QList lst = selectedNodes(); if ( lst.count() != 1 ) { return 0; } return lst.first(); } Node *TaskWorkPackageView::currentNode() const { Node * n = proxyModel()->taskFromIndex( m_view->selectionModel()->currentIndex() ); if ( n == 0 || n->type() == Node::Type_Project ) { return 0; } return n; } void TaskWorkPackageView::slotContextMenuRequested( const QModelIndex& index, const QPoint& pos ) { QString name; Node *node = proxyModel()->taskFromIndex( index ); if ( node ) { switch ( node->type() ) { case Node::Type_Task: name = "workpackage_popup"; break; case Node::Type_Milestone: name = "taskview_milestone_popup"; break; case Node::Type_Summarytask: name = "taskview_summary_popup"; break; default: break; } } else debugPlan<<"No node: "<setContextMenuIndex(index); emit requestPopupMenu( name, pos ); m_view->setContextMenuIndex(QModelIndex()); } void TaskWorkPackageView::setScheduleManager( ScheduleManager *sm ) { //debugPlan<baseModel()->setScheduleManager( sm ); } void TaskWorkPackageView::slotEnableActions() { updateActionsEnabled( true ); } void TaskWorkPackageView::updateActionsEnabled( bool on ) { bool o = ! selectedNodes().isEmpty(); actionMailWorkpackage->setEnabled( o && on ); } void TaskWorkPackageView::setupGui() { // KActionCollection *coll = actionCollection(); QString name = "workpackage_list"; actionMailWorkpackage = new QAction(koIcon("mail-send"), i18n("Send..."), this); actionCollection()->setDefaultShortcut( actionMailWorkpackage, Qt::CTRL + Qt::Key_M ); actionCollection()->addAction("send_workpackage", actionMailWorkpackage ); connect( actionMailWorkpackage, SIGNAL(triggered(bool)), SLOT(slotMailWorkpackage()) ); addAction( name, actionMailWorkpackage ); // Add the context menu actions for the view options connect(m_view->actionSplitView(), SIGNAL(triggered(bool)), SLOT(slotSplitView())); addContextAction( m_view->actionSplitView() ); createOptionAction(); } void TaskWorkPackageView::slotMailWorkpackage() { QList lst = selectedNodes(); if ( ! lst.isEmpty() ) { // TODO find a better way to log to avoid undo/redo m_cmd = new MacroCommand( kundo2_i18n( "Log Send Workpackage" ) ); QPointer dlg = new WorkPackageSendDialog( lst, scheduleManager(), this ); connect ( dlg->panel(), SIGNAL(sendWorkpackages(QList,Resource*)), this, SIGNAL(mailWorkpackages(QList,Resource*)) ); connect ( dlg->panel(), SIGNAL(sendWorkpackages(QList,Resource*)), this, SLOT(slotWorkPackageSent(QList,Resource*)) ); dlg->exec(); delete dlg; if ( ! m_cmd->isEmpty() ) { part()->addCommand( m_cmd ); m_cmd = 0; } delete m_cmd; m_cmd = 0; } } void TaskWorkPackageView::slotWorkPackageSent( const QList &nodes, Resource *resource ) { foreach ( Node *n, nodes ) { WorkPackage *wp = new WorkPackage( static_cast( n )->workPackage() ); wp->setOwnerName( resource->name() ); wp->setOwnerId( resource->id() ); wp->setTransmitionTime( DateTime::currentDateTime() ); wp->setTransmitionStatus( WorkPackage::TS_Send ); m_cmd->addCommand( new WorkPackageAddCmd( static_cast( n->projectNode() ), n, wp ) ); } } void TaskWorkPackageView::slotSplitView() { debugPlan; m_view->setViewSplitMode( ! m_view->isViewSplit() ); emit optionsModified(); } void TaskWorkPackageView::slotOptions() { debugPlan; SplitItemViewSettupDialog *dlg = new SplitItemViewSettupDialog( this, m_view, this ); dlg->addPrintingOptions(); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } bool TaskWorkPackageView::loadContext( const KoXmlElement &context ) { debugPlan; ViewBase::loadContext( context ); return m_view->loadContext( m_view->baseModel()->columnMap(), context ); } void TaskWorkPackageView::saveContext( QDomElement &context ) const { ViewBase::saveContext( context ); m_view->saveContext( m_view->baseModel()->columnMap(), context ); } KoPrintJob *TaskWorkPackageView::createPrintJob() { return m_view->createPrintJob( this ); } } // namespace KPlato diff --git a/plan/libs/ui/kpttaskeditor.h b/plan/libs/ui/kpttaskeditor.h index 29705b2296d..c27c22662fc 100644 --- a/plan/libs/ui/kpttaskeditor.h +++ b/plan/libs/ui/kpttaskeditor.h @@ -1,354 +1,356 @@ /* This file is part of the KDE project Copyright (C) 2006 -20010 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 KPTTASKEDITOR_H #define KPTTASKEDITOR_H #include "kplatoui_export.h" #include "kptglobal.h" #include "kptnodeitemmodel.h" #include "kptviewbase.h" class KoDocument; class KActionMenu; namespace KPlato { class Project; class Node; class NodeItemModel; class MacroCommand; class KPLATOUI_EXPORT TaskEditorItemModel : public NodeItemModel { Q_OBJECT public: explicit TaskEditorItemModel( QObject *parent = 0 ); virtual Qt::ItemFlags flags( const QModelIndex & index ) const; virtual QVariant headerData( int section, Qt::Orientation orientation, int role ) const; virtual QVariant data( const QModelIndex & index, int role = Qt::DisplayRole ) const; virtual bool setData( const QModelIndex & index, const QVariant &value, int role = Qt::EditRole ); protected: QVariant type( const Node *node, int role ) const; virtual bool setType( Node *node, const QVariant &value, int role ); }; class KPLATOUI_EXPORT TaskEditorTreeView : public DoubleTreeViewBase { Q_OBJECT public: explicit TaskEditorTreeView(QWidget *parent); //void setSelectionModel( QItemSelectionModel *selectionModel ); NodeItemModel *baseModel() const; NodeSortFilterProxyModel *proxyModel() const { return qobject_cast( model() ); } Project *project() const { return baseModel()->project(); } void setProject( Project *project ) { baseModel()->setProject( project ); } Q_SIGNALS: void currentColumnChanged( const QModelIndex&, const QModelIndex& ); protected Q_SLOTS: void slotDropAllowed( const QModelIndex &index, int dropIndicatorPosition, QDragMoveEvent *event ); }; class KPLATOUI_EXPORT NodeTreeView : public DoubleTreeViewBase { Q_OBJECT public: explicit NodeTreeView(QWidget *parent); //void setSelectionModel( QItemSelectionModel *selectionModel ); NodeItemModel *baseModel() const; NodeSortFilterProxyModel *proxyModel() const { return qobject_cast( model() ); } Project *project() const { return baseModel()->project(); } void setProject( Project *project ) { baseModel()->setProject( project ); } Q_SIGNALS: void currentColumnChanged( const QModelIndex&, const QModelIndex& ); protected Q_SLOTS: void slotDropAllowed( const QModelIndex &index, int dropIndicatorPosition, QDragMoveEvent *event ); }; class KPLATOUI_EXPORT TaskEditor : public ViewBase { Q_OBJECT public: TaskEditor(KoPart *part, KoDocument *doc, QWidget *parent); void setupGui(); void setProject( Project *project ); Project *project() const { return m_view->project(); } virtual void createDockers(); virtual Node *currentNode() const; QList selectedNodes() const ; Node *selectedNode() const; virtual void updateReadWrite( bool readwrite ); NodeItemModel *baseModel() const { return m_view->baseModel(); } NodeSortFilterProxyModel *proxyModel() const { return m_view->proxyModel(); } QAbstractItemModel *model() const { return m_view->model(); } /// Loads context info into this view. Reimplement. virtual bool loadContext( const KoXmlElement &/*context*/ ); /// Save context info from this view. Reimplement. virtual void saveContext( QDomElement &/*context*/ ) const; virtual KoPrintJob *createPrintJob(); - void setTaskModules( const QStringList &files ); - Q_SIGNALS: void taskSelected( Task *task ); void openNode(); void addTask(); void addMilestone(); void addSubtask(); void addSubMilestone(); void deleteTaskList( const QList& ); void moveTaskUp(); void moveTaskDown(); void indentTask(); void unindentTask(); void loadTaskModules( const QStringList &files ); void saveTaskModule( const QUrl &url, Project *project ); void removeTaskModule( const QUrl &url ); public Q_SLOTS: /// Activate/deactivate the gui virtual void setGuiActive( bool activate ); void setScheduleManager( ScheduleManager *sm ); + void setTaskModules( const QStringList &files ); + protected: void updateActionsEnabled( bool on ); int selectedRowCount() const; QModelIndexList selectedRows() const; void editTasks(const QList &tasks, const QPoint &pos); protected Q_SLOTS: virtual void slotOptions(); private Q_SLOTS: void slotSelectionChanged( const QModelIndexList& ); void slotCurrentChanged( const QModelIndex&, const QModelIndex& ); void slotContextMenuRequested(const QModelIndex &index, const QPoint& pos , const QModelIndexList &rows); void slotEnableActions(); void slotAddTask(); void slotAddSubtask(); void slotAddMilestone(); void slotAddSubMilestone(); void slotDeleteTask(); void slotIndentTask(); void slotUnindentTask(); void slotMoveTaskUp(); void slotMoveTaskDown(); void slotSplitView(); void slotProjectShown( bool ); + void taskModuleDoubleClicked(QModelIndex idx); + private: void edit( const QModelIndex &index ); private: TaskEditorTreeView *m_view; KActionMenu *menuAddTask; KActionMenu *menuAddSubTask; QAction *actionAddTask; QAction *actionAddMilestone; QAction *actionAddSubtask; QAction *actionAddSubMilestone; QAction *actionDeleteTask; QAction *actionMoveTaskUp; QAction *actionMoveTaskDown; QAction *actionIndentTask; QAction *actionUnindentTask; QAction *actionShowProject; QDomDocument m_domdoc; }; class KPLATOUI_EXPORT TaskView : public ViewBase { Q_OBJECT public: TaskView(KoPart *part, KoDocument *doc, QWidget *parent); void setupGui(); Project *project() const { return m_view->project(); } virtual void draw( Project &project ); virtual void draw(); NodeItemModel *baseModel() const { return m_view->baseModel(); } NodeSortFilterProxyModel *proxyModel() const { return m_view->proxyModel(); } virtual Node *currentNode() const; QList selectedNodes() const ; Node *selectedNode() const; virtual void updateReadWrite( bool readwrite ); /// Loads context info into this view. Reimplement. virtual bool loadContext( const KoXmlElement &/*context*/ ); /// Save context info from this view. Reimplement. virtual void saveContext( QDomElement &/*context*/ ) const; KoPrintJob *createPrintJob(); Q_SIGNALS: void openNode(); public Q_SLOTS: /// Activate/deactivate the gui virtual void setGuiActive( bool activate ); void setScheduleManager( ScheduleManager *sm ); protected: void updateActionsEnabled( bool on ); int selectedNodeCount() const; protected Q_SLOTS: virtual void slotOptions(); private Q_SLOTS: void slotSelectionChanged( const QModelIndexList& ); void slotCurrentChanged( const QModelIndex&, const QModelIndex& ); void slotContextMenuRequested( const QModelIndex &index, const QPoint& pos ); void slotEnableActions(); void slotSplitView(); private: NodeTreeView *m_view; QAction *actionShowProject; QDomDocument m_domdoc; }; //----------------------------------- class WorkPackageTreeView : public DoubleTreeViewBase { Q_OBJECT public: explicit WorkPackageTreeView(QWidget *parent); //void setSelectionModel( QItemSelectionModel *selectionModel ); NodeItemModel *baseModel() const; WorkPackageProxyModel *proxyModel() const { return m; } Project *project() const { return baseModel()->project(); } void setProject( Project *project ) { m->setProject( project ); } ScheduleManager *scheduleManager() const { return baseModel()->manager(); } Q_SIGNALS: void currentColumnChanged( const QModelIndex&, const QModelIndex& ); protected Q_SLOTS: void slotDropAllowed( const QModelIndex &index, int dropIndicatorPosition, QDragMoveEvent *event ); protected: WorkPackageProxyModel *m; }; class KPLATOUI_EXPORT TaskWorkPackageView : public ViewBase { Q_OBJECT public: TaskWorkPackageView(KoPart *part, KoDocument *doc, QWidget *parent); void setupGui(); Project *project() const; void setProject( Project *project ); ScheduleManager *scheduleManager() const { return m_view->scheduleManager(); } WorkPackageProxyModel *proxyModel() const; virtual Node *currentNode() const; QList selectedNodes() const ; Node *selectedNode() const; virtual void updateReadWrite( bool readwrite ); /// Loads context info into this view. Reimplement. virtual bool loadContext( const KoXmlElement &/*context*/ ); /// Save context info from this view. Reimplement. virtual void saveContext( QDomElement &/*context*/ ) const; KoPrintJob *createPrintJob(); Q_SIGNALS: void mailWorkpackage( Node *n, Resource *r = 0 ); void mailWorkpackages( const QList &nodes, Resource *r ); void checkForWorkPackages(); public Q_SLOTS: /// Activate/deactivate the gui virtual void setGuiActive( bool activate ); void slotRefreshView(); void setScheduleManager( ScheduleManager *sm ); protected: void updateActionsEnabled( bool on ); int selectedNodeCount() const; protected Q_SLOTS: virtual void slotOptions(); void slotMailWorkpackage(); void slotWorkPackageSent( const QList &nodes, Resource *resource ); private Q_SLOTS: void slotSelectionChanged( const QModelIndexList& ); void slotCurrentChanged( const QModelIndex&, const QModelIndex& ); void slotContextMenuRequested( const QModelIndex &index, const QPoint& pos ); void slotEnableActions(); void slotSplitView(); private: WorkPackageTreeView *m_view; MacroCommand *m_cmd; QAction *actionMailWorkpackage; }; } //namespace KPlato #endif diff --git a/plan/libs/ui/kptviewbase.h b/plan/libs/ui/kptviewbase.h index 6d5579f94b8..126c3f804aa 100644 --- a/plan/libs/ui/kptviewbase.h +++ b/plan/libs/ui/kptviewbase.h @@ -1,672 +1,673 @@ /* This file is part of the KDE project Copyright (C) 2006 -2010 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 KPTVIEWBASE_H #define KPTVIEWBASE_H #include "kplatoui_export.h" #include "kptitemmodelbase.h" #include "ui_kptprintingheaderfooter.h" #include #include #include #include #include #include #include #include #include #include class QMetaEnum; class QAbstractItemModel; class QDomElement; class QModelIndex; class KoDocument; class KoPrintJob; class KoPart; /// The main namespace namespace KPlato { class Project; class Node; class Resource; class ResourceGroup; class Relation; class Calendar; class ViewBase; class TreeViewBase; class DoubleTreeViewBase; //------------------ class KPLATOUI_EXPORT DockWidget : public QDockWidget { Q_OBJECT public: DockWidget( ViewBase *v, const QString &identity, const QString &title ); void activate( KoMainWindow *mainWindow ); void deactivate( KoMainWindow *mainWindow ); bool shown() const; bool saveXml( QDomElement &context ) const; void loadXml( const KoXmlElement &context ); const ViewBase *view; /// The view this docker belongs to QString id; /// Docker identity Qt::DockWidgetArea location; /// The area the docker should go when visible bool editor; /// Editor dockers will not be shown in read only mode public Q_SLOTS: void setShown( bool show ); void setLocation( Qt::DockWidgetArea area ); private: bool m_shown; /// The dockers visivbility when the view is active }; //------------------ class KPLATOUI_EXPORT PrintingOptions { public: PrintingOptions() { headerOptions.group = true; headerOptions.project = Qt::Checked; headerOptions.date = Qt::Checked; headerOptions.manager = Qt::Checked; headerOptions.page = Qt::Checked; footerOptions.group = false; footerOptions.project = Qt::Checked; footerOptions.date = Qt::Checked; footerOptions.manager = Qt::Checked; footerOptions.page = Qt::Checked; } ~PrintingOptions() {} bool loadXml( KoXmlElement &element ); void saveXml( QDomElement &element ) const; struct Data { bool group; Qt::CheckState project; Qt::CheckState date; Qt::CheckState manager; Qt::CheckState page; }; struct Data headerOptions; struct Data footerOptions; }; //------------------ class KPLATOUI_EXPORT PrintingHeaderFooter : public QWidget, public Ui::PrintingHeaderFooter { Q_OBJECT public: explicit PrintingHeaderFooter( const PrintingOptions &opt, QWidget *parent = 0 ); ~PrintingHeaderFooter(); void setOptions( const PrintingOptions &options ); PrintingOptions options() const; Q_SIGNALS: void changed(const PrintingOptions&); protected Q_SLOTS: void slotChanged(); private: PrintingOptions m_options; }; //------------------ class KPLATOUI_EXPORT PrintingDialog : public KoPrintingDialog { Q_OBJECT public: explicit PrintingDialog(ViewBase *view); ~PrintingDialog(); virtual QList createOptionWidgets() const; virtual QList shapesOnPage(int); QRect headerRect() const; QRect footerRect() const; void paintHeaderFooter( QPainter &p, const PrintingOptions &options, int pageNumber, const Project &project ); PrintingOptions printingOptions() const; QWidget *createPageLayoutWidget() const; QAbstractPrintDialog::PrintDialogOptions printDialogOptions() const; Q_SIGNALS: void changed( const PrintingOptions &opt ); void changed(); public Q_SLOTS: void setPrintingOptions( const PrintingOptions &opt); void setPrinterPageLayout( const KoPageLayout &pagelayout ); virtual void startPrinting(RemovePolicy removePolicy = DoNotDelete); protected: virtual void paint( QPainter &p, const PrintingOptions::Data &options, const QRect &rect, int pageNumber, const Project &project ); int headerFooterHeight( const PrintingOptions::Data &options ) const; void drawRect( QPainter &p, const QRect &r, Qt::Edges edges = Qt::LeftEdge | Qt::RightEdge | Qt::BottomEdge ); protected: ViewBase *m_view; PrintingHeaderFooter *m_widget; int m_textheight; }; class KPLATOUI_EXPORT ViewActionLists { public: ViewActionLists() : actionOptions( 0 ) {} virtual ~ViewActionLists() {} /// Returns the list of action lists that shall be plugged/unplugged virtual QStringList actionListNames() const { return m_actionListMap.keys(); } /// Returns the list of actions associated with the action list name virtual QList actionList( const QString &name ) const { return m_actionListMap[name]; } /// Add an action to the specified action list void addAction( const QString &list, QAction *action ) { m_actionListMap[list].append( action ); } virtual QList viewlistActionList() const { return m_viewlistActionList; } void addViewlistAction( QAction *action ) { m_viewlistActionList.append( action ); } QList contextActionList() const { return m_contextActionList; } void addContextAction( QAction *action ) { m_contextActionList.append( action ); } protected: /// List of all menu/toolbar actions (used for plug/unplug) QMap > m_actionListMap; /// List of actions that will be shown in the viewlist context menu QList m_viewlistActionList; /// List of actions that will be shown in the views header context menu QList m_contextActionList; // View options context menu QAction *actionOptions; }; /** ViewBase is the baseclass of all sub-views to View. */ class KPLATOUI_EXPORT ViewBase : public KoView, public ViewActionLists { Q_OBJECT public: /// Contructor ViewBase(KoPart *part, KoDocument *doc, QWidget *parent); /// Destructor virtual ~ViewBase(); /// Return the part (document) this view handles KoDocument *part() const; /// Return the page layout used for printing this view virtual KoPageLayout pageLayout() const; /// Return the type of view this is (class name) QString viewType() const { return metaObject()->className(); } /// Returns true if this view or any child widget has focus bool isActive() const; /// Set the project this view shall handle. virtual void setProject( Project *project ); /// Return the project virtual Project *project() const { return m_proj; } /// Return the schedule manager virtual ScheduleManager *scheduleManager() const { return m_schedulemanager; } /// Draw data from current part / project virtual void draw() {} /// Draw data from project. virtual void draw(Project &/*project*/) {} /// Draw changed data from project. virtual void drawChanges(Project &project) { draw(project); } /// Set readWrite mode virtual void updateReadWrite( bool ); bool isReadWrite() const { return m_readWrite; } /// Reimplement if your view handles nodes virtual Node* currentNode() const { return 0; } /// Reimplement if your view handles resources virtual Resource* currentResource() const { return 0; } /// Reimplement if your view handles resource groups virtual ResourceGroup* currentResourceGroup() const { return 0; } /// Reimplement if your view handles calendars virtual Calendar* currentCalendar() const { return 0; } /// Reimplement if your view handles relations virtual Relation *currentRelation() const { return 0; } /// Reimplement if your view handles zoom virtual KoZoomController *zoomController() const { return 0; } /// Loads context info (printer settings) into this view. virtual bool loadContext( const KoXmlElement &context ); /// Save context info (printer settings) from this view. virtual void saveContext( QDomElement &context ) const; virtual KoPrintJob *createPrintJob(); PrintingOptions printingOptions() const { return m_printingOptions; } static QWidget *createPageLayoutWidget( ViewBase *view ); static PrintingHeaderFooter *createHeaderFooterWidget( ViewBase *view ); void addAction( const QString &list, QAction *action ) { ViewActionLists::addAction( list, action ); } virtual void createDockers() {} void addDocker( DockWidget *ds ); QList dockers() const; DockWidget *findDocker( const QString &id ) const; public Q_SLOTS: void setPrintingOptions( const PrintingOptions &opt ) { m_printingOptions = opt; } /// Activate/deactivate the gui virtual void setGuiActive( bool activate ); virtual void setScheduleManager( ScheduleManager *sm ) { m_schedulemanager = sm; } void slotUpdateReadWrite( bool ); virtual void slotHeaderContextMenuRequested( const QPoint &pos ); virtual void slotEditCopy() {} virtual void slotEditCut() {} virtual void slotEditPaste() {} virtual void slotRefreshView() {} void setPageLayout( const KoPageLayout &layout ); Q_SIGNALS: /// Emitted when the gui has been activated or deactivated void guiActivated( ViewBase*, bool ); /// Request for a context menu popup void requestPopupMenu( const QString&, const QPoint & ); /// Emitted when options are modified void optionsModified(); void projectChanged( Project *project ); void readWriteChanged( bool ); void expandAll(); void collapseAll(); + void openDocument(const QUrl &url); protected Q_SLOTS: virtual void slotOptions() {} virtual void slotOptionsFinished( int result ); protected: void createOptionAction(); bool m_readWrite; PrintingOptions m_printingOptions; Project *m_proj; ScheduleManager *m_schedulemanager; KoPageLayout m_pagelayout; QList m_dockers; }; //------------------ class KPLATOUI_EXPORT TreeViewPrintingDialog : public PrintingDialog { Q_OBJECT public: TreeViewPrintingDialog( ViewBase *view, TreeViewBase *treeview, Project *project = 0 ); ~TreeViewPrintingDialog() {} virtual int documentFirstPage() const { return 1; } virtual int documentLastPage() const; QList createOptionWidgets() const; protected: virtual void printPage( int pageNumber, QPainter &painter ); int firstRow( int page ) const; private: TreeViewBase *m_tree; Project *m_project; int m_firstRow; }; //----------------- class KPLATOUI_EXPORT TreeViewBase : public QTreeView { Q_OBJECT public: explicit TreeViewBase( QWidget *parent = 0 ); void setReadWrite( bool rw ); virtual void createItemDelegates( ItemModelBase *model ); void setArrowKeyNavigation( bool on ) { m_arrowKeyNavigation = on; } bool arrowKeyNavigation() const { return m_arrowKeyNavigation; } /// Move move to first visual QModelIndex firstColumn( int row, const QModelIndex &parent ); /// Move move to last visual QModelIndex lastColumn( int row, const QModelIndex &parent ); /// Move from @p current to next item QModelIndex nextColumn( const QModelIndex ¤t ); /// Move from @p current to next item QModelIndex previousColumn( const QModelIndex ¤t ); /// Move to first editable index in @p row with @p parent QModelIndex firstEditable( int row, const QModelIndex &parent ); /// Move to last editable index in @p row with @p parent QModelIndex lastEditable( int row, const QModelIndex &parent ); void setAcceptDropsOnView( bool mode ) { m_acceptDropsOnView = mode; } virtual void setModel( QAbstractItemModel *model ); virtual void setSelectionModel( QItemSelectionModel *model ); void setStretchLastSection( bool ); void mapToSection( int column, int section ); int section( int col ) const; void setColumnsHidden( const QList &list ); /// Loads context info into this view. Reimplement. virtual bool loadContext(const QMetaEnum &map, const KoXmlElement &element, bool expand = true); /// Save context info from this view. Reimplement. virtual void saveContext(const QMetaEnum &map, QDomElement &context , bool expand = true) const; /** Reimplemented to fix qt bug 160083: Doesn't scroll horisontally. Scroll the contents of the tree view until the given model item \a index is visible. The \a hint parameter specifies more precisely where the item should be located after the operation. If any of the parents of the model item are collapsed, they will be expanded to ensure that the model item is visible. */ void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible); void setDefaultColumns( const QList &lst ) { m_defaultColumns = lst; } QList defaultColumns() const { return m_defaultColumns; } KoPrintJob *createPrintJob( ViewBase *parent ); QModelIndex firstVisibleIndex( const QModelIndex &idx ) const; ItemModelBase *itemModel() const; void setContextMenuIndex(const QModelIndex &idx); void loadExpanded(const KoXmlElement &element); void saveExpanded(QDomElement &element, const QModelIndex &parent = QModelIndex()) const; void expandRecursivly(QDomElement element, const QModelIndex &parent = QModelIndex()); void doExpand(QDomDocument &doc); public Q_SLOTS: void slotExpand(); void slotCollapse(); Q_SIGNALS: /// Context menu requested from viewport at global position @p pos void contextMenuRequested( const QModelIndex&, const QPoint &pos, const QModelIndexList& ); /// Context menu requested from header at global position @p pos void headerContextMenuRequested( const QPoint &pos ); void moveAfterLastColumn( const QModelIndex & ); void moveBeforeFirstColumn( const QModelIndex & ); void editAfterLastColumn( const QModelIndex & ); void editBeforeFirstColumn( const QModelIndex & ); void dropAllowed( const QModelIndex &index, int dropIndicatorPosition, QDragMoveEvent *event ); protected: void keyPressEvent(QKeyEvent *event); void mousePressEvent( QMouseEvent *event ); /** Reimplemented from QTreeView to make tab/backtab in editor work reasonably well. Move the cursor in the way described by \a cursorAction, *not* using the information provided by the button \a modifiers. */ QModelIndex moveCursor( CursorAction cursorAction, Qt::KeyboardModifiers modifiers ); /// Move cursor from @p index in direction @p cursorAction. @p modifiers is not used. QModelIndex moveCursor( const QModelIndex &index, CursorAction cursorAction, Qt::KeyboardModifiers = Qt::NoModifier ); /// Move from @p index to next editable item, in direction @p cursorAction. QModelIndex moveToEditable( const QModelIndex &index, CursorAction cursorAction ); void contextMenuEvent ( QContextMenuEvent * event ); void dragMoveEvent(QDragMoveEvent *event); void dropEvent( QDropEvent *e ); void updateSelection( const QModelIndex &oldidx, const QModelIndex &newidx, QKeyEvent *event ); void expandRecursive(const QModelIndex &parent, bool xpand); protected Q_SLOTS: /// Close the @p editor, using sender()->endEditHint(). /// Use @p hint if sender is not of type ItemDelegate. virtual void closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint); virtual void slotCurrentChanged ( const QModelIndex & current, const QModelIndex & previous ); void slotHeaderContextMenuRequested( const QPoint& ); //Copied from QAbstractItemView inline QItemSelectionModel::SelectionFlags selectionBehaviorFlags() const { switch (selectionBehavior()) { case QAbstractItemView::SelectRows: return QItemSelectionModel::Rows; case QAbstractItemView::SelectColumns: return QItemSelectionModel::Columns; case QAbstractItemView::SelectItems: default: return QItemSelectionModel::NoUpdate; } } void doContextExpanded(); void doExpanded(); protected: virtual void focusInEvent(QFocusEvent *event); bool m_arrowKeyNavigation; bool m_acceptDropsOnView; QList m_hideList; bool m_readWrite; QList m_defaultColumns; QPersistentModelIndex m_contextMenuIndex; QDomDocument m_loadContextDoc; QDomDocument m_expandDoc; }; //------------------ class KPLATOUI_EXPORT DoubleTreeViewPrintingDialog : public PrintingDialog { Q_OBJECT public: DoubleTreeViewPrintingDialog( ViewBase *view, DoubleTreeViewBase *treeview, Project *project ); ~DoubleTreeViewPrintingDialog() {} virtual int documentFirstPage() const { return 1; } virtual int documentLastPage() const; QList createOptionWidgets() const; protected: virtual void printPage( int pageNumber, QPainter &painter ); int firstRow( int page ) const; private: DoubleTreeViewBase *m_tree; Project *m_project; int m_firstRow; }; class KPLATOUI_EXPORT DoubleTreeViewBase : public QSplitter { Q_OBJECT public: explicit DoubleTreeViewBase( QWidget *parent ); DoubleTreeViewBase( bool mode, QWidget *parent ); ~DoubleTreeViewBase(); void setReadWrite( bool rw ); void closePersistentEditor( const QModelIndex &index ); void setModel( QAbstractItemModel *model ); QAbstractItemModel *model() const; void setArrowKeyNavigation( bool on ) { m_arrowKeyNavigation = on; } bool arrowKeyNavigation() const { return m_arrowKeyNavigation; } QItemSelectionModel *selectionModel() const { return m_selectionmodel; } void setSelectionModel( QItemSelectionModel *model ); void setSelectionMode( QAbstractItemView::SelectionMode mode ); void setSelectionBehavior( QAbstractItemView::SelectionBehavior mode ); virtual void createItemDelegates( ItemModelBase *model ); void setItemDelegateForColumn( int col, QAbstractItemDelegate * delegate ); void setEditTriggers ( QAbstractItemView::EditTriggers ); QAbstractItemView::EditTriggers editTriggers() const; void setAcceptDrops( bool ); void setAcceptDropsOnView( bool ); void setDropIndicatorShown( bool ); void setDragDropMode( QAbstractItemView::DragDropMode mode ); void setDragDropOverwriteMode( bool mode ); void setDragEnabled ( bool mode ); void setDefaultDropAction( Qt::DropAction action ); void setStretchLastSection( bool ); /// Hide columns in the @p hideList, show all other columns. /// If the hideList.last() == -1, the rest of the columns are hidden. void hideColumns( TreeViewBase *view, const QList &hideList ); void hideColumns( const QList &masterList, const QList &slaveList = QList() ); void hideColumn( int col ) { m_leftview->hideColumn( col ); if ( m_rightview ) m_rightview->hideColumn( col ); } void showColumn( int col ) { if ( col == 0 || m_rightview == 0 ) m_leftview->showColumn( col ); else m_rightview->showColumn( col ); } bool isColumnHidden( int col ) const { return m_rightview ? m_rightview->isColumnHidden( col ) : m_leftview->isColumnHidden( col ); } TreeViewBase *masterView() const { return m_leftview; } TreeViewBase *slaveView() const { return m_rightview; } /// Loads context info into this view. Reimplement. virtual bool loadContext( const QMetaEnum &map, const KoXmlElement &element ); /// Save context info from this view. Reimplement. virtual void saveContext( const QMetaEnum &map, QDomElement &context ) const; void setViewSplitMode( bool split ); bool isViewSplit() const { return m_mode; } QAction *actionSplitView() const { return m_actionSplitView; } void setRootIsDecorated ( bool show ); KoPrintJob *createPrintJob( ViewBase *parent ); void setStretchFactors(); QModelIndex indexAt( const QPoint &pos ) const; void setParentsExpanded( const QModelIndex &idx, bool expanded ); void setSortingEnabled( bool on ) { m_leftview->setSortingEnabled( on ); m_rightview->setSortingEnabled( on ); } void sortByColumn( int col, Qt::SortOrder order = Qt::AscendingOrder ) { if ( ! m_leftview->isColumnHidden( col ) || ! m_rightview->isVisible() || m_rightview->isColumnHidden( col ) ) { m_leftview->sortByColumn( col, order ); } else { m_rightview->sortByColumn( col, order ); } } void setContextMenuIndex(const QModelIndex &idx); Q_SIGNALS: /// Context menu requested from the viewport, pointer over @p index at global position @p pos void contextMenuRequested( const QModelIndex &index, const QPoint& pos, const QModelIndexList& ); /// Context menu requested from master- or slave header at global position @p pos void headerContextMenuRequested( const QPoint &pos ); /// Context menu requested from master header at global position @p pos void masterHeaderContextMenuRequested( const QPoint &pos ); /// Context menu requested from slave header at global position @p pos void slaveHeaderContextMenuRequested( const QPoint &pos ); void currentChanged ( const QModelIndex & current, const QModelIndex & previous ); void selectionChanged( const QModelIndexList& ); void dropAllowed( const QModelIndex &index, int dropIndicatorPosition, QDragMoveEvent *event ); public Q_SLOTS: void edit( const QModelIndex &index ); void slotExpand(); void slotCollapse(); protected Q_SLOTS: void slotSelectionChanged( const QItemSelection &sel, const QItemSelection & ); void slotToRightView( const QModelIndex &index ); void slotToLeftView( const QModelIndex &index ); void slotEditToRightView( const QModelIndex &index ); void slotEditToLeftView( const QModelIndex &index ); void slotRightHeaderContextMenuRequested( const QPoint &pos ); void slotLeftHeaderContextMenuRequested( const QPoint &pos ); void slotLeftSortIndicatorChanged( int logicalIndex, Qt::SortOrder order ); void slotRightSortIndicatorChanged( int logicalIndex, Qt::SortOrder order ); protected: void init(); QList expandColumnList( const QList &lst ) const; protected: TreeViewBase *m_leftview; TreeViewBase *m_rightview; QItemSelectionModel *m_selectionmodel; bool m_arrowKeyNavigation; bool m_readWrite; bool m_mode; QAction *m_actionSplitView; }; } // namespace KPlato #endif diff --git a/plan/libs/ui/reportsgenerator/ReportsGeneratorView.cpp b/plan/libs/ui/reportsgenerator/ReportsGeneratorView.cpp index 60fc0725230..bf48fb22082 100644 --- a/plan/libs/ui/reportsgenerator/ReportsGeneratorView.cpp +++ b/plan/libs/ui/reportsgenerator/ReportsGeneratorView.cpp @@ -1,474 +1,520 @@ /* This file is part of the KDE project Copyright (C) 2017 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 "ReportsGeneratorView.h" #include "reportgenerator/ReportGenerator.h" #include "kptdebug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KPlato { #define FULLPATHROLE Qt::UserRole + 123 class TemplateFileDelegate : public QStyledItemDelegate { public: TemplateFileDelegate(QObject *parent); QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; void setEditorData(QWidget *editor, const QModelIndex &index) const; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; QMap files; }; TemplateFileDelegate::TemplateFileDelegate(QObject *parent) : QStyledItemDelegate(parent) { } QWidget *TemplateFileDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_UNUSED(option) Q_UNUSED(index); qDebug()<(editor); qDebug()<setEditable(true); cb->addItems(files.keys()); QString file = index.data().toString(); cb->setCurrentText(file); } void TemplateFileDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QComboBox *cb = qobject_cast(editor); qDebug()<currentText(); qDebug()<<"template file:"<setData(index, nfile); if (files.contains(nfile)) { nfile = files[nfile].url(); } model->setData(index, nfile, FULLPATHROLE); } } else qDebug()<<" No combo box editor!!"; } class FileItemDelegate : public QStyledItemDelegate { public: FileItemDelegate(QObject *parent); QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; void setEditorData(QWidget *editor, const QModelIndex &index) const; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; QMap files; }; FileItemDelegate::FileItemDelegate(QObject *parent) : QStyledItemDelegate(parent) { } QWidget *FileItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_UNUSED(option); Q_UNUSED(index); KUrlRequester *u = new KUrlRequester(parent); u->setMode(KFile::File); return u; } void FileItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { KUrlRequester *u = qobject_cast(editor); QString file = index.data().toString(); if (!file.isEmpty()) { u->setUrl(QUrl(file)); } } void FileItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { KUrlRequester *u = qobject_cast(editor); if (u && index.isValid()) { model->setData(index, u->url().url()); } } class FileNameExtensionDelegate : public QStyledItemDelegate { public: FileNameExtensionDelegate(QObject *parent); QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; void setEditorData(QWidget *editor, const QModelIndex &index) const; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; - QStringList options; }; FileNameExtensionDelegate::FileNameExtensionDelegate(QObject *parent) : QStyledItemDelegate(parent) { - options << "Nothing" << "Date" << "Number"; } QWidget *FileNameExtensionDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_UNUSED(option); Q_UNUSED(index); QComboBox *cb = new QComboBox(parent); - cb->addItems(options); + for (int i = 0; i < ReportsGeneratorView::addOptions().count(); ++i) { + cb->addItem(ReportsGeneratorView::addOptions().at(i), ReportsGeneratorView::addTags().value(i)); + } return cb; } void FileNameExtensionDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { QComboBox *cb = qobject_cast(editor); - QString data = index.data().toString(); - cb->setCurrentText(data.isEmpty() ? options.at(0) : data); + if (cb) { + int idx = ReportsGeneratorView::addTags().indexOf(index.data(Qt::UserRole).toString()); + cb->setCurrentIndex(idx < 0 ? 0 : idx); + } } void FileNameExtensionDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QComboBox *cb = qobject_cast(editor); if (cb && index.isValid()) { + model->setData(index, cb->currentData(), Qt::UserRole); model->setData(index, cb->currentText()); } } +QStringList ReportsGeneratorView::addOptions() +{ + return QStringList() << i18n("Nothing") << i18n("Date") << i18n("Number"); +} + +QStringList ReportsGeneratorView::addTags() +{ + return QStringList() << "Nothing" << "Date" << "Number"; + +} + ReportsGeneratorView::ReportsGeneratorView(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent) { debugPlan<<"----------------- Create ReportsGeneratorView ----------------------"; QVBoxLayout * l = new QVBoxLayout(this); l->setMargin(0); m_view = new QTreeView(this); QStandardItemModel *m = new QStandardItemModel(m_view); m->setHorizontalHeaderLabels(QStringList() << i18n("Name") << i18n("Report Template") << i18n("Report File") << i18n("Add")); m->setHeaderData(0, Qt::Horizontal, xi18nc("@info:tooltip", "Report name"), Qt::ToolTipRole); m->setHeaderData(1, Qt::Horizontal, xi18nc("@info:tooltip", "Report template file name"), Qt::ToolTipRole); m->setHeaderData(2, Qt::Horizontal, xi18nc("@info:tooltip", "Name of the generated report file"), Qt::ToolTipRole); m->setHeaderData(3, Qt::Horizontal, xi18nc("@info:tooltip", "Information added to filename"), Qt::ToolTipRole); m_view->setModel(m); m_view->setContextMenuPolicy(Qt::CustomContextMenu); m_view->setRootIsDecorated(false); m_view->setAlternatingRowColors(true); connect(m_view, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(slotContextMenuRequested(const QPoint&))); l->addWidget(m_view); TemplateFileDelegate *del = new TemplateFileDelegate(m_view); QString path = QStandardPaths::locate(QStandardPaths::AppDataLocation, "reports", QStandardPaths::LocateDirectory); qDebug()<<"standardpath:"<files.insert(url.fileName(), url); } } m_view->setItemDelegateForColumn(1, del); m_view->setItemDelegateForColumn(2, new FileItemDelegate(m_view)); m_view->setItemDelegateForColumn(3, new FileNameExtensionDelegate(m_view)); m_view->header()->setSectionResizeMode(3, QHeaderView::Fixed); m_view->header()->resizeSection(3, 12); connect(m_view->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(slotSelectionChanged())); setupGui(); } void ReportsGeneratorView::setGuiActive(bool activate) { debugPlan<selectionModel()->selectedRows(); } int ReportsGeneratorView::selectedRowCount() const { return selectedRows().count(); } void ReportsGeneratorView::slotContextMenuRequested(const QPoint& pos) { debugPlan; emit requestPopupMenu("reportsgeneratorview_popup", m_view->mapToGlobal(pos)); } void ReportsGeneratorView::slotEnableActions() { updateActionsEnabled(isReadWrite()); } void ReportsGeneratorView::updateActionsEnabled(bool on) { actionAddReport->setEnabled(on); actionRemoveReport->setEnabled(on && selectedRowCount() > 0); actionGenerateReport->setEnabled(on && selectedRowCount() > 0); } void ReportsGeneratorView::setupGui() { // Umpff, adding a specific list name for this view in calligraplan.rc does not work! // But reusing an already existing name works, so... // Not important atm, the whole setup should be refactored anyway. //QString name = "reportsgeneratorview_list"; QString name = "workpackage_list"; KActionCollection *coll = actionCollection(); actionAddReport = new QAction(koIcon("list-add"), i18n("Add Report"), this); coll->addAction("add_report", actionAddReport); coll->setDefaultShortcut(actionAddReport, Qt::CTRL + Qt::Key_I); connect(actionAddReport, SIGNAL(triggered(bool)), SLOT(slotAddReport())); addAction(name, actionAddReport); addContextAction(actionAddReport); actionRemoveReport = new QAction(koIcon("list-remove"), i18n("Remove Report"), this); coll->addAction("remove_report", actionRemoveReport); coll->setDefaultShortcut(actionRemoveReport, Qt::CTRL + Qt::Key_D); connect(actionRemoveReport, SIGNAL(triggered(bool)), SLOT(slotRemoveReport())); addAction(name, actionRemoveReport); addContextAction(actionRemoveReport); actionGenerateReport = new QAction(koIcon("document-export"), i18n("Generate Report"), this); coll->addAction("generate_report", actionGenerateReport); coll->setDefaultShortcut(actionGenerateReport, Qt::CTRL + Qt::Key_G); connect(actionGenerateReport, SIGNAL(triggered(bool)), SLOT(slotGenerateReport())); addAction(name, actionGenerateReport); addContextAction(actionGenerateReport); // createOptionAction(); } void ReportsGeneratorView::slotOptions() { debugPlan; // SplitItemViewSettupDialog *dlg = new SplitItemViewSettupDialog(this, m_view, this); // dlg->addPrintingOptions(); // connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); // dlg->show(); // dlg->raise(); // dlg->activateWindow(); } void ReportsGeneratorView::slotAddReport() { debugPlan; QAbstractItemModel *m = m_view->model(); int row = m->rowCount(); m->insertRow(row); QModelIndex idx = m->index(row, 0); - m->setData(idx, "New report"); + m->setData(idx, i18n("New report")); + QModelIndex add = m->index(row, 3); + m->setData(add, ReportsGeneratorView::addOptions().at(0)); + m->setData(add, ReportsGeneratorView::addTags().at(0), Qt::UserRole); m_view->selectionModel()->setCurrentIndex(idx, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect); m_view->edit(idx); + emit optionsModified(); } void ReportsGeneratorView::slotRemoveReport() { - debugPlan; + debugPlan<model(); - for (QModelIndexList lst = selectedRows(); !lst.isEmpty(); lst = selectedRows()) { - QModelIndex idx = lst.first(); + QModelIndexList lst = selectedRows(); + if (lst.isEmpty()) { + return; + } + // Assumption: model is flat + // We must do this in descending row order + QMap map; + for (int i = 0; i < lst.count(); ++i) { + map.insert(-lst.at(i).row(), lst.at(i)); // sort descending + } + for (const QModelIndex &idx : map) { + Q_ASSERT(!idx.parent().isValid()); // must be flat m->removeRow(idx.row(), idx.parent()); } + emit optionsModified(); } void ReportsGeneratorView::slotGenerateReport() { debugPlan; QAbstractItemModel *model = m_view->model(); for (const QModelIndex &idx : selectedRows()) { QString name = model->index(idx.row(), 0).data().toString(); QString tmp = model->index(idx.row(), 1).data(FULLPATHROLE).toString(); QString file = model->index(idx.row(), 2).data().toString(); - if (tmp.isEmpty() || file.isEmpty()) { + if (tmp.isEmpty()) { + QMessageBox::information(this, xi18nc("@title:window", "Generate Report"), + i18n("Failed to generate %1." + "\nTemplate file name is empty.", name)); + continue; + } + if (file.isEmpty()) { debugPlan<<"No files for report:"<index(idx.row(), 3).data().toString(); + QString addition = model->index(idx.row(), 3).data(Qt::UserRole).toString(); if (addition == "Date") { - + int dotpos = file.lastIndexOf('.'); + QString date = QDate::currentDate().toString(); + file = file.insert(dotpos, date.prepend('-')); } else if (addition == "Number") { - + int dotpos = file.lastIndexOf('.'); + QString fn = file; + for (int i = 1; QFile::exists(fn); ++i) { + fn = file.insert(dotpos, QString::number(i).prepend('-')); + } + file = fn; } generateReport(tmp, file); } } bool ReportsGeneratorView::generateReport(const QString &templateFile, const QString &file) { ReportGenerator rg; rg.setReportType("odt"); // TODO: handle different report types rg.setTemplateFile(templateFile); rg.setReportFile(file); rg.setProject(project()); rg.setScheduleManager(scheduleManager()); if (!rg.open()) { debugPlan<<"Failed to open report generator"; QMessageBox::warning(this, i18n("Failed to open report generator"), rg.lastError()); return false; } if (!rg.createReport()) { QMessageBox::warning(this, i18n("Failed to create report"), rg.lastError()); return false; } return true; } bool ReportsGeneratorView::loadContext(const KoXmlElement &context) { debugPlan; m_view->header()->setStretchLastSection((bool)(context.attribute("stretch-last-column", "1").toInt())); KoXmlElement e = context.namedItem("sections").toElement(); if (!e.isNull()) { QHeaderView *h = m_view->header(); QString s("section-%1"); for (int i = 0; i < h->count(); ++i) { if (e.hasAttribute(s.arg(i))) { int index = e.attribute(s.arg(i), "-1").toInt(); if (index >= 0 && index < h->count()) { h->moveSection(h->visualIndex(index), i); } } } } KoXmlElement parent = context.namedItem("data").toElement(); if (!parent.isNull()) { debugPlan<<"Load data"; int row = 0; QAbstractItemModel *model = m_view->model(); forEachElement(e, parent) { if (e.tagName() != "row") { continue; } model->insertRow(row); QString name = e.attribute("name"); QString tmp = e.attribute("template"); QString file = e.attribute("file"); QString add = e.attribute("add"); QModelIndex idx = model->index(row, 0); model->setData(idx, name); idx = model->index(row, 1); model->setData(idx, tmp, FULLPATHROLE); model->setData(idx, QUrl(tmp).fileName()); idx = model->index(row, 2); model->setData(idx, file); idx = model->index(row, 3); - model->setData(idx, add); - debugPlan<<"Load row:"<setData(idx, add, Qt::UserRole); + model->setData(idx, ReportsGeneratorView::addOptions().value(ReportsGeneratorView::addTags().indexOf(add))); + ++row; } } ViewBase::loadContext(context); for (int c = 0; c < m_view->header()->count(); ++c) { m_view->resizeColumnToContents(c); } return true; } void ReportsGeneratorView::saveContext(QDomElement &context) const { debugPlan; context.setAttribute( "stretch-last-column", QString::number(m_view->header()->stretchLastSection()) ); QDomElement e = context.ownerDocument().createElement("sections"); context.appendChild(e); QHeaderView *h = m_view->header(); for (int i = 0; i < h->count(); ++i) { e.setAttribute(QString("section-%1").arg(i), h->logicalIndex(i)); } QDomElement data = context.ownerDocument().createElement("data"); context.appendChild(data); const QAbstractItemModel *model = m_view->model(); - for (int row = 0; row < m_view->model()->rowCount(); ++row) { + for (int row = 0; row < model->rowCount(); ++row) { e = data.ownerDocument().createElement("row"); data.appendChild(e); QModelIndex idx = model->index(row, 0); e.setAttribute("name", idx.data().toString()); idx = model->index(row, 1); e.setAttribute("template", idx.data(FULLPATHROLE).toString()); idx = model->index(row, 2); e.setAttribute("file", idx.data().toString()); idx = model->index(row, 3); - e.setAttribute("add", idx.data().toString()); + e.setAttribute("add", idx.data(Qt::UserRole).toString()); } ViewBase::saveContext(context); } } // namespace KPlato diff --git a/plan/libs/ui/reportsgenerator/ReportsGeneratorView.h b/plan/libs/ui/reportsgenerator/ReportsGeneratorView.h index 4ff7f4ca100..8597ac776a8 100644 --- a/plan/libs/ui/reportsgenerator/ReportsGeneratorView.h +++ b/plan/libs/ui/reportsgenerator/ReportsGeneratorView.h @@ -1,90 +1,92 @@ /* This file is part of the KDE project Copyright (C) 2017 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 REPORTSGENERATORVIEW_H #define REPORTSGENERATORVIEW_H #include "kplatoui_export.h" #include "kptglobal.h" #include "kptviewbase.h" class KoDocument; class KActionMenu; class QWidget; class QTreeView; namespace KPlato { class KPLATOUI_EXPORT ReportsGeneratorView : public ViewBase { Q_OBJECT public: ReportsGeneratorView(KoPart *part, KoDocument *doc, QWidget *parent); void setupGui(); /// Loads context info into this view. Reimplement. virtual bool loadContext( const KoXmlElement &/*context*/ ); /// Save context info from this view. Reimplement. virtual void saveContext( QDomElement &/*context*/ ) const; + static QStringList addOptions(); + static QStringList addTags(); public Q_SLOTS: /// Activate/deactivate the gui virtual void setGuiActive( bool activate ); void slotAddReport(); void slotRemoveReport(); void slotGenerateReport(); protected: void updateActionsEnabled( bool on ); int selectedRowCount() const; QModelIndexList selectedRows() const; bool generateReport(const QString &templateFile, const QString &file); protected Q_SLOTS: virtual void slotOptions(); private Q_SLOTS: void slotSelectionChanged(); void slotCurrentChanged( const QModelIndex&, const QModelIndex& ); void slotContextMenuRequested(const QPoint &pos); void slotEnableActions(); private: QTreeView *m_view; QAction *actionAddReport; QAction *actionRemoveReport; QAction *actionGenerateReport; }; } //namespace KPlato #endif diff --git a/plan/libs/ui/welcome/WelcomeView.cpp b/plan/libs/ui/welcome/WelcomeView.cpp index 1aa2ea9276b..2dd613c12fb 100644 --- a/plan/libs/ui/welcome/WelcomeView.cpp +++ b/plan/libs/ui/welcome/WelcomeView.cpp @@ -1,270 +1,322 @@ /* This file is part of the KDE project Copyright (C) 2017 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 "WelcomeView.h" #include "kptcommand.h" #include "kptdebug.h" +#include "WhatsThis.h" #include #include #include #include #include #include #include #include #include #include +#include const QLoggingCategory &PLANWELCOME_LOG() { static const QLoggingCategory category("calligra.plan.welcome"); return category; } #define debugWelcome qCDebug(PLANWELCOME_LOG) #define warnWelcome qCWarning(PLANWELCOME_LOG) #define errorWelcome qCCritical(PLANWELCOME_LOG) namespace KPlato { class RecentFilesModel : public QStringListModel { public: RecentFilesModel(QObject *parent = 0); Qt::ItemFlags flags(const QModelIndex &idx) const; QVariant data(const QModelIndex &idx, int role) const; }; RecentFilesModel::RecentFilesModel(QObject *parent) : QStringListModel(parent) { } Qt::ItemFlags RecentFilesModel::flags(const QModelIndex &idx) const { Qt::ItemFlags f = (QStringListModel::flags(idx) & ~Qt::ItemIsEditable); return f; } QVariant RecentFilesModel::data(const QModelIndex &idx, int role) const { switch(role) { case Qt::DecorationRole: return QIcon::fromTheme(QStringLiteral("document-open")); break; case Qt::FontRole: break; default: break; } return QStringListModel::data(idx, role); } //----------------------------------- WelcomeView::WelcomeView(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent) , m_projectdialog(0) , m_filedialog(0) { widget.setupUi(this); widget.recentProjects->setBackgroundRole(QPalette::Midlight); - widget.createResourceFileBtn->hide(); // disable this for now - widget.createResourceFileBtn->setWhatsThis(xi18nc("@info:whatsthis", - "Shared resources" - "Create a shared resources file." - " Resources can be shared between projects" - " to avoid overbooking resources across projects." - " Shared resources must be defined in a separate file." - )); + WhatsThis::add(widget.newProjectBtn, + xi18nc("@info:whatsthis", + "Create a new project" + "" + "Creates a new project with default values defined in" + " Settings." + "Opens the project dialog" + " so you can define project specific properties like" + " Project Name," + " Target Start" + " and - End times." + "More..." + "", "https://userbase.kde.org/Plan/Howto/Create_New_Project")); + + WhatsThis::add(widget.createResourceFileBtn, + xi18nc("@info:whatsthis", + "Shared resources" + "" + "Create a shared resources file." + "This enables you to only create your resources once," + " you just refer to your resources file when you create a new project." + "These resources can then be shared between projects" + " to avoid overbooking resources across projects." + "Shared resources must be defined in a separate file." + "More..." + "", "https://userbase.kde.org/Plan/Howto/Create_Shared_Resources")); + + WhatsThis::add(widget.recentProjects, + xi18nc("@info:whatsthis", + "Recent Projects" + "" + "A list of the 10 most recent project files opened." + "" + "This enables you to quickly open projects you have worked on recently." + "More..." + "", "https://userbase.kde.org/Plan/Howto")); + + WhatsThis::add(widget.introductionBtn, + xi18nc("@info:whatsthis", + "Introduction to <application>Plan</application>" + "" + "These introductory pages gives you hints and tips on what" + " you can use Plan for, and how to use it." + "")); + + WhatsThis::add(widget.contextHelp, + xi18nc("@info:whatsthis", + "Context help" + "" + "Help is available many places using What's This." + "It is activated using the menu entry Help->What's this?" + " or the keyboard shortcut Shift+F1." + "" + "In dialogs it is available via the ? in the dialog title bar." + "" + "If you see More... in the text," + " pressing it will display more information from online resources in your browser." + "", "https://userbase.kde.org/Plan/Howto")); m_model = new RecentFilesModel(this); widget.recentProjects->setModel(m_model); setupGui(); connect(widget.newProjectBtn, SIGNAL(clicked(bool)), this, SLOT(slotNewProject())); connect(widget.createResourceFileBtn, SIGNAL(clicked(bool)), this, SLOT(slotCreateResourceFile())); connect(widget.openProjectBtn, SIGNAL(clicked(bool)), this, SLOT(slotOpenProject())); connect(widget.introductionBtn, SIGNAL(clicked(bool)), this, SIGNAL(showIntroduction())); connect(widget.recentProjects->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(slotRecentFileSelected(const QItemSelection&))); } WelcomeView::~WelcomeView() { debugWelcome; } void WelcomeView::setRecentFiles(const QStringList &files) { QStringList lst; for (const QString &s : files) { lst.prepend(s); } m_model->setStringList(lst); widget.recentProjects->resizeColumnToContents(0); } void WelcomeView::updateReadWrite(bool /*readwrite */) { } void WelcomeView::setGuiActive(bool activate) { debugPlan<show(); m_projectdialog->raise(); m_projectdialog->activateWindow(); } } void WelcomeView::slotProjectEditFinished(int result) { qDebug()<(sender()); if (dia == 0) { return; } if (result == QDialog::Accepted) { MacroCommand *cmd = dia->buildCommand(); if (cmd) { cmd->execute(); delete cmd; koDocument()->setModified(true); } emit projectCreated(); emit selectDefaultView(); emit finished(); } dia->deleteLater(); } void WelcomeView::slotCreateResourceFile() { QString file = QStandardPaths::locate(QStandardPaths::AppDataLocation, "templates/.source/SharedResources.plant"); emit openTemplate(QUrl::fromUserInput(file)); emit finished(); } void WelcomeView::slotOpenProject() { if (m_projectdialog) { qWarning()<setFileMode(QFileDialog::ExistingFile); m_filedialog->setNameFilters(QStringList()<<"Plan files (*.plan)"); m_filedialog->setOption(QFileDialog::HideNameFilterDetails, true); connect(m_filedialog, SIGNAL(finished(int)), this, SLOT(slotOpenFileFinished(int))); } m_filedialog->show(); m_filedialog->raise(); m_filedialog->activateWindow(); } } void WelcomeView::slotOpenFileFinished(int result) { QFileDialog *dia = qobject_cast(sender()); if (dia == 0) { return; } if (result == QDialog::Accepted) { QUrl url = dia->selectedUrls().value(0); if (!url.isEmpty() && mainWindow()->openDocument(url)) { emit finished(); } } dia->deleteLater(); } -void WelcomeView::slotLoadSharedResources(const QString &file, const QUrl &projects) +void WelcomeView::slotLoadSharedResources(const QString &file, const QUrl &projects, bool loadProjectsAtStartup) { QUrl url(file); if (url.scheme().isEmpty()) { url.setScheme("file"); } if (url.isValid()) { - emit loadSharedResources(url, projects); + emit loadSharedResources(url, loadProjectsAtStartup ? projects :QUrl()); } } } // namespace KPlato diff --git a/plan/libs/ui/welcome/WelcomeView.h b/plan/libs/ui/welcome/WelcomeView.h index 30a250af447..c235a6a09c1 100644 --- a/plan/libs/ui/welcome/WelcomeView.h +++ b/plan/libs/ui/welcome/WelcomeView.h @@ -1,102 +1,102 @@ /* This file is part of the KDE project Copyright (C) 2017 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 WELCOMEVIEW_H #define WELCOMEVIEW_H #include "kplatoui_export.h" #include "kptviewbase.h" #include "ui_WelcomeView.h" #include "kptmainprojectdialog.h" #include class KoDocument; class QUrl; class QItemSelecteion; namespace KPlato { class RecentFilesModel; class KPLATOUI_EXPORT WelcomeView : public ViewBase { Q_OBJECT public: WelcomeView(KoPart *part, KoDocument *doc, QWidget *parent); ~WelcomeView(); void setRecentFiles(const QStringList &files); void setupGui(); virtual void updateReadWrite(bool readwrite); KoPrintJob *createPrintJob(); public Q_SLOTS: /// Activate/deactivate the gui virtual void setGuiActive(bool activate); Q_SIGNALS: void newProject(); void openProject(); void recentProject(const QUrl &file); void showIntroduction(); void selectDefaultView(); void loadSharedResources(const QUrl &url, const QUrl &projects); void openExistingFile(const QUrl &url); void projectCreated(); void finished(); void openTemplate(QUrl); protected: void updateActionsEnabled( bool on = true); private Q_SLOTS: void slotContextMenuRequested(const QModelIndex &index, const QPoint& pos); void slotRecentFileSelected(const QItemSelection &selected); void slotEnableActions(bool on); void slotNewProject(); void slotOpenProject(); - void slotLoadSharedResources(const QString &file, const QUrl &projects); + void slotLoadSharedResources(const QString &file, const QUrl &projects, bool loadProjectsAtStartup); void slotProjectEditFinished(int result); void slotOpenFileFinished(int result); void slotCreateResourceFile(); private: Ui::WelcomeView widget; RecentFilesModel *m_model; QPointer m_projectdialog; QPointer m_filedialog; }; } //KPlato namespace #endif diff --git a/plan/libs/ui/welcome/WelcomeView.ui b/plan/libs/ui/welcome/WelcomeView.ui index 1e3cd90ad7f..5063a3b5a70 100644 --- a/plan/libs/ui/welcome/WelcomeView.ui +++ b/plan/libs/ui/welcome/WelcomeView.ui @@ -1,277 +1,349 @@ KPlato::WelcomeView 0 0 688 364 Qt::Horizontal 13 14 - <html><head/><body><p><span style=" font-weight:600;">Create a new project</span></p><p>Creates a new project with default values defined in <span style=" font-style:italic;">Settings.</span></p><p>Opens the <span style=" font-style:italic;">project dialog </span>so you can define project specific properties like Project Name and <span style=" font-style:italic;">Target Start</span> and <span style=" font-style:italic;">End</span> times.</p><p>You can change the default settings by selecting <span style=" font-style:italic;">Settings-&gt;Configure Plan</span>.</p></body></html> + New project .. Qt::Horizontal 13 17 Qt::Vertical 20 40 Qt::Horizontal 40 20 Create Shared Resources .. Qt::Horizontal 40 20 Qt::Horizontal 40 20 <html><head/><body><p><span style=" font-weight:600;">Open Project</span></p><p>Displays a file dialog enabling you to open an existing project.</p></body></html> Open Project... .. Qt::Horizontal 40 20 <html><head/><body><p><span style=" font-size:8pt; font-style:italic;">Recent projects:</span></p></body></html> Qt::AlignCenter - <html><head/><body><p><span style=" font-weight:600;">Recent Projects</span></p><p>A list of the 10 most recent project files opened.</p><p>This enables you to quickly open projects you have worked on recently.</p></body></html> + QFrame::Plain false false false false + + + + Qt::Vertical + + + Qt::Horizontal 40 20 - - <html><head/><body><p><span style=" font-weight:600;">A Short Introduction to Plan</span></p><p>These introductory pages gives you hints and tips on what you can use Plan for, and how to use it.</p></body></html> - Introduction .. Qt::Horizontal 40 20 - + + + Qt::Vertical + + + + 20 + 40 + + + + + + - <html><head/><body><p><span style=" font-size:11pt; font-weight:600;">Context help</span></p><p>Many functions has help and hints that can be displayed with <span style=" font-style:italic;">What's this</span>.</p><p>Activate it by selecting <span style=" font-style:italic;">Help-&gt;What's this</span> or <span style=" font-style:italic;">Shift+F1</span>.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Context Help</span></p><p>Many functions has help and hints that can be displayed with <span style=" font-style:italic;">What's this</span>.</p><p>Activate it by selecting <span style=" font-style:italic;">Help-&gt;What's this</span> or <span style=" font-style:italic;">Shift+F1</span>.</p><p>Try it on this text!</p></body></html> true Qt::AlignHCenter|Qt::AlignTop true Qt::Vertical 20 40 + + + + Qt::Horizontal + + + + + + + https://userbase.kde.org/Plan + + + <a href="https://userbase.kde.org/Plan">Plan user documentation</a> + + + Qt::AlignCenter + + + true + + + + + + + https://forum.kde.org/viewforum.php?f=203 + + + <a href="https://forum.kde.org/viewforum.php?f=203">Community forum</a> + + + Qt::AlignCenter + + + true + + + + + + + https://calligra.org + + + <a href="https://calligra.org">Calligra</a> + + + Qt::AlignCenter + + + true + + + diff --git a/plan/workpackage/org.kde.calligraplanwork.desktop b/plan/workpackage/org.kde.calligraplanwork.desktop index c397f7bdbd7..9214046889f 100644 --- a/plan/workpackage/org.kde.calligraplanwork.desktop +++ b/plan/workpackage/org.kde.calligraplanwork.desktop @@ -1,114 +1,115 @@ [Desktop Entry] Name=Plan WorkPackage Handler Name[bs]=Upravljač planskih radnih paketa Name[ca]=Gestor de paquets de feina del Plan Name[ca@valencia]=Gestor de paquets de faena del Plan Name[da]=Håndtering af WorkPackage til Plan Name[de]=Plan-Arbeitspaketverwaltung Name[el]=Χειριστής πακέτου εργασίας Plan Name[en_GB]=Plan WorkPackage Handler Name[es]=Gestor de paquetes de trabajo de Plan Name[et]=Plani töölõikude käitleja Name[eu]=Plan-en lan-paketeen maneiatzailea Name[fi]=Plan-työpakettikäsittelijä Name[fr]=Paquet de travail de Plan Name[gl]=Xestor para Plan de paquetes de traballo Name[hu]=Plan munkacsomag-kezelő Name[it]=Gestore dei pacchetti di lavoro di Plan Name[ja]=Plan ワークパッケージハンドラ Name[kk]=Plan жұмыс дестесінің өңдеуіші Name[nb]=Plan arbeidspakkestyring Name[nl]=Plan werkpakketbeheerder Name[pl]=Program obsługujący pakiety pracy Plan Name[pt]=Tratamento de Pacotes de Trabalho do Plan Name[pt_BR]=Tratamento de pacotes de trabalho do Plan Name[ru]=Программа обработки Plan WorkPackage Name[sk]=Spracovač pracovných balíkov Plan Name[sv]=Hantering av arbetspaket i Plan Name[tr]=Plan Çalışma Paketi İşleyicisi Name[ug]=Plan خىزمەت بوغچا بىر تەرەپ قىلغۇچ Name[uk]=Програма опрацювання робочих пакунків Plan Name[x-test]=xxPlan WorkPackage Handlerxx Name[zh_CN]=Plan 工作包处理程序 Name[zh_TW]=Plan 工作套件處理器 GenericName=Project Management GenericName[bg]=Управление на проекти GenericName[br]=Mererezh raktresioù GenericName[bs]=Upravljanje projektima GenericName[ca]=Gestió de projectes GenericName[ca@valencia]=Gestió de projectes GenericName[cs]=Správa projektů GenericName[cy]=Rheoli Cywaith GenericName[da]=Projektstyring GenericName[de]=Projektmanagement GenericName[el]=Διαχείριση έργων GenericName[en_GB]=Project Management GenericName[eo]=Projektadministrado GenericName[es]=Gestión de proyectos GenericName[et]=Projektihaldus GenericName[eu]=Proiektu-kudeaketa GenericName[fa]=مدیریت پروژه GenericName[fi]=Projektinhallinta GenericName[fr]=Gestion de projets GenericName[fy]=Projektbehear GenericName[ga]=Bainisteoireacht Tionscadal GenericName[gl]=Xestión de proxectos GenericName[he]=ניהול פרוייקטים GenericName[hi]=परियोजना प्रबंधन GenericName[hne]=परियोजना प्रबंधन GenericName[hr]=Upravljanje projektima GenericName[hu]=Projektkezelő GenericName[ia]=Administration de projectos GenericName[is]=Verkefnisstjórn GenericName[it]=Gestione dei progetti GenericName[ja]=プロジェクト管理 GenericName[kk]=Жоба басқаруы GenericName[ko]=프로젝트 관리 GenericName[lt]=Projektų valdymas GenericName[lv]=Projektu pārvaldība GenericName[mai]=प्रोजेक्ट प्रबन्धन GenericName[mr]=परियोजना व्यवस्थापन GenericName[ms]=Pengurusan Projek GenericName[nb]=Prosjektstyring GenericName[nds]=Projektpleeg GenericName[ne]=परियोजना व्यवस्थापन GenericName[nl]=Projectbeheer GenericName[oc]=Gestion de projècte GenericName[pl]=Zarządzanie projektami GenericName[pt]=Gestão de Projectos GenericName[pt_BR]=Gerenciamento de Projetos GenericName[ru]=Проекты GenericName[sk]=Správa projektov GenericName[sl]=Projektno vodenje GenericName[sv]=Projekthantering GenericName[ta]=திட்ட மேலாண்மை GenericName[tg]=Идоракунии лоиҳа GenericName[tr]=Proje Yönetimi GenericName[ug]=قۇرۇلۇش باشقۇرۇش GenericName[uk]=Керування проектами GenericName[uz]=Loyiha boshqaruvi GenericName[uz@cyrillic]=Лойиҳа бошқаруви GenericName[wa]=Manaedjmint di pordjet GenericName[x-test]=xxProject Managementxx GenericName[zh_CN]=项目管理 GenericName[zh_TW]=專案管理 Comment=Work Package handler for the Plan project planning tool Comment[ca]=Gestor de paquets de feina per a l'eina de planificació de projectes Plan Comment[ca@valencia]=Gestor de paquets de faena per a l'eina de planificació de projectes Plan Comment[de]=Arbeitspaketverwaltung für das Plan-Projektplanungsprogramm Comment[es]=Gestor de paquetes de trabajo para la herramienta de planificación de proyectos Plan Comment[it]=Gestore dei pacchetti di lavoro dello strumento di pianificazione dei progetti Plan Comment[nl]=Werkpakketbeheerder voor het Plan-projectplanninghulpmiddel Comment[pl]=Program obsługujący pakiety pracy dla narzędzia planowania projektów Plan Comment[pt]=Tratamento de Pacotes de Trabalho para a ferramenta de gestão de projectos Plan Comment[sv]=Hantering av arbetspaket för projektplaneringsverktyget Plan +Comment[tr]=Plan proje planlama aracı için Çalışma Paketi işleyici Comment[uk]=Обробник робочих пакунків для засобу планування проектів Plan Comment[x-test]=xxWork Package handler for the Plan project planning toolxx Exec=calligraplanwork %u MimeType=application/x-vnd.kde.plan.work;application/x-vnd.kde.kplato.work; Type=Application Icon=calligraplanwork X-KDE-ServiceTypes=Calligra/Application Categories=Qt;KDE;Office; X-KDE-StartupNotify=true X-DocPath=http://userbase.kde.org/PlanWork/Manual diff --git a/plugins/semanticitems/event/calligra_semanticitem_event.desktop b/plugins/semanticitems/event/calligra_semanticitem_event.desktop index 8145f51482a..92bfb191417 100644 --- a/plugins/semanticitems/event/calligra_semanticitem_event.desktop +++ b/plugins/semanticitems/event/calligra_semanticitem_event.desktop @@ -1,59 +1,59 @@ [Desktop Entry] Name=RDF Calendar Event Plugin Name[bs]=RDF dodatak za kalendarske događaje Name[ca]=Connector d'esdeveniments de calendari RDF Name[ca@valencia]=Connector d'esdeveniments de calendari RDF Name[da]=Plugin til RDF-kalenderbegivenheder Name[de]=RDF-Kalender-Ereignismodul Name[el]=Πρόσθετο συμβάντων ημερολογίου RDF Name[en_GB]=RDF Calendar Event Plugin Name[es]=Complemento de calendario de eventos RDF Name[et]=RDF-kalendrisündmuste plugin Name[fi]=RDF-kalenteritapahtumaliitännäinen Name[fr]=Module externe d'évènement de calendrier RDF -Name[gl]=Complemento de acontecementos de calendario de RDF +Name[gl]=Complemento de eventos de calendario de RDF Name[hu]=RDF naptáresemény bővítmény Name[it]=Estensione RDF degli eventi di calendario Name[kk]=RDF күнтізбе оқиға плагині Name[nb]=RDF kalender programtillegg for hendelser Name[nl]=Plug-in voor gebeurtenis in RDF-agenda Name[pl]=Wtyczka wydarzeń kalendarza RDF Name[pt]='Plugin' de Eventos do Calendário RDF Name[pt_BR]=Plugin de eventos do calendário RDF Name[sk]=Plugin udalosti kalendára RDF Name[sv]=Insticksprogram för RDF-kalenderhändelser Name[tr]=RDF Takvim Olayı Eklentisi Name[uk]=Додаток подій календаря RDF Name[x-test]=xxRDF Calendar Event Pluginxx Comment=A plugin to map calendar event items between document and RDF database Comment[bs]=Dodatak koji mapira kalendarske događaje između dokumenta i RDF baze podataka Comment[ca]=Un connector per relacionar elements de calendari entre documents i una base de dades RDF Comment[ca@valencia]=Un connector per relacionar elements de calendari entre documents i una base de dades RDF Comment[da]=Et plugin til at koble kalenderbegivenheder mellem dokument og RDF-database Comment[de]=Ein Modul, um Kalenderereignisse zwischen Dokument und RDF-Datenbank zuzuordnen Comment[el]=Ένα πρόσθετο για την αντιστοίχηση αντικειμένων συμβάντων ημερολογίου μεταξύ εγγράφου και βάσης δεδομένων RDF Comment[en_GB]=A plugin to map calendar event items between document and RDF database Comment[es]=Un complemento para asignar elementos de calendarios de eventos entre un documento y una base de datos RDF Comment[et]=Plugin dokumendi ja RDF-andmebaasi kalendrisündmuste elementide seondamiseks Comment[fr]=Un module externe pour faire correspondre un évènement de calendrier entre un document et une base de données RDF -Comment[gl]=Un complemento para asociar elementos de acontecemento de calendario entre un documento e unha base de datos RDF. +Comment[gl]=Un complemento para asociar elementos de evento de calendario entre un documento e unha base de datos RDF. Comment[hu]=Egy bővítmény a naptáresemény elemek leképezéséhez a dokumentum és az RDF adatbázis között Comment[it]=Una estensione per associare gli eventi di calendario tra documento e database RDF Comment[kk]=Құжаттағы және RDF деректер қорындағы күнтізбе оқиғаларды сәйкестіретін плагині Comment[nb]=Et programtillegg som avbilder kalenderhendelser mellom dokument og RDF-database Comment[nl]=Een plug-in om verbinding te maken tussen gebeurtenis-items in een document en een RDF-database Comment[pl]=Wtyczka do mapowania elementów wydarzeń kalendarza pomiędzy dokumentem a bazą danych RDF Comment[pt]=Um 'plugin' para associar os itens do evento entre o documento e a base de dados RDF Comment[pt_BR]=Um plugin para associar os eventos de calendário entre o documento e o banco de dados RDF Comment[sk]=Plugin na mapovanie položiek kalendára medzi dokumentom a RDF databázou Comment[sv]=Ett insticksprogram för att avbilda kalenderhändelseobjekt mellan dokument och en RDF-databas Comment[tr]=Belgeler ile RDF veritabanı arasında takvim olaylarını eşleyen eklenti Comment[uk]=Додаток для створення зв’язку між записами подій календаря у документі та у базі даних RDF Comment[x-test]=xxA plugin to map calendar event items between document and RDF databasexx Type=Service X-KDE-ServiceTypes=Calligra/SemanticItem X-KDE-Library=calligra_semanticitem_event X-KDE-PluginInfo-Name=calligra_semanticitem_event X-Calligra-MinVersion=28 X-Calligra-PluginVersion=28 diff --git a/sheets/functions/kspreaddatabasemodule.desktop b/sheets/functions/kspreaddatabasemodule.desktop index 16ca5a67943..f170461707d 100644 --- a/sheets/functions/kspreaddatabasemodule.desktop +++ b/sheets/functions/kspreaddatabasemodule.desktop @@ -1,96 +1,96 @@ [Desktop Entry] Name=Database Functions Name[bg]=Функции за бази от данни Name[bs]=Funkcije Baze Podataka Name[ca]=Funcions de base de dades Name[ca@valencia]=Funcions de base de dades Name[cs]=Funkce databází Name[da]=Databaserfunktioner Name[de]=Datenbankfunktionen Name[el]=Συναρτήσεις βάσης δεδομένων Name[en_GB]=Database Functions Name[es]=Funciones de bases de datos Name[et]=Andmebaasifunktsioonid Name[eu]=Datu-baseen funtzioak Name[fi]=Tietokantafunktiot Name[fr]=Fonctions de données Name[ga]=Feidhmeanna Bunachar Sonraí -Name[gl]=Funcións de bases de datos +Name[gl]=Funcións de bases de datos Name[he]=פונקציות מסד־נתונים Name[hne]=डाटाबेस फंक्सन्स Name[hu]=Adatbázis függvények Name[it]=Funzioni per banche dati Name[ja]=データベース関数 Name[kk]=Деректер қоры функциялары Name[lt]=Duomenų bazės funkcijos Name[lv]=Datu bāzu veidotājs Name[nb]=Databasefunksjoner Name[nds]=Datenbankfunkschonen Name[nl]=Databasefucties Name[oc]=Foncions de basa de donadas Name[pl]=Funkcje baz danych Name[pt]=Funções de Bases de Dados Name[pt_BR]=Funções de bancos de dados Name[ru]=Функции баз данных Name[sk]=Databázové funkcie Name[sl]=Funkcije podatkovnih zbirk Name[sv]=Databasfunktioner Name[tr]=Veritabanı Fonksiyonları Name[ug]=ساندان ئىقتىدارى Name[uk]=Функції баз даних Name[wa]=Fonccions di båze di dnêyes Name[x-test]=xxDatabase Functionsxx Name[zh_CN]=数据库函数 Name[zh_TW]=資料庫函數 Comment=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[bs]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[ca]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[ca@valencia]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[cs]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[da]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[de]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[el]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[en_GB]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[eo]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[es]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[et]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[eu]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[fi]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[fr]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[ga]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[gl]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[hu]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[it]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[ja]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[kk]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[lv]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[nb]=DGJENNOMSNITT,DANTALL,DANTALLA,DHENT,DMAKS,DMIN,DPRODUKT,DSTDAV,DSTDAVP,DSUMMER,DVARIANS,DVARIANSP,HENTPIVOTDATA Comment[nds]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[nl]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[pl]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[pt]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[pt_BR]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[ru]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[sk]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[sl]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[sv]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[tr]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[uk]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[wa]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[x-test]=xxDAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATAxx Comment[zh_CN]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Comment[zh_TW]=DAVERAGE, DCOUNT, DCOUNTA, DGET, DMAX, DMIN, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DVAR, DVARP, GETPIVOTDATA Icon=funct Type=Service X-KDE-Library=kspreaddatabasemodule X-KDE-ServiceTypes=CalligraSheets/Plugin,KPluginInfo X-CalligraSheets-InterfaceVersion=0 X-KDE-PluginInfo-Author=The KSpread Team X-KDE-PluginInfo-Email=calligra-devel@kde.org X-KDE-PluginInfo-Name=DatabaseModule X-KDE-PluginInfo-Version=1.0 X-KDE-PluginInfo-Website=http://www.calligra.org/ X-KDE-PluginInfo-Category=FunctionModule X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-EnabledByDefault=true diff --git a/sheets/functions/kspreadengineeringmodule.desktop b/sheets/functions/kspreadengineeringmodule.desktop index bf2025f4485..9ae80502db4 100644 --- a/sheets/functions/kspreadengineeringmodule.desktop +++ b/sheets/functions/kspreadengineeringmodule.desktop @@ -1,92 +1,92 @@ [Desktop Entry] Name=Engineering Functions Name[bg]=Инженерни функции Name[bs]=Inženjerske funkcije Name[ca]=Funcions d'enginyeria Name[ca@valencia]=Funcions d'enginyeria Name[cs]=Inženýrské funkce Name[da]=Udviklingsfunktioner Name[de]=Ingenieurwesen-Funktionen Name[el]=Συναρτήσεις μηχανικής Name[en_GB]=Engineering Functions Name[es]=Funciones de ingeniería Name[et]=Insenerarvutuste funktsioonid Name[eu]=Ingeniaritza-funtzioak Name[fi]=Insinöörifunktiot Name[fr]=Fonctions technologiques -Name[gl]=Funcións de enxeñería +Name[gl]=Funcións de enxeñaría Name[he]=פונקציות הנדסה Name[hu]=Műszaki függvények Name[it]=Funzioni ingegneristiche Name[ja]=エンジニアリング関数 Name[kk]=Инженерлік функциялары Name[lt]=Inžinerinės funkcijos Name[lv]=Inžinieru funkcijas Name[nb]=Tekniske funksjoner Name[nds]=Technikfunkschonen Name[nl]=Engineering-functies Name[pl]=Funkcje inżynierskie Name[pt]=Funções de Engenharia Name[pt_BR]=Funções de engenharia Name[ru]=Инженерные функции Name[sk]=Inžinierske funkcie Name[sl]=Inženirske funkcije Name[sv]=Ingenjörsfunktioner Name[tr]=Mühendislik Fonksiyonları Name[uk]=Інженерні функції Name[wa]=Fonccions d' indjenieus Name[x-test]=xxEngineering Functionsxx Name[zh_CN]=工程函数 Name[zh_TW]=工程函數 Comment=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[bs]=BAZA, BESSELI, BESSELJ, BESSELK, BESSELY, BINUDEC, BINUHEX, BINUOKT, KOMPLEKS, KONVERTUJ, DECUBIN, DECUHEX, DECUOKT, DELTA, ERF, ERFC, GESTEP, HEXUBIN, HEXUDEC, HEXUOKT, IMABS, IMAGINARNI, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMSNAGA, IMPRODUKT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCTUBIN, OCTUDEC, OCTUHEX Comment[ca]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[ca@valencia]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[cs]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[da]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[de]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[el]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[en_GB]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[eo]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[es]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[et]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[eu]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[fi]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[fr]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[ga]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[gl]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[hu]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[it]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[ja]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[kk]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[lv]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[nb]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[nds]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[nl]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[pl]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[pt]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[pt_BR]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[ru]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[sk]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[sl]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[sv]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[tr]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[uk]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[wa]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[x-test]=xxBASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEXxx Comment[zh_CN]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Comment[zh_TW]=BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BIN2DEC, BIN2HEX, BIN2OCT, COMPLEX, CONVERT, DEC2BIN, DEC2HEX, DEC2OCT, DELTA, ERF, ERFC, GESTEP, HEX2BIN, HEX2DEC, HEX2OCT, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, IMTANH, OCT2BIN, OCT2DEC, OCT2HEX Icon=funct Type=Service X-KDE-Library=kspreadengineeringmodule X-KDE-ServiceTypes=CalligraSheets/Plugin,KPluginInfo X-CalligraSheets-InterfaceVersion=0 X-KDE-PluginInfo-Author=The KSpread Team X-KDE-PluginInfo-Email=calligra-devel@kde.org X-KDE-PluginInfo-Name=EngineeringModule X-KDE-PluginInfo-Version=1.0 X-KDE-PluginInfo-Website=http://www.calligra.org/ X-KDE-PluginInfo-Category=FunctionModule X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-EnabledByDefault=true diff --git a/sheets/functions/kspreadreferencemodule.desktop b/sheets/functions/kspreadreferencemodule.desktop index 0d4d809bfaf..78186625cd1 100644 --- a/sheets/functions/kspreadreferencemodule.desktop +++ b/sheets/functions/kspreadreferencemodule.desktop @@ -1,90 +1,90 @@ [Desktop Entry] Name=Reference Functions Name[bg]=Справочни функции Name[bs]=Referencne funkcije Name[ca]=Funcions de referència Name[ca@valencia]=Funcions de referència Name[cs]=Referenční funkce Name[da]=Referencefunktioner Name[de]=Verweisfunktionen Name[el]=Συναρτήσεις αναφοράς Name[en_GB]=Reference Functions Name[es]=Funciones de referencia Name[et]=Viitefunktsioonid Name[eu]=Erreferentzia-funtzioak Name[fi]=Viittausfunktiot Name[fr]=Fonctions de référence Name[gl]=Funcións de referencia Name[hu]=Hivatkozás függvények Name[it]=Funzioni di riferimento Name[ja]=検索・参照関数 Name[kk]=Сілтеме функциялары Name[lv]=Atsaukšanās funkcijas Name[nb]=Referansefunksjoner Name[nds]=Referenzfunkschonen Name[nl]=Referentie-functies Name[pl]=Funkcje odniesienia Name[pt]=Funções de Referência Name[pt_BR]=Funções de referência Name[ru]=Таблица функций Name[sk]=Referenčné funkcie Name[sl]=Referenčne funkcije Name[sv]=Referensfunktioner Name[tr]=Referans Fonksiyonları Name[uk]=Еталонні функції Name[wa]=Fonccions di referince Name[x-test]=xxReference Functionsxx Name[zh_CN]=引用函数 Name[zh_TW]=參考函數 Comment=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[bs]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[ca]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[ca@valencia]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[cs]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[da]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[de]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[el]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[en_GB]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[eo]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[es]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[et]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[eu]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[fi]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[fr]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[ga]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP -Comment[gl]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, ROW, ROWS, VLOOKUP +Comment[gl]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, ROW, ROWS, VLOOKUP Comment[hu]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[it]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[ja]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[kk]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[nb]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[nds]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[nl]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, ROW, ROWS, VLOOKUP Comment[pl]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[pt]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[pt_BR]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[ru]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[sk]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[sl]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[sv]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[tr]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[ug]=ADDRESS، AREAS، CHOOSE، COLUMN، COLUMNS، HLOOKUP، INDEX، INDIRECT، LOOKUP، MULTIPLE.OPERATIONS ROW، ROWS، VLOOKUP Comment[uk]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[wa]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[x-test]=xxADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUPxx Comment[zh_CN]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Comment[zh_TW]=ADDRESS, AREAS, CHOOSE, COLUMN, COLUMNS, HLOOKUP, INDEX, INDIRECT, LOOKUP, MULTIPLE.OPERATIONS ROW, ROWS, VLOOKUP Icon=funct Type=Service X-KDE-Library=kspreadreferencemodule X-KDE-ServiceTypes=CalligraSheets/Plugin,KPluginInfo X-CalligraSheets-InterfaceVersion=0 X-KDE-PluginInfo-Author=The KSpread Team X-KDE-PluginInfo-Email=calligra-devel@kde.org X-KDE-PluginInfo-Name=ReferenceModule X-KDE-PluginInfo-Version=1.0 X-KDE-PluginInfo-Website=http://www.calligra.org/ X-KDE-PluginInfo-Category=FunctionModule X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-EnabledByDefault=true diff --git a/stage/templates/odf/kde_events.desktop b/stage/templates/odf/kde_events.desktop index 87b83de8ef4..d85f5849d68 100644 --- a/stage/templates/odf/kde_events.desktop +++ b/stage/templates/odf/kde_events.desktop @@ -1,76 +1,76 @@ [Desktop Entry] Icon=kde_events Name=KDE Events Name[bs]=KDE događaji Name[ca]=Esdeveniments del KDE Name[ca@valencia]=Esdeveniments del KDE Name[cs]=Události KDE Name[da]=KDE Events Name[de]=KDE-Termine Name[el]=KDE Events Name[en_GB]=KDE Events Name[es]=Eventos de KDE Name[et]=KDE sündmused Name[eu]=KDE gertaerak Name[fi]=KDE-tapahtumat Name[fr]=Événements KDE -Name[gl]=Acontecementos de KDE +Name[gl]=Eventos de KDE Name[hu]=KDE események Name[it]=Eventi di KDE Name[kk]=KDE оқиғалары Name[mr]=केडीई घटना Name[nb]=KDE-hendelser Name[nds]=KDE-Begeefnissen Name[nl]=KDE-gebeurtenissen Name[pl]=Zdarzenia KDE Name[pt]=Eventos do KDE Name[pt_BR]=Eventos do KDE Name[ru]=События KDE Name[sk]=KDE udalosti Name[sl]=Dogodki KDE Name[sv]=KDE-händelser Name[tr]=KDE Olaylar Name[ug]=KDE ھادىسىسى Name[uk]=Події KDE Name[wa]=Evenmints di KDE Name[x-test]=xxKDE Eventsxx Name[zh_TW]=KDE 事件 Comment=KDE Events Comment[bs]=KDE događaji Comment[ca]=Esdeveniments del KDE Comment[ca@valencia]=Esdeveniments del KDE Comment[cs]=Události KDE Comment[da]=KDE-arrangementer Comment[de]=KDE-Termine Comment[el]=KDE γεγονότα Comment[en_GB]=KDE Events Comment[es]=Eventos de KDE Comment[et]=KDE sündmused Comment[eu]=KDE gertaerak Comment[fi]=KDE-tapahtumat Comment[fr]=Événements KDE -Comment[gl]=Acontecementos de KDE. +Comment[gl]=Eventos de KDE. Comment[hu]=KDE események Comment[it]=Eventi di KDE Comment[kk]=KDE оқиғалары Comment[mr]=केडीई घटना Comment[nb]=KDE-hendelser Comment[nds]=KDE-Begeefnissen Comment[nl]=KDE-gebeurtenissen Comment[pl]=Zdarzenia KDE Comment[pt]=Eventos do KDE Comment[pt_BR]=Eventos do KDE Comment[ru]=События KDE Comment[sk]=KDE udalosti Comment[sl]=Dogodki KDE Comment[sv]=KDE-händelser Comment[tr]=KDE Olaylar Comment[ug]=KDE ھادىسىسى Comment[uk]=Події KDE Comment[wa]=Evenmints di KDE Comment[x-test]=xxKDE Eventsxx Comment[zh_TW]=KDE 事件 Type=Link URL=.source/kde_events.otp X-KDE-Hidden=false X-KDE-Thumbnail=.thumbnail/kde_events.png diff --git a/words/app/org.kde.calligrawords.appdata.xml b/words/app/org.kde.calligrawords.appdata.xml index fb8215a1137..a4eaa4fe09c 100644 --- a/words/app/org.kde.calligrawords.appdata.xml +++ b/words/app/org.kde.calligrawords.appdata.xml @@ -1,226 +1,235 @@ org.kde.calligrawords.desktop CC0-1.0 GPL-2.0+ Calligra Words Calligra Words Words del Calligra Words del Calligra Calligra Words Calligra Words Calligra Words Calligra Words Calligra Words Calligra Words Calligra Words Słowa Calligra Calligra Words Calligra Words Calligra Words Calligra Words + Calligra Kelime İşlemci Calligra Words xxCalligra Wordsxx Calligra Words Word Processor Program za obradu teksta Processador de textos Processador de textos Textový procesor Textverarbeitung Word Processor Procesador de texto Tekstitöötlus Tekstinkäsittely Traitement de texte Procesador de texto Processator de parolas Elaboratore di testi ワードプロセッサ Tekstbehandler Tekstverwerker Edytor tekstu Processador de Texto Processador de Texto Textový procesor Ordbehandlare + Kelime İşlemci Текстовий процесор xxWord Processorxx 文字处理器

Words is an intuitive word processor and desktop publisher application. With it, you can create informative and attractive documents with pleasure and ease.

Words je intuitivan program za obradu teksta i desktop aplikacija stonog izdavaštva. Uz to, možete kreirati informativne i atraktivne dokumente sa zadovoljstvom i lakoćom.

El Words és una aplicació intuïtiva de procés de textos i de publicació d'escriptori. Amb ella es poden crear documents informatius i atractius amb satisfacció i facilitat.

El Words és una aplicació intuïtiva de procés de textos i de publicació d'escriptori. Amb ella es poden crear documents informatius i atractius amb satisfacció i facilitat.

Words is an intuitive word processor and desktop publisher application. With it, you can create informative and attractive documents with pleasure and ease.

Words es un procesador de texto intuitivo y un editor para el escritorio. Con él, podrá crear documentos informativos y atractivos con gusto y facilidad.

Words on intuitiivselt kasutatav tekstitöötlus- ja küljendusrakendus. Selle abil saab luua lusti ja rõõmuga teabeküllaseid ja silmailu pakkuvaid dokumente.

Words on intuitiivinen tekstinkäsittely- ja taitto-ohjelma. Sen avulla voit luoda informatiivisia ja vaikuttavia tekstitiedostoja mukavasti ja helposti.

Words est un traitement de texte intuitif et une application bureautique de publication. Avec lui, vous pouvez facilement créer des documents informatifs et attractifs.

Words é un aplicativo intuitivo de procesamento de texto e publicación de escritorio. Con el pode crear documentos informativos e atractivos plácida e facilmente.

Words è un elaboratore di testi intuitivo e un'applicazione di pubblicazione per desktop. Con esso, puoi creare documenti informativi e accattivanti con soddisfazione e facilità.

Words はワードプロセッサおよびデスクトップ出版のためのアプリケーションです。直感的な操作で有益かつ魅力的な文書が簡単に作成できます

Words er en intuitiv tekstbehandler, som kan brrukes til skrivebordspublisering. Du kan lett lage informative og attraktive dokumenter med glede.

Words is een intuïtieve toepassing voor tekstverwerken en weergeven op het bureaublad. Hiermee kunt u informatieve en attractieve documenten met plezier en gemak maken.

Słowa jest intuicyjnym edytorem tekstu i biurkowym programem do publikowania. Dzięki niemu można tworzyć informacyjne i atrakcyjne dokumenty z łatwością użycia.

O Words é um processador de texto intuitivo e uma aplicação de publicações no ecrã. Com ele, pode criar documentos informativos e atraentes com prazer e facilidade.

Words é um processador de texto intuitivo e um aplicativo de publicação no desktop. Com ele, você pode criar documentos informativos e atraentes com prazer e facilidade.

Words je intuitívny textový procesor a aplikácia na desktopové publikovanie. Môžete pomocou neho vytvoriť informatívne a atraktívne dokumenty s radosťou a jednoduchosťou.

Words är en intuitiv ordbehandlare och skrivbordspubliceringsprogram. Det gör att du kan skapa informativa och attraktiva dokument med nöje och enkelhet.

+

Kelime İşlemci, sezgisel bir kelime işlemci ve masaüstü yayın uygulamasıdır. Bununla birlikte, zevkli ve kolaylıkla bilgilendirici ve çekici belgeler oluşturabilirsiniz.

Words — інтуїтивно зрозуміла у користування програма для редагування текстів та приготування матеріалів для друку. За її допомогою ви можете створювати інформативні та візуально красиві документи із задоволенням та без напруження.

xxWords is an intuitive word processor and desktop publisher application. With it, you can create informative and attractive documents with pleasure and ease.xx

Features:

Svojstva:

Característiques:

Característiques:

Vlastnosti:

Funktionen:

Features:

Características:

Omadused:

Ominaisuuksia:

Fonctionnalités :

Funcionalidades:

Characteristicas:

Funzionalità:

機能:

Egenskaper:

Mogelijkheden:

Cechy:

Funcionalidades:

Funcionalidades:

Funkcie:

Funktioner:

+

Özellikler:

Можливості:

xxFeatures:xx

功能:

  • Frame-based editing
  • Uređivanje bazirano na okvirima
  • Edició basada en marcs
  • Edició basada en marcs
  • Editor auf der Grundlage von Rahmen
  • Frame-based editing
  • Edición basada en marcos
  • Paneelipõhine redigeerimine
  • Kehyksiin perustuva muokkaus
  • Édition à base de cadres
  • Edición baseada en marcos.
  • Modifica basata su riquadri
  • フレームベースの編集
  • Ramme-basert redigering
  • Bewerken op basis van frames
  • Edytowanie oparte na ramkach
  • Edição baseada em molduras
  • Edição baseada em molduras
  • Rámcovo založené editovanie
  • Rambaserad redigering
  • +
  • Çerçeve tabanlı düzenleme
  • Редагування на основі блоків.
  • xxFrame-based editingxx
  • Allows embedding of Documents
  • Dopušta ugradnju dokumenata
  • Permet incrustar documents
  • Permet incrustar documents
  • Ermöglicht das Einbetten von Dokumenten
  • Allows embedding of Documents
  • Permite incrustar documentos
  • Dokumentide lõimimise toetamine
  • Tiedostojen upottamisen tuki
  • Permet les documents intégrés
  • Permite incrustar documentos.
  • Il permitte insertar documentos
  • Consente l'integrazione di documenti
  • 文書への埋め込みを許可
  • Tillater innebygde dokumenter
  • Staat inbedden van documenten toe
  • Umożliwia osadzanie dokumentów
  • Permite a incorporação de documentos
  • Permite a incorporação de documentos
  • Umožňuje vkladanie dokumentov
  • Tillåter att dokument inbäddas
  • +
  • Belgelerin gömülmesine izin verir
  • Вбудовування об’єктів до документів.
  • xxAllows embedding of Documentsxx
  • Customization of user interface
  • Prilagođenje korisničkog interfejsa
  • Personalització de la interfície d'usuari
  • Personalització de la interfície d'usuari
  • Anpassung der Benutzeroberfläche
  • Customisation of user interface
  • Personalización de la interfaz de usuario
  • Kohandatav kasutajaliides
  • Käyttöliittymä mukautettavissa
  • Personnalisation de l'interface
  • Personalización da interface.
  • Prsonalisation de le Interfacie de usator
  • Personalizzazion e dell'interfaccia utente
  • ユーザインターフェースのカスタマイズ
  • Tilpassing av brukerflaten
  • Aanpassen naar behoefte van het gebruikersinterface
  • Dostosowywanie układu sterowania
  • Personalização da interface do utilizador
  • Personalização da interface do usuário
  • Úprava používateľského rozhrania
  • Anpassning av användargränssnitt
  • +
  • Kullanıcı arayüzü özelleştirmesi
  • Налаштовуваність інтерфейсу користувача.
  • xxCustomization of user interfacexx
  • Includes all features expected from a modern word processor
  • Uključuje sve osobine koje se očekuju od modernog programa za obradu teksta
  • Inclou totes les funcionalitats esperades d'un processador de textos modern
  • Inclou totes les funcionalitats esperades d'un processador de textos modern
  • Enthält alle Funktionen einer modernen Textverarbeitung
  • Includes all features expected from a modern word processor
  • Incluye todas las características que se esperan de un procesador de texto moderno
  • Kõigi tänapäeva tekstitöötlusrakendusele omaste võimaluste pakkumine
  • Kaikki nykyaikaiselta tekstinkäsittelyohjelmalta odotetut ominaisuudet
  • Inclut toutes les fonctionnalités que l'on peut attendre d'un traitement de texte moderne
  • Inclúe todas as funcionalidades que pode esperar dun procesador de textos moderno.
  • Include tutte le funzionalità attese da un elaboratore di testi moderno
  • 現在のワードプロセッサに求められるすべての機能を含む
  • Har alle egenskaper forventet av en moderne tekstbehandler
  • Bevat alle functies die verwacht worden van een moderne tekstverwerker
  • Zawiera wszystkie cechy oczekiwane od nowoczesnego edytora tekstu
  • Inclui todas as funcionalidades esperadas de um processador de texto moderno
  • Inclui todas as funcionalidades esperadas de um processador de texto moderno
  • Obsahuje všetky funkcie očakávané od moderného textového procesora
  • Innehåller alla funktioner som förväntas av en modern ordbehandlare
  • +
  • Modern bir kelime işlemciden beklenen tüm özellikleri sağlar
  • Повний спектр можливостей сучасної програми для редагування тексту.
  • xxIncludes all features expected from a modern word processorxx
  • ODT (Open Document Text) support
  • ODT (Open Document Text) podrška
  • Admet ODT (Open Document Text)
  • Admet ODT (Open Document Text)
  • Unterstützung für ODT (Open Document Text)
  • ODT (Open Document Text) support
  • Admite el formato ODT («Open Document Text»)
  • ODT (OpenDocument Text) toetamine
  • ODT- eli OpenDocument-tekstitiedostojen tuki
  • Prise en charge du format ODT (Open Document Text)
  • Compatíbel co formato ODT (Open Document Text).
  • Supporto ODT (Open Document Text)
  • ODT (Open Document Text) サポート
  • Støtte for ODT (Open Document Text)
  • Ondersteuning van ODT (Open Document Text)
  • Obsługa ODT (Open Document Text)
  • Suporte para o ODT (Texto do Open Document)
  • Suporte para ODT (Texto Open Document)
  • Podpora ODT (Open Document Text)
  • Stöd för ODT (Open Document Text)
  • +
  • ODT (Açık Belge Metni) desteği
  • Підтримка стандартів ODT (Open Document Text).
  • xxODT (Open Document Text) supportxx
http://www.calligra.org/words/ https://bugs.kde.org/enter_bug.cgi?format=guided&product=calligrawords http://kde.org/images/screenshots/words.png KDE calligrawords