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 }