File indexing completed on 2024-04-14 15:17:40

0001 /**************************************************************************
0002 *   Copyright (C) 2004 by Jeroen Wijnhout (Jeroen.Wijnhout@kdemail.net)   *
0003 *             (C) 2006-2018 by Michel Ludwig (michel.ludwig@kdemail.net)  *
0004 ***************************************************************************/
0005 
0006 /***************************************************************************
0007  *                                                                         *
0008  *   This program is free software; you can redistribute it and/or modify  *
0009  *   it under the terms of the GNU General Public License as published by  *
0010  *   the Free Software Foundation; either version 2 of the License, or     *
0011  *   (at your option) any later version.                                   *
0012  *                                                                         *
0013  ***************************************************************************/
0014 
0015 #include "kileviewmanager.h"
0016 #include <config.h>
0017 
0018 #include <okular/interfaces/viewerinterface.h>
0019 
0020 #include <KAcceleratorManager>
0021 #include <KActionCollection>
0022 #include <KConfigGroup>
0023 #include <KIconLoader>
0024 #include <kio/global.h>
0025 #include <KLocalizedString>
0026 #include <KMessageBox>
0027 #include <KTextEditor/Application>
0028 #include <KTextEditor/CodeCompletionInterface>
0029 #include <KTextEditor/Document>
0030 #include <KTextEditor/Editor>
0031 #include <KTextEditor/MainWindow>
0032 #include <KTextEditor/View>
0033 #include <KToolBar>
0034 #include <KToggleAction>
0035 #include <KXMLGUIClient>
0036 #include <KXMLGUIFactory>
0037 
0038 #include <QAction>
0039 #include <QApplication>
0040 #include <QClipboard>
0041 #include <QDragMoveEvent>
0042 #include <QDropEvent>
0043 #include <QLayout>
0044 #include <QMenu>
0045 #include <QMimeData>
0046 #include <QPixmap>
0047 #include <QSplitter>
0048 #include <QTimer> //for QTimer::singleShot trick
0049 #include <QToolButton>
0050 
0051 #include "editorkeysequencemanager.h"
0052 #include "kileinfo.h"
0053 #include "kileconstants.h"
0054 #include "kileproject.h"
0055 #include "kiledocmanager.h"
0056 #include "kileextensions.h"
0057 #include "kiletool_enums.h"
0058 #include "usermenu/usermenu.h"
0059 #include "livepreview.h"
0060 #include "widgets/projectview.h"
0061 #include "widgets/structurewidget.h"
0062 #include "editorextension.h"
0063 #include "plaintolatexconverter.h"
0064 #include "widgets/previewwidget.h"
0065 #include "quickpreview.h"
0066 #include "codecompletion.h"
0067 
0068 
0069 namespace KileView
0070 {
0071 
0072 bool sortDocuments(const KTextEditor::View * const lhs, const KTextEditor::View * const rhs)
0073 {
0074     return lhs->document()->documentName().compare(rhs->document()->documentName(), Qt::CaseInsensitive) < 0;
0075 }
0076 
0077 //BEGIN DocumentViewerWindow
0078 
0079 DocumentViewerWindow::DocumentViewerWindow(QWidget *parent, Qt::WindowFlags f)
0080     : KMainWindow(parent, f)
0081 {
0082 }
0083 
0084 DocumentViewerWindow::~DocumentViewerWindow()
0085 {
0086 }
0087 
0088 void DocumentViewerWindow::showEvent(QShowEvent *event)
0089 {
0090     KMainWindow::showEvent(event);
0091     emit visibilityChanged(true);
0092 }
0093 
0094 void DocumentViewerWindow::closeEvent(QCloseEvent *event)
0095 {
0096     KMainWindow::closeEvent(event);
0097     emit visibilityChanged(false);
0098 }
0099 
0100 //END DocumentViewerWindow
0101 
0102 Manager::Manager(KileInfo *info, KActionCollection *actionCollection, QObject *parent, const char *name) :
0103     QObject(parent),
0104     m_ki(info),
0105 //  m_projectview(Q_NULLPTR),
0106     m_tabsAndEditorWidget(Q_NULLPTR),
0107     m_tabBar(Q_NULLPTR),
0108     m_documentListButton(Q_NULLPTR),
0109     m_viewerPartWindow(Q_NULLPTR),
0110     m_widgetStack(Q_NULLPTR),
0111     m_pasteAsLaTeXAction(Q_NULLPTR),
0112     m_convertToLaTeXAction(Q_NULLPTR),
0113     m_quickPreviewAction(Q_NULLPTR),
0114     m_showCursorPositionInViewerAction(Q_NULLPTR),
0115     m_viewerControlToolBar(Q_NULLPTR),
0116     m_cursorPositionChangedTimer(Q_NULLPTR),
0117     m_clearLastShownSourceLocationTimer(Q_NULLPTR),
0118     m_synchronizeViewWithCursorAction(Q_NULLPTR)
0119 {
0120     setObjectName(name);
0121     createViewerPart(actionCollection);
0122 
0123     m_showCursorPositionInViewerAction = new QAction(QIcon::fromTheme("go-jump-symbolic"), i18n("Show Cursor Position in Viewer"), this);
0124     connect(m_showCursorPositionInViewerAction, &QAction::triggered, this, &KileView::Manager::showCursorPositionInDocumentViewer);
0125     actionCollection->addAction("show_cursor_position_in_document_viewer", m_showCursorPositionInViewerAction);
0126 
0127     m_synchronizeViewWithCursorAction = new KToggleAction(i18n("Synchronize Cursor Position with Viewer"), this);
0128     connect(m_synchronizeViewWithCursorAction, &KToggleAction::toggled, this, &KileView::Manager::synchronizeViewWithCursorActionToggled);
0129     connect(m_synchronizeViewWithCursorAction, &KToggleAction::changed,
0130     this, [=] () {
0131         m_showCursorPositionInViewerAction->setEnabled(!m_synchronizeViewWithCursorAction->isChecked());
0132     });
0133     actionCollection->addAction("synchronize_cursor_with_document_viewer", m_synchronizeViewWithCursorAction);
0134 
0135     m_cursorPositionChangedTimer = new QTimer(this);
0136     m_cursorPositionChangedTimer->setSingleShot(true);
0137     connect(m_cursorPositionChangedTimer, &QTimer::timeout, this, &KileView::Manager::handleCursorPositionChangedTimeout);
0138 
0139     m_clearLastShownSourceLocationTimer = new QTimer(this);
0140     m_clearLastShownSourceLocationTimer->setInterval(3000);
0141     m_clearLastShownSourceLocationTimer->setSingleShot(true);
0142     connect(m_clearLastShownSourceLocationTimer, &QTimer::timeout, this, &KileView::Manager::clearLastShownSourceLocationInDocumentViewer);
0143 
0144     createViewerControlToolBar();
0145 }
0146 
0147 Manager::~Manager()
0148 {
0149     KILE_DEBUG_MAIN;
0150 
0151     // the parent of the widget might be Q_NULLPTR; see 'destroyDocumentViewerWindow()'
0152     if(m_viewerPart) {
0153         delete m_viewerPart->widget();
0154         delete m_viewerPart;
0155     }
0156 
0157     destroyDocumentViewerWindow();
0158 }
0159 
0160 KTextEditor::View * Manager::textViewAtTab(int index) const
0161 {
0162     return m_tabBar->tabData(index).value<KTextEditor::View*>();
0163 }
0164 
0165 void Manager::createViewerControlToolBar()
0166 {
0167     m_viewerControlToolBar = new KToolBar(Q_NULLPTR, false, false);
0168     m_viewerControlToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
0169     m_viewerControlToolBar->setFloatable(false);
0170     m_viewerControlToolBar->setMovable(false);
0171     m_viewerControlToolBar->setIconDimensions(KIconLoader::SizeSmall);
0172 
0173     m_viewerControlToolBar->addAction(m_showCursorPositionInViewerAction);
0174 }
0175 
0176 void Manager::setClient(KXMLGUIClient *client)
0177 {
0178     m_client = client;
0179     if(Q_NULLPTR == m_client->actionCollection()->action("popup_pasteaslatex")) {
0180         m_pasteAsLaTeXAction = new QAction(i18n("Paste as LaTe&X"), this);
0181         connect(m_pasteAsLaTeXAction, &QAction::triggered, this, &Manager::pasteAsLaTeX);
0182     }
0183     if(Q_NULLPTR == m_client->actionCollection()->action("popup_converttolatex")) {
0184         m_convertToLaTeXAction = new QAction(i18n("Convert Selection to &LaTeX"), this);
0185         connect(m_convertToLaTeXAction, &QAction::triggered, this, &Manager::convertSelectionToLaTeX);
0186     }
0187     if(Q_NULLPTR == m_client->actionCollection()->action("popup_quickpreview")) {
0188         m_quickPreviewAction = new QAction(this);
0189         connect(m_quickPreviewAction, &QAction::triggered, this, &Manager::quickPreviewPopup);
0190     }
0191 }
0192 
0193 void Manager::readConfig(QSplitter *splitter)
0194 {
0195     // we might have to change the location of the viewer part
0196     setupViewerPart(splitter);
0197 
0198     setDocumentViewerVisible(KileConfig::showDocumentViewer());
0199 
0200     m_synchronizeViewWithCursorAction->setChecked(KileConfig::synchronizeCursorWithView());
0201 
0202     Okular::ViewerInterface *viewerInterface = dynamic_cast<Okular::ViewerInterface*>(m_viewerPart.data());
0203     if(viewerInterface && !m_ki->livePreviewManager()->isLivePreviewActive()) {
0204         viewerInterface->setWatchFileModeEnabled(KileConfig::watchFileForDocumentViewer());
0205         // also reload the document; this is necessary for switching back on watch-file mode as otherwise
0206         // it would only enabled after the document has been reloaded anyway
0207         if(m_viewerPart->url().isValid()) {
0208             m_viewerPart->openUrl(m_viewerPart->url());
0209         }
0210     }
0211 }
0212 
0213 void Manager::writeConfig()
0214 {
0215     if(m_viewerPart) {
0216         KileConfig::setShowDocumentViewer(isViewerPartShown());
0217     }
0218     if(m_viewerPartWindow) {
0219         KConfigGroup group(KSharedConfig::openConfig(), "KileDocumentViewerWindow");
0220         m_viewerPartWindow->saveMainWindowSettings(group);
0221     }
0222 
0223     KileConfig::setSynchronizeCursorWithView(m_synchronizeViewWithCursorAction->isChecked());
0224 }
0225 
0226 void Manager::setTabsAndEditorVisible(bool b)
0227 {
0228     m_tabsAndEditorWidget->setVisible(b);
0229 }
0230 
0231 QWidget * Manager::createTabs(QWidget *parent)
0232 {
0233     delete m_widgetStack;
0234     m_widgetStack = new QStackedWidget(parent);
0235     DropWidget *emptyDropWidget = new DropWidget(m_widgetStack);
0236     m_widgetStack->insertWidget(0, emptyDropWidget);
0237     connect(emptyDropWidget, &KileView::DropWidget::testCanDecode, this, static_cast<void (Manager::*)(const QDragEnterEvent *, bool &)>(&Manager::testCanDecodeURLs));
0238     connect(emptyDropWidget, &KileView::DropWidget::receivedDropEvent, m_ki->docManager(), &KileDocument::Manager::openDroppedURLs);
0239     connect(emptyDropWidget, &KileView::DropWidget::mouseDoubleClick, [=]() {
0240         m_ki->docManager()->fileNew();
0241     });
0242     m_tabBar = new QTabBar(parent);
0243     QWidget *tabBarWidget = new QWidget();
0244     tabBarWidget->setLayout(new QHBoxLayout);
0245     tabBarWidget->layout()->setSpacing(0);
0246     tabBarWidget->layout()->setContentsMargins(0, 0, 0, 0);
0247     KAcceleratorManager::setNoAccel(m_tabBar);
0248 
0249     // quick menu for all open documents
0250     m_documentListButton = new QToolButton(parent);
0251     m_documentListButton->setIcon(QIcon::fromTheme("format-list-unordered"));
0252     m_documentListButton->setMenu(new QMenu(parent));
0253     m_documentListButton->setPopupMode(QToolButton::InstantPopup);
0254     m_documentListButton->setAutoRaise(true);
0255     m_documentListButton->setToolTip(i18n("Show sorted list of opened documents"));
0256     m_documentListButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
0257     // lambda: update context menu
0258     connect(m_documentListButton->menu(), &QMenu::aboutToShow, [=]() {
0259         qDeleteAll(m_documentListButton->menu()->actions());
0260         m_documentListButton->menu()->clear();
0261 
0262         // create a lexicographically sorted list
0263         QVector<KTextEditor::View*> views;
0264         views.reserve(m_tabBar->count());
0265         for(int i = 0; i < m_tabBar->count(); ++i) {
0266             views << textViewAtTab(i);
0267         }
0268         std::sort(views.begin(), views.end(), sortDocuments);
0269 
0270         foreach(KTextEditor::View* view, views) {
0271             QAction *action = m_documentListButton->menu()->addAction(view->document()->documentName());
0272             action->setData(QVariant::fromValue(view));
0273         }
0274     });
0275     // lambda: handle context menu action triggers
0276     connect(m_documentListButton->menu(), &QMenu::triggered, [=](QAction *action) {
0277         KTextEditor::View *view = action->data().value<KTextEditor::View*>();
0278         Q_ASSERT(view);
0279         m_tabBar->setCurrentIndex(tabIndexOf(view));
0280     });
0281     // lambda: menu button is enabled if and only if at least two documents are open
0282     connect(this, &KileView::Manager::textViewCreated, [=]() {
0283         m_documentListButton->setEnabled(m_tabBar->count() > 1);
0284     });
0285     connect(this, &KileView::Manager::textViewClosed, [=]() {
0286         m_documentListButton->setEnabled(m_tabBar->count() > 1);
0287         m_cursorPositionChangedTimer->stop();
0288     });
0289     connect(this, &KileView::Manager::textViewClosed, [=]() {
0290         m_documentListButton->setEnabled(m_tabBar->count() > 1);
0291     });
0292     tabBarWidget->layout()->addWidget(m_documentListButton);
0293 
0294     // tabbar
0295     m_tabBar->setFocusPolicy(Qt::ClickFocus);
0296     m_tabBar->setMovable(true);
0297     m_tabBar->setTabsClosable(true);
0298     m_tabBar->setUsesScrollButtons(true);
0299     m_tabBar->setFocus();
0300     m_tabBar->setContextMenuPolicy(Qt::CustomContextMenu);
0301     tabBarWidget->layout()->addWidget(m_tabBar);
0302 
0303     // connect tabbar with document views
0304     connect(m_tabBar, &QTabBar::currentChanged, this, &Manager::currentTabChanged);
0305     connect(m_tabBar, &QTabBar::tabCloseRequested, this, &Manager::closeTab);
0306     connect(m_tabBar, &QTabBar::customContextMenuRequested, this, &Manager::tabContext);
0307 
0308     // main widget in which we put everything
0309     m_tabsAndEditorWidget = new QWidget(parent);
0310     m_tabsAndEditorWidget->setLayout(new QVBoxLayout);
0311     m_tabsAndEditorWidget->layout()->setSpacing(0);
0312     m_tabsAndEditorWidget->layout()->setContentsMargins(0, 0, 0, 0);
0313     m_tabsAndEditorWidget->layout()->addWidget(tabBarWidget);
0314     m_tabsAndEditorWidget->layout()->addWidget(m_widgetStack);
0315 
0316     return m_tabsAndEditorWidget;
0317 }
0318 
0319 void Manager::closeTab(int index)
0320 {
0321     QWidget *widget = textViewAtTab(index);
0322     if(widget->inherits("KTextEditor::View")) {
0323         KTextEditor::View *view = static_cast<KTextEditor::View*>(widget);
0324         m_ki->docManager()->fileClose(view->document());
0325     }
0326 }
0327 
0328 void Manager::currentTabChanged(int index)
0329 {
0330     QWidget *newlyActivatedWidget = textViewAtTab(index);
0331     if(!newlyActivatedWidget) {
0332         return;
0333     }
0334     QWidget *oldViewWidget = m_widgetStack->widget(1);
0335     if(oldViewWidget == newlyActivatedWidget) {
0336         return;
0337     }
0338     if(oldViewWidget) {
0339         m_widgetStack->removeWidget(oldViewWidget);
0340     }
0341     m_widgetStack->insertWidget(1, newlyActivatedWidget);
0342     m_widgetStack->setCurrentIndex(1);
0343     emit currentViewChanged(newlyActivatedWidget);
0344     KTextEditor::View *view = dynamic_cast<KTextEditor::View*>(newlyActivatedWidget);
0345     if(view) {
0346         emit textViewActivated(view);
0347     }
0348 }
0349 
0350 void Manager::handleCursorPositionChangedTimeout()
0351 {
0352     if(m_ki->livePreviewManager()->isLivePreviewEnabledForCurrentDocument()) {
0353         m_ki->livePreviewManager()->showCursorPositionInDocumentViewer();
0354     }
0355 }
0356 
0357 void Manager::handleCursorPositionChanged(KTextEditor::View *view, const KTextEditor::Cursor &pos)
0358 {
0359     Q_UNUSED(view);
0360     Q_UNUSED(pos);
0361 
0362     if(!m_synchronizeViewWithCursorAction->isChecked()) {
0363         return;
0364     }
0365     m_cursorPositionChangedTimer->start(100);
0366 }
0367 
0368 KTextEditor::View * Manager::createTextView(KileDocument::TextInfo *info, int index)
0369 {
0370     KTextEditor::Document *doc = info->getDoc();
0371     KTextEditor::View *view = info->createView(m_tabBar, Q_NULLPTR);
0372     Q_ASSERT(view);
0373 
0374     if(!view) {
0375         KMessageBox::error(m_ki->mainWindow(), i18n("Could not create an editor view."), i18n("Fatal Error"));
0376     }
0377 
0378     //install a key sequence recorder on the view
0379     view->focusProxy()->installEventFilter(new KileEditorKeySequence::Recorder(view, m_ki->editorKeySequenceManager()));
0380 
0381     // in the case of simple text documents, we mimic the behaviour of LaTeX documents
0382     if(info->getType() == KileDocument::Text) {
0383 //      view->focusProxy()->installEventFilter(m_ki->eventFilter());
0384     }
0385 
0386     index = m_tabBar->insertTab(index, QString()); // if index=-1 for appending tab, it gets assigned a new index
0387     m_tabBar->setTabData(index, QVariant::fromValue(view));
0388 
0389     connect(view, &KTextEditor::View::cursorPositionChanged, this, &Manager::cursorPositionChanged);
0390     connect(view, &KTextEditor::View::viewModeChanged, this, &Manager::viewModeChanged);
0391     connect(view, &KTextEditor::View::selectionChanged, this, &Manager::selectionChanged);
0392     connect(view, &KTextEditor::View::viewModeChanged, this, &Manager::updateCaption);
0393     connect(view, &KTextEditor::View::viewInputModeChanged, this, &Manager::updateModeStatus);
0394 //TODO KF5: signals not available anymore
0395 //  connect(view, SIGNAL(informationMessage(KTextEditor::View*,QString)), this, SIGNAL(informationMessage(KTextEditor::View*,QString)));
0396 //  connect(view, SIGNAL(dropEventPass(QDropEvent*)), m_ki->docManager(), SLOT(openDroppedURLs(QDropEvent*)));
0397     connect(view, &KTextEditor::View::textInserted, m_ki->codeCompletionManager(), &KileCodeCompletion::Manager::textInserted);
0398     connect(doc, &KTextEditor::Document::documentNameChanged, this, &Manager::updateTabTexts);
0399     connect(doc, &KTextEditor::Document::documentUrlChanged, this, &Manager::updateTabTexts);
0400 
0401     connect(this, &KileView::Manager::textViewClosed, m_cursorPositionChangedTimer, &QTimer::stop);
0402 
0403     // code completion
0404     KTextEditor::CodeCompletionInterface *completionInterface = qobject_cast<KTextEditor::CodeCompletionInterface*>(view);
0405     if(completionInterface) {
0406         completionInterface->setAutomaticInvocationEnabled(true);
0407     }
0408 
0409     // install a working text editor part popup dialog thingy
0410     installContextMenu(view);
0411 
0412     // delete the 'Configure Editor...' action
0413     delete view->actionCollection()->action("set_confdlg");
0414     // delete the "save as with encoding" action as it's too technical for Kile
0415     // also, there is currently no way to preset the desired extension in the save-as dialog
0416     // (the functionality is still available via Tools/Encoding + save)
0417     delete view->actionCollection()->action("file_save_as_with_encoding");
0418 
0419     // use Kile's save and save-as functions instead of the text editor's
0420     QAction *action = view->actionCollection()->action(KStandardAction::name(KStandardAction::Save));
0421     if(action) {
0422         KILE_DEBUG_MAIN << "   reconnect action 'file_save'...";
0423         disconnect(action, &QAction::triggered, 0, 0);
0424         connect(action, &QAction::triggered, [=]() {
0425             m_ki->docManager()->fileSave();
0426         });
0427     }
0428     action = view->actionCollection()->action(KStandardAction::name(KStandardAction::SaveAs));
0429     if(action) {
0430         KILE_DEBUG_MAIN << "   reconnect action 'file_save_as'...";
0431         disconnect(action, &QAction::triggered, 0, 0);
0432         connect(action, &QAction::triggered, [=]() {
0433             m_ki->docManager()->fileSaveAs();
0434         });
0435     }
0436 
0437     // use Kile's smart-new-line feature
0438     action = view->actionCollection()->action("smart_newline");
0439     if(action) {
0440         disconnect(action, &QAction::triggered, 0, 0);
0441         connect(action, &QAction::triggered, [=]() {
0442             m_ki->editorExtension()->insertIntelligentNewline();
0443         });
0444     }
0445 
0446     updateTabTexts(doc);
0447     // we do this twice as otherwise the tool tip for the first view did not appear (Qt issue ?)
0448     // (BUG 205245)
0449     updateTabTexts(doc);
0450 
0451     m_tabBar->setCurrentIndex(index);
0452     if(m_tabBar->count() == 1) { // when the tab bar is empty initially, 'setCurrentIndex' won't have any effect
0453         currentTabChanged(0);      // at this point; so we do it manually
0454     }
0455 
0456     //activate the newly created view
0457     emit(textViewCreated(view));
0458     emit(activateView(view, false));
0459     emit(updateCaption());  //make sure the caption gets updated
0460 
0461     reflectDocumentModificationStatus(view->document(), false, KTextEditor::ModificationInterface::OnDiskUnmodified);
0462 
0463     return view;
0464 }
0465 
0466 void Manager::installContextMenu(KTextEditor::View *view)
0467 {
0468     QMenu *popupMenu = view->defaultContextMenu();
0469 
0470     if(popupMenu) {
0471         connect(popupMenu, &QMenu::aboutToShow, this, &Manager::onTextEditorPopupMenuRequest);
0472 
0473         // install some more actions on it
0474         popupMenu->addSeparator();
0475         popupMenu->addAction(m_pasteAsLaTeXAction);
0476         popupMenu->addAction(m_convertToLaTeXAction);
0477         popupMenu->addSeparator();
0478         popupMenu->addAction(m_quickPreviewAction);
0479 
0480         // insert actions from user-defined latex menu
0481         KileMenu::UserMenu *usermenu = m_ki->userMenu();
0482         if(usermenu) {
0483             KILE_DEBUG_MAIN << "Insert actions from user-defined latex menu";
0484             popupMenu->addSeparator();
0485             foreach(QAction *action, usermenu->contextMenuActions()) {
0486                 if(action) {
0487                     popupMenu->addAction(action);
0488                 }
0489                 else {
0490                     popupMenu->addSeparator();
0491                 }
0492             }
0493         }
0494 
0495         view->setContextMenu(popupMenu);
0496     }
0497 }
0498 
0499 void Manager::tabContext(const QPoint &pos)
0500 {
0501     KILE_DEBUG_MAIN << pos;
0502     const int tabUnderPos = m_tabBar->tabAt(pos);
0503     if(tabUnderPos < 0) {
0504         KILE_DEBUG_MAIN << tabUnderPos;
0505         return;
0506     }
0507 
0508     KTextEditor::View *view = textViewAtTab(tabUnderPos);
0509 
0510     if(!view || !view->document()) {
0511         return;
0512     }
0513 
0514     QMenu tabMenu;
0515 
0516     tabMenu.addSection(m_ki->getShortName(view->document()));
0517 
0518     // 'action1' can become null if it belongs to a view that has been closed, for example
0519     QPointer<QAction> action1 = m_ki->mainWindow()->action("move_view_tab_left");
0520     if(action1) {
0521         action1->setData(QVariant::fromValue(view));
0522         tabMenu.addAction(action1);
0523     }
0524 
0525     QPointer<QAction> action2 = m_ki->mainWindow()->action("move_view_tab_right");
0526     if(action2) {
0527         action2->setData(QVariant::fromValue(view));
0528         tabMenu.addAction(action2);
0529     }
0530 
0531     tabMenu.addSeparator();
0532 
0533     QPointer<QAction> action3;
0534     if(view->document()->isModified()) {
0535         action3 = view->actionCollection()->action(KStandardAction::name(KStandardAction::Save));
0536         if(action3) {
0537             action3->setData(QVariant::fromValue(view));
0538             tabMenu.addAction(action3);
0539         }
0540     }
0541 
0542     QPointer<QAction> action4 = view->actionCollection()->action(KStandardAction::name(KStandardAction::SaveAs));
0543     if(action4) {
0544         action4->setData(QVariant::fromValue(view));
0545         tabMenu.addAction(action4);
0546     }
0547 
0548     QPointer<QAction> action5 = view->action("file_save_copy_as");
0549     if(action5) {
0550         tabMenu.addAction(action5);
0551     }
0552 
0553     tabMenu.addSeparator();
0554 
0555     QPointer<QAction> action6 = m_ki->mainWindow()->action("file_close");
0556     if(action6) {
0557         action6->setData(QVariant::fromValue(view));
0558         tabMenu.addAction(action6);
0559     }
0560 
0561     QPointer<QAction> action7 = m_ki->mainWindow()->action("file_close_all_others");
0562     if(action7) {
0563         action7->setData(QVariant::fromValue(view));
0564         tabMenu.addAction(action7);
0565     }
0566     /*
0567         FIXME create proper actions which delete/add the current file without asking stupidly
0568         QAction* removeAction = m_ki->mainWindow()->action("project_remove");
0569         QAction* addAction = m_ki->mainWindow()->action("project_add");
0570 
0571         tabMenu.insertSeparator(addAction);
0572         tabMenu.addAction(addAction);
0573         tabMenu.addAction(removeAction);*/
0574 
0575     tabMenu.exec(m_tabBar->mapToGlobal(pos));
0576 
0577     if(action1) {
0578         action1->setData(QVariant());
0579     }
0580     if(action2) {
0581         action2->setData(QVariant());
0582     }
0583     if(action3) {
0584         action3->setData(QVariant());
0585     }
0586     if(action4) {
0587         action4->setData(QVariant());
0588     }
0589     // action5 doesn't need to be given extra data
0590     if(action6) {
0591         action6->setData(QVariant());
0592     }
0593     if(action7) {
0594         action7->setData(QVariant());
0595     }
0596 }
0597 
0598 void Manager::removeView(KTextEditor::View *view)
0599 {
0600     if(view) {
0601         m_client->factory()->removeClient(view);
0602 
0603         const bool isActiveView = (KTextEditor::Editor::instance()->application()->activeMainWindow()->activeView() == view);
0604         m_tabBar->removeTab(tabIndexOf(view));
0605 
0606         emit(updateCaption());  //make sure the caption gets updated
0607         if(m_tabBar->count() == 0) {
0608             m_ki->structureWidget()->clear();
0609             m_widgetStack->setCurrentIndex(0); // if there are no open views, then show the DropWidget
0610         }
0611 
0612         emit(textViewClosed(view, isActiveView));
0613         delete view;
0614     }
0615     else {
0616         KILE_DEBUG_MAIN << "View should be removed but is Q_NULLPTR";
0617     }
0618 }
0619 
0620 KTextEditor::View * Manager::currentTextView() const
0621 {
0622     return textViewAtTab(m_tabBar->currentIndex());
0623 }
0624 
0625 KTextEditor::View * Manager::textView(int index) const
0626 {
0627     Q_ASSERT(textViewAtTab(index));
0628     return textViewAtTab(index);
0629 }
0630 
0631 KTextEditor::View * Manager::textView(KileDocument::TextInfo *info) const
0632 {
0633     KTextEditor::Document *doc = info->getDoc();
0634     if(!doc) {
0635         return Q_NULLPTR;
0636     }
0637     for(int i = 0; i < m_tabBar->count(); ++i) {
0638         KTextEditor::View *view = textViewAtTab(i);
0639         if(!view) {
0640             continue;
0641         }
0642 
0643         if(view->document() == doc) {
0644             return view;
0645         }
0646     }
0647 
0648     return Q_NULLPTR;
0649 }
0650 
0651 int Manager::textViewCount() const
0652 {
0653     return m_tabBar->count();
0654 }
0655 
0656 int Manager::tabIndexOf(KTextEditor::View* view) const
0657 {
0658     for(int i = 0; i < m_tabBar->count(); ++i) {
0659         if(textViewAtTab(i) == view) {
0660             return i;
0661         }
0662     }
0663     return -1;
0664 }
0665 
0666 unsigned int Manager::getTabCount() const
0667 {
0668     return m_tabBar->count();
0669 }
0670 
0671 KTextEditor::View * Manager::switchToTextView(const QUrl &url, bool requestFocus)
0672 {
0673     return switchToTextView(m_ki->docManager()->docFor(url), requestFocus);
0674 }
0675 
0676 KTextEditor::View * Manager::switchToTextView(KTextEditor::Document *doc, bool requestFocus)
0677 {
0678     KTextEditor::View *view = Q_NULLPTR;
0679     if(doc) {
0680         if(doc->views().count() > 0) {
0681             view = doc->views().first();
0682             if(view) {
0683                 switchToTextView(view, requestFocus);
0684             }
0685         }
0686     }
0687     return view;
0688 }
0689 
0690 void Manager::switchToTextView(KTextEditor::View *view, bool requestFocus)
0691 {
0692     int index = tabIndexOf(view);
0693     if(index < 0) {
0694         return;
0695     }
0696     m_tabBar->setCurrentIndex(index);
0697     if(requestFocus) {
0698         focusTextView(view);
0699     }
0700 }
0701 
0702 void Manager::setTabIcon(QWidget *view, const QIcon& icon)
0703 {
0704     m_tabBar->setTabIcon(tabIndexOf(qobject_cast<KTextEditor::View *>(view)), icon);
0705 }
0706 
0707 void Manager::updateStructure(bool parse /* = false */, KileDocument::Info *docinfo /* = Q_NULLPTR */)
0708 {
0709     if(!docinfo) {
0710         docinfo = m_ki->docManager()->getInfo();
0711     }
0712 
0713     if(docinfo) {
0714         m_ki->structureWidget()->update(docinfo, parse);
0715     }
0716 
0717     if(m_tabBar->count() == 0) {
0718         m_ki->structureWidget()->clear();
0719     }
0720 }
0721 
0722 void Manager::gotoNextView()
0723 {
0724     if(m_tabBar->count() < 2) {
0725         return;
0726     }
0727 
0728     int cPage = m_tabBar->currentIndex() + 1;
0729     if(cPage >= m_tabBar->count()) {
0730         m_tabBar->setCurrentIndex(0);
0731     }
0732     else {
0733         m_tabBar->setCurrentIndex(cPage);
0734     }
0735 }
0736 
0737 void Manager::gotoPrevView()
0738 {
0739     if(m_tabBar->count() < 2) {
0740         return;
0741     }
0742 
0743     int cPage = m_tabBar->currentIndex() - 1;
0744     if(cPage < 0) {
0745         m_tabBar->setCurrentIndex(m_tabBar->count() - 1);
0746     }
0747     else {
0748         m_tabBar->setCurrentIndex(cPage);
0749     }
0750 }
0751 
0752 void Manager::moveTabLeft(QWidget *widget)
0753 {
0754     if(m_tabBar->count() < 2) {
0755         return;
0756     }
0757 
0758     // the 'data' property can be set by 'tabContext'
0759     QAction *action = dynamic_cast<QAction*>(QObject::sender());
0760     if(action) {
0761         QVariant var = action->data();
0762         if(!widget && var.isValid()) {
0763             // the action's 'data' property is cleared
0764             // when the context menu is destroyed
0765             widget = var.value<QWidget*>();
0766         }
0767     }
0768     if(!widget) {
0769         widget = currentTextView();
0770     }
0771     if(!widget) {
0772         return;
0773     }
0774     int currentIndex = tabIndexOf(qobject_cast<KTextEditor::View *>(widget));
0775     int newIndex = (currentIndex == 0 ? m_tabBar->count() - 1 : currentIndex - 1);
0776     m_tabBar->moveTab(currentIndex, newIndex);
0777 }
0778 
0779 void Manager::moveTabRight(QWidget *widget)
0780 {
0781     if(m_tabBar->count() < 2) {
0782         return;
0783     }
0784 
0785     // the 'data' property can be set by 'tabContext'
0786     QAction *action = dynamic_cast<QAction*>(QObject::sender());
0787     if(action) {
0788         QVariant var = action->data();
0789         if(!widget && var.isValid()) {
0790             // the action's 'data' property is cleared
0791             // when the context menu is destroyed
0792             widget = var.value<QWidget*>();
0793         }
0794     }
0795     if(!widget) {
0796         widget = currentTextView();
0797     }
0798     if(!widget) {
0799         return;
0800     }
0801     int currentIndex = tabIndexOf(qobject_cast<KTextEditor::View *>(widget));
0802     int newIndex = (currentIndex == m_tabBar->count() - 1 ? 0 : currentIndex + 1);
0803     m_tabBar->moveTab(currentIndex, newIndex);
0804 }
0805 
0806 void Manager::reflectDocumentModificationStatus(KTextEditor::Document *doc,
0807         bool isModified,
0808         KTextEditor::ModificationInterface::ModifiedOnDiskReason reason)
0809 {
0810     QIcon icon;
0811     if(reason == KTextEditor::ModificationInterface::OnDiskUnmodified && isModified) { //nothing
0812         icon = QIcon::fromTheme("modified"); // This icon is taken from Kate. Therefore
0813         // our thanks go to the authors of Kate.
0814     }
0815     else if(reason == KTextEditor::ModificationInterface::OnDiskModified
0816             || reason == KTextEditor::ModificationInterface::OnDiskCreated) { //dirty file
0817         icon = QIcon::fromTheme("emblem-warning"); // This icon is taken from Kate. Therefore
0818         // our thanks go to the authors of Kate.
0819     }
0820     else if(reason == KTextEditor::ModificationInterface::OnDiskDeleted) { //file deleted
0821         icon = QIcon::fromTheme("emblem-warning");
0822     }
0823     else if(m_ki->extensions()->isScriptFile(doc->url())) {
0824         icon = QIcon::fromTheme("js");
0825     }
0826     else {
0827         icon = QIcon::fromTheme(KIO::iconNameForUrl(doc->url()));
0828     }
0829 
0830     const QList<KTextEditor::View*> &viewsList = doc->views();
0831     for(QList<KTextEditor::View*>::const_iterator i = viewsList.begin(); i != viewsList.end(); ++i) {
0832         setTabIcon(*i, icon);
0833     }
0834 }
0835 
0836 /**
0837  * Adds/removes the "Convert to LaTeX" entry in Kate's popup menu according to the selection.
0838  */
0839 void Manager::onTextEditorPopupMenuRequest()
0840 {
0841     KTextEditor::View *view = currentTextView();
0842     if(!view) {
0843         return;
0844     }
0845 
0846     const QString quickPreviewSelection = i18n("&QuickPreview Selection");
0847     const QString quickPreviewEnvironment = i18n("&QuickPreview Environment");
0848     const QString quickPreviewMath = i18n("&QuickPreview Math");
0849 
0850     // Setting up the "QuickPreview selection" entry
0851     if(view->selection()) {
0852         m_quickPreviewAction->setText(quickPreviewSelection);
0853         m_quickPreviewAction->setEnabled(true);
0854 
0855     }
0856     else if(m_ki->editorExtension()->hasMathgroup(view)) {
0857         m_quickPreviewAction->setText(quickPreviewMath);
0858         m_quickPreviewAction->setEnabled(true);
0859     }
0860     else if(m_ki->editorExtension()->hasEnvironment(view)) {
0861         m_quickPreviewAction->setText(quickPreviewEnvironment);
0862         m_quickPreviewAction->setEnabled(true);
0863     }
0864     else {
0865         m_quickPreviewAction->setText(quickPreviewSelection);
0866         m_quickPreviewAction->setEnabled(false);
0867     }
0868 
0869 
0870     // Setting up the "Convert to LaTeX" entry
0871     m_convertToLaTeXAction->setEnabled(view->selection());
0872 
0873     // Setting up the "Paste as LaTeX" entry
0874     QClipboard *clipboard = QApplication::clipboard();
0875     if(clipboard) {
0876         m_pasteAsLaTeXAction->setEnabled(!clipboard->text().isEmpty());
0877     }
0878 }
0879 
0880 void Manager::convertSelectionToLaTeX()
0881 {
0882     KTextEditor::View *view = currentTextView();
0883 
0884     if(view == Q_NULLPTR) {
0885         return;
0886     }
0887 
0888     KTextEditor::Document *doc = view->document();
0889 
0890     if(doc == Q_NULLPTR) {
0891         return;
0892     }
0893 
0894     // Getting the selection
0895     KTextEditor::Range range = view->selectionRange();
0896     uint selStartLine = range.start().line(), selStartCol = range.start().column();
0897     uint selEndLine = range.end().line(), selEndCol = range.start().column();
0898 
0899     /* Variable to "restore" the selection after replacement: if {} was selected,
0900        we increase the selection of two characters */
0901     uint newSelEndCol;
0902 
0903     PlainToLaTeXConverter cvt;
0904 
0905     // "Notifying" the editor that what we're about to do must be seen as ONE operation
0906     KTextEditor::Document::EditingTransaction transaction(doc);
0907 
0908     // Processing the first line
0909     int firstLineLength;
0910     if(selStartLine != selEndLine) {
0911         firstLineLength = doc->lineLength(selStartLine);
0912     } else {
0913         firstLineLength = selEndCol;
0914     }
0915     QString firstLine = doc->text(KTextEditor::Range(selStartLine, selStartCol, selStartLine, firstLineLength));
0916     QString firstLineCvt = cvt.ConvertToLaTeX(firstLine);
0917     doc->removeText(KTextEditor::Range(selStartLine, selStartCol, selStartLine, firstLineLength));
0918     doc->insertText(KTextEditor::Cursor(selStartLine, selStartCol), firstLineCvt);
0919     newSelEndCol = selStartCol + firstLineCvt.length();
0920 
0921     // Processing the intermediate lines
0922     for(uint nLine = selStartLine + 1; nLine < selEndLine; ++nLine) {
0923         QString line = doc->line(nLine);
0924         QString newLine = cvt.ConvertToLaTeX(line);
0925         doc->removeLine(nLine);
0926         doc->insertLine(nLine, newLine);
0927     }
0928 
0929     // Processing the final line
0930     if(selStartLine != selEndLine) {
0931         QString lastLine = doc->text(KTextEditor::Range(selEndLine, 0, selEndLine, selEndCol));
0932         QString lastLineCvt = cvt.ConvertToLaTeX(lastLine);
0933         doc->removeText(KTextEditor::Range(selEndLine, 0, selEndLine, selEndCol));
0934         doc->insertText(KTextEditor::Cursor(selEndLine, 0), lastLineCvt);
0935         newSelEndCol = lastLineCvt.length();
0936     }
0937 
0938     // End of the "atomic edit operation"
0939     transaction.finish();
0940 
0941     view->setSelection(KTextEditor::Range(selStartLine, selStartCol, selEndLine, newSelEndCol));
0942 }
0943 
0944 /**
0945  * Pastes the clipboard's contents as LaTeX (ie. % -> \%, etc.).
0946  */
0947 void Manager::pasteAsLaTeX()
0948 {
0949     KTextEditor::View *view = currentTextView();
0950 
0951     if(!view) {
0952         return;
0953     }
0954 
0955     KTextEditor::Document *doc = view->document();
0956 
0957     if(!doc) {
0958         return;
0959     }
0960 
0961     // Getting a proper text insertion point BEFORE the atomic editing operation
0962     uint cursorLine, cursorCol;
0963     if(view->selection()) {
0964         KTextEditor::Range range = view->selectionRange();
0965         cursorLine = range.start().line();
0966         cursorCol = range.start().column();
0967     } else {
0968         KTextEditor::Cursor cursor = view->cursorPosition();
0969         cursorLine = cursor.line();
0970         cursorCol = cursor.column();
0971     }
0972 
0973     // "Notifying" the editor that what we're about to do must be seen as ONE operation
0974     KTextEditor::Document::EditingTransaction transaction(doc);
0975 
0976     // If there is a selection, one must remove it
0977     if(view->selection()) {
0978         doc->removeText(view->selectionRange());
0979     }
0980 
0981     PlainToLaTeXConverter cvt;
0982     QString toPaste = cvt.ConvertToLaTeX(QApplication::clipboard()->text());
0983     doc->insertText(KTextEditor::Cursor(cursorLine, cursorCol), toPaste);
0984 
0985     // End of the "atomic edit operation"
0986     transaction.finish();
0987 }
0988 
0989 void Manager::quickPreviewPopup()
0990 {
0991     KTextEditor::View *view = currentTextView();
0992     if(!view) {
0993         return;
0994     }
0995 
0996     if(view->selection()) {
0997         emit(startQuickPreview(KileTool::qpSelection));
0998     }
0999     else if(m_ki->editorExtension()->hasMathgroup(view)) {
1000         emit(startQuickPreview(KileTool::qpMathgroup));
1001     }
1002     else if(m_ki->editorExtension()->hasEnvironment(view)) {
1003         emit(startQuickPreview(KileTool::qpEnvironment));
1004     }
1005 }
1006 
1007 void Manager::testCanDecodeURLs(const QDragEnterEvent *e, bool &accept)
1008 {
1009     accept = e->mimeData()->hasUrls(); // only accept URL drops
1010 }
1011 
1012 void Manager::testCanDecodeURLs(const QDragMoveEvent *e, bool &accept)
1013 {
1014     accept = e->mimeData()->hasUrls(); // only accept URL drops
1015 }
1016 
1017 void Manager::replaceLoadedURL(QWidget *w, QDropEvent *e)
1018 {
1019     QList<QUrl> urls = e->mimeData()->urls();
1020     if(urls.isEmpty()) {
1021         return;
1022     }
1023     int index = tabIndexOf(qobject_cast<KTextEditor::View *>(w));
1024     KileDocument::Extensions *extensions = m_ki->extensions();
1025     bool hasReplacedTab = false;
1026     for(QList<QUrl>::iterator i = urls.begin(); i != urls.end(); ++i) {
1027         QUrl url = *i;
1028         if(extensions->isProjectFile(url)) {
1029             m_ki->docManager()->projectOpen(url);
1030         }
1031         else if(!hasReplacedTab) {
1032             closeTab(index);
1033             m_ki->docManager()->fileOpen(url, QString(), index);
1034             hasReplacedTab = true;
1035         }
1036         else {
1037             m_ki->docManager()->fileOpen(url);
1038         }
1039     }
1040 }
1041 
1042 void Manager::updateTabTexts(KTextEditor::Document *changedDoc)
1043 {
1044     const QList<KTextEditor::View*> &viewsList = changedDoc->views();
1045     for(QList<KTextEditor::View*>::const_iterator i = viewsList.begin(); i != viewsList.end(); ++i) {
1046         QString documentName = changedDoc->documentName();
1047         if(documentName.isEmpty()) {
1048             documentName = i18n("Untitled");
1049         }
1050         const int viewIndex = tabIndexOf(*i);
1051         m_tabBar->setTabText(viewIndex, documentName);
1052         m_tabBar->setTabToolTip(viewIndex, changedDoc->url().toString());
1053     }
1054 }
1055 
1056 DropWidget::DropWidget(QWidget *parent, const char *name, Qt::WindowFlags f) : QWidget(parent, f)
1057 {
1058     setObjectName(name);
1059     setAcceptDrops(true);
1060 }
1061 
1062 DropWidget::~DropWidget()
1063 {
1064 }
1065 
1066 void DropWidget::dragEnterEvent(QDragEnterEvent *e)
1067 {
1068     bool b;
1069     emit testCanDecode(e, b);
1070     if(b) {
1071         e->acceptProposedAction();
1072     }
1073 }
1074 
1075 void DropWidget::dropEvent(QDropEvent *e)
1076 {
1077     emit receivedDropEvent(e);
1078 }
1079 
1080 void DropWidget::mouseDoubleClickEvent(QMouseEvent *e)
1081 {
1082     Q_UNUSED(e);
1083     emit mouseDoubleClick();
1084 }
1085 
1086 void Manager::installEventFilter(KTextEditor::View *view, QObject *eventFilter)
1087 {
1088     QWidget *focusProxy = view->focusProxy();
1089     if(focusProxy) {
1090         focusProxy->installEventFilter(eventFilter);
1091     }
1092     else {
1093         view->installEventFilter(eventFilter);
1094     }
1095 }
1096 
1097 void Manager::removeEventFilter(KTextEditor::View *view, QObject *eventFilter)
1098 {
1099     QWidget *focusProxy = view->focusProxy();
1100     if(focusProxy) {
1101         focusProxy->removeEventFilter(eventFilter);
1102     }
1103     else {
1104         view->removeEventFilter(eventFilter);
1105     }
1106 }
1107 
1108 //BEGIN ViewerPart methods
1109 
1110 void Manager::createViewerPart(KActionCollection *actionCollection)
1111 {
1112     m_viewerPart = Q_NULLPTR;
1113 
1114     const KPluginMetaData okularPart(QStringLiteral(OKULAR_LIBRARY_NAME));
1115     const QVariantList args {"ViewerWidget", "ConfigFileName=kile-livepreview-okularpartrc"};
1116 
1117     const auto result = KPluginFactory::instantiatePlugin<KParts::ReadOnlyPart>(okularPart, this, args);
1118 
1119     if(!result) {
1120         KILE_DEBUG_MAIN << "Could not load the Okular library:" << result.errorString;
1121         m_viewerPart = Q_NULLPTR;
1122         return;
1123     }
1124     else {
1125         m_viewerPart = result.plugin;
1126         Okular::ViewerInterface *viewerInterface = dynamic_cast<Okular::ViewerInterface*>(m_viewerPart.data());
1127         if(!viewerInterface) {
1128             // OkularPart doesn't provide the ViewerInterface
1129             delete m_viewerPart;
1130             m_viewerPart = Q_NULLPTR;
1131             return;
1132         }
1133         viewerInterface->setWatchFileModeEnabled(false);
1134         viewerInterface->setShowSourceLocationsGraphically(true);
1135         connect(m_viewerPart, SIGNAL(openSourceReference(QString,int,int)), this, SLOT(handleActivatedSourceReference(QString,int,int)));
1136 
1137         QAction *paPrintCompiledDocument = actionCollection->addAction(KStandardAction::Print, "print_compiled_document", m_viewerPart, SLOT(slotPrint()));
1138         paPrintCompiledDocument->setText(i18n("Print Compiled Document..."));
1139         paPrintCompiledDocument->setShortcut(QKeySequence());
1140         paPrintCompiledDocument->setEnabled(false);
1141         connect(m_viewerPart, SIGNAL(enablePrintAction(bool)), paPrintCompiledDocument, SLOT(setEnabled(bool)));
1142         QAction *printPreviewAction = m_viewerPart->actionCollection()->action("file_print_preview");
1143         if(printPreviewAction) {
1144             printPreviewAction->setText(i18n("Print Preview For Compiled Document..."));
1145         }
1146     }
1147 }
1148 
1149 void Manager::setupViewerPart(QSplitter *splitter)
1150 {
1151     if(!m_viewerPart) {
1152         return;
1153     }
1154     if(KileConfig::showDocumentViewerInExternalWindow()) {
1155         if(m_viewerPartWindow && m_viewerPart->widget()->window() == m_viewerPartWindow) { // nothing to be done
1156             return;
1157         }
1158         m_viewerPartWindow = new DocumentViewerWindow();
1159         m_viewerPartWindow->setObjectName("KileDocumentViewerWindow");
1160         m_viewerPartWindow->setCentralWidget(m_viewerPart->widget());
1161         m_viewerPartWindow->setAttribute(Qt::WA_DeleteOnClose, false);
1162         m_viewerPartWindow->setAttribute(Qt::WA_QuitOnClose, false);
1163         connect(m_viewerPartWindow, &KileView::DocumentViewerWindow::visibilityChanged, this, &Manager::documentViewerWindowVisibilityChanged);
1164 
1165         m_viewerPartWindow->setWindowTitle(i18n("Document Viewer"));
1166         m_viewerPartWindow->applyMainWindowSettings(KSharedConfig::openConfig()->group("KileDocumentViewerWindow"));
1167     }
1168     else {
1169         if(m_viewerPart->widget()->parent() && m_viewerPart->widget()->parent() != m_viewerPartWindow) { // nothing to be done
1170             return;
1171         }
1172         splitter->addWidget(m_viewerPart->widget()); // remove it from the window first!
1173         destroyDocumentViewerWindow();
1174     }
1175 }
1176 
1177 void Manager::destroyDocumentViewerWindow()
1178 {
1179     if(!m_viewerPartWindow) {
1180         return;
1181     }
1182 
1183     KConfigGroup group(KSharedConfig::openConfig(), "KileDocumentViewerWindow");
1184     m_viewerPartWindow->saveMainWindowSettings(group);
1185     // we don't want it to influence the document viewer visibility setting as
1186     // this is a forced close
1187     disconnect(m_viewerPartWindow, &KileView::DocumentViewerWindow::visibilityChanged, this, &Manager::documentViewerWindowVisibilityChanged);
1188     m_viewerPartWindow->hide();
1189     delete m_viewerPartWindow;
1190     m_viewerPartWindow = Q_NULLPTR;
1191 }
1192 
1193 void Manager::handleActivatedSourceReference(const QString& absFileName, int line, int col)
1194 {
1195     KILE_DEBUG_MAIN << "absFileName:" << absFileName << "line:" << line << "column:" << col;
1196 
1197     QFileInfo fileInfo(absFileName);
1198     if(!fileInfo.isFile() || !fileInfo.isReadable()) {
1199         qWarning() << "Got passed an unreadable file:" << absFileName;
1200         return;
1201     }
1202 
1203     const QString canonicalFileName = fileInfo.canonicalFilePath(); // remove symbolic links, and
1204                                                                     // '.', '..' path components
1205                                                                     // (XeLaTeX + synctex sometimes produces paths containing ./)
1206 
1207     KILE_DEBUG_MAIN << "canonicalFileName:" << canonicalFileName;
1208 
1209     KileDocument::TextInfo *textInfo = m_ki->docManager()->textInfoFor(canonicalFileName);
1210     // check whether the file or the project item associated with 'canonicalFileName' is already open
1211     if(!textInfo || !m_ki->isOpen(canonicalFileName)) {
1212         m_ki->docManager()->fileOpen(canonicalFileName);
1213         textInfo = m_ki->docManager()->textInfoFor(canonicalFileName);
1214     }
1215     if(!textInfo) {
1216         KILE_DEBUG_MAIN << "no document found!";
1217         return;
1218     }
1219     KTextEditor::View *view = textView(textInfo);
1220     if(!view) {
1221         KILE_DEBUG_MAIN << "no view found!";
1222         return;
1223     }
1224     view->setCursorPosition(KTextEditor::Cursor(line, col));
1225     switchToTextView(view, true);
1226 }
1227 
1228 void Manager::showCursorPositionInDocumentViewer()
1229 {
1230     if(m_ki->livePreviewManager()->isLivePreviewEnabledForCurrentDocument()) {
1231         m_ki->livePreviewManager()->showCursorPositionInDocumentViewer();
1232     }
1233 }
1234 
1235 void Manager::synchronizeViewWithCursorActionToggled(bool checked)
1236 {
1237     m_showCursorPositionInViewerAction->setEnabled(!checked);
1238     if(checked) {
1239         showCursorPositionInDocumentViewer();
1240     }
1241 }
1242 
1243 void Manager::setDocumentViewerVisible(bool b)
1244 {
1245     if(!m_viewerPart) {
1246         return;
1247     }
1248     KileConfig::setShowDocumentViewer(b);
1249     if(m_viewerPartWindow) {
1250         m_viewerPartWindow->setVisible(b);
1251     }
1252     m_viewerPart->widget()->setVisible(b);
1253 }
1254 
1255 bool Manager::isViewerPartShown() const
1256 {
1257     if(!m_viewerPart) {
1258         return false;
1259     }
1260 
1261     if(m_viewerPartWindow) {
1262         return !m_viewerPartWindow->isHidden();
1263     }
1264     else {
1265         return !m_viewerPart->widget()->isHidden();
1266     }
1267 }
1268 
1269 bool Manager::openInDocumentViewer(const QUrl &url)
1270 {
1271     Okular::ViewerInterface *v = dynamic_cast<Okular::ViewerInterface*>(m_viewerPart.data());
1272     if(!v) {
1273         return false;
1274     }
1275     bool r = m_viewerPart->openUrl(url);
1276     v->clearLastShownSourceLocation();
1277     return r;
1278 }
1279 
1280 void Manager::clearLastShownSourceLocationInDocumentViewer()
1281 {
1282     Okular::ViewerInterface *v = dynamic_cast<Okular::ViewerInterface*>(m_viewerPart.data());
1283     if(v) {
1284         v->clearLastShownSourceLocation();
1285     }
1286 }
1287 
1288 void Manager::showSourceLocationInDocumentViewer(const QString& fileName, int line, int column)
1289 {
1290     Okular::ViewerInterface *v = dynamic_cast<Okular::ViewerInterface*>(m_viewerPart.data());
1291     if(v) {
1292         m_clearLastShownSourceLocationTimer->stop();
1293         v->showSourceLocation(fileName, line, column, true);
1294         m_clearLastShownSourceLocationTimer->start();
1295     }
1296 }
1297 
1298 void Manager::setLivePreviewModeForDocumentViewer(bool b)
1299 {
1300     Okular::ViewerInterface *viewerInterface = dynamic_cast<Okular::ViewerInterface*>(m_viewerPart.data());
1301     if(viewerInterface) {
1302         if(b) {
1303             viewerInterface->setWatchFileModeEnabled(false);
1304         }
1305         else {
1306             viewerInterface->setWatchFileModeEnabled(KileConfig::watchFileForDocumentViewer());
1307 
1308         }
1309     }
1310 }
1311 
1312 KToolBar* Manager::getViewerControlToolBar()
1313 {
1314     return m_viewerControlToolBar;
1315 }
1316 
1317 bool Manager::isSynchronisingCursorWithDocumentViewer() const
1318 {
1319     return m_synchronizeViewWithCursorAction->isChecked();
1320 }
1321 
1322 //END ViewerPart methods
1323 
1324 bool Manager::viewForLocalFilePresent(const QString& localFileName)
1325 {
1326     for(int i = 0; i < m_tabBar->count(); ++i) {
1327         KTextEditor::View *view = textViewAtTab(i);
1328         if(!view) {
1329             continue;
1330         }
1331         if(view->document()->url().toLocalFile() == localFileName) {
1332             return true;
1333         }
1334     }
1335     return false;
1336 }
1337 
1338 }
1339 
1340 void focusTextView(KTextEditor::View *view)
1341 {
1342     // we work around a potential Qt bug here which can result in dead keys
1343     // being treated as 'alive' keys in some circumstances, probably when 'setFocus'
1344     // is called when the widget hasn't been shown yet (see bug 269590)
1345     QTimer::singleShot(0, view, SLOT(setFocus()));
1346 }