File indexing completed on 2024-04-21 05:54:01

0001 /*
0002     This file is part of the Okteta program, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2006-2011 Friedrich W. H. Kossebau <kossebau@kde.org>
0005 
0006     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0007 */
0008 
0009 #include "mainwindow.hpp"
0010 
0011 // program
0012 #include "program.hpp"
0013 // tmp
0014 #include <Kasten/Okteta/ByteArrayViewProfileManager>
0015 // tools
0016 #include <Kasten/Okteta/StringsExtractToolViewFactory>
0017 #include <Kasten/Okteta/StringsExtractToolFactory>
0018 #include <Kasten/Okteta/InfoToolViewFactory>
0019 #include <Kasten/Okteta/InfoToolFactory>
0020 #include <Kasten/Okteta/FilterToolViewFactory>
0021 #include <Kasten/Okteta/FilterToolFactory>
0022 #include <Kasten/Okteta/CharsetConversionToolViewFactory>
0023 #include <Kasten/Okteta/CharsetConversionToolFactory>
0024 #include <Kasten/Okteta/ChecksumToolViewFactory>
0025 #include <Kasten/Okteta/ChecksumToolFactory>
0026 #include <Kasten/Okteta/DocumentInfoToolViewFactory>
0027 #include <Kasten/Okteta/DocumentInfoToolFactory>
0028 #include <Kasten/Okteta/PODDecoderToolViewFactory>
0029 #include <Kasten/Okteta/PODDecoderToolFactory>
0030 #include <Kasten/Okteta/ByteTableToolViewFactory>
0031 #include <Kasten/Okteta/ByteTableToolFactory>
0032 #include <Kasten/Okteta/BookmarksToolViewFactory>
0033 #include <Kasten/Okteta/BookmarksToolFactory>
0034 #include <Kasten/Okteta/StructuresToolViewFactory>
0035 #include <Kasten/Okteta/StructuresToolFactory>
0036 
0037 // Kasten tools
0038 #include <Kasten/VersionViewToolViewFactory>
0039 #include <Kasten/VersionViewToolFactory>
0040 #include <Kasten/FileSystemBrowserToolViewFactory>
0041 #include <Kasten/FileSystemBrowserToolFactory>
0042 #include <Kasten/DocumentsToolViewFactory>
0043 #include <Kasten/DocumentsToolFactory>
0044 #include <Kasten/TerminalToolViewFactory>
0045 #include <Kasten/TerminalToolFactory>
0046 // controllers
0047 // #include <Kasten/Okteta/OverwriteOnlyControllerFactory>
0048 #include <Kasten/Okteta/OverwriteModeControllerFactory>
0049 #include <Kasten/Okteta/GotoOffsetControllerFactory>
0050 #include <Kasten/Okteta/SelectRangeControllerFactory>
0051 #include <Kasten/Okteta/SearchControllerFactory>
0052 #include <Kasten/Okteta/ReplaceControllerFactory>
0053 #include <Kasten/Okteta/BookmarksControllerFactory>
0054 #include <Kasten/Okteta/PrintControllerFactory>
0055 #include <Kasten/Okteta/ViewConfigControllerFactory>
0056 #include <Kasten/Okteta/ViewModeControllerFactory>
0057 #include <Kasten/Okteta/ViewContextMenuControllerFactory>
0058 #include <Kasten/Okteta/ViewStatusControllerFactory>
0059 #include <Kasten/Okteta/ViewProfileControllerFactory>
0060 #include <Kasten/Okteta/ViewProfilesManageControllerFactory>
0061 // Kasten controllers
0062 #include <Kasten/ModifiedBarControllerFactory>
0063 #include <Kasten/ReadOnlyControllerFactory>
0064 #include <Kasten/ReadOnlyBarControllerFactory>
0065 #include <Kasten/CreatorControllerFactory>
0066 #include <Kasten/LoaderControllerFactory>
0067 #include <Kasten/CloseControllerFactory>
0068 #include <Kasten/SetRemoteControllerFactory>
0069 #include <Kasten/SynchronizeControllerFactory>
0070 #include <Kasten/ClipboardControllerFactory>
0071 #include <Kasten/InsertControllerFactory>
0072 #include <Kasten/CopyAsControllerFactory>
0073 #include <Kasten/ExportControllerFactory>
0074 #include <Kasten/VersionControllerFactory>
0075 #include <Kasten/ZoomControllerFactory>
0076 #include <Kasten/ZoomBarControllerFactory>
0077 #include <Kasten/SelectControllerFactory>
0078 #include <Kasten/ViewAreaContextMenuControllerFactory>
0079 #include <Kasten/SwitchViewControllerFactory>
0080 #include <Kasten/ViewListMenuControllerFactory>
0081 #include <Kasten/ViewAreaSplitControllerFactory>
0082 #include <Kasten/ToolListMenuControllerFactory>
0083 #include <Kasten/FullScreenControllerFactory>
0084 #include <Kasten/UiColorSchemeControllerFactory>
0085 #include <Kasten/QuitControllerFactory>
0086 // Kasten gui
0087 #include <Kasten/MultiDocumentStrategy>
0088 #include <Kasten/ModelCodecViewManager>
0089 #include <Kasten/ViewManager>
0090 #include <Kasten/MultiViewAreas>
0091 #include <Kasten/StatusBar>
0092 // Kasten core
0093 #include <Kasten/ModelCodecManager>
0094 #include <Kasten/DocumentCreateManager>
0095 #include <Kasten/DocumentSyncManager>
0096 #include <Kasten/DocumentManager>
0097 // KF
0098 #include <KConfigGroup>
0099 #include <KSharedConfig>
0100 // Qt
0101 #include <QUrl>
0102 #include <QMimeData>
0103 
0104 namespace Kasten {
0105 
0106 static constexpr char LoadedUrlsKey[] = "LoadedUrls";
0107 
0108 OktetaMainWindow::OktetaMainWindow(OktetaProgram* program)
0109     : ShellWindow(program->viewManager())
0110     , mProgram(program)
0111 {
0112     setObjectName(QStringLiteral("Shell"));
0113 
0114     // there is only one mainwindow, so have this show the document if requested
0115     connect(mProgram->documentManager(), &DocumentManager::focusRequested,
0116             this, &OktetaMainWindow::showDocument);
0117     connect(viewArea(), &MultiViewAreas::dataOffered,
0118             this, &OktetaMainWindow::onDataOffered);
0119     connect(viewArea(), &MultiViewAreas::dataDropped,
0120             this, &OktetaMainWindow::onDataDropped);
0121     connect(viewArea(), &MultiViewAreas::newDocumentRequested,
0122             this, &OktetaMainWindow::onNewDocumentRequested);
0123     connect(viewArea(), &AbstractGroupedViews::closeRequest,
0124             this, &OktetaMainWindow::onCloseRequest);
0125 
0126 // Using State value as generated with Qt 5.15.11-KDE
0127 #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 11)
0128     // XXX: Workaround for Qt 4.4's lacking of proper handling of the initial layout of dock widgets
0129     //      This state is taken from an oktetarc where the docker constellation was configured by hand.
0130     //      Setting this state if none is present seems to work, but there's
0131     //      still the versioning problem to be accounted for.
0132     //      Hack borrowed from trunk/koffice/krita/ui/kis_view2.cpp:
0133     const QString mainWindowState = QStringLiteral(
0134         "AAAA/wAAAAD9AAAAAwAAAAAAAAEVAAACLvwCAAAAAfwAAABLAAACLgAAAI8BAAAd+gAAAAABAAAAAvsAAAAiAEYAaQBsAGUAUwB5AHMAdABlAG0AQgByAG8AdwBzAGUAcgEAAAAA/////wAAAGQA////+wAAABIARABvAGMAdQBtAGUAbgB0AHMBAAAAAP////8AAABcAP///wAAAAEAAAHhAAACLvwCAAAABfsAAAAUAFMAdAByAHUAYwB0AFQAbwBvAGwDAAACjQAAAPwAAAIyAAABT/sAAAAQAFYAZQByAHMAaQBvAG4AcwAAAAA2AAAAiQAAAAAAAAAA/AAAAEsAAAEqAAABKgEAAB36AAAAAQEAAAAH+wAAABgARABvAGMAdQBtAGUAbgB0AEkAbgBmAG8BAAAAAP////8AAACMAP////sAAAASAEIAeQB0AGUAVABhAGIAbABlAQAAAAD/////AAAAXAD////7AAAADgBTAHQAcgBpAG4AZwBzAQAAAAD/////AAAAiQD////7AAAAEABDAGgAZQBjAGsAcwB1AG0BAAAAAP////8AAAEFAP////sAAAAcAFMAdAByAHUAYwB0AHUAcgBlAHMAVABvAG8AbAEAAAAA/////wAAAJkA////+wAAABQAUwB0AHIAdQBjAHQAVABvAG8AbAMAAAKNAAAA/AAAAjIAAAFP+wAAABQAUABPAEQARABlAGMAbwBkAGUAcgEAAAAA/////wAAAJQA/////AAAAQsAAADsAAAAAAD////6AAAAAAEAAAAB+wAAABAAQwBoAGUAYwBrAFMAdQBtAQAAAAD/////AAAAAAAAAAD8AAABdgAAAQMAAAEDAQAAHfoAAAAAAQAAAAT7AAAAGABCAGkAbgBhAHIAeQBGAGkAbAB0AGUAcgEAAAAA/////wAAAVMA////+wAAACIAQwBoAGEAcgBzAGUAdABDAG8AbgB2AGUAcgBzAGkAbwBuAQAAAAD/////AAABRAD////7AAAACABJAG4AZgBvAQAAAAD/////AAAAiQD////7AAAAEgBCAG8AbwBrAG0AYQByAGsAcwEAAAAA/////wAAAFwA////AAAAAwAABVYAAABC/AEAAAAB+wAAABAAVABlAHIAbQBpAG4AYQBsAAAAAAAAAAVWAAAAXAD///8AAADlAAACLgAAAAQAAAAEAAAACAAAAAj8AAAAAQAAAAIAAAABAAAAFgBtAGEAaQBuAFQAbwBvAGwAQgBhAHIBAAAAAAAABAYAAAAAAAAAAA==");
0135     const char mainWindowStateKey[] = "State";
0136     KConfigGroup group(KSharedConfig::openConfig(), QStringLiteral("MainWindow"));
0137     if (!group.hasKey(mainWindowStateKey)) {
0138         group.writeEntry(mainWindowStateKey, mainWindowState);
0139     }
0140 #endif
0141 
0142     setStatusBar(new Kasten::StatusBar(this));
0143 
0144     setupControllers();
0145     setupGUI();
0146 
0147     // all controllers which use plugActionList have to do so after(!) setupGUI() or their entries will be removed
0148     // TODO: why is this so?
0149     // tmp
0150     addXmlGuiControllerFromFactory(ToolListMenuControllerFactory(this));
0151     addXmlGuiControllerFromFactory(ViewListMenuControllerFactory(viewManager(), viewArea()));
0152 }
0153 
0154 OktetaMainWindow::~OktetaMainWindow() = default;
0155 
0156 void OktetaMainWindow::setupControllers()
0157 {
0158     MultiDocumentStrategy* const documentStrategy = mProgram->documentStrategy();
0159     ViewManager* const viewManager = this->viewManager();
0160     MultiViewAreas* const viewArea = this->viewArea();
0161     ModelCodecViewManager* const codecViewManager = viewManager->codecViewManager();
0162     DocumentManager* const documentManager = mProgram->documentManager();
0163     ModelCodecManager* const codecManager = documentManager->codecManager();
0164     DocumentSyncManager* const syncManager = documentManager->syncManager();
0165     // tmp
0166     ByteArrayViewProfileManager* const byteArrayViewProfileManager = mProgram->byteArrayViewProfileManager();
0167 
0168     // general, part of Kasten
0169     addXmlGuiControllerFromFactory(CreatorControllerFactory(codecManager, documentStrategy));
0170     addXmlGuiControllerFromFactory(LoaderControllerFactory(documentStrategy));
0171     addXmlGuiControllerFromFactory(SetRemoteControllerFactory(syncManager));
0172     addXmlGuiControllerFromFactory(SynchronizeControllerFactory(syncManager));
0173     addXmlGuiControllerFromFactory(ExportControllerFactory(codecViewManager, codecManager));
0174     addXmlGuiControllerFromFactory(CloseControllerFactory(documentStrategy));
0175     addXmlGuiControllerFromFactory(VersionControllerFactory());
0176     addXmlGuiControllerFromFactory(ReadOnlyControllerFactory());
0177     addXmlGuiControllerFromFactory(ViewAreaContextMenuControllerFactory(viewArea, syncManager));
0178     addXmlGuiControllerFromFactory(SwitchViewControllerFactory(viewArea));
0179     addXmlGuiControllerFromFactory(ViewAreaSplitControllerFactory(viewManager, viewArea));
0180     addXmlGuiControllerFromFactory(FullScreenControllerFactory(this));
0181     addXmlGuiControllerFromFactory(UiColorSchemeControllerFactory(this));
0182     addXmlGuiControllerFromFactory(QuitControllerFactory(this));
0183 
0184     addXmlGuiControllerFromFactory(ZoomControllerFactory());
0185     addXmlGuiControllerFromFactory(SelectControllerFactory());
0186     addXmlGuiControllerFromFactory(ClipboardControllerFactory());
0187     addXmlGuiControllerFromFactory(InsertControllerFactory(codecViewManager, codecManager));
0188     addXmlGuiControllerFromFactory(CopyAsControllerFactory(codecViewManager, codecManager));
0189 
0190     addToolFromFactory(FileSystemBrowserToolViewFactory(), FileSystemBrowserToolFactory(syncManager));
0191     addToolFromFactory(DocumentsToolViewFactory(), DocumentsToolFactory(documentManager));
0192     addToolFromFactory(TerminalToolViewFactory(), TerminalToolFactory(syncManager));
0193 #ifndef NDEBUG
0194     addToolFromFactory(VersionViewToolViewFactory(), VersionViewToolFactory());
0195 #endif
0196 
0197     // Okteta specific
0198 //     addXmlGuiControllerFromFactory(OverwriteOnlyControllerFactory() );
0199     addXmlGuiControllerFromFactory(OverwriteModeControllerFactory());
0200     addXmlGuiControllerFromFactory(SearchControllerFactory(this));
0201     addXmlGuiControllerFromFactory(ReplaceControllerFactory(this));
0202     addXmlGuiControllerFromFactory(GotoOffsetControllerFactory(viewArea));
0203     addXmlGuiControllerFromFactory(SelectRangeControllerFactory(viewArea));
0204     addXmlGuiControllerFromFactory(BookmarksControllerFactory());
0205     addXmlGuiControllerFromFactory(PrintControllerFactory());
0206     addXmlGuiControllerFromFactory(ViewConfigControllerFactory());
0207     addXmlGuiControllerFromFactory(ViewModeControllerFactory());
0208     addXmlGuiControllerFromFactory(ViewContextMenuControllerFactory());
0209     addXmlGuiControllerFromFactory(ViewProfileControllerFactory(byteArrayViewProfileManager, this));
0210     addXmlGuiControllerFromFactory(ViewProfilesManageControllerFactory(byteArrayViewProfileManager, this));
0211 
0212     auto* const bottomBar = static_cast<Kasten::StatusBar*>(statusBar());
0213     addXmlGuiControllerFromFactory(ViewStatusControllerFactory(bottomBar));
0214     addXmlGuiControllerFromFactory(ModifiedBarControllerFactory(bottomBar));
0215     addXmlGuiControllerFromFactory(ReadOnlyBarControllerFactory(bottomBar));
0216     addXmlGuiControllerFromFactory(ZoomBarControllerFactory(bottomBar));
0217 
0218     addToolFromFactory(DocumentInfoToolViewFactory(), DocumentInfoToolFactory(syncManager));
0219     addToolFromFactory(ChecksumToolViewFactory(), ChecksumToolFactory());
0220     addToolFromFactory(FilterToolViewFactory(), FilterToolFactory());
0221     addToolFromFactory(CharsetConversionToolViewFactory(), CharsetConversionToolFactory());
0222     addToolFromFactory(StringsExtractToolViewFactory(), StringsExtractToolFactory());
0223     addToolFromFactory(ByteTableToolViewFactory(), ByteTableToolFactory());
0224     addToolFromFactory(InfoToolViewFactory(), InfoToolFactory());
0225     addToolFromFactory(PodDecoderToolViewFactory(), PodDecoderToolFactory());
0226     addToolFromFactory(StructuresToolViewFactory(), StructuresToolFactory());
0227     addToolFromFactory(BookmarksToolViewFactory(), BookmarksToolFactory());
0228 }
0229 
0230 void OktetaMainWindow::addToolFromFactory(const AbstractToolViewFactory& toolViewFactory,
0231                                           const AbstractToolFactory& toolFactory)
0232 {
0233     AbstractTool* tool = toolFactory.create();
0234     AbstractToolView* toolView = toolViewFactory.create(tool);
0235 
0236     addTool(toolView);
0237 }
0238 
0239 void OktetaMainWindow::addXmlGuiControllerFromFactory(const AbstractXmlGuiControllerFactory& factory)
0240 {
0241     AbstractXmlGuiController* controller = factory.create(this);
0242     addXmlGuiController(controller);
0243 }
0244 
0245 
0246 bool OktetaMainWindow::queryClose()
0247 {
0248     // TODO: query the document manager or query the view manager?
0249     return mProgram->documentManager()->canCloseAll();
0250 }
0251 
0252 void OktetaMainWindow::saveProperties(KConfigGroup& configGroup)
0253 {
0254     DocumentManager* const documentManager = mProgram->documentManager();
0255     DocumentSyncManager* const syncManager = documentManager->syncManager();
0256     const QVector<AbstractDocument*> documents = documentManager->documents();
0257 
0258     QStringList urls;
0259     urls.reserve(documents.size());
0260     for (AbstractDocument* document : documents) {
0261         urls.append(syncManager->urlOf(document).url());
0262     }
0263 
0264     configGroup.writePathEntry(LoadedUrlsKey, urls);
0265 }
0266 
0267 void OktetaMainWindow::readProperties(const KConfigGroup& configGroup)
0268 {
0269     const QStringList urls = configGroup.readPathEntry(LoadedUrlsKey, QStringList());
0270 
0271     DocumentManager* const documentManager = mProgram->documentManager();
0272     DocumentSyncManager* const syncManager = documentManager->syncManager();
0273     DocumentCreateManager* const createManager = documentManager->createManager();
0274     for (const QString& url : urls) {
0275         if (url.isEmpty()) {
0276             createManager->createNew();
0277         } else {
0278             syncManager->load(QUrl(url, QUrl::TolerantMode));
0279         }
0280         // TODO: set view to offset
0281         // if( offset != -1 )
0282     }
0283 }
0284 
0285 void OktetaMainWindow::onDataOffered(const QMimeData* mimeData, bool& accept)
0286 {
0287     accept = mimeData->hasUrls()
0288              || mProgram->documentManager()->createManager()->canCreateNewFromData(mimeData);
0289 }
0290 
0291 void OktetaMainWindow::onDataDropped(const QMimeData* mimeData)
0292 {
0293     const QList<QUrl> urls = mimeData->urls();
0294 
0295     DocumentManager* const documentManager = mProgram->documentManager();
0296     if (!urls.isEmpty()) {
0297         DocumentSyncManager* const syncManager = documentManager->syncManager();
0298 
0299         for (const QUrl& url : urls) {
0300             syncManager->load(url);
0301         }
0302     } else {
0303         documentManager->createManager()->createNewFromData(mimeData, true);
0304     }
0305 }
0306 
0307 void OktetaMainWindow::onNewDocumentRequested()
0308 {
0309     mProgram->documentManager()->createManager()->createNew();
0310 }
0311 
0312 void OktetaMainWindow::onCloseRequest(const QVector<Kasten::AbstractView*>& views)
0313 {
0314     // group views per document
0315     QHash<AbstractDocument*, QVector<AbstractView*>> viewsToClosePerDocument;
0316     for (AbstractView* view : views) {
0317         auto* document = view->findBaseModel<AbstractDocument*>();
0318         viewsToClosePerDocument[document].append(view);
0319     }
0320 
0321     // find documents which lose all views
0322     const QVector<AbstractView*> allViews = viewManager()->views();
0323     for (AbstractView* view : allViews) {
0324         auto* document = view->findBaseModel<AbstractDocument*>();
0325         QHash<AbstractDocument*, QVector<AbstractView*>>::Iterator it =
0326             viewsToClosePerDocument.find(document);
0327 
0328         if (it != viewsToClosePerDocument.end()) {
0329             const QVector<AbstractView*>& viewsOfDocument = it.value();
0330             const bool isAnotherView = !viewsOfDocument.contains(view);
0331             if (isAnotherView) {
0332                 viewsToClosePerDocument.erase(it);
0333             }
0334         }
0335     }
0336 
0337     const QVector<AbstractDocument*> documentsWithoutViews = viewsToClosePerDocument.keys().toVector();
0338 
0339     DocumentManager* const documentManager = mProgram->documentManager();
0340     if (documentManager->canClose(documentsWithoutViews)) {
0341         viewManager()->removeViews(views);
0342         documentManager->closeDocuments(documentsWithoutViews);
0343     }
0344 }
0345 
0346 }
0347 
0348 #include "moc_mainwindow.cpp"