diff --git a/src/calligraplan_readonly.rc b/src/calligraplan_readonly.rc
index 855308b9..077fd291 100644
--- a/src/calligraplan_readonly.rc
+++ b/src/calligraplan_readonly.rc
@@ -1,25 +1,9 @@
diff --git a/src/libs/main/KoMainWindow.cpp b/src/libs/main/KoMainWindow.cpp
index c3e4175c..52814368 100644
--- a/src/libs/main/KoMainWindow.cpp
+++ b/src/libs/main/KoMainWindow.cpp
@@ -1,2162 +1,2163 @@
/* This file is part of the KDE project
Copyright (C) 1998, 1999 Torben Weis
Copyright (C) 2000-2006 David Faure
Copyright (C) 2007, 2009 Thomas zander
Copyright (C) 2010 Benjamin Port
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
// clazy:excludeall=qstring-arg
#include "KoMainWindow.h"
#include "KoView.h"
#include "KoDocument.h"
#include "KoFilterManager.h"
#include "KoDocumentInfo.h"
#include "KoDocumentInfoDlg.h"
#include "KoFileDialog.h"
#include "KoDockFactoryBase.h"
#include "KoDockWidgetTitleBar.h"
#include "KoPrintJob.h"
#include "KoDocumentEntry.h"
#include "KoPart.h"
#include
#include
#include "KoApplication.h"
#include
#include "KoResourcePaths.h"
#include "KoComponentData.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef HAVE_KACTIVITIES
#include
#endif
// // qt includes
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "MainDebug.h"
class KoMainWindowPrivate
{
public:
KoMainWindowPrivate(const QByteArray &_nativeMimeType, const KoComponentData &componentData_, KoMainWindow *w)
: componentData(componentData_)
{
nativeMimeType = _nativeMimeType;
parent = w;
rootDocument = 0;
rootPart = 0;
partToOpen = 0;
mainWindowGuiIsBuilt = false;
forQuit = false;
activePart = 0;
activeView = 0;
firstTime = true;
progress = 0;
showDocumentInfo = 0;
saveAction = 0;
saveActionAs = 0;
printAction = 0;
printActionPreview = 0;
sendFileAction = 0;
exportPdf = 0;
closeFile = 0;
reloadFile = 0;
importFile = 0;
exportFile = 0;
#if 0
encryptDocument = 0;
#ifndef NDEBUG
uncompressToDir = 0;
#endif
#endif
isImporting = false;
isExporting = false;
windowSizeDirty = false;
lastExportSpecialOutputFlag = 0;
readOnly = false;
dockWidgetMenu = 0;
deferredClosingEvent = 0;
#ifdef HAVE_KACTIVITIES
activityResource = 0;
#endif
m_helpMenu = 0;
// PartManger
m_activeWidget = 0;
m_activePart = 0;
noCleanup = false;
openingDocument = false;
printPreviewJob = nullptr;
}
~KoMainWindowPrivate() {
qDeleteAll(toolbarList);
}
void applyDefaultSettings(QPrinter &printer) {
QString title = rootDocument->documentInfo()->aboutInfo("title");
if (title.isEmpty()) {
title = rootDocument->url().fileName();
// strip off the native extension (I don't want foobar.kwd.ps when printing into a file)
QMimeType mime = QMimeDatabase().mimeTypeForName(rootDocument->outputMimeType());
if (mime.isValid()) {
const QString extension = mime.preferredSuffix();
if (title.endsWith(extension))
title.chop(extension.length());
}
}
if (title.isEmpty()) {
// #139905
title = i18n("%1 unsaved document (%2)", parent->componentData().componentDisplayName(),
QLocale().toString(QDate::currentDate(), QLocale::ShortFormat));
}
printer.setDocName(title);
}
QByteArray nativeMimeType;
KoMainWindow *parent;
KoDocument *rootDocument;
QList rootViews;
// PartManager
QPointer rootPart;
QPointer partToOpen;
QPointer activePart;
QPointer m_activePart;
QPointer m_registeredPart;
KoView *activeView;
QWidget *m_activeWidget;
QPointer progress;
QMutex progressMutex;
QList toolbarList;
bool mainWindowGuiIsBuilt;
bool forQuit;
bool firstTime;
bool windowSizeDirty;
bool readOnly;
QAction *showDocumentInfo;
QAction *saveAction;
QAction *saveActionAs;
QAction *printAction;
QAction *printActionPreview;
QAction *sendFileAction;
QAction *exportPdf;
QAction *closeFile;
QAction *reloadFile;
QAction *importFile;
QAction *exportFile;
#if 0
QAction *encryptDocument;
#ifndef NDEBUG
QAction *uncompressToDir;
#endif
#endif
KToggleAction *toggleDockers;
KToggleAction *toggleDockerTitleBars;
KRecentFilesAction *recent;
bool isImporting;
bool isExporting;
QUrl lastExportUrl;
QByteArray lastExportedFormat;
int lastExportSpecialOutputFlag;
QMap dockWidgetsMap;
KActionMenu *dockWidgetMenu;
QMap dockWidgetVisibilityMap;
QList dockWidgets;
QByteArray m_dockerStateBeforeHiding;
QCloseEvent *deferredClosingEvent;
#ifdef HAVE_KACTIVITIES
KActivities::ResourceInstance *activityResource;
#endif
KoComponentData componentData;
KHelpMenu *m_helpMenu;
bool noCleanup;
bool openingDocument;
KoPrintJob *printPreviewJob;
};
KoMainWindow::KoMainWindow(const QByteArray &nativeMimeType, const KoComponentData &componentData)
: KXmlGuiWindow()
, d(new KoMainWindowPrivate(nativeMimeType, componentData, this))
{
#ifdef Q_OS_MAC
setUnifiedTitleAndToolBarOnMac(true);
#endif
setStandardToolBarMenuEnabled(true);
setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North);
connect(this, &KoMainWindow::restoringDone, this, &KoMainWindow::forceDockTabFonts);
// PartManager
// End
QString doc;
const QStringList allFiles = KoResourcePaths::findAllResources("data", "calligraplan/calligraplan_shell.rc");
setXMLFile(findMostRecentXMLFile(allFiles, doc));
setLocalXMLFile(KoResourcePaths::locateLocal("data", "calligraplan/calligraplan_shell.rc"));
actionCollection()->addAction(KStandardAction::New, "file_new", this, SLOT(slotFileNew()));
actionCollection()->addAction(KStandardAction::Open, "file_open", this, SLOT(slotFileOpen()));
d->recent = KStandardAction::openRecent(this, SLOT(slotFileOpenRecent(QUrl)), actionCollection());
connect(d->recent, &KRecentFilesAction::recentListCleared, this, &KoMainWindow::saveRecentFiles);
d->saveAction = actionCollection()->addAction(KStandardAction::Save, "file_save", this, SLOT(slotFileSave()));
d->saveActionAs = actionCollection()->addAction(KStandardAction::SaveAs, "file_save_as", this, SLOT(slotFileSaveAs()));
d->printAction = actionCollection()->addAction(KStandardAction::Print, "file_print", this, SLOT(slotFilePrint()));
d->printActionPreview = actionCollection()->addAction(KStandardAction::PrintPreview, "file_print_preview", this, SLOT(slotFilePrintPreview()));
d->exportPdf = new QAction(i18n("Print to PDF..."), this);
d->exportPdf->setIcon(koIcon("application-pdf"));
actionCollection()->addAction("file_export_pdf", d->exportPdf);
connect(d->exportPdf, &QAction::triggered, this, static_cast(&KoMainWindow::exportToPdf));
d->sendFileAction = actionCollection()->addAction(KStandardAction::Mail, "file_send_file", this, SLOT(slotEmailFile()));
d->closeFile = actionCollection()->addAction(KStandardAction::Close, "file_close", this, SLOT(slotFileClose()));
actionCollection()->addAction(KStandardAction::Quit, "file_quit", this, SLOT(slotFileQuit()));
d->reloadFile = new QAction(i18n("Reload"), this);
actionCollection()->addAction("file_reload_file", d->reloadFile);
connect(d->reloadFile, &QAction::triggered, this, &KoMainWindow::slotReloadFile);
d->importFile = new QAction(koIcon("document-import"), i18n("Import..."), this);
actionCollection()->addAction("file_import_file", d->importFile);
connect(d->importFile, &QAction::triggered, this, &KoMainWindow::slotImportFile);
d->exportFile = new QAction(koIcon("document-export"), i18n("E&xport..."), this);
actionCollection()->addAction("file_export_file", d->exportFile);
connect(d->exportFile, &QAction::triggered, this, &KoMainWindow::slotExportFile);
#if 0
// encryption not supported
d->encryptDocument = new QAction(i18n("En&crypt Document"), this);
actionCollection()->addAction("file_encrypt_doc", d->encryptDocument);
connect(d->encryptDocument, SIGNAL(triggered(bool)), this, SLOT(slotEncryptDocument()));
#ifndef NDEBUG
d->uncompressToDir = new QAction(i18n("&Uncompress to Directory"), this);
actionCollection()->addAction("file_uncompress_doc", d->uncompressToDir);
connect(d->uncompressToDir, SIGNAL(triggered(bool)), this, SLOT(slotUncompressToDir()));
#endif
#endif
QAction *actionNewView = new QAction(koIcon("window-new"), i18n("&New View"), this);
actionCollection()->addAction("view_newview", actionNewView);
connect(actionNewView, &QAction::triggered, this, &KoMainWindow::newView);
/* The following entry opens the document information dialog. Since the action is named so it
intends to show data this entry should not have a trailing ellipses (...). */
d->showDocumentInfo = new QAction(koIcon("document-properties"), i18n("Document Information"), this);
actionCollection()->addAction("file_documentinfo", d->showDocumentInfo);
connect(d->showDocumentInfo, &QAction::triggered, this, &KoMainWindow::slotDocumentInfo);
KStandardAction::keyBindings(this, SLOT(slotConfigureKeys()), actionCollection());
KStandardAction::configureToolbars(this, SLOT(slotConfigureToolbars()), actionCollection());
d->showDocumentInfo->setEnabled(false);
d->saveActionAs->setEnabled(false);
d->reloadFile->setEnabled(false);
d->importFile->setEnabled(true); // always enabled like File --> Open
d->exportFile->setEnabled(false);
d->saveAction->setEnabled(false);
d->printAction->setEnabled(false);
d->printActionPreview->setEnabled(false);
d->sendFileAction->setEnabled(false);
d->exportPdf->setEnabled(false);
d->closeFile->setEnabled(false);
#if 0
d->encryptDocument->setEnabled(false);
#ifndef NDEBUG
d->uncompressToDir->setEnabled(false);
#endif
#endif
KToggleAction *fullscreenAction = new KToggleAction(koIcon("view-fullscreen"), i18n("Full Screen Mode"), this);
actionCollection()->addAction("view_fullscreen", fullscreenAction);
actionCollection()->setDefaultShortcut(fullscreenAction, QKeySequence::FullScreen);
connect(fullscreenAction, &QAction::toggled, this, &KoMainWindow::viewFullscreen);
d->toggleDockers = new KToggleAction(i18n("Show Dockers"), this);
d->toggleDockers->setChecked(true);
actionCollection()->addAction("view_toggledockers", d->toggleDockers);
connect(d->toggleDockers, &QAction::toggled, this, &KoMainWindow::toggleDockersVisibility);
d->toggleDockerTitleBars = new KToggleAction(i18nc("@action:inmenu", "Show Docker Titlebars"), this);
KConfigGroup configGroupInterface = KSharedConfig::openConfig()->group("Interface");
d->toggleDockerTitleBars->setChecked(configGroupInterface.readEntry("ShowDockerTitleBars", true));
d->toggleDockerTitleBars->setVisible(false);
actionCollection()->addAction("view_toggledockertitlebars", d->toggleDockerTitleBars);
connect(d->toggleDockerTitleBars, &QAction::toggled, this, &KoMainWindow::showDockerTitleBars);
d->dockWidgetMenu = new KActionMenu(i18n("Dockers"), this);
actionCollection()->addAction("settings_dockers_menu", d->dockWidgetMenu);
d->dockWidgetMenu->setVisible(false);
d->dockWidgetMenu->setDelayed(false);
// Load list of recent files
KSharedConfigPtr configPtr = componentData.config();
d->recent->loadEntries(configPtr->group("RecentFiles"));
createMainwindowGUI();
d->mainWindowGuiIsBuilt = true;
// we first figure out some good default size and restore the x,y position. See bug 285804Z.
KConfigGroup cfg( KSharedConfig::openConfig(), "MainWindow");
QByteArray geom = QByteArray::fromBase64(cfg.readEntry("ko_geometry", QByteArray()));
if (!restoreGeometry(geom)) {
const int scnum = QApplication::desktop()->screenNumber(parentWidget());
QRect desk = QApplication::desktop()->availableGeometry(scnum);
// if the desktop is virtual then use virtual screen size
if (QApplication::desktop()->isVirtualDesktop()) {
desk = QApplication::desktop()->availableGeometry(QApplication::desktop()->screen());
desk = QApplication::desktop()->availableGeometry(QApplication::desktop()->screen(scnum));
}
quint32 x = desk.x();
quint32 y = desk.y();
quint32 w = 0;
quint32 h = 0;
// Default size -- maximize on small screens, something useful on big screens
const int deskWidth = desk.width();
if (deskWidth > 1024) {
// a nice width, and slightly less than total available
// height to componensate for the window decs
w = (deskWidth / 3) * 2;
h = (desk.height() / 3) * 2;
}
else {
w = desk.width();
h = desk.height();
}
x += (desk.width() - w) / 2;
y += (desk.height() - h) / 2;
move(x,y);
setGeometry(geometry().x(), geometry().y(), w, h);
}
restoreState(QByteArray::fromBase64(cfg.readEntry("ko_windowstate", QByteArray())));
}
void KoMainWindow::setNoCleanup(bool noCleanup)
{
d->noCleanup = noCleanup;
}
KoMainWindow::~KoMainWindow()
{
KConfigGroup cfg( KSharedConfig::openConfig(), "MainWindow");
cfg.writeEntry("ko_geometry", saveGeometry().toBase64());
cfg.writeEntry("ko_windowstate", saveState().toBase64());
// The doc and view might still exist (this is the case when closing the window)
if (d->rootPart)
d->rootPart->removeMainWindow(this);
if (d->partToOpen) {
d->partToOpen->removeMainWindow(this);
delete d->partToOpen;
}
// safety first ;)
setActivePart(0, 0);
if (d->rootViews.indexOf(d->activeView) == -1) {
delete d->activeView;
d->activeView = 0;
}
while (!d->rootViews.isEmpty()) {
delete d->rootViews.takeFirst();
}
if(d->noCleanup)
return;
// We have to check if this was a root document.
// This has to be checked from queryClose, too :)
if (d->rootPart && d->rootPart->viewCount() == 0) {
//debugMain <<"Destructor. No more views, deleting old doc" << d->rootDocument;
delete d->rootDocument; // FIXME: Why delete here and not only in KoPart?
}
delete d;
}
void KoMainWindow::setRootDocument(KoDocument *doc, KoPart *part, bool deletePrevious)
{
if (d->rootDocument == doc)
return;
if (d->partToOpen && d->partToOpen->document() != doc) {
d->partToOpen->removeMainWindow(this);
if (deletePrevious) delete d->partToOpen;
}
d->partToOpen = 0;
//debugMain <<"KoMainWindow::setRootDocument this =" << this <<" doc =" << doc;
QList oldRootViews = d->rootViews;
d->rootViews.clear();
KoDocument *oldRootDoc = d->rootDocument;
KoPart *oldRootPart = d->rootPart;
if (oldRootDoc) {
oldRootDoc->disconnect(this);
oldRootPart->removeMainWindow(this);
// Hide all dockwidgets and remember their old state
d->dockWidgetVisibilityMap.clear();
foreach(QDockWidget* dockWidget, d->dockWidgetsMap) {
d->dockWidgetVisibilityMap.insert(dockWidget, dockWidget->isVisible());
dockWidget->setVisible(false);
}
d->toggleDockerTitleBars->setVisible(false);
d->dockWidgetMenu->setVisible(false);
}
d->rootDocument = doc;
// XXX remove this after the splitting
if (!part && doc) {
d->rootPart = doc->documentPart();
}
else {
d->rootPart = part;
}
if (doc) {
d->toggleDockerTitleBars->setVisible(true);
d->dockWidgetMenu->setVisible(true);
d->m_registeredPart = d->rootPart.data();
KoView *view = d->rootPart->createView(doc, this);
setCentralWidget(view);
d->rootViews.append(view);
view->show();
view->setFocus();
// The addMainWindow has been done already if using openUrl
if (!d->rootPart->mainWindows().contains(this)) {
d->rootPart->addMainWindow(this);
}
}
bool enable = d->rootDocument != 0 ? true : false;
d->showDocumentInfo->setEnabled(enable);
d->saveAction->setEnabled(enable);
d->saveActionAs->setEnabled(enable);
d->importFile->setEnabled(enable);
d->exportFile->setEnabled(enable);
#if 0
d->encryptDocument->setEnabled(enable);
#ifndef NDEBUG
d->uncompressToDir->setEnabled(enable);
#endif
#endif
d->printAction->setEnabled(enable);
d->printActionPreview->setEnabled(enable);
d->sendFileAction->setEnabled(enable);
d->exportPdf->setEnabled(enable);
d->closeFile->setEnabled(enable);
updateCaption();
setActivePart(d->rootPart, doc ? d->rootViews.first() : 0);
emit restoringDone();
while(!oldRootViews.isEmpty()) {
delete oldRootViews.takeFirst();
}
if (oldRootPart && oldRootPart->viewCount() == 0) {
//debugMain <<"No more views, deleting old doc" << oldRootDoc;
oldRootDoc->clearUndoHistory();
if(deletePrevious)
delete oldRootDoc;
}
if (doc && !d->dockWidgetVisibilityMap.isEmpty()) {
foreach(QDockWidget* dockWidget, d->dockWidgetsMap) {
dockWidget->setVisible(d->dockWidgetVisibilityMap.value(dockWidget));
}
}
if (!d->rootDocument) {
statusBar()->setVisible(false);
}
else {
#ifdef Q_OS_MAC
statusBar()->setMaximumHeight(28);
#endif
connect(d->rootDocument, &KoDocument::titleModified, this, &KoMainWindow::slotDocumentTitleModified);
}
}
void KoMainWindow::updateReloadFileAction(KoDocument *doc)
{
d->reloadFile->setEnabled(doc && !doc->url().isEmpty());
}
void KoMainWindow::setReadWrite(bool readwrite)
{
d->saveAction->setEnabled(readwrite);
d->importFile->setEnabled(readwrite);
d->readOnly = !readwrite;
updateCaption();
}
void KoMainWindow::addRecentURL(const QString &projectName, const QUrl &url)
{
debugMain << "url=" << url.toDisplayString();
// Add entry to recent documents list
// (call coming from KoDocument because it must work with cmd line, template dlg, file/open, etc.)
if (!url.isEmpty()) {
bool ok = true;
if (url.isLocalFile()) {
QString path = url.adjusted(QUrl::StripTrailingSlash).toLocalFile();
const QStringList tmpDirs = QStandardPaths::standardLocations(QStandardPaths::TempLocation);
foreach (const QString &tmpDir, tmpDirs) {
if (path.startsWith(tmpDir)) {
ok = false; // it's in the tmp resource
break;
}
}
if (ok) {
KRecentDocument::add(QUrl::fromLocalFile(path));
KRecentDirs::add(":OpenDialog", QFileInfo(path).dir().canonicalPath());
}
} else {
KRecentDocument::add(url.adjusted(QUrl::StripTrailingSlash));
}
if (ok) {
d->recent->addUrl(url, projectName);
}
saveRecentFiles();
#ifdef HAVE_KACTIVITIES
if (!d->activityResource) {
d->activityResource = new KActivities::ResourceInstance(winId(), this);
}
d->activityResource->setUri(url);
#endif
}
}
void KoMainWindow::saveRecentFiles()
{
// Save list of recent files
KSharedConfigPtr config = componentData().config();
debugMain << this << " Saving recent files list into config. componentData()=" << componentData().componentName();
d->recent->saveEntries(config->group("RecentFiles"));
config->sync();
// Tell all windows to reload their list, after saving
// Doesn't work multi-process, but it's a start
foreach(KMainWindow* window, KMainWindow::memberList())
static_cast(window)->reloadRecentFileList();
}
void KoMainWindow::reloadRecentFileList()
{
KSharedConfigPtr config = componentData().config();
d->recent->loadEntries(config->group("RecentFiles"));
}
KoPart* KoMainWindow::createPart() const
{
KoDocumentEntry entry = KoDocumentEntry::queryByMimeType(d->nativeMimeType);
QString errorMsg;
KoPart *part = entry.createKoPart(&errorMsg);
if (!part || !errorMsg.isEmpty()) {
return 0;
}
return part;
}
void KoMainWindow::updateCaption()
{
debugMain;
if (!d->rootDocument) {
updateCaption(QString(), false);
}
else {
QString caption( d->rootDocument->caption() );
if (d->readOnly) {
caption += ' ' + i18n("(write protected)");
}
updateCaption(caption, d->rootDocument->isModified());
if (!rootDocument()->url().fileName().isEmpty())
d->saveAction->setToolTip(i18n("Save as %1", d->rootDocument->url().fileName()));
else
d->saveAction->setToolTip(i18n("Save"));
}
}
void KoMainWindow::updateCaption(const QString & caption, bool mod)
{
debugMain << caption << "," << mod;
#ifdef PLAN_ALPHA
setCaption(QString("ALPHA %1: %2").arg(PLAN_ALPHA).arg(caption), mod);
return;
#endif
#ifdef PLAN_BETA
setCaption(QString("BETA %1: %2").arg(PLAN_BETA).arg(caption), mod);
return;
#endif
#ifdef PLAN_RC
setCaption(QString("RELEASE CANDIDATE %1: %2").arg(PLAN_RC).arg(caption), mod);
return;
#endif
setCaption(caption, mod);
}
KoDocument *KoMainWindow::rootDocument() const
{
return d->rootDocument;
}
KoView *KoMainWindow::rootView() const
{
if (d->rootViews.indexOf(d->activeView) != -1)
return d->activeView;
return d->rootViews.first();
}
bool KoMainWindow::openDocument(const QUrl &url)
{
if (!KIO::NetAccess::exists(url, KIO::NetAccess::SourceSide, 0)) {
KMessageBox::error(0, i18n("The file %1 does not exist.", url.url()));
d->recent->removeUrl(url); //remove the file from the recent-opened-file-list
saveRecentFiles();
return false;
}
return openDocumentInternal(url);
}
bool KoMainWindow::openDocument(KoPart *newPart, const QUrl &url)
{
if (!newPart) {
return openDocument(url);
}
// the part always has a document; the document doesn't know about the part.
KoDocument *newdoc = newPart->document();
if (!KIO::NetAccess::exists(url, KIO::NetAccess::SourceSide, 0)) {
newdoc->initEmpty(); //create an empty document
setRootDocument(newdoc, newPart);
newdoc->setUrl(url);
QMimeType mime = QMimeDatabase().mimeTypeForUrl(url);
QString mimetype = (!mime.isValid() || mime.isDefault()) ? newdoc->nativeFormatMimeType() : mime.name();
newdoc->setMimeTypeAfterLoading(mimetype);
updateCaption();
return true;
}
return openDocumentInternal(url, newPart, newdoc);
}
bool KoMainWindow::openDocumentInternal(const QUrl &url, KoPart *newpart, KoDocument *newdoc)
{
debugMain << newpart << newdoc << url.url();
if (!newpart)
newpart = createPart();
if (!newpart)
return false;
if (!newdoc)
newdoc = newpart->document();
+ KFileItem file(url, newdoc->mimeType(), KFileItem::Unknown);
+ if (!file.isWritable()) {
+ newdoc->setReadWrite(false);
+ }
+
d->firstTime = true;
connect(newdoc, &KoDocument::sigProgress, this, &KoMainWindow::slotProgress);
connect(newdoc, &KoDocument::completed, this, &KoMainWindow::slotLoadCompleted);
connect(newdoc, &KoDocument::canceled, this, &KoMainWindow::slotLoadCanceled);
d->openingDocument = true;
newpart->addMainWindow(this); // used by openUrl
bool openRet = (!isImporting()) ? newdoc->openUrl(url) : newdoc->importDocument(url);
if (!openRet) {
newpart->removeMainWindow(this);
delete newdoc;
delete newpart;
d->openingDocument = false;
return false;
}
updateReloadFileAction(newdoc);
- KFileItem file(url, newdoc->mimeType(), KFileItem::Unknown);
- if (!file.isWritable()) {
- setReadWrite(false);
- }
return true;
}
// Separate from openDocument to handle async loading (remote URLs)
void KoMainWindow::slotLoadCompleted()
{
debugMain;
KoDocument *newdoc = qobject_cast(sender());
KoPart *newpart = newdoc->documentPart();
if (d->rootDocument && d->rootDocument->isEmpty()) {
// Replace current empty document
setRootDocument(newdoc);
} else if (d->rootDocument && !d->rootDocument->isEmpty()) {
// Open in a new main window
// (Note : could create the main window first and the doc next for this
// particular case, that would give a better user feedback...)
KoMainWindow *s = newpart->createMainWindow();
s->show();
newpart->removeMainWindow(this);
s->setRootDocument(newdoc, newpart);
} else {
// We had no document, set the new one
setRootDocument(newdoc);
}
slotProgress(-1);
disconnect(newdoc, &KoDocument::sigProgress, this, &KoMainWindow::slotProgress);
disconnect(newdoc, &KoDocument::completed, this, &KoMainWindow::slotLoadCompleted);
disconnect(newdoc, &KoDocument::canceled, this, &KoMainWindow::slotLoadCanceled);
d->openingDocument = false;
emit loadCompleted();
}
void KoMainWindow::slotLoadCanceled(const QString & errMsg)
{
debugMain;
if (!errMsg.isEmpty()) // empty when canceled by user
KMessageBox::error(this, errMsg);
// ... can't delete the document, it's the one who emitted the signal...
KoDocument* doc = qobject_cast(sender());
Q_ASSERT(doc);
disconnect(doc, &KoDocument::sigProgress, this, &KoMainWindow::slotProgress);
disconnect(doc, &KoDocument::completed, this, &KoMainWindow::slotLoadCompleted);
disconnect(doc, &KoDocument::canceled, this, &KoMainWindow::slotLoadCanceled);
d->openingDocument = false;
emit loadCanceled();
}
void KoMainWindow::slotSaveCanceled(const QString &errMsg)
{
debugMain;
if (!errMsg.isEmpty()) // empty when canceled by user
KMessageBox::error(this, errMsg);
slotSaveCompleted();
}
void KoMainWindow::slotSaveCompleted()
{
debugMain;
KoDocument* doc = qobject_cast(sender());
Q_ASSERT(doc);
disconnect(doc, &KoDocument::sigProgress, this, &KoMainWindow::slotProgress);
disconnect(doc, &KoDocument::completed, this, &KoMainWindow::slotSaveCompleted);
disconnect(doc, &KoDocument::canceled, this, &KoMainWindow::slotSaveCanceled);
if (d->deferredClosingEvent) {
KXmlGuiWindow::closeEvent(d->deferredClosingEvent);
}
}
// returns true if we should save, false otherwise.
bool KoMainWindow::exportConfirmation(const QByteArray &outputFormat)
{
KConfigGroup group = KSharedConfig::openConfig()->group(d->rootPart->componentData().componentName());
if (!group.readEntry("WantExportConfirmation", true)) {
return true;
}
QMimeType mime = QMimeDatabase().mimeTypeForName(outputFormat);
QString comment = mime.isValid() ? mime.comment() : i18n("%1 (unknown file type)", QString::fromLatin1(outputFormat));
// Warn the user
int ret;
if (!isExporting()) { // File --> Save
ret = KMessageBox::warningContinueCancel
(
this,
i18n("Saving as a %1 may result in some loss of formatting."
"
Do you still want to save in this format?
",
QString("%1").arg(comment)), // in case we want to remove the bold later
i18n("Confirm Save"),
KStandardGuiItem::save(),
KStandardGuiItem::cancel(),
"NonNativeSaveConfirmation"
);
} else { // File --> Export
ret = KMessageBox::warningContinueCancel
(
this,
i18n("Exporting as a %1 may result in some loss of formatting."
"
Do you still want to export to this format?
",
QString("%1").arg(comment)), // in case we want to remove the bold later
i18n("Confirm Export"),
KGuiItem(i18n("Export")),
KStandardGuiItem::cancel(),
"NonNativeExportConfirmation" // different to the one used for Save (above)
);
}
return (ret == KMessageBox::Continue);
}
bool KoMainWindow::saveDocument(bool saveas, bool silent, int specialOutputFlag)
{
if (!d->rootDocument || !d->rootPart) {
return true;
}
bool reset_url;
if (d->rootDocument->url().isEmpty()) {
emit saveDialogShown();
reset_url = true;
saveas = true;
} else {
reset_url = false;
}
connect(d->rootDocument, &KoDocument::sigProgress, this, &KoMainWindow::slotProgress);
connect(d->rootDocument, &KoDocument::completed, this, &KoMainWindow::slotSaveCompleted);
connect(d->rootDocument, &KoDocument::canceled, this, &KoMainWindow::slotSaveCanceled);
QUrl oldURL = d->rootDocument->url();
QString oldFile = d->rootDocument->localFilePath();
QByteArray _native_format = d->rootDocument->nativeFormatMimeType();
QByteArray oldOutputFormat = d->rootDocument->outputMimeType();
int oldSpecialOutputFlag = d->rootDocument->specialOutputFlag();
QUrl suggestedURL = d->rootDocument->url();
QStringList mimeFilter;
QMimeType mime = QMimeDatabase().mimeTypeForName(_native_format);
if (!mime.isValid())
// QT5TODO: find if there is no better way to get an object for the default type
mime = QMimeDatabase().mimeTypeForName(QStringLiteral("application/octet-stream"));
if (specialOutputFlag)
mimeFilter = mime.globPatterns();
else
mimeFilter = KoFilterManager::mimeFilter(_native_format,
KoFilterManager::Export,
d->rootDocument->extraNativeMimeTypes());
if (oldOutputFormat.isEmpty() && !d->rootDocument->url().isEmpty()) {
// Not been saved yet, but there is a default url so open dialog with this url
if (suggestedURL.path() == suggestedURL.fileName()) {
// only a filename has been given, so add the default dir
KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs");
QString path = group.readEntry("SaveDocument");
path += '/' + suggestedURL.fileName();
suggestedURL.setPath(path);
suggestedURL.setScheme("file");
}
saveas = true;
debugMain << "newly created doc, default file name:" << d->rootDocument->url() << "save to:" << suggestedURL;
} else if (!mimeFilter.contains(oldOutputFormat) && !isExporting()) {
debugMain << "no export filter for" << oldOutputFormat;
// --- don't setOutputMimeType in case the user cancels the Save As
// dialog and then tries to just plain Save ---
// suggest a different filename extension (yes, we fortunately don't all live in a world of magic :))
QString suggestedFilename = suggestedURL.fileName();
if (!suggestedFilename.isEmpty()) { // ".kra" looks strange for a name
int c = suggestedFilename.lastIndexOf('.');
const QString ext = mime.preferredSuffix();
if (!ext.isEmpty()) {
if (c < 0)
suggestedFilename += ext;
else
suggestedFilename = suggestedFilename.left(c) + ext;
} else { // current filename extension wrong anyway
if (c > 0) {
// this assumes that a . signifies an extension, not just a .
suggestedFilename = suggestedFilename.left(c);
}
}
suggestedURL = suggestedURL.adjusted(QUrl::RemoveFilename);
suggestedURL.setPath(suggestedURL.path() + suggestedFilename);
}
// force the user to choose outputMimeType
saveas = true;
}
bool ret = false;
if (d->rootDocument->url().isEmpty() || saveas) {
// if you're just File/Save As'ing to change filter options you
// don't want to be reminded about overwriting files etc.
bool justChangingFilterOptions = false;
KoFileDialog dialog(this, KoFileDialog::SaveFile, "SaveDocument");
dialog.setCaption(i18n("untitled"));
dialog.setDefaultDir((isExporting() && !d->lastExportUrl.isEmpty()) ?
d->lastExportUrl.toLocalFile() : suggestedURL.toLocalFile());
dialog.setMimeTypeFilters(mimeFilter);
QUrl newURL = QUrl::fromUserInput(dialog.filename());
if (newURL.isLocalFile()) {
QString fn = newURL.toLocalFile();
if (QFileInfo(fn).completeSuffix().isEmpty()) {
QMimeType mime = QMimeDatabase().mimeTypeForName(_native_format);
fn.append(mime.preferredSuffix());
newURL = QUrl::fromLocalFile(fn);
}
}
QByteArray outputFormat = _native_format;
if (!specialOutputFlag) {
QMimeType mime = QMimeDatabase().mimeTypeForUrl(newURL);
outputFormat = mime.name().toLatin1();
}
if (!isExporting())
justChangingFilterOptions = (newURL == d->rootDocument->url()) &&
(outputFormat == d->rootDocument->mimeType()) &&
(specialOutputFlag == oldSpecialOutputFlag);
else
justChangingFilterOptions = (newURL == d->lastExportUrl) &&
(outputFormat == d->lastExportedFormat) &&
(specialOutputFlag == d->lastExportSpecialOutputFlag);
bool bOk = true;
if (newURL.isEmpty()) {
bOk = false;
}
// adjust URL before doing checks on whether the file exists.
if (specialOutputFlag) {
QString fileName = newURL.fileName();
if ( specialOutputFlag== KoDocument::SaveAsDirectoryStore) {
// Do nothing
}
#if 0
else if (specialOutputFlag == KoDocument::SaveEncrypted) {
int dot = fileName.lastIndexOf('.');
QString ext = mime.preferredSuffix();
if (!ext.isEmpty()) {
if (dot < 0) fileName += ext;
else fileName = fileName.left(dot) + ext;
} else { // current filename extension wrong anyway
if (dot > 0) fileName = fileName.left(dot);
}
newURL = newURL.adjusted(QUrl::RemoveFilename);
newURL.setPath(newURL.path() + fileName);
}
#endif
}
if (bOk) {
bool wantToSave = true;
// don't change this line unless you know what you're doing :)
if (!justChangingFilterOptions || d->rootDocument->confirmNonNativeSave(isExporting())) {
if (!d->rootDocument->isNativeFormat(outputFormat))
wantToSave = exportConfirmation(outputFormat);
}
if (wantToSave) {
//
// Note:
// If the user is stupid enough to Export to the current URL,
// we do _not_ change this operation into a Save As. Reasons
// follow:
//
// 1. A check like "isExporting() && oldURL == newURL"
// doesn't _always_ work on case-insensitive filesystems
// and inconsistent behaviour is bad.
// 2. It is probably not a good idea to change d->rootDocument->mimeType
// and friends because the next time the user File/Save's,
// (not Save As) they won't be expecting that they are
// using their File/Export settings
//
// As a bad side-effect of this, the modified flag will not
// be updated and it is possible that what is currently on
// their screen is not what is stored on disk (through loss
// of formatting). But if you are dumb enough to change
// mimetype but not the filename, then arguably, _you_ are
// the "bug" :)
//
// - Clarence
//
d->rootDocument->setOutputMimeType(outputFormat, specialOutputFlag);
if (!isExporting()) { // Save As
ret = d->rootDocument->saveAs(newURL);
if (ret) {
debugMain << "Successful Save As!";
addRecentURL(d->rootDocument->projectName(), newURL);
setReadWrite(true);
} else {
debugMain << "Failed Save As!";
d->rootDocument->setUrl(oldURL);
d->rootDocument->setLocalFilePath(oldFile);
d->rootDocument->setOutputMimeType(oldOutputFormat, oldSpecialOutputFlag);
}
} else { // Export
ret = d->rootDocument->exportDocument(newURL);
if (ret) {
// a few file dialog convenience things
d->lastExportUrl = newURL;
d->lastExportedFormat = outputFormat;
d->lastExportSpecialOutputFlag = specialOutputFlag;
}
// always restore output format
d->rootDocument->setOutputMimeType(oldOutputFormat, oldSpecialOutputFlag);
}
if (silent) // don't let the document change the window caption
d->rootDocument->setTitleModified();
} // if (wantToSave) {
else
ret = false;
} // if (bOk) {
else
ret = false;
} else { // saving
bool needConfirm = d->rootDocument->confirmNonNativeSave(false) && !d->rootDocument->isNativeFormat(oldOutputFormat);
if (!needConfirm ||
(needConfirm && exportConfirmation(oldOutputFormat /* not so old :) */))
) {
// be sure d->rootDocument has the correct outputMimeType!
if (isExporting() || d->rootDocument->isModified() || d->rootDocument->alwaysAllowSaving()) {
ret = d->rootDocument->save();
}
if (!ret) {
debugMain << "Failed Save!";
d->rootDocument->setUrl(oldURL);
d->rootDocument->setLocalFilePath(oldFile);
}
} else
ret = false;
}
if (!ret && reset_url)
d->rootDocument->resetURL(); //clean the suggested filename as the save dialog was rejected
updateReloadFileAction(d->rootDocument);
updateCaption();
return ret;
}
void KoMainWindow::closeEvent(QCloseEvent *e)
{
// If we are in the process of opening a new document, rootDocument() may not have been set yet,
// so we must prevent closing to avoid crash.
if(d->openingDocument || (rootDocument() && rootDocument()->isLoading())) {
e->setAccepted(false);
return;
}
if (queryClose()) {
d->deferredClosingEvent = e;
if (!d->m_dockerStateBeforeHiding.isEmpty()) {
restoreState(d->m_dockerStateBeforeHiding);
}
statusBar()->setVisible(true);
menuBar()->setVisible(true);
saveWindowSettings();
if(d->noCleanup)
return;
setRootDocument(0);
if (!d->dockWidgetVisibilityMap.isEmpty()) { // re-enable dockers for persistency
foreach(QDockWidget* dockWidget, d->dockWidgetsMap)
dockWidget->setVisible(d->dockWidgetVisibilityMap.value(dockWidget));
}
} else {
e->setAccepted(false);
}
}
void KoMainWindow::saveWindowSettings()
{
KSharedConfigPtr config = componentData().config();
if (d->windowSizeDirty ) {
// Save window size into the config file of our componentData
// TODO: check if this is ever read again, seems lost over the years
debugMain;
KConfigGroup mainWindowConfigGroup = config->group("MainWindow");
KWindowConfig::saveWindowSize(windowHandle(), mainWindowConfigGroup);
config->sync();
d->windowSizeDirty = false;
}
if ( rootDocument() && d->rootPart) {
// Save toolbar position into the config file of the app, under the doc's component name
KConfigGroup group = KSharedConfig::openConfig()->group(d->rootPart->componentData().componentName());
//debugMain <<"KoMainWindow::closeEvent -> saveMainWindowSettings rootdoc's componentData=" << d->rootPart->componentData().componentName();
saveMainWindowSettings(group);
// Save collapsable state of dock widgets
for (QMap::const_iterator i = d->dockWidgetsMap.constBegin();
i != d->dockWidgetsMap.constEnd(); ++i) {
if (i.value()->widget()) {
KConfigGroup dockGroup = group.group(QString("DockWidget ") + i.key());
dockGroup.writeEntry("Collapsed", i.value()->widget()->isHidden());
dockGroup.writeEntry("Locked", i.value()->property("Locked").toBool());
dockGroup.writeEntry("DockArea", (int) dockWidgetArea(i.value()));
}
}
}
KSharedConfig::openConfig()->sync();
resetAutoSaveSettings(); // Don't let KMainWindow override the good stuff we wrote down
}
void KoMainWindow::resizeEvent(QResizeEvent * e)
{
d->windowSizeDirty = true;
KXmlGuiWindow::resizeEvent(e);
}
bool KoMainWindow::queryClose()
{
if (rootDocument() == 0)
return true;
//debugMain <<"KoMainWindow::queryClose() viewcount=" << rootDocument()->viewCount()
// << " mainWindowCount=" << rootDocument()->mainWindowCount() << endl;
if (!d->forQuit && d->rootPart && d->rootPart->mainwindowCount() > 1)
// there are more open, and we are closing just one, so no problem for closing
return true;
// main doc + internally stored child documents
if (d->rootDocument->isModified()) {
QString name;
if (rootDocument()->documentInfo()) {
name = rootDocument()->documentInfo()->aboutInfo("title");
}
if (name.isEmpty())
name = rootDocument()->url().fileName();
if (name.isEmpty())
name = i18n("Untitled");
int res = KMessageBox::warningYesNoCancel(this,
i18n("
The document '%1' has been modified.
Do you want to save it?
", name),
QString(),
KStandardGuiItem::save(),
KStandardGuiItem::discard());
switch (res) {
case KMessageBox::Yes : {
bool isNative = (d->rootDocument->outputMimeType() == d->rootDocument->nativeFormatMimeType());
if (!saveDocument(!isNative))
return false;
break;
}
case KMessageBox::No :
rootDocument()->removeAutoSaveFiles();
rootDocument()->setModified(false); // Now when queryClose() is called by closeEvent it won't do anything.
break;
default : // case KMessageBox::Cancel :
return false;
}
}
return true;
}
// Helper method for slotFileNew and slotFileClose
void KoMainWindow::chooseNewDocument(InitDocFlags initDocFlags)
{
KoDocument* doc = rootDocument();
KoPart *newpart = createPart();
KoDocument *newdoc = newpart->document();
if (!newdoc)
return;
disconnect(newdoc, &KoDocument::sigProgress, this, &KoMainWindow::slotProgress);
if ((!doc && initDocFlags == InitDocFileNew) || (doc && !doc->isEmpty())) {
KoMainWindow *s = newpart->createMainWindow();
s->show();
newpart->addMainWindow(s);
newpart->showStartUpWidget(s);
return;
}
if (doc) {
setRootDocument(0);
if(d->rootDocument)
d->rootDocument->clearUndoHistory();
delete d->rootDocument;
d->rootDocument = 0;
}
newpart->addMainWindow(this);
newpart->showStartUpWidget(this);
}
void KoMainWindow::slotFileNew()
{
chooseNewDocument(InitDocFileNew);
}
void KoMainWindow::slotFileOpen()
{
QUrl url;
if (!isImporting()) {
KoFileDialog dialog(this, KoFileDialog::OpenFile, "OpenDocument");
dialog.setCaption(i18n("Open Document"));
dialog.setDefaultDir(qApp->applicationName().contains("karbon")
? QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)
: QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
dialog.setMimeTypeFilters(koApp->mimeFilter(KoFilterManager::Import));
dialog.setHideNameFilterDetailsOption();
url = QUrl::fromUserInput(dialog.filename());
} else {
KoFileDialog dialog(this, KoFileDialog::ImportFile, "OpenDocument");
dialog.setCaption(i18n("Import Document"));
dialog.setDefaultDir(qApp->applicationName().contains("karbon")
? QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)
: QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
dialog.setMimeTypeFilters(koApp->mimeFilter(KoFilterManager::Import));
dialog.setHideNameFilterDetailsOption();
url = QUrl::fromUserInput(dialog.filename());
}
if (url.isEmpty())
return;
(void) openDocument(url);
}
void KoMainWindow::slotFileOpenRecent(const QUrl & url, KoPart *part)
{
// Create a copy, because the original QUrl in the map of recent files in
// KRecentFilesAction may get deleted.
(void) openDocument(part, QUrl(url));
}
void KoMainWindow::slotFileSave()
{
if (saveDocument())
emit documentSaved();
}
void KoMainWindow::slotFileSaveAs()
{
if (saveDocument(true))
emit documentSaved();
}
void KoMainWindow::slotEncryptDocument()
{
if (saveDocument(false, false, KoDocument::SaveEncrypted))
emit documentSaved();
}
void KoMainWindow::slotUncompressToDir()
{
if (saveDocument(true, false, KoDocument::SaveAsDirectoryStore))
emit documentSaved();
}
void KoMainWindow::slotDocumentInfo()
{
if (!rootDocument())
return;
KoDocumentInfo *docInfo = rootDocument()->documentInfo();
if (!docInfo)
return;
KoDocumentInfoDlg *dlg = d->rootDocument->createDocumentInfoDialog(this, docInfo);
if (dlg->exec()) {
if (dlg->isDocumentSaved()) {
rootDocument()->setModified(false);
} else {
rootDocument()->setModified(true);
}
rootDocument()->setTitleModified();
}
delete dlg;
}
void KoMainWindow::slotFileClose()
{
if (queryClose()) {
saveWindowSettings();
setRootDocument(0); // don't delete this main window when deleting the document
if(d->rootDocument)
d->rootDocument->clearUndoHistory();
delete d->rootDocument;
d->rootDocument = 0;
chooseNewDocument(InitDocFileClose);
}
}
void KoMainWindow::slotFileQuit()
{
close();
}
void KoMainWindow::slotFilePrint()
{
if (!rootView())
return;
KoPrintJob *printJob = rootView()->createPrintJob();
if (printJob == 0)
return;
d->applyDefaultSettings(printJob->printer());
QPrintDialog *printDialog = rootView()->createPrintDialog( printJob, this );
if (printDialog && printDialog->exec() == QDialog::Accepted)
printJob->startPrinting(KoPrintJob::DeleteWhenDone);
else
delete printJob;
delete printDialog;
}
void KoMainWindow::slotFilePrintPreview()
{
if (!rootView())
return;
KoPrintJob *printJob = rootView()->createPrintJob();
if (printJob == 0)
return;
/* Sets the startPrinting() slot to be blocking.
The Qt print-preview dialog requires the printing to be completely blocking
and only return when the full document has been printed.
By default the KoPrintingDialog is non-blocking and
multithreading, setting blocking to true will allow it to be used in the preview dialog */
printJob->setProperty("blocking", true);
QPrintPreviewDialog *preview = new QPrintPreviewDialog(&printJob->printer(), this);
printJob->setParent(preview); // will take care of deleting the job
d->printPreviewJob = printJob;
connect(preview, SIGNAL(paintRequested(QPrinter*)), this, SLOT(slotPrintPreviewPaintRequest(QPrinter*))); // clazy:exclude=old-style-connect
preview->exec();
delete preview;
d->printPreviewJob = nullptr;
}
void KoMainWindow::slotPrintPreviewPaintRequest(QPrinter *printer)
{
KoPageLayout pl = rootView()->pageLayout();
pl.updatePageLayout(printer);
rootView()->setPageLayout(pl);
d->printPreviewJob->startPrinting();
}
KoPrintJob* KoMainWindow::exportToPdf()
{
return exportToPdf(QString());
}
KoPrintJob* KoMainWindow::exportToPdf(const QString &_pdfFileName)
{
if (!rootView())
return 0;
KoPageLayout pageLayout;
pageLayout = rootView()->pageLayout();
QString pdfFileName = _pdfFileName;
if (pdfFileName.isEmpty()) {
KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs");
QString defaultDir = group.readEntry("SavePdfDialog");
if (defaultDir.isEmpty())
defaultDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
QUrl startUrl = QUrl::fromLocalFile(defaultDir);
KoDocument* pDoc = rootDocument();
/** if document has a file name, take file name and replace extension with .pdf */
if (pDoc && pDoc->url().isValid()) {
startUrl = pDoc->url();
QString fileName = startUrl.fileName();
fileName = fileName.replace( QRegExp( "\\.\\w{2,5}$", Qt::CaseInsensitive ), ".pdf" );
startUrl = startUrl.adjusted(QUrl::RemoveFilename);
startUrl.setPath(startUrl.path() + fileName );
}
QPointer layoutDlg(new KoPageLayoutDialog(this, pageLayout));
layoutDlg->setWindowModality(Qt::WindowModal);
if (layoutDlg->exec() != QDialog::Accepted || !layoutDlg) {
delete layoutDlg;
return 0;
}
pageLayout = layoutDlg->pageLayout();
delete layoutDlg;
KoFileDialog dialog(this, KoFileDialog::SaveFile, "SaveDocument");
dialog.setCaption(i18n("Export as PDF"));
dialog.setDefaultDir(startUrl.toLocalFile());
dialog.setMimeTypeFilters(QStringList() << "application/pdf");
QUrl url = QUrl::fromUserInput(dialog.filename());
pdfFileName = url.toLocalFile();
if (pdfFileName.isEmpty())
return 0;
}
KoPrintJob *printJob = rootView()->createPdfPrintJob();
if (printJob == 0)
return 0;
if (isHidden()) {
printJob->setProperty("noprogressdialog", true);
}
d->applyDefaultSettings(printJob->printer());
// TODO for remote files we have to first save locally and then upload.
printJob->printer().setOutputFileName(pdfFileName);
printJob->printer().setColorMode(QPrinter::Color);
if (pageLayout.format == KoPageFormat::CustomSize) {
printJob->printer().setPaperSize(QSizeF(pageLayout.width, pageLayout.height), QPrinter::Millimeter);
} else {
printJob->printer().setPaperSize(KoPageFormat::printerPageSize(pageLayout.format));
}
switch (pageLayout.orientation) {
case KoPageFormat::Portrait: printJob->printer().setOrientation(QPrinter::Portrait); break;
case KoPageFormat::Landscape: printJob->printer().setOrientation(QPrinter::Landscape); break;
}
printJob->printer().setPageMargins(pageLayout.leftMargin, pageLayout.topMargin, pageLayout.rightMargin, pageLayout.bottomMargin, QPrinter::Millimeter);
//before printing check if the printer can handle printing
if (!printJob->canPrint()) {
KMessageBox::error(this, i18n("Cannot export to the specified file"));
}
printJob->startPrinting(KoPrintJob::DeleteWhenDone);
rootView()->setPageLayout(pageLayout);
return printJob;
}
void KoMainWindow::slotConfigureKeys()
{
QAction* undoAction=0;
QAction* redoAction=0;
QString oldUndoText;
QString oldRedoText;
if(currentView()) {
//The undo/redo action text is "undo" + command, replace by simple text while inside editor
undoAction = currentView()->actionCollection()->action("edit_undo");
redoAction = currentView()->actionCollection()->action("edit_redo");
oldUndoText = undoAction->text();
oldRedoText = redoAction->text();
undoAction->setText(i18n("Undo"));
redoAction->setText(i18n("Redo"));
}
guiFactory()->configureShortcuts();
if(currentView()) {
undoAction->setText(oldUndoText);
redoAction->setText(oldRedoText);
}
emit keyBindingsChanged();
}
void KoMainWindow::slotConfigureToolbars()
{
if (rootDocument()) {
KConfigGroup componentConfigGroup = KSharedConfig::openConfig()->group(d->rootPart->componentData().componentName());
saveMainWindowSettings(componentConfigGroup);
}
KEditToolBar edit(factory(), this);
connect(&edit, &KEditToolBar::newToolBarConfig, this, &KoMainWindow::slotNewToolbarConfig);
(void) edit.exec();
}
void KoMainWindow::slotNewToolbarConfig()
{
if (rootDocument()) {
KConfigGroup componentConfigGroup = KSharedConfig::openConfig()->group(d->rootPart->componentData().componentName());
applyMainWindowSettings(componentConfigGroup);
}
KXMLGUIFactory *factory = guiFactory();
Q_UNUSED(factory);
// Check if there's an active view
if (!d->activeView)
return;
plugActionList("toolbarlist", d->toolbarList);
}
void KoMainWindow::slotToolbarToggled(bool toggle)
{
//debugMain <<"KoMainWindow::slotToolbarToggled" << sender()->name() <<" toggle=" << true;
// The action (sender) and the toolbar have the same name
KToolBar * bar = toolBar(sender()->objectName());
if (bar) {
if (toggle)
bar->show();
else
bar->hide();
if (rootDocument()) {
KConfigGroup componentConfigGroup = KSharedConfig::openConfig()->group(d->rootPart->componentData().componentName());
saveMainWindowSettings(componentConfigGroup);
}
} else
warnMain << "slotToolbarToggled : Toolbar " << sender()->objectName() << " not found!";
}
bool KoMainWindow::toolbarIsVisible(const char *tbName)
{
QWidget *tb = toolBar(tbName);
return !tb->isHidden();
}
void KoMainWindow::showToolbar(const char * tbName, bool shown)
{
QWidget * tb = toolBar(tbName);
if (!tb) {
warnMain << "KoMainWindow: toolbar " << tbName << " not found.";
return;
}
if (shown)
tb->show();
else
tb->hide();
// Update the action appropriately
foreach(QAction* action, d->toolbarList) {
if (action->objectName() != tbName) {
//debugMain <<"KoMainWindow::showToolbar setChecked" << shown;
static_cast(action)->setChecked(shown);
break;
}
}
}
void KoMainWindow::viewFullscreen(bool fullScreen)
{
if (fullScreen) {
window()->setWindowState(window()->windowState() | Qt::WindowFullScreen); // set
} else {
window()->setWindowState(window()->windowState() & ~Qt::WindowFullScreen); // reset
}
}
void KoMainWindow::slotProgress(int value)
{
QMutexLocker locker(&d->progressMutex);
debugMain << value;
if (value <= -1 || value >= 100) {
if (d->progress) {
statusBar()->removeWidget(d->progress);
delete d->progress;
d->progress = 0;
}
d->firstTime = true;
return;
}
if (d->firstTime || !d->progress) {
// The statusbar might not even be created yet.
// So check for that first, and create it if necessary
QStatusBar *bar = findChild();
if (!bar) {
statusBar()->show();
QApplication::sendPostedEvents(this, QEvent::ChildAdded);
}
if (d->progress) {
statusBar()->removeWidget(d->progress);
delete d->progress;
d->progress = 0;
}
d->progress = new QProgressBar(statusBar());
d->progress->setMaximumHeight(statusBar()->fontMetrics().height());
d->progress->setRange(0, 100);
statusBar()->addPermanentWidget(d->progress);
d->progress->show();
d->firstTime = false;
}
if (!d->progress.isNull()) {
d->progress->setValue(value);
}
locker.unlock();
qApp->processEvents();
}
void KoMainWindow::setMaxRecentItems(uint _number)
{
d->recent->setMaxItems(_number);
}
void KoMainWindow::slotEmailFile()
{
if (!rootDocument())
return;
// Subject = Document file name
// Attachment = The current file
// Message Body = The current document in HTML export? <-- This may be an option.
QString theSubject;
QStringList urls;
QString fileURL;
if (rootDocument()->url().isEmpty() ||
rootDocument()->isModified()) {
//Save the file as a temporary file
bool const tmp_modified = rootDocument()->isModified();
QUrl const tmp_url = rootDocument()->url();
QByteArray const tmp_mimetype = rootDocument()->outputMimeType();
// a little open, close, delete dance to make sure we have a nice filename
// to use, but won't block windows from creating a new file with this name.
QTemporaryFile *tmpfile = new QTemporaryFile();
tmpfile->open();
QString fileName = tmpfile->fileName();
tmpfile->close();
delete tmpfile;
QUrl u = QUrl::fromLocalFile(fileName);
rootDocument()->setUrl(u);
rootDocument()->setModified(true);
rootDocument()->setOutputMimeType(rootDocument()->nativeFormatMimeType());
saveDocument(false, true);
fileURL = fileName;
theSubject = i18n("Document");
urls.append(fileURL);
rootDocument()->setUrl(tmp_url);
rootDocument()->setModified(tmp_modified);
rootDocument()->setOutputMimeType(tmp_mimetype);
} else {
fileURL = rootDocument()->url().url();
theSubject = i18n("Document - %1", rootDocument()->url().fileName());
urls.append(fileURL);
}
debugMain << "(" << fileURL << ")";
if (!fileURL.isEmpty()) {
KToolInvocation::invokeMailer(QString(), QString(), QString(), theSubject,
QString(), //body
QString(),
urls); // attachments
}
}
void KoMainWindow::slotReloadFile()
{
KoDocument* pDoc = rootDocument();
if (!pDoc || pDoc->url().isEmpty() || !pDoc->isModified())
return;
bool bOk = KMessageBox::questionYesNo(this,
i18n("You will lose all changes made since your last save\n"
"Do you want to continue?"),
i18n("Warning")) == KMessageBox::Yes;
if (!bOk)
return;
QUrl url = pDoc->url();
if (!pDoc->isEmpty()) {
saveWindowSettings();
setRootDocument(0); // don't delete this main window when deleting the document
if(d->rootDocument)
d->rootDocument->clearUndoHistory();
delete d->rootDocument;
d->rootDocument = 0;
}
openDocument(url);
return;
}
void KoMainWindow::slotImportFile()
{
debugMain;
d->isImporting = true;
slotFileOpen();
d->isImporting = false;
}
void KoMainWindow::slotExportFile()
{
debugMain;
d->isExporting = true;
slotFileSaveAs();
d->isExporting = false;
}
bool KoMainWindow::isImporting() const
{
return d->isImporting;
}
bool KoMainWindow::isExporting() const
{
return d->isExporting;
}
void KoMainWindow::setPartToOpen(KoPart *part)
{
d->partToOpen = part;
}
KoComponentData KoMainWindow::componentData() const
{
return d->componentData;
}
QDockWidget* KoMainWindow::createDockWidget(KoDockFactoryBase* factory)
{
QDockWidget* dockWidget = 0;
if (!d->dockWidgetsMap.contains(factory->id())) {
dockWidget = factory->createDockWidget();
// It is quite possible that a dock factory cannot create the dock; don't
// do anything in that case.
if (!dockWidget) return 0;
d->dockWidgets.push_back(dockWidget);
KoDockWidgetTitleBar *titleBar = 0;
// Check if the dock widget is supposed to be collapsable
if (!dockWidget->titleBarWidget()) {
titleBar = new KoDockWidgetTitleBar(dockWidget);
dockWidget->setTitleBarWidget(titleBar);
titleBar->setCollapsable(factory->isCollapsable());
}
dockWidget->setObjectName(factory->id());
dockWidget->setParent(this);
if (dockWidget->widget() && dockWidget->widget()->layout())
dockWidget->widget()->layout()->setContentsMargins(1, 1, 1, 1);
Qt::DockWidgetArea side = Qt::RightDockWidgetArea;
bool visible = true;
switch (factory->defaultDockPosition()) {
case KoDockFactoryBase::DockTornOff:
dockWidget->setFloating(true); // position nicely?
break;
case KoDockFactoryBase::DockTop:
side = Qt::TopDockWidgetArea; break;
case KoDockFactoryBase::DockLeft:
side = Qt::LeftDockWidgetArea; break;
case KoDockFactoryBase::DockBottom:
side = Qt::BottomDockWidgetArea; break;
case KoDockFactoryBase::DockRight:
side = Qt::RightDockWidgetArea; break;
case KoDockFactoryBase::DockMinimized:
default:
side = Qt::RightDockWidgetArea;
visible = false;
}
if (rootDocument()) {
KConfigGroup group = KSharedConfig::openConfig()->group(d->rootPart->componentData().componentName()).group("DockWidget " + factory->id());
side = static_cast(group.readEntry("DockArea", static_cast(side)));
if (side == Qt::NoDockWidgetArea) side = Qt::RightDockWidgetArea;
}
addDockWidget(side, dockWidget);
if (dockWidget->features() & QDockWidget::DockWidgetClosable) {
d->dockWidgetMenu->addAction(dockWidget->toggleViewAction());
if (!visible)
dockWidget->hide();
}
bool collapsed = factory->defaultCollapsed();
bool locked = false;
if (rootDocument()) {
KConfigGroup group = KSharedConfig::openConfig()->group(d->rootPart->componentData().componentName()).group("DockWidget " + factory->id());
collapsed = group.readEntry("Collapsed", collapsed);
locked = group.readEntry("Locked", locked);
}
if (titleBar && collapsed)
titleBar->setCollapsed(true);
if (titleBar && locked)
titleBar->setLocked(true);
if (titleBar) {
KConfigGroup configGroupInterface = KSharedConfig::openConfig()->group("Interface");
titleBar->setVisible(configGroupInterface.readEntry("ShowDockerTitleBars", true));
}
d->dockWidgetsMap.insert(factory->id(), dockWidget);
} else {
dockWidget = d->dockWidgetsMap[ factory->id()];
}
#ifdef Q_OS_MAC
dockWidget->setAttribute(Qt::WA_MacSmallSize, true);
#endif
dockWidget->setFont(KoDockRegistry::dockFont());
connect(dockWidget, &QDockWidget::dockLocationChanged, this, &KoMainWindow::forceDockTabFonts);
return dockWidget;
}
void KoMainWindow::forceDockTabFonts()
{
QObjectList chis = children();
for (int i = 0; i < chis.size(); ++i) {
if (chis.at(i)->inherits("QTabBar")) {
((QTabBar *)chis.at(i))->setFont(KoDockRegistry::dockFont());
}
}
}
QList KoMainWindow::dockWidgets() const
{
return d->dockWidgetsMap.values();
}
/*QList KoMainWindow::canvasObservers() const
{
QList observers;
foreach(QDockWidget *docker, dockWidgets()) {
KoCanvasObserverBase *observer = dynamic_cast(docker);
if (observer) {
observers << observer;
}
}
return observers;
}*/
void KoMainWindow::toggleDockersVisibility(bool visible)
{
if (!visible) {
d->m_dockerStateBeforeHiding = saveState();
foreach(QObject* widget, children()) {
if (widget->inherits("QDockWidget")) {
QDockWidget* dw = static_cast(widget);
if (dw->isVisible()) {
dw->hide();
}
}
}
}
else {
restoreState(d->m_dockerStateBeforeHiding);
}
}
KRecentFilesAction *KoMainWindow::recentAction() const
{
return d->recent;
}
KoView* KoMainWindow::currentView() const
{
// XXX
if (d->activeView) {
return d->activeView;
}
else if (!d->rootViews.isEmpty()) {
return d->rootViews.first();
}
return 0;
}
void KoMainWindow::newView()
{
Q_ASSERT((d != 0 && d->activeView && d->activePart && d->activeView->koDocument()));
KoMainWindow *mainWindow = d->activePart->createMainWindow();
mainWindow->setRootDocument(d->activeView->koDocument(), d->activePart);
mainWindow->show();
}
void KoMainWindow::createMainwindowGUI()
{
if ( isHelpMenuEnabled() && !d->m_helpMenu ) {
d->m_helpMenu = new KHelpMenu( this, componentData().aboutData(), true );
KActionCollection *actions = actionCollection();
QAction *helpContentsAction = d->m_helpMenu->action(KHelpMenu::menuHelpContents);
QAction *whatsThisAction = d->m_helpMenu->action(KHelpMenu::menuWhatsThis);
QAction *reportBugAction = d->m_helpMenu->action(KHelpMenu::menuReportBug);
QAction *switchLanguageAction = d->m_helpMenu->action(KHelpMenu::menuSwitchLanguage);
QAction *aboutAppAction = d->m_helpMenu->action(KHelpMenu::menuAboutApp);
QAction *aboutKdeAction = d->m_helpMenu->action(KHelpMenu::menuAboutKDE);
if (helpContentsAction) {
actions->addAction(helpContentsAction->objectName(), helpContentsAction);
}
if (whatsThisAction) {
actions->addAction(whatsThisAction->objectName(), whatsThisAction);
}
if (reportBugAction) {
actions->addAction(reportBugAction->objectName(), reportBugAction);
}
if (switchLanguageAction) {
actions->addAction(switchLanguageAction->objectName(), switchLanguageAction);
}
if (aboutAppAction) {
actions->addAction(aboutAppAction->objectName(), aboutAppAction);
}
if (aboutKdeAction) {
actions->addAction(aboutKdeAction->objectName(), aboutKdeAction);
}
}
QString f = xmlFile();
setXMLFile( QStandardPaths::locate(QStandardPaths::ConfigLocation, QStringLiteral("ui/ui_standards.rc")) );
if ( !f.isEmpty() )
setXMLFile( f, true );
else
{
QString auto_file( componentData().componentName() + "ui.rc" );
setXMLFile( auto_file, true );
}
guiFactory()->addClient( this );
}
// PartManager
void KoMainWindow::removePart( KoPart *part )
{
if (d->m_registeredPart.data() != part) {
return;
}
d->m_registeredPart = 0;
if ( part == d->m_activePart ) {
setActivePart(0, 0);
}
}
void KoMainWindow::setActivePart(KoPart *part, QWidget *widget )
{
if (part && d->m_registeredPart.data() != part) {
warnMain << "trying to activate a non-registered part!" << part->objectName();
return; // don't allow someone call setActivePart with a part we don't know about
}
// don't activate twice
if ( d->m_activePart && part && d->m_activePart == part &&
(!widget || d->m_activeWidget == widget) )
return;
KoPart *oldActivePart = d->m_activePart;
QWidget *oldActiveWidget = d->m_activeWidget;
d->m_activePart = part;
d->m_activeWidget = widget;
if (oldActivePart) {
KoPart *savedActivePart = part;
QWidget *savedActiveWidget = widget;
if ( oldActiveWidget ) {
disconnect( oldActiveWidget, &QObject::destroyed, this, &KoMainWindow::slotWidgetDestroyed );
}
d->m_activePart = savedActivePart;
d->m_activeWidget = savedActiveWidget;
}
if (d->m_activePart && d->m_activeWidget ) {
connect( d->m_activeWidget, &QObject::destroyed, this, &KoMainWindow::slotWidgetDestroyed );
}
// Set the new active instance in KGlobal
// KGlobal::setActiveComponent(d->m_activePart ? d->m_activePart->componentData() : KGlobal::mainComponent());
// old slot called from part manager
KoPart *newPart = static_cast(d->m_activePart.data());
if (d->activePart && d->activePart == newPart) {
//debugMain <<"no need to change the GUI";
return;
}
KXMLGUIFactory *factory = guiFactory();
if (d->activeView) {
factory->removeClient(d->activeView);
unplugActionList("toolbarlist");
qDeleteAll(d->toolbarList);
d->toolbarList.clear();
}
if (!d->mainWindowGuiIsBuilt) {
createMainwindowGUI();
}
if (newPart && d->m_activeWidget && d->m_activeWidget->inherits("KoView")) {
d->activeView = qobject_cast(d->m_activeWidget);
d->activeView->actionCollection()->addAction("view_newview", actionCollection()->action("view_newview"));
d->activePart = newPart;
//debugMain <<"new active part is" << d->activePart;
factory->addClient(d->activeView);
// Position and show toolbars according to user's preference
setAutoSaveSettings(newPart->componentData().componentName(), false);
KConfigGroup configGroupInterface = KSharedConfig::openConfig()->group("Interface");
const bool showDockerTitleBar = configGroupInterface.readEntry("ShowDockerTitleBars", true);
foreach (QDockWidget *wdg, d->dockWidgets) {
if ((wdg->features() & QDockWidget::DockWidgetClosable) == 0) {
if (wdg->titleBarWidget()) {
wdg->titleBarWidget()->setVisible(showDockerTitleBar);
}
wdg->setVisible(true);
}
}
// Create and plug toolbar list for Settings menu
foreach(QWidget* it, factory->containers("ToolBar")) {
KToolBar * toolBar = ::qobject_cast(it);
if (toolBar) {
KToggleAction * act = new KToggleAction(i18n("Show %1 Toolbar", toolBar->windowTitle()), this);
actionCollection()->addAction(toolBar->objectName().toUtf8(), act);
act->setCheckedState(KGuiItem(i18n("Hide %1 Toolbar", toolBar->windowTitle())));
connect(act, &QAction::toggled, this, &KoMainWindow::slotToolbarToggled);
act->setChecked(!toolBar->isHidden());
d->toolbarList.append(act);
} else
warnMain << "Toolbar list contains a " << it->metaObject()->className() << " which is not a toolbar!";
}
plugActionList("toolbarlist", d->toolbarList);
}
else {
d->activeView = 0;
d->activePart = 0;
}
if (d->activeView) {
d->activeView->guiActivateEvent(true);
}
}
void KoMainWindow::slotWidgetDestroyed()
{
debugMain;
if ( static_cast( sender() ) == d->m_activeWidget )
setActivePart(0, 0); //do not remove the part because if the part's widget dies, then the
//part will delete itself anyway, invoking removePart() in its destructor
}
void KoMainWindow::slotDocumentTitleModified(const QString &caption, bool mod)
{
updateCaption(caption, mod);
updateReloadFileAction(d->rootDocument);
}
void KoMainWindow::showDockerTitleBars(bool show)
{
foreach (QDockWidget *dock, dockWidgets()) {
if (dock->titleBarWidget()) {
dock->titleBarWidget()->setVisible(show);
}
}
KConfigGroup configGroupInterface = KSharedConfig::openConfig()->group("Interface");
configGroupInterface.writeEntry("ShowDockerTitleBars", show);
}
diff --git a/src/libs/main/calligraplan_shell.rc b/src/libs/main/calligraplan_shell.rc
index af1a143d..d56fda2e 100644
--- a/src/libs/main/calligraplan_shell.rc
+++ b/src/libs/main/calligraplan_shell.rc
@@ -1,55 +1,56 @@
+
File
diff --git a/src/libs/ui/performance/ProjectStatusViewUi.rc b/src/libs/ui/AccountsEditorUi_readonly.rc
similarity index 70%
copy from src/libs/ui/performance/ProjectStatusViewUi.rc
copy to src/libs/ui/AccountsEditorUi_readonly.rc
index a6fcbe6f..941587a0 100644
--- a/src/libs/ui/performance/ProjectStatusViewUi.rc
+++ b/src/libs/ui/AccountsEditorUi_readonly.rc
@@ -1,21 +1,18 @@
-
-
+
+
diff --git a/src/libs/ui/CMakeLists.txt b/src/libs/ui/CMakeLists.txt
index e3289b19..adad8bd0 100644
--- a/src/libs/ui/CMakeLists.txt
+++ b/src/libs/ui/CMakeLists.txt
@@ -1,217 +1,225 @@
include_directories(
${PLANKERNEL_INCLUDES}
${PLANMODELS_INCLUDES}
${PLANMAIN_INCLUDES}
${PLANWIDGETS_INCLUDES}
${KDEPIMLIBS_INCLUDE_DIR}
)
#add_subdirectory( tests )
########### KPlato private library ###############
if (PLAN_USE_KREPORT)
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(planui_LIB_SRCS
${planreports_LIB_SRC}
RelationEditorDialog.cpp
TasksEditController.cpp
TasksEditDialog.cpp
RichTextWidget.cpp
welcome/WelcomeView.cpp
reportsgenerator/ReportsGeneratorView.cpp
kptganttitemdelegate.cpp
kptworkpackagesendpanel.cpp
kptworkpackagesenddialog.cpp
kptdocumentseditor.cpp
kptdocumentspanel.cpp
kptdocumentsdialog.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
gantt/DateTimeTimeLine.cpp
gantt/DateTimeGrid.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
kptresourceallocationeditor.cpp
kptworkpackagemergedialog.cpp
kptrecalculatedialog.cpp
kpthtmlview.cpp
locale/localemon.cpp
kptlocaleconfigmoneydialog.cpp
ResourceAllocationView.cpp
performance/KPlatoChart.cpp
performance/PerformanceStatusBase.cpp
performance/ProjectStatusView.cpp
performance/PerformanceStatusView.cpp
performance/PerformanceTableView.cpp
)
ki18n_wrap_ui(planui_LIB_SRCS
${planreports_ui_LIB_SRCS}
RelationEditorDialog.ui
welcome/WelcomeView.ui
kptresourceappointmentsdisplayoptions.ui
kptganttchartdisplayoptions.ui
kptprintingheaderfooter.ui
kptganttprintingoptions.ui
kptworkpackagesendpanel.ui
kptdocumentspanel.ui
performance/PerformanceStatus.ui
performance/PerformanceStatusViewSettingsPanel.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
kptworkpackagemergepanel.ui
kptrecalculatedialog.ui
kptscheduleeditor.ui
locale/localemon.ui
)
add_library(planui SHARED ${planui_LIB_SRCS})
generate_export_header(planui)
target_link_libraries(planui
PUBLIC
planmain
planmodels
KF5::KHtml
PRIVATE
KChart
KF5::ItemViews
KF5::IconThemes
KF5::Archive
KF5::TextWidgets
KF5::KIOCore
KF5::KIOFileWidgets
KF5::KIOWidgets
KF5::KIONTLM
)
if (PLAN_USE_KREPORT)
target_link_libraries(planui PUBLIC KReport PRIVATE KPropertyWidgets)
endif()
if(KF5AkonadiContact_FOUND)
target_link_libraries(planui PRIVATE KF5::AkonadiContact)
endif()
set_target_properties(planui PROPERTIES VERSION ${GENERIC_PLAN_LIB_VERSION} SOVERSION ${GENERIC_PLAN_LIB_SOVERSION} )
install(TARGETS planui ${INSTALL_TARGETS_DEFAULT_ARGS})
install( FILES
AccountsEditorUi.rc
+ AccountsEditorUi_readonly.rc
AccountsViewUi.rc
CalendarEditorUi.rc
+ CalendarEditorUi_readonly.rc
TaskEditorUi.rc
+ TaskEditorUi_readonly.rc
DependencyEditorUi.rc
+ DependencyEditorUi_readonly.rc
ResourceEditorUi.rc
+ ResourceEditorUi_readonly.rc
ResourceAppointmentsViewUi.rc
ScheduleEditorUi.rc
+ ScheduleEditorUi_readonly.rc
GanttViewUi.rc
WorkPackageViewUi.rc
+ WorkPackageViewUi_readonly.rc
reportsgenerator/ReportsGeneratorViewUi.rc
+ reportsgenerator/ReportsGeneratorViewUi_readonly.rc
performance/PerformanceStatusViewUi.rc
performance/ProjectStatusViewUi.rc
PertResultUi.rc
TaskViewUi.rc
TaskStatusViewUi.rc
DESTINATION ${KXMLGUI_INSTALL_DIR}/calligraplan
)
# reports files
install(FILES
reportsgenerator/templates/EmptyTemplate.odt
reportsgenerator/templates/ProjectPerformanceCost.odt
reportsgenerator/templates/ProjectPerformanceEffort.odt
reportsgenerator/templates/TaskStatus.odt
DESTINATION ${DATA_INSTALL_DIR}/calligraplan/reports
)
diff --git a/src/libs/ui/CalendarEditorUi.rc b/src/libs/ui/CalendarEditorUi.rc
index f4363b48..705a7ace 100644
--- a/src/libs/ui/CalendarEditorUi.rc
+++ b/src/libs/ui/CalendarEditorUi.rc
@@ -1,28 +1,28 @@
-
+
diff --git a/src/libs/ui/performance/ProjectStatusViewUi.rc b/src/libs/ui/CalendarEditorUi_readonly.rc
similarity index 70%
copy from src/libs/ui/performance/ProjectStatusViewUi.rc
copy to src/libs/ui/CalendarEditorUi_readonly.rc
index a6fcbe6f..941587a0 100644
--- a/src/libs/ui/performance/ProjectStatusViewUi.rc
+++ b/src/libs/ui/CalendarEditorUi_readonly.rc
@@ -1,21 +1,18 @@
-
-
+
+
diff --git a/src/libs/ui/performance/ProjectStatusViewUi.rc b/src/libs/ui/DependencyEditorUi_readonly.rc
similarity index 79%
copy from src/libs/ui/performance/ProjectStatusViewUi.rc
copy to src/libs/ui/DependencyEditorUi_readonly.rc
index a6fcbe6f..9dd7cf9e 100644
--- a/src/libs/ui/performance/ProjectStatusViewUi.rc
+++ b/src/libs/ui/DependencyEditorUi_readonly.rc
@@ -1,21 +1,20 @@
-
-
+
+
diff --git a/src/libs/ui/performance/PerformanceStatusViewUi.rc b/src/libs/ui/ResourceEditorUi_readonly.rc
similarity index 83%
copy from src/libs/ui/performance/PerformanceStatusViewUi.rc
copy to src/libs/ui/ResourceEditorUi_readonly.rc
index 7b2628bc..b1679592 100644
--- a/src/libs/ui/performance/PerformanceStatusViewUi.rc
+++ b/src/libs/ui/ResourceEditorUi_readonly.rc
@@ -1,21 +1,21 @@
-
-
+
+
diff --git a/src/libs/ui/performance/ProjectStatusViewUi.rc b/src/libs/ui/ScheduleEditorUi_readonly.rc
similarity index 63%
copy from src/libs/ui/performance/ProjectStatusViewUi.rc
copy to src/libs/ui/ScheduleEditorUi_readonly.rc
index a6fcbe6f..f4b42eeb 100644
--- a/src/libs/ui/performance/ProjectStatusViewUi.rc
+++ b/src/libs/ui/ScheduleEditorUi_readonly.rc
@@ -1,21 +1,17 @@
-
-
+
+
diff --git a/src/libs/ui/performance/ProjectStatusViewUi.rc b/src/libs/ui/TaskEditorUi_readonly.rc
similarity index 79%
copy from src/libs/ui/performance/ProjectStatusViewUi.rc
copy to src/libs/ui/TaskEditorUi_readonly.rc
index a6fcbe6f..e6010b69 100644
--- a/src/libs/ui/performance/ProjectStatusViewUi.rc
+++ b/src/libs/ui/TaskEditorUi_readonly.rc
@@ -1,21 +1,20 @@
-
-
+
+
diff --git a/src/libs/ui/performance/PerformanceStatusViewUi.rc b/src/libs/ui/WorkPackageViewUi_readonly.rc
similarity index 64%
copy from src/libs/ui/performance/PerformanceStatusViewUi.rc
copy to src/libs/ui/WorkPackageViewUi_readonly.rc
index 7b2628bc..a3abef4c 100644
--- a/src/libs/ui/performance/PerformanceStatusViewUi.rc
+++ b/src/libs/ui/WorkPackageViewUi_readonly.rc
@@ -1,21 +1,24 @@
-
-
+
+
+
diff --git a/src/libs/ui/kptaccountseditor.cpp b/src/libs/ui/kptaccountseditor.cpp
index 5cc310f2..5e81cb93 100644
--- a/src/libs/ui/kptaccountseditor.cpp
+++ b/src/libs/ui/kptaccountseditor.cpp
@@ -1,386 +1,392 @@
/* This file is part of the KDE project
- Copyright (C) 2007 Dag Andersen
- Copyright (C) 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.
-*/
+ * Copyright (C) 2007 Dag Andersen
+ * Copyright (C) 2011, 2012 Dag Andersen
+ * Copyright (C) 2019 Dag Andersen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
// clazy:excludeall=qstring-arg
#include "kptaccountseditor.h"
#include "kptcommand.h"
#include "kptcalendar.h"
#include "kptduration.h"
#include "kptnode.h"
#include "kptproject.h"
#include "kpttask.h"
#include "kptaccount.h"
#include "kptdatetime.h"
#include "Help.h"
#include "kptdebug.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace KPlato
{
AccountseditorConfigDialog::AccountseditorConfigDialog( ViewBase *view, AccountTreeView *treeview, QWidget *p, bool selectPrint)
: KPageDialog(p),
m_view( view ),
m_treeview( treeview )
{
setWindowTitle( i18n("Settings") );
QTabWidget *tab = new QTabWidget();
QWidget *w = ViewBase::createPageLayoutWidget( view );
tab->addTab( w, w->windowTitle() );
m_pagelayout = w->findChild();
Q_ASSERT( m_pagelayout );
m_headerfooter = ViewBase::createHeaderFooterWidget( view );
m_headerfooter->setOptions( view->printingOptions() );
tab->addTab( m_headerfooter, m_headerfooter->windowTitle() );
KPageWidgetItem *page = addPage( tab, i18n( "Printing" ) );
page->setHeader( i18n( "Printing Options" ) );
if (selectPrint) {
setCurrentPage(page);
}
connect( this, &QDialog::accepted, this, &AccountseditorConfigDialog::slotOk);
}
void AccountseditorConfigDialog::slotOk()
{
debugPlan;
m_view->setPageLayout( m_pagelayout->pageLayout() );
m_view->setPrintingOptions( m_headerfooter->options() );
}
//--------------------
AccountTreeView::AccountTreeView( QWidget *parent )
: TreeViewBase( parent )
{
setDragPixmap(koIcon("account").pixmap(32));
header()->setContextMenuPolicy( Qt::CustomContextMenu );
setModel( new AccountItemModel( this ) );
setSelectionModel( new QItemSelectionModel( model() ) );
setSelectionMode( QAbstractItemView::ExtendedSelection );
// setSelectionBehavior( QAbstractItemView::SelectRows );
connect( header(), SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotHeaderContextMenuRequested(QPoint)) );
}
void AccountTreeView::slotHeaderContextMenuRequested( const QPoint &pos )
{
debugPlan<logicalIndexAt(pos)<<" at"<pos()), event->globalPos() );
}
void AccountTreeView::selectionChanged( const QItemSelection &sel, const QItemSelection &desel )
{
debugPlan<selectedIndexes() ) {
debugPlan<selectedIndexes() );
}
void AccountTreeView::currentChanged( const QModelIndex & current, const QModelIndex & previous )
{
debugPlan;
QTreeView::currentChanged( current, previous );
emit currentChanged( current );
// possible bug in qt: in QAbstractItemView::SingleSelection you can select multiple items/rows
selectionModel()->select( current, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
}
Account *AccountTreeView::currentAccount() const
{
return model()->account( currentIndex() );
}
Account *AccountTreeView::selectedAccount() const
{
QModelIndexList lst = selectionModel()->selectedRows();
if ( lst.count() == 1 ) {
return model()->account( lst.first() );
}
return 0;
}
QList AccountTreeView::selectedAccounts() const
{
QList lst;
foreach ( const QModelIndex &i, selectionModel()->selectedRows() ) {
Account *a = model()->account( i );
if ( a ) {
lst << a;
}
}
return lst;
}
//-----------------------------------
AccountsEditor::AccountsEditor(KoPart *part, KoDocument *doc, QWidget *parent)
: ViewBase(part, doc, parent)
{
- setXMLFile("AccountsEditorUi.rc");
+ if (doc && doc->isReadWrite()) {
+ setXMLFile("AccountsEditorUi.rc");
+ } else {
+ setXMLFile("AccountsEditorUi_readonly.rc");
+ }
+
setupGui();
QVBoxLayout * l = new QVBoxLayout( this );
l->setMargin( 0 );
m_view = new AccountTreeView( this );
connect(this, &ViewBase::expandAll, m_view, &TreeViewBase::slotExpand);
connect(this, &ViewBase::collapseAll, m_view, &TreeViewBase::slotCollapse);
l->addWidget( m_view );
m_view->setEditTriggers( m_view->editTriggers() | QAbstractItemView::EditKeyPressed );
m_view->setDragDropMode(QAbstractItemView::DragOnly);
m_view->setDropIndicatorShown( false );
m_view->setDragEnabled ( true );
m_view->setAcceptDrops( false );
m_view->setAcceptDropsOnView( false );
connect( model(), &ItemModelBase::executeCommand, doc, &KoDocument::addCommand );
connect( m_view, SIGNAL(currentChanged(QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex)) );
connect( m_view, SIGNAL(selectionChanged(QModelIndexList)), this, SLOT(slotSelectionChanged(QModelIndexList)) );
connect( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint)), this, SLOT(slotContextMenuRequested(QModelIndex,QPoint)) );
connect( m_view, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) );
Help::add(this,
xi18nc("@info:whatsthis",
"Cost Breakdown Structure Editor"
""
"The Cost Breakdown Structure (CBS) consists of accounts"
" organized into a tree structure."
" Accounts can be tied to tasks or resources."
" Usually there will be two top accounts, one for aggregating costs from tasks"
" and one for aggregating costs from resources."
""
"This view supports printing using the context menu."
"More..."
"", Help::page("Manual/Cost_Breakdown_Structure_Editor")));
}
void AccountsEditor::updateReadWrite( bool readwrite )
{
m_view->setReadWrite( readwrite );
}
void AccountsEditor::draw( Project &project )
{
m_view->setProject( &project );
}
void AccountsEditor::draw()
{
}
void AccountsEditor::setGuiActive( bool activate )
{
debugPlan<currentIndex().isValid() ) {
m_view->selectionModel()->setCurrentIndex(m_view->model()->index( 0, 0 ), QItemSelectionModel::NoUpdate);
}
slotSelectionChanged( m_view->selectionModel()->selectedRows() );
}
}
void AccountsEditor::slotContextMenuRequested( const QModelIndex &index, const QPoint& pos )
{
debugPlan<setContextMenuIndex(index);
slotHeaderContextMenuRequested( pos );
m_view->setContextMenuIndex(QModelIndex());
}
void AccountsEditor::slotHeaderContextMenuRequested( const QPoint &pos )
{
debugPlan;
QList lst = contextActionList();
if ( ! lst.isEmpty() ) {
QMenu::exec( lst, pos, lst.first() );
}
}
Account *AccountsEditor::currentAccount() const
{
return m_view->currentAccount();
}
void AccountsEditor::slotCurrentChanged( const QModelIndex &curr )
{
debugPlan< lst = m_view->selectedAccounts();
bool one = lst.count() == 1;
bool more = lst.count() > 1;
actionAddAccount->setEnabled( on && !more );
actionAddSubAccount->setEnabled( on && one );
bool baselined = project() ? project()->isBaselined() : false;
actionDeleteSelection->setEnabled( on && one && ! baselined );
}
void AccountsEditor::setupGui()
{
actionAddAccount = new QAction(koIcon("document-new"), i18n("Add Account"), this);
actionCollection()->addAction("add_account", actionAddAccount );
actionCollection()->setDefaultShortcut(actionAddAccount, Qt::CTRL + Qt::Key_I);
connect( actionAddAccount, &QAction::triggered, this, &AccountsEditor::slotAddAccount );
actionAddSubAccount = new QAction(koIcon("document-new"), i18n("Add Subaccount"), this);
actionCollection()->addAction("add_subaccount", actionAddSubAccount );
actionCollection()->setDefaultShortcut(actionAddSubAccount, Qt::SHIFT + Qt::CTRL + Qt::Key_I);
connect( actionAddSubAccount, &QAction::triggered, this, &AccountsEditor::slotAddSubAccount );
actionDeleteSelection = new QAction(koIcon("edit-delete"), i18nc("@action", "Delete"), this);
actionCollection()->addAction("delete_selection", actionDeleteSelection );
actionCollection()->setDefaultShortcut(actionDeleteSelection, Qt::Key_Delete);
connect( actionDeleteSelection, &QAction::triggered, this, &AccountsEditor::slotDeleteSelection );
createOptionActions(ViewBase::OptionExpand | ViewBase::OptionCollapse | ViewBase::OptionPrint | ViewBase::OptionPrintPreview | ViewBase::OptionPrintPdf | ViewBase::OptionPrintConfig);
}
void AccountsEditor::slotOptions()
{
debugPlan;
AccountseditorConfigDialog *dlg = new AccountseditorConfigDialog( this, m_view, this );
connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int)));
dlg->open();
}
void AccountsEditor::slotAddAccount()
{
debugPlan;
int row = -1;
Account *parent = m_view->selectedAccount(); // sibling
if ( parent ) {
row = parent->parent() ? parent->parent()->indexOf( parent ) : project()->accounts().indexOf( parent );
if ( row >= 0 ) {
++row;
}
parent = parent->parent();
}
insertAccount( new Account(), parent, row );
}
void AccountsEditor::slotAddSubAccount()
{
debugPlan;
insertAccount( new Account(), m_view->selectedAccount(), -1 );
}
void AccountsEditor::insertAccount( Account *account, Account *parent, int row )
{
m_view->closePersistentEditor( m_view->selectionModel()->currentIndex() );
QModelIndex i = m_view->model()->insertAccount( account, parent, row );
if ( i.isValid() ) {
QModelIndex p = m_view->model()->parent( i );
if (parent) debugPlan<<" parent="<name()<<":"<setExpanded( p, true );
}
m_view->selectionModel()->select( i, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect );
m_view->selectionModel()->setCurrentIndex( i, QItemSelectionModel::NoUpdate );
m_view->edit( i );
}
}
void AccountsEditor::slotDeleteSelection()
{
debugPlan;
m_view->model()->removeAccounts( m_view->selectedAccounts() );
}
void AccountsEditor::slotAccountsOk()
{
debugPlan<<"Account Editor : slotAccountsOk";
//QModelList
//QModelIndex i = m_view->model()->insertGroup( g );
}
KoPrintJob *AccountsEditor::createPrintJob()
{
return m_view->createPrintJob( this );
}
bool AccountsEditor::loadContext(const KoXmlElement &context)
{
m_view->loadContext(model()->columnMap(), context);
return true;
}
void AccountsEditor::saveContext(QDomElement &context) const
{
m_view->saveContext(model()->columnMap(), context);
}
void AccountsEditor::slotEditCopy()
{
m_view->editCopy();
}
} // namespace KPlato
diff --git a/src/libs/ui/kptcalendareditor.cpp b/src/libs/ui/kptcalendareditor.cpp
index d4023fd0..b813847d 100644
--- a/src/libs/ui/kptcalendareditor.cpp
+++ b/src/libs/ui/kptcalendareditor.cpp
@@ -1,864 +1,869 @@
/* This file is part of the KDE project
* Copyright (C) 2007, 2012 Dag Andersen
* Copyright (C) 2017 Dag Andersen
+ * Copyright (C) 2019 Dag Andersen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
// clazy:excludeall=qstring-arg
#include "kptcalendareditor.h"
#include "kcalendar/kdatepicker.h"
#include "kcalendar/kdatetable.h"
//#include "kptcalendarpanel.h"
#include "kptcommand.h"
#include "kptcalendarmodel.h"
#include "kptcalendar.h"
#include "kptduration.h"
#include "kptnode.h"
#include "kptproject.h"
#include "kpttask.h"
#include "kptdatetime.h"
#include "kptintervaledit.h"
#include "kptitemviewsettup.h"
#include "Help.h"
#include "kptdebug.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace KPlato
{
//--------------------
CalendarTreeView::CalendarTreeView( QWidget *parent )
: TreeViewBase( parent )
{
header()->setContextMenuPolicy( Qt::CustomContextMenu );
setModel( new CalendarItemModel() );
setSelectionBehavior( QAbstractItemView::SelectRows );
setSelectionMode( QAbstractItemView::SingleSelection );
setSelectionModel( new QItemSelectionModel( model() ) );
setItemDelegateForColumn( CalendarItemModel::Scope, new EnumDelegate( this ) );
setItemDelegateForColumn( CalendarItemModel::TimeZone, new EnumDelegate( this ) ); // timezone
#ifdef HAVE_KHOLIDAYS
setItemDelegateForColumn( CalendarItemModel::HolidayRegion, new EnumDelegate( this ) );
#endif
connect( header(), SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotHeaderContextMenuRequested(QPoint)) );
}
void CalendarTreeView::slotHeaderContextMenuRequested( const QPoint &pos )
{
emit contextMenuRequested(QModelIndex(), mapToGlobal(pos));
}
void CalendarTreeView::contextMenuEvent ( QContextMenuEvent *event )
{
emit contextMenuRequested( indexAt(event->pos()), event->globalPos() );
}
void CalendarTreeView::focusInEvent ( QFocusEvent *event )
{
//debugPlan;
TreeViewBase::focusInEvent( event );
emit focusChanged();
}
void CalendarTreeView::focusOutEvent ( QFocusEvent * event )
{
//debugPlan;
TreeViewBase::focusInEvent( event );
emit focusChanged();
}
void CalendarTreeView::selectionChanged( const QItemSelection &sel, const QItemSelection &desel )
{
//debugPlan<selectedIndexes() ) { debugPlan<selectedIndexes() );
}
void CalendarTreeView::currentChanged( const QModelIndex & current, const QModelIndex & previous )
{
//debugPlan;
TreeViewBase::currentChanged( current, previous );
// possible bug in qt: in QAbstractItemView::SingleSelection you can select multiple items/rows
selectionModel()->select( current, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
emit currentChanged( current );
}
Calendar *CalendarTreeView::currentCalendar() const
{
return model()->calendar( currentIndex() );
}
Calendar *CalendarTreeView::selectedCalendar() const
{
QModelIndexList lst = selectionModel()->selectedRows();
if ( lst.count() == 1 ) {
return model()->calendar( lst.first() );
}
return 0;
}
QList CalendarTreeView::selectedCalendars() const
{
QList lst;
foreach ( const QModelIndex &i, selectionModel()->selectedRows() ) {
Calendar *a = model()->calendar( i );
if ( a ) {
lst << a;
}
}
return lst;
}
void CalendarTreeView::dragMoveEvent(QDragMoveEvent *event)
{
if (dragDropMode() == InternalMove && (event->source() != this || !(event->possibleActions() & Qt::MoveAction))) {
return;
}
TreeViewBase::dragMoveEvent( event );
if ( ! event->isAccepted() ) {
return;
}
// QTreeView thinks it's ok to drop, but it might not be...
event->ignore();
QModelIndex index = indexAt( event->pos() );
if ( ! index.isValid() ) {
if ( model()->dropAllowed( 0, event->mimeData() ) ) {
event->accept();
}
return;
}
Calendar *c = model()->calendar( index );
if ( c == 0 ) {
errorPlan<<"no calendar to drop on!";
return; // hmmm
}
switch ( dropIndicatorPosition() ) {
case AboveItem:
case BelowItem:
// c == sibling
// if siblings parent is me or child of me: illegal
if ( model()->dropAllowed( c->parentCal(), event->mimeData() ) ) {
event->accept();
}
break;
case OnItem:
// c == new parent
if ( model()->dropAllowed( c, event->mimeData() ) ) {
event->accept();
}
break;
default:
break;
}
}
//--------------------
CalendarDayView::CalendarDayView( QWidget *parent )
: QTableView( parent ),
m_readwrite( false )
{
setTabKeyNavigation( false );
setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
horizontalHeader()->setSectionResizeMode( QHeaderView::Stretch );
m_model = new CalendarDayItemModel( this );
setModel(m_model);
verticalHeader()->hide();
actionSetWork = new QAction( i18n( "Work..." ), this );
connect( actionSetWork, &QAction::triggered, this, &CalendarDayView::slotSetWork );
actionSetVacation = new QAction( i18n( "Non-working" ), this );
connect( actionSetVacation, &QAction::triggered, this, &CalendarDayView::slotSetVacation );
actionSetUndefined = new QAction( i18n( "Undefined" ), this );
connect( actionSetUndefined, &QAction::triggered, this, &CalendarDayView::slotSetUndefined );
}
QSize CalendarDayView::sizeHint() const
{
QSize s = QTableView::sizeHint();
s.setHeight( horizontalHeader()->height() + rowHeight( 0 ) + frameWidth() * 2 );
return s;
}
void CalendarDayView::slotSetWork()
{
debugPlan;
if ( receivers( SIGNAL(executeCommand(KUndo2Command*)) ) == 0 ) {
return;
}
Calendar *cal = model()->calendar();
if ( cal == 0 ) {
return;
}
QModelIndexList lst = selectionModel()->selectedIndexes();
if ( lst.isEmpty() ) {
lst << currentIndex();
}
if ( lst.isEmpty() ) {
return;
}
QList days;
foreach ( const QModelIndex &i, lst ) {
CalendarDay *day = model()->day( i );
if ( day == 0 ) {
continue;
}
days << day;
}
IntervalEditDialog *dlg = new IntervalEditDialog( cal, days, this );
connect(dlg, SIGNAL(finished(int)), SLOT(slotIntervalEditDialogFinished(int)));
dlg->open();
}
void CalendarDayView::slotIntervalEditDialogFinished( int result )
{
IntervalEditDialog *dlg = qobject_cast( sender() );
if ( dlg == 0 ) {
return;
}
if ( result == QDialog::Accepted ) {
MacroCommand *cmd = dlg->buildCommand();
if ( cmd ) {
emit executeCommand( cmd );
}
}
dlg->deleteLater();
}
void CalendarDayView::slotSetVacation()
{
debugPlan;
if ( receivers( SIGNAL(executeCommand(KUndo2Command*)) ) == 0 ) {
return;
}
QModelIndexList lst = selectionModel()->selectedIndexes();
if ( lst.isEmpty() ) {
lst << currentIndex();
}
if ( lst.isEmpty() ) {
return;
}
bool mod = false;
MacroCommand *m = new MacroCommand( kundo2_i18n( "Modify Weekday State" ) );
foreach ( const QModelIndex &i, lst ) {
CalendarDay *day = model()->day( i );
if ( day == 0 || day->state() == CalendarDay::NonWorking ) {
continue;
}
mod = true;
m->addCommand( new CalendarModifyStateCmd( model()->calendar(), day, CalendarDay::NonWorking ) );
}
if ( mod ) {
emit executeCommand( m );
} else {
delete m;
}
}
void CalendarDayView::slotSetUndefined()
{
debugPlan;
if ( receivers( SIGNAL(executeCommand(KUndo2Command*)) ) == 0 ) {
return;
}
QModelIndexList lst = selectionModel()->selectedIndexes();
if ( lst.isEmpty() ) {
lst << currentIndex();
}
if ( lst.isEmpty() ) {
return;
}
bool mod = false;
MacroCommand *m = new MacroCommand( kundo2_i18n( "Modify Weekday State" ) );
foreach ( const QModelIndex &i, lst ) {
CalendarDay *day = model()->day( i );
if ( day == 0 || day->state() == CalendarDay::Undefined ) {
continue;
}
mod = true;
m->addCommand( new CalendarModifyStateCmd( model()->calendar(), day, CalendarDay::Undefined ) );
}
if ( mod ) {
emit executeCommand( m );
} else {
delete m;
}
}
void CalendarDayView::setCurrentCalendar( Calendar *calendar )
{
model()->setCalendar( calendar );
}
void CalendarDayView::contextMenuEvent ( QContextMenuEvent *event )
{
//debugPlan;
if ( !isReadWrite() || !model()->calendar() || model()->calendar()->isShared() ) {
return;
}
QMenu menu;
menu.addAction( actionSetWork );
menu.addAction( actionSetVacation );
menu.addAction( actionSetUndefined );
menu.exec( event->globalPos(), actionSetWork );
//emit contextMenuRequested( indexAt(event->pos()), event->globalPos() );
}
void CalendarDayView::focusInEvent ( QFocusEvent *event )
{
//debugPlan;
QTableView::focusInEvent( event );
emit focusChanged();
}
void CalendarDayView::focusOutEvent ( QFocusEvent * event )
{
//debugPlan;
QTableView::focusInEvent( event );
emit focusChanged();
}
void CalendarDayView::selectionChanged( const QItemSelection &sel, const QItemSelection &desel )
{
//debugPlan<selectedIndexes() ) { debugPlan<selectedIndexes() );
}
void CalendarDayView::currentChanged( const QModelIndex & current, const QModelIndex & previous )
{
//debugPlan;
QTableView::currentChanged( current, previous );
// selectionModel()->select( current, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
emit currentChanged( current );
}
CalendarDay *CalendarDayView::selectedDay() const
{
QModelIndexList lst = selectionModel()->selectedIndexes();
if ( lst.count() == 1 ) {
return model()->day( lst.first() );
}
return 0;
}
//-----------------------------------
CalendarEditor::CalendarEditor(KoPart *part, KoDocument *doc, QWidget *parent )
: ViewBase(part, doc, parent ),
m_model( new DateTableDataModel( this ) )
{
- setXMLFile("CalendarEditorUi.rc");
+ if (doc && doc->isReadWrite()) {
+ setXMLFile("CalendarEditorUi.rc");
+ } else {
+ setXMLFile("CalendarEditorUi_readonly.rc");
+ }
Help::add(this,
xi18nc( "@info:whatsthis",
"Work & Vacation Editor"
""
"A calendar defines availability for resources or tasks of type Duration. "
"A calendar can be specific to a resource or task, or shared by multiple resources or tasks. "
"A day can be of type Undefined, Non-working day or Working day. "
"A working day has one or more work intervals defined. "
""
"A calendar can have sub calendars. If a day is undefined in a calendar, the parent calendar is checked. "
"An Undefined day defaults to Non-working if used by a resource, or available all day if used by a task."
""
"A calendar can be defined as the Default calendar. "
"The default calendar is used by a working resource, when the resources calendar is not explicitly set."
"More..."
"", Help::page("Manual/Work_and_Vacation_Editor")));
setupGui();
QVBoxLayout *l = new QVBoxLayout( this );
l->setMargin( 0 );
QSplitter *sp = new QSplitter( this );
l->addWidget( sp );
m_calendarview = new CalendarTreeView( sp );
connect(this, &ViewBase::expandAll, m_calendarview, &TreeViewBase::slotExpand);
connect(this, &ViewBase::collapseAll, m_calendarview, &TreeViewBase::slotCollapse);
QFrame *f = new QFrame( sp );
l = new QVBoxLayout( f );
l->setMargin( 0 );
m_dayview = new CalendarDayView( f );
l->addWidget( m_dayview );
sp = new QSplitter( f );
l->addWidget( sp );
m_datePicker = new KDatePicker( sp );
m_datePicker->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
m_datePicker->dateTable()->setWeekNumbersEnabled( true );
m_datePicker->dateTable()->setGridEnabled( true );
m_datePicker->dateTable()->setSelectionMode( KDateTable::ExtendedSelection );
m_datePicker->dateTable()->setDateDelegate( new DateTableDateDelegate( m_datePicker->dateTable() ) );
m_datePicker->dateTable()->setModel( m_model );
m_datePicker->dateTable()->setPopupMenuEnabled( true );
m_calendarview->setDragDropMode( QAbstractItemView::InternalMove );
m_calendarview->setDropIndicatorShown( true );
m_calendarview->setDragEnabled ( true );
m_calendarview->setAcceptDrops( true );
m_calendarview->setAcceptDropsOnView( true );
connect( m_datePicker->dateTable(), SIGNAL(aboutToShowContextMenu(QMenu*,QDate)), SLOT(slotContextMenuDate(QMenu*,QDate)) );
connect( m_datePicker->dateTable(), SIGNAL(aboutToShowContextMenu(QMenu*,QList)), SLOT(slotContextMenuDate(QMenu*,QList)) );
/* const QDate date(2007,7,19);
const QColor fgColor(Qt::darkGray);
KDateTable::BackgroundMode bgMode = KDateTable::CircleMode;
const QColor bgColor( Qt::lightGray);
m_datePicker->dateTable()->setCustomDatePainting( date, fgColor, bgMode, bgColor );*/
m_calendarview->setEditTriggers( m_calendarview->editTriggers() | QAbstractItemView::EditKeyPressed );
m_dayview->setEditTriggers( m_dayview->editTriggers() | QAbstractItemView::EditKeyPressed );
m_calendarview->setDragDropMode( QAbstractItemView::InternalMove );
m_calendarview->setDropIndicatorShown ( true );
m_calendarview->setDragEnabled ( true );
m_calendarview->setAcceptDrops( true );
connect( m_calendarview->model(), &ItemModelBase::executeCommand, doc, &KoDocument::addCommand );
connect( m_dayview->model(), &ItemModelBase::executeCommand, doc, &KoDocument::addCommand );
connect( m_dayview, &CalendarDayView::executeCommand, doc, &KoDocument::addCommand );
connect( m_calendarview, SIGNAL(currentChanged(QModelIndex)), this, SLOT(slotCurrentCalendarChanged(QModelIndex)) );
connect( m_calendarview, &CalendarTreeView::sigSelectionChanged, this, &CalendarEditor::slotCalendarSelectionChanged );
connect( m_calendarview, SIGNAL(contextMenuRequested(QModelIndex,QPoint)), this, SLOT(slotContextMenuCalendar(QModelIndex,QPoint)) );
connect( m_dayview, SIGNAL(currentChanged(QModelIndex)), this, SLOT(slotCurrentDayChanged(QModelIndex)) );
connect( m_dayview, &CalendarDayView::sigSelectionChanged, this, &CalendarEditor::slotDaySelectionChanged );
connect( m_dayview, &CalendarDayView::contextMenuRequested, this, &CalendarEditor::slotContextMenuDay );
connect( m_dayview->model(), &QAbstractItemModel::dataChanged, this, &CalendarEditor::slotEnableActions );
connect( m_calendarview, &CalendarTreeView::focusChanged, this, &CalendarEditor::slotEnableActions );
connect( m_dayview, &CalendarDayView::focusChanged, this, &CalendarEditor::slotEnableActions );
}
void CalendarEditor::draw( Project &project )
{
m_calendarview->setProject( &project );
m_dayview->setProject( &project );
}
void CalendarEditor::draw()
{
}
void CalendarEditor::setGuiActive( bool activate )
{
//debugPlan<currentIndex().isValid() ) {
m_calendarview->selectionModel()->setCurrentIndex(m_calendarview->model()->index( 0, 0 ), QItemSelectionModel::NoUpdate);
}
//slotSelectionChanged( m_calendarview->selectionModel()->selectedRows() );
}
}
void CalendarEditor::slotContextMenuDate( QMenu *menu, const QList &dates )
{
if ( ! isReadWrite() ) {
return;
}
if (!currentCalendar() || currentCalendar()->isShared()) {
return;
}
if ( dates.isEmpty() ) {
m_currentMenuDateList << m_datePicker->date();
} else {
m_currentMenuDateList = dates;
}
menu->addAction( actionSetWork );
menu->addAction( actionSetVacation );
menu->addAction( actionSetUndefined );
}
void CalendarEditor::slotContextMenuDate( QMenu *menu, const QDate &date )
{
debugPlan<