File indexing completed on 2024-04-28 16:26:35
0001 /************************************************************************************************* 0002 Copyright (C) 2003 by Jeroen Wijnhout (Jeroen.Wijnhout@kdemail.net 0003 2005-2007 by Holger Danielsson (holger.danielsson@versanet.de) 0004 2008-2022 by Michel Ludwig (michel.ludwig@kdemail.net) 0005 *************************************************************************************************/ 0006 0007 /*************************************************************************** 0008 * * 0009 * This program is free software; you can redistribute it and/or modify * 0010 * it under the terms of the GNU General Public License as published by * 0011 * the Free Software Foundation; either version 2 of the License, or * 0012 * (at your option) any later version. * 0013 * * 0014 ***************************************************************************/ 0015 0016 // 2005-11-02: dani 0017 // - cleaning up source (local variables etc.) 0018 // - added different QToolTips for each item 0019 // - add more types of KilelistViewItems 0020 // - KileStruct::Sect and KileStruct::BeginFloat will remember assigned labels, 0021 // which are displayed as QToolTips, if these labels are defined in the 0022 // same or the next line 0023 // - Caption for type KileStruct::BeginFloat are displayed in the title 0024 // of this item 0025 // - \includegraphics and float environment items are displayed 0026 // - if an item has a companion label, you can use the context menu (right mouse) 0027 // to insert this label as reference, as a page reference or only the keyword 0028 // into the text or copy it to the clipboard. 0029 // - graphics files have also a context menu to open them with a special program 0030 0031 // 2005-12-08: dani 0032 // - make some items like labels, bibitems, graphics and float environments 0033 // configurable for the user 0034 0035 // 2005-12-16: dani 0036 // - add listview item for undefined references 0037 0038 // 2007-02-15: dani 0039 // - class StructureViewItem gets two new members to 0040 // save the real cursor position of the command 0041 0042 // 2007-03-12 dani 0043 // - use KileDocument::Extensions 0044 0045 // 2007-03-17 dani 0046 // - remember how document structure is collapsed, when structure view is refreshed 0047 0048 // 2007-03-24: dani 0049 // - preliminary minimal support for Beamer class 0050 // - \begin{frame}...\end{frame} and \frame{...} are shown in the structure view 0051 // - if a \frametitle command follows as next LaTeX command, its parameter 0052 // is taken to replace the standard title of this entry in the structure view 0053 // - \begin{block}...\end{block} is taken as child of a frame 0054 0055 // 2007-04-06 dani 0056 // - add TODO/FIXME section to structure view 0057 0058 #include "widgets/structurewidget.h" 0059 0060 #include <QClipboard> 0061 #include <QFileInfo> 0062 #include <QIcon> 0063 #include <QHeaderView> 0064 #include <QMimeDatabase> 0065 #include <QMimeType> 0066 #include <QRegExp> 0067 #include <QScrollBar> 0068 #include <QUrl> 0069 0070 #include <KApplicationTrader> 0071 #include <KIO/ApplicationLauncherJob> 0072 #include <KIO/JobUiDelegateFactory> 0073 #include <KIO/OpenUrlJob> 0074 #include <KJobUiDelegate> 0075 #include <KLocalizedString> 0076 #include <KMessageBox> 0077 0078 #include "documentinfo.h" 0079 #include "errorhandler.h" 0080 #include "kileconfig.h" 0081 #include "kiledebug.h" 0082 #include "kiledocmanager.h" 0083 #include "kileinfo.h" 0084 #include "kileproject.h" 0085 #include "kiletool_enums.h" 0086 #include "parser/parsermanager.h" 0087 #include "widgets/logwidget.h" 0088 0089 namespace KileWidget 0090 { 0091 ////////////////////// StructureViewItem with all info ////////////////////// 0092 0093 StructureViewItem::StructureViewItem(QTreeWidgetItem* parent, const QString &title, const QUrl &url, uint line, uint column, int type, int level, uint startline, uint startcol) : 0094 QTreeWidgetItem(parent), 0095 m_title(title), m_url(url), m_line(line), m_column(column), m_type(type), m_level(level), 0096 m_startline(startline), m_startcol(startcol) 0097 { 0098 setItemEntry(); 0099 } 0100 0101 StructureViewItem::StructureViewItem(QTreeWidget* parent, const QString& label) : 0102 QTreeWidgetItem(parent, QStringList(label)), 0103 m_title(label), m_url(QUrl()), m_line(0), m_column(0), m_type(KileStruct::None), m_level(0) 0104 { 0105 setToolTip(0, i18n("Click left to jump to the line. A double click will open\n a text file or a graphics file. When a label is assigned\nto this item, it will be shown when the mouse is over\nthis item. Items for a graphics file or an assigned label\nalso offer a context menu (right mouse button).")); 0106 } 0107 0108 StructureViewItem::StructureViewItem(const QString& label, QTreeWidgetItem* parent) : 0109 QTreeWidgetItem(parent, QStringList(label)), 0110 m_title(label), m_url(QUrl()), m_line(0), m_column(0), m_type(KileStruct::None), m_level(0) 0111 {} 0112 0113 void StructureViewItem::setTitle(const QString &title) 0114 { 0115 m_title = title; 0116 setItemEntry(); 0117 } 0118 0119 void StructureViewItem::setItemEntry() 0120 { 0121 setText(0, i18nc("structure view entry: title (line)", "%1 (line %2)", m_title, QString::number(m_line))); 0122 setToolTip(0, text(0)); 0123 } 0124 0125 void StructureViewItem::setLabel(const QString &label) 0126 { 0127 m_label = label; 0128 if(!m_label.isEmpty()) { 0129 setToolTip(0, i18n("Label: %1", m_label)); 0130 } 0131 } 0132 0133 ////////////////////// StructureView tree widget ////////////////////// 0134 0135 StructureView::StructureView(StructureWidget *stack, KileDocument::Info *docinfo) : 0136 QTreeWidget(stack), 0137 m_stack(stack), m_docinfo(docinfo) 0138 { 0139 stack->addWidget(this); 0140 setColumnCount(1); 0141 QStringList labelList; 0142 labelList << i18n("Structure"); 0143 setHeaderLabels(labelList); 0144 0145 header()->hide(); 0146 header()->setSectionResizeMode(QHeaderView::ResizeToContents); 0147 setAllColumnsShowFocus(true); 0148 setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); 0149 0150 //connect(this, SIGNAL(clicked(QListViewItem*)), m_stack, SLOT(slotClicked(QListViewItem*))); 0151 connect(this, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), m_stack, SLOT(slotDoubleClicked(QTreeWidgetItem*))); 0152 0153 connect(this, SIGNAL(itemClicked(QTreeWidgetItem*,int)), m_stack, SLOT(slotClicked(QTreeWidgetItem*))); 0154 connect(m_stack, SIGNAL(configChanged()), this, SLOT(slotConfigChanged())); 0155 0156 init(); 0157 } 0158 0159 StructureView::~StructureView() {} 0160 0161 void StructureView::init() 0162 { 0163 QString title = (!m_docinfo) ? i18n("No \"structure data\" to display.") : m_docinfo->url().fileName(); 0164 m_root = new StructureViewItem(this, title); 0165 if(m_docinfo) { 0166 m_root->setURL(m_docinfo->url()); 0167 m_root->setExpanded(true); 0168 m_root->setIcon(0, QIcon::fromTheme("contents")); 0169 connect(m_docinfo, SIGNAL(foundItem(QString,uint,uint,int,int,uint,uint,QString,QString)), 0170 this, SLOT(addItem(QString,uint,uint,int,int,uint,uint,QString,QString))); 0171 } 0172 0173 m_parent[0]=m_parent[1]=m_parent[2]=m_parent[3]=m_parent[4]=m_parent[5]=m_parent[6]=m_root; 0174 m_lastType = KileStruct::None; 0175 m_lastSectioning = Q_NULLPTR; 0176 m_lastFloat = Q_NULLPTR; 0177 m_lastFrame = Q_NULLPTR; 0178 m_lastFrameEnv = Q_NULLPTR; 0179 m_stop = false; 0180 0181 m_folders.clear(); 0182 m_references.clear(); 0183 0184 if(m_docinfo) { 0185 m_openStructureLabels = m_docinfo->openStructureLabels(); 0186 m_openStructureReferences = m_docinfo->openStructureReferences(); 0187 m_openStructureBibitems = m_docinfo->openStructureBibitems(); 0188 m_openStructureTodo = m_docinfo->openStructureTodo(); 0189 m_showStructureLabels = m_docinfo->showStructureLabels(); 0190 } 0191 else { 0192 m_openStructureLabels = false; 0193 m_openStructureReferences = false; 0194 m_openStructureBibitems = false; 0195 m_openStructureTodo = false; 0196 m_showStructureLabels = false; 0197 } 0198 } 0199 0200 void StructureView::updateRoot() 0201 { 0202 m_root->setURL( m_docinfo->url() ); 0203 m_root->setText(0, m_docinfo->url().fileName() ); 0204 } 0205 0206 void StructureView::cleanUp(bool preserveState/* = true */) 0207 { 0208 KILE_DEBUG_MAIN << "==void StructureView::cleanUp()========"; 0209 if(preserveState) { 0210 saveState(); 0211 } 0212 clear(); 0213 if(m_docinfo) { 0214 disconnect(m_docinfo, 0, this, 0); 0215 } 0216 init(); 0217 } 0218 0219 void StructureView::slotConfigChanged() { 0220 QWidget *current = m_stack->currentWidget(); 0221 if(!current) { 0222 return; 0223 } 0224 cleanUp(false); 0225 m_stack->update(m_docinfo, true); 0226 } 0227 0228 void StructureView::contextMenuEvent(QContextMenuEvent *event) 0229 { 0230 m_stack->viewContextMenuEvent(this, event); 0231 } 0232 0233 void StructureView::saveState() 0234 { 0235 KILE_DEBUG_MAIN << "===void StructureView::saveState()"; 0236 m_openByTitle.clear(); 0237 m_openByLine.clear(); 0238 m_openByFolders.clear(); 0239 0240 QTreeWidgetItemIterator it(this); 0241 StructureViewItem *item = Q_NULLPTR; 0242 while(*it) { 0243 item = dynamic_cast<StructureViewItem*>(*it); 0244 if(item && item->child(0)) { 0245 //we don't accept duplicate entries in the map, remove this item alltogether 0246 //and rely on the openByLine map instead 0247 if(m_openByTitle.contains(item->title())) { 0248 m_openByTitle.remove(item->title()); 0249 } 0250 else { 0251 m_openByTitle[item->title()] = item->isExpanded(); 0252 } 0253 0254 m_openByLine[item->line()] = item->isExpanded(); 0255 } 0256 ++it; 0257 } 0258 0259 if(m_folders.contains("labels")) { 0260 m_openByFolders["labels"] = m_folders["labels"]->isExpanded(); 0261 } 0262 if(m_folders.contains("refs")) { 0263 m_openByFolders["refs"] = m_folders["refs"]->isExpanded(); 0264 } 0265 if(m_folders.contains("bibs")) { 0266 m_openByFolders["bibs"] = m_folders["bibs"]->isExpanded(); 0267 } 0268 if(m_folders.contains("todo")) { 0269 m_openByFolders["todo"] = m_folders["todo"]->isExpanded(); 0270 } 0271 if(m_folders.contains("fixme")) { 0272 m_openByFolders["fixme"] = m_folders["fixme"]->isExpanded(); 0273 } 0274 } 0275 0276 bool StructureView::shouldBeOpen(StructureViewItem *item, const QString & folder, int level) 0277 { 0278 if(!item->parent()) { 0279 return true; 0280 } 0281 if(folder == "labels") { 0282 if(m_openByFolders.contains("labels")) { 0283 return m_openByFolders["labels"]; 0284 } 0285 else { 0286 return m_openStructureLabels; 0287 } 0288 } 0289 else if(folder == "refs") { 0290 if(m_openByFolders.contains("refs")) { 0291 return m_openByFolders["refs"]; 0292 } 0293 else { 0294 return m_openStructureReferences; 0295 } 0296 } 0297 else if(folder == "bibs") { 0298 if(m_openByFolders.contains("bibs")) { 0299 return m_openByFolders["bibs"]; 0300 } 0301 else { 0302 return m_openStructureBibitems; 0303 } 0304 } 0305 else if(folder=="todo" || folder=="fixme") { 0306 if(m_openByFolders.contains(folder)) { 0307 return m_openByFolders[folder]; 0308 } 0309 else { 0310 return m_openStructureTodo; 0311 } 0312 } 0313 0314 if(m_openByTitle.contains(item->title())) { 0315 return m_openByTitle[item->title()]; 0316 } 0317 else if(m_openByLine.contains(item->line())) { 0318 return m_openByLine[item->line()]; //TODO check surrounding lines as well 0319 } 0320 else { 0321 return ((folder == "root") && level <= m_stack->level()); 0322 } 0323 } 0324 0325 StructureViewItem* StructureView::createFolder(const QString &folder) 0326 { 0327 StructureViewItem *fldr = new StructureViewItem(folder); 0328 // add it as a top-level child 0329 m_root->insertChild(0, fldr); 0330 fldr->setExpanded(false); 0331 if(folder == "labels") { 0332 fldr->setText(0, i18n("Labels")); 0333 fldr->setIcon(0, QIcon::fromTheme("label")); 0334 } 0335 else if(folder == "bibs") { 0336 fldr->setText(0, i18n("BibTeX References")); 0337 fldr->setIcon(0, QIcon::fromTheme("viewbib")); 0338 } 0339 else if(folder == "refs") { 0340 fldr->setText(0, i18n("Undefined References")); 0341 fldr->setIcon(0, QIcon::fromTheme("dialog-error")); 0342 } 0343 else if(folder == "todo") { 0344 fldr->setText(0, i18n("TODO")); 0345 fldr->setIcon(0, QIcon::fromTheme("bookmarks")); 0346 } 0347 else if(folder == "fixme") { 0348 fldr->setText(0, i18n("FIXME")); 0349 fldr->setIcon(0, QIcon::fromTheme("bookmarks")); 0350 } 0351 0352 m_folders[folder] = fldr; 0353 0354 return m_folders[folder]; 0355 } 0356 0357 StructureViewItem* StructureView::folder(const QString &folder) 0358 { 0359 StructureViewItem *item = m_folders[folder]; 0360 if(!item) { 0361 item = createFolder(folder); 0362 } 0363 return item; 0364 } 0365 0366 void StructureView::activate() 0367 { 0368 if(m_stack->indexOf(this) >= 0) { 0369 m_stack->setCurrentWidget(this); 0370 } 0371 } 0372 0373 StructureViewItem *StructureView::parentFor(int lev, const QString & fldr) 0374 { 0375 StructureViewItem *par = Q_NULLPTR; 0376 0377 if(fldr == "root") { 0378 switch(lev) { 0379 case KileStruct::Object: 0380 case KileStruct::File: 0381 par = (!m_lastSectioning) ? m_root : m_lastSectioning; 0382 break; 0383 0384 case 0: 0385 case 1: 0386 par = m_root; 0387 break; 0388 0389 default: 0390 par = m_parent[lev - 2]; 0391 break; 0392 } 0393 } 0394 else { 0395 par = folder(fldr); 0396 } 0397 0398 return par; 0399 } 0400 0401 ////////////////////// add a new item to the tree widget ////////////////////// 0402 0403 /* some items have a special action: 0404 - KileStruct::Sect: 0405 The new item is saved in m_lastSectioning, so that all following entries 0406 can be inserted as children. \part will drop back to level 0 of the Listview, 0407 all other sectioning commands will be children of the last sectioning item. 0408 If a \label command follows in the same or the next line, it is assigned 0409 to this item. 0410 - KileStruct::BeginFloat: 0411 The new item is saved in m_lastFloat. If a \caption command follows before 0412 the floating environment is closed, it is inserted into the title of this item. 0413 If a \label command follows, it is assigned to this float item. 0414 - KileStruct::EndFloat 0415 Reset m_lastFloat to Q_NULLPTR to close this environment. No more \caption or \label 0416 commands are assigned to this float after this. 0417 - KileStruct::Caption 0418 If a float environment is opened, the caption is assigned to the float item. 0419 A caption item has hidden attribute, so that no other action is performed and 0420 function addItem() will return immediately. 0421 - KileStruct::Label 0422 If we are inside a float, this label is assigned to this environment. If the last 0423 type was a sectioning command on the current line or the line before, the label is 0424 assigned to this sectioning item. Assigning means that a popup menu will open, 0425 when the mouse is over this item. 0426 - KileStruct::BeamerBeginFrame 0427 The new item is saved in m_lastFrameEnv. If a \frametitle command follows before 0428 the frame environment is closed, it is inserted into the title of this item. 0429 If a \label command follows, it is assigned to this float item. 0430 - KileStruct::BeamerEndFrame 0431 Reset m_lastFloatEnv to Q_NULLPTR to close this environment. No more \frametitle 0432 or \label commands are assigned to this frame after this. 0433 - KileStruct::BeamerBeginBlock 0434 Inside a beamer frame this environment is taken as child of this frame 0435 - KileStruct::BeamerFrame 0436 The new item is saved in m_lastFrame. If a \frametitle command follows 0437 immediately as next command, it is inserted into the title of this item. 0438 */ 0439 0440 void StructureView::addItem(const QString &title, uint line, uint column, int type, int lev, 0441 uint startline, uint startcol, 0442 const QString &pix, const QString &fldr /* = "root" */) 0443 { 0444 // KILE_DEBUG_MAIN << "\t\taddItem: " << title << ", with type " << type; 0445 if(m_stop) { 0446 return; 0447 } 0448 0449 // some types need a special action 0450 if(type == KileStruct::Reference) { 0451 m_references.prepend(KileReferenceData(title, line, column)); 0452 } 0453 else if(type==KileStruct::Caption && m_lastFloat) { 0454 QString floattitle = m_lastFloat->title(); 0455 if(floattitle == "figure" || floattitle == "table") { 0456 m_lastFloat->setTitle(floattitle+": "+title); 0457 } 0458 } 0459 else if(type == KileStruct::EndFloat) { 0460 m_lastFloat = Q_NULLPTR; 0461 } 0462 else if(type == KileStruct::BeamerFrametitle) { 0463 if(m_lastFrameEnv) { 0464 m_lastFrameEnv->setTitle(title); 0465 } 0466 else if(m_lastFrame) { 0467 m_lastFrame->setTitle(title); 0468 } 0469 } 0470 else if(type == KileStruct::BeamerEndFrame) { 0471 m_lastFrameEnv = Q_NULLPTR; 0472 } 0473 m_lastFrame = Q_NULLPTR; 0474 0475 // that's all for hidden types: we must immediately return 0476 if(lev == KileStruct::Hidden) { 0477 //KILE_DEBUG_MAIN << "\t\thidden item: not created"; 0478 return; 0479 } 0480 0481 //KILE_DEBUG_MAIN << "\t\tcreate new item"; 0482 // check if we have to update a label before loosing this item 0483 if(type==KileStruct::Label) { 0484 if(m_lastFloat) { 0485 m_lastFloat->setLabel(title); 0486 } 0487 else if(m_lastType == KileStruct::Sect) { 0488 // check if this is a follow up label for the last sectioning item 0489 if(m_lastSectioning && (m_lastLine == line-1 || m_lastLine==line)) { 0490 m_lastSectioning->setLabel(title); 0491 } 0492 } 0493 else if(m_lastType == KileStruct::BeamerBeginFrame && m_lastFrameEnv) { 0494 m_lastFrameEnv->setLabel(title); 0495 } 0496 0497 if(!m_showStructureLabels) { // if we don't want to have it displayed return here 0498 return; 0499 } 0500 } 0501 0502 // remember current type and line for the next call of addItem() 0503 m_lastType = type; 0504 m_lastLine = line; 0505 0506 //find the parent for the new element 0507 StructureViewItem *parentItem = (type == KileStruct::BeamerBeginBlock && m_lastFrameEnv) ? m_lastFrameEnv : parentFor(lev, fldr); 0508 if(!parentItem) { 0509 KMessageBox::error(m_stack->info()->mainWindow(), i18n("Cannot create a list view item: no parent found.")); 0510 return; 0511 } 0512 0513 // create a new item 0514 StructureViewItem *newChild = new StructureViewItem(parentItem, title, m_docinfo->url(), line, column, type, lev, startline, startcol); 0515 if(!pix.isEmpty()) { 0516 newChild->setIcon(0, QIcon::fromTheme(pix)); 0517 } 0518 //m_stop = true; 0519 0520 //if the level is not greater than the defaultLevel 0521 //open the parentItem to make this item visible 0522 parentItem->setExpanded(shouldBeOpen(parentItem, fldr, lev)); 0523 0524 //update the m_parent levels, such that section etc. get inserted at the correct level 0525 //m_current = newChild; 0526 if(lev > 0) { 0527 m_parent[lev - 1] = newChild; 0528 for(int l = lev; l < 7; ++l) { 0529 m_parent[l] = newChild; 0530 } 0531 } 0532 else if(lev == 0) { 0533 m_lastSectioning = Q_NULLPTR; 0534 for(int l = 0; l < 7; ++l) { 0535 m_parent[l] = m_root; 0536 } 0537 } 0538 0539 // check if we have to remember the new item for setting a label or caption 0540 if(type == KileStruct::Sect) { 0541 m_lastSectioning = newChild; 0542 } 0543 else if(type == KileStruct::BeginFloat) { 0544 m_lastFloat = newChild; 0545 } 0546 else if(type == KileStruct::BeamerBeginFrame) { 0547 m_lastFrameEnv = newChild; 0548 } 0549 else if(type == KileStruct::BeamerFrame) { 0550 m_lastFrame = newChild; 0551 } 0552 } 0553 0554 void StructureView::showReferences(KileInfo *ki) 0555 { 0556 // remove old listview item for references, if it exists 0557 if(m_folders.contains("refs")) { 0558 StructureViewItem *refitem = m_folders["refs"]; 0559 m_root->removeChild(refitem); 0560 delete refitem; 0561 0562 m_folders.remove("refs"); 0563 } 0564 0565 //KILE_DEBUG_MAIN << "==void StructureView::showReferences()========"; 0566 //KILE_DEBUG_MAIN << "\tfound " << m_references.count() << " references"; 0567 if(m_references.count() == 0) { 0568 return; 0569 } 0570 0571 // read list with all labels 0572 QStringList list = ki->allLabels(); 0573 //KILE_DEBUG_MAIN << "\tfound " << list.count() << " labels"; 0574 QMap<QString,bool> labelmap; 0575 for (QStringList::const_iterator itmap = list.constBegin(); itmap != list.constEnd(); ++itmap) { 0576 labelmap[(*itmap)] = true; 0577 } 0578 0579 // now check if there are unsolved references 0580 for (QList<KileReferenceData>::const_iterator it = m_references.constBegin(); it!=m_references.constEnd(); ++it) { 0581 if(!labelmap.contains((*it).name())) { 0582 StructureViewItem *refitem = folder("refs"); 0583 refitem->setExpanded(shouldBeOpen(refitem, "refs", 0)); 0584 new StructureViewItem(refitem, (*it).name(), m_docinfo->url(), (*it).line(), (*it).column(), KileStruct::Reference, KileStruct::NotSpecified, 0, 0); 0585 } 0586 } 0587 } 0588 0589 ////////////////////// StructureWidget: QWidgetStack ////////////////////// 0590 0591 StructureWidget::StructureWidget(KileInfo *ki, QWidget * parent, const char* name) : 0592 QStackedWidget(parent), 0593 m_ki(ki), 0594 m_docinfo(Q_NULLPTR), 0595 m_showingContextMenu(Q_NULLPTR) 0596 { 0597 setObjectName(name); 0598 KILE_DEBUG_MAIN << "==KileWidget::StructureWidget::StructureWidget()==========="; 0599 setLineWidth(0); 0600 setMidLineWidth(0); 0601 setContentsMargins(0, 0, 0, 0); 0602 setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); 0603 0604 m_default = new StructureView(this, Q_NULLPTR); 0605 m_default->activate(); 0606 0607 connect(m_ki->parserManager(), SIGNAL(documentParsingStarted()), this, SLOT(handleDocumentParsingStarted())); 0608 connect(m_ki->parserManager(), SIGNAL(documentParsingComplete()), this, SLOT(handleDocumentParsingCompleted())); 0609 } 0610 0611 StructureWidget::~StructureWidget() 0612 { 0613 } 0614 0615 int StructureWidget::level() 0616 { 0617 return KileConfig::defaultLevel(); 0618 } 0619 0620 void StructureWidget::addDocumentInfo(KileDocument::Info *docinfo) 0621 { 0622 StructureView *view = new StructureView(this, docinfo); 0623 addWidget(view); 0624 m_map.insert(docinfo, view); 0625 } 0626 0627 void StructureWidget::slotClicked(QTreeWidgetItem * itm) 0628 { 0629 KILE_DEBUG_MAIN << "\tStructureWidget::slotClicked"; 0630 0631 StructureViewItem *item = dynamic_cast<StructureViewItem*>(itm); 0632 //return if user didn't click on an item 0633 if(!item) { 0634 return; 0635 } 0636 0637 if(!(item->type() & KileStruct::None)) { 0638 emit(setCursor(item->url(), item->line()-1, item->column())); 0639 } 0640 else if(!item->parent()) { //root item 0641 emit(setCursor(item->url(), 0, 0)); 0642 } 0643 } 0644 0645 void StructureWidget::slotDoubleClicked(QTreeWidgetItem * itm) 0646 { 0647 KILE_DEBUG_MAIN << "\tStructureWidget::slotDoubleClicked"; 0648 StructureViewItem *item = dynamic_cast<StructureViewItem*>(itm); 0649 static QRegExp suffix("\\.[\\d\\w]*$"); 0650 0651 if (!item) { 0652 return; 0653 } 0654 0655 KILE_DEBUG_MAIN <<"item->url() is " << item->url() << ", item->title() is " << item->title(); 0656 0657 if(item->type() & (KileStruct::Input | KileStruct::Bibliography | KileStruct::Graphics)) { 0658 QString fname = item->title(); 0659 0660 0661 if(fname.indexOf(suffix) != -1) { // check if we have a suffix, if not add standard suffixes 0662 KILE_DEBUG_MAIN << "Suffix found: " << suffix.cap(0); 0663 } 0664 else { 0665 // filename in structureview entry has no extension: this shouldn't happen anymore, 0666 // because all have got one in function updateStruct(). But who knows? 0667 if(item->type() == KileStruct::Input) { 0668 fname += m_ki->extensions()->latexDocumentDefault(); 0669 } 0670 else if(item->type() == KileStruct::Bibliography) { 0671 fname += m_ki->extensions()->bibtexDefault(); 0672 } 0673 else if(item->type() == KileStruct::Graphics) { 0674 0675 KileProjectItem *kiItem = m_ki->docManager()->itemFor(item->url()); 0676 KileProject *proj; 0677 QString extToAdd; 0678 bool fromProject = true; 0679 0680 if(kiItem && (proj = kiItem->project())) { 0681 extToAdd = proj->defaultGraphicExt(); 0682 } 0683 if(extToAdd.isEmpty()) { 0684 extToAdd = KileConfig::svDefaultGraphicExt(); 0685 fromProject = false; 0686 } 0687 0688 m_ki->errorHandler()->printMessage(KileTool::Info, 0689 (fromProject ? 0690 i18n("No extension specified for graphic file. Using .%1 from Project settings.", extToAdd) : 0691 i18n("No extension specified for graphic file. Using .%1 from global Structure View settings.", extToAdd)), 0692 i18n("File extension not specified")); 0693 0694 fname += '.' + extToAdd; 0695 0696 } 0697 else { 0698 KILE_DEBUG_MAIN << "Suffixless item with unknown type found"; 0699 } 0700 0701 } 0702 0703 if(QDir::isRelativePath(fname)) { // no absolute path 0704 QString fn = m_ki->getCompileName(); 0705 fname= QFileInfo(fn).path() + QDir::separator() + fname; 0706 } 0707 0708 QFileInfo fi(fname); 0709 0710 if(fi.isReadable()) { 0711 QUrl url = QUrl::fromLocalFile(fname); 0712 if(item->type() == KileStruct::Graphics) { 0713 QMimeDatabase db; 0714 QMimeType pMime = db.mimeTypeForUrl(url); 0715 auto *job = new KIO::OpenUrlJob(url, pMime.name()); 0716 job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this)); 0717 job->start(); 0718 } 0719 else { 0720 emit(fileOpen(url, QString())); 0721 } 0722 } 0723 else { 0724 QString otherFilename; 0725 0726 if(item->type() == KileStruct::Bibliography) { 0727 otherFilename = m_ki->checkOtherPaths(fi.path(), fi.fileName(), KileInfo::bibinputs); 0728 } 0729 else if(item->type() == KileStruct::Input) { 0730 otherFilename = m_ki->checkOtherPaths(fi.path(), fi.fileName(), KileInfo::texinputs); 0731 } 0732 0733 fi.setFile(otherFilename); 0734 0735 if(fi.isReadable()) { 0736 emit(fileOpen(QUrl::fromLocalFile(otherFilename), QString())); 0737 } 0738 else { 0739 if(KMessageBox::warningTwoActions(this, 0740 i18n("Cannot find the included file. The file does not exist, is not readable or Kile is unable to determine the correct path to it. The filename causing this error was: %1.\nDo you want to create this file?", fname), 0741 i18n("Cannot Find File"), 0742 KStandardGuiItem::ok(), 0743 KStandardGuiItem::cancel()) 0744 == KMessageBox::PrimaryAction) { 0745 emit(fileNew(QUrl::fromLocalFile(fname))); 0746 } 0747 } 0748 } 0749 } 0750 } 0751 0752 // all popup items get different id's, so that we can see, what item is activated 0753 // - label: 1 - 6 0754 // - sectioning: 10 - 16 0755 // - graphics: 100ff 0756 void StructureWidget::viewContextMenuEvent(StructureView *view, QContextMenuEvent *event) 0757 { 0758 KILE_DEBUG_MAIN << "\tcalled"; 0759 0760 QMenu popup; 0761 m_showingContextMenu = Q_NULLPTR; 0762 0763 m_popupItem = dynamic_cast<StructureViewItem*>(view->itemAt(event->pos())); 0764 if(!m_popupItem) { 0765 KILE_DEBUG_MAIN << "not a pointer to a StructureViewItem object."; 0766 return; 0767 } 0768 0769 bool hasLabel = !(m_popupItem->label().isEmpty()); 0770 0771 if(m_popupItem->type() == KileStruct::Sect) { 0772 if(hasLabel) { 0773 popup.addSection(i18n("Sectioning")); 0774 } 0775 popup.addAction(i18n("Cu&t"), this, [this] { slotPopupSectioning(SectioningCut); }); 0776 popup.addAction(i18n("&Copy"), this, [this] { slotPopupSectioning(SectioningCopy); }); 0777 popup.addAction(i18n("&Paste below"), this, [this] { slotPopupSectioning(SectioningPaste); }); 0778 popup.addSeparator(); 0779 popup.addAction(i18n("&Select"), this, [this] { slotPopupSectioning(SectioningSelect); }); 0780 popup.addAction(i18n("&Delete"), this, [this] { slotPopupSectioning(SectioningDelete); }); 0781 popup.addSeparator(); 0782 popup.addAction(i18n("C&omment"), this, [this] { slotPopupSectioning(SectioningComment); }); 0783 popup.addSeparator(); 0784 popup.addAction(i18n("Run QuickPreview"), this, [this] { slotPopupSectioning(SectioningPreview); }); 0785 } 0786 else if(m_popupItem->type() == KileStruct::Graphics) { 0787 m_popupInfo = m_popupItem->title(); 0788 0789 if(!QDir::isAbsolutePath(m_popupInfo)) { 0790 QString fn = m_ki->getCompileName(); 0791 m_popupInfo = QFileInfo(fn).path() + '/' + m_popupInfo; 0792 } 0793 0794 QFileInfo fi(m_popupInfo); 0795 if(fi.isReadable()) { 0796 QUrl url; 0797 url.setPath(m_popupInfo); 0798 0799 QMimeDatabase db; 0800 m_offerList = KApplicationTrader::queryByMimeType(db.mimeTypeForUrl(url).name()); 0801 for(int i = 0; i < m_offerList.count(); ++i) { 0802 popup.addAction(QIcon::fromTheme(m_offerList[i]->icon()), m_offerList[i]->name(), 0803 this, [this, i] { slotPopupGraphics(i + SectioningGraphicsOfferlist); }); 0804 } 0805 popup.addSeparator(); 0806 popup.addAction(i18n("Other..."), this, [this] { slotPopupGraphics(SectioningGraphicsOther); }); 0807 } 0808 } 0809 0810 if(hasLabel) { 0811 popup.addSection(i18n("Insert Label")); 0812 popup.addAction(i18n("As &reference"), this, [this] { emit(sendText("\\ref{" + m_popupItem->label() + '}')); }); 0813 popup.addAction(i18n("As &page reference"), this, [this] { emit(sendText("\\pageref{" + m_popupItem->label() + '}')); }); 0814 popup.addAction(i18n("Only the &label"), this, [this] { emit(sendText(m_popupItem->label())); }); 0815 popup.addSeparator(); 0816 popup.addSection(i18n("Copy Label to Clipboard")); 0817 popup.addAction(i18n("As reference"), this, [this] { QApplication::clipboard()->setText("\\ref{" + m_popupItem->label() + '}'); }); 0818 popup.addAction(i18n("As page reference"), this, [this] { QApplication::clipboard()->setText("\\pageref{" + m_popupItem->label() + '}'); }); 0819 popup.addAction(i18n("Only the label"), this, [this] { QApplication::clipboard()->setText(m_popupItem->label()); }); 0820 } 0821 0822 if(!popup.isEmpty()) { 0823 m_showingContextMenu = &popup; 0824 popup.exec(event->globalPos()); 0825 m_showingContextMenu = Q_NULLPTR; 0826 } 0827 } 0828 0829 // id's 10..16 (already checked) 0830 void StructureWidget::slotPopupSectioning(int id) 0831 { 0832 KILE_DEBUG_MAIN << "\tStructureWidget::slotPopupSectioning (" << id << ")"<< Qt::endl; 0833 if(m_popupItem->level() >= 1 && m_popupItem->level() <= 7) { 0834 emit(sectioningPopup(m_popupItem, id)); 0835 } 0836 } 0837 0838 // id's 100ff (already checked) 0839 void StructureWidget::slotPopupGraphics(int id) 0840 { 0841 KILE_DEBUG_MAIN << "\tStructureWidget::slotPopupGraphics (" << id << ")"<< Qt::endl; 0842 0843 QUrl url; 0844 url.setPath(m_popupInfo); 0845 0846 if(id == SectioningGraphicsOther) { 0847 // open with dialog 0848 auto *job = new KIO::ApplicationLauncherJob(); 0849 job->setUrls(QList<QUrl>() << url); 0850 job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this)); 0851 job->start(); 0852 } 0853 else { 0854 auto *job = new KIO::ApplicationLauncherJob(m_offerList[id-SectioningGraphicsOfferlist]); 0855 job->setUrls(QList<QUrl>() << url); 0856 job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this)); 0857 job->start(); 0858 } 0859 } 0860 0861 StructureView* StructureWidget::viewFor(KileDocument::Info *info) 0862 { 0863 if(!info) { 0864 return Q_NULLPTR; 0865 } 0866 0867 if(!viewExistsFor(info)) { 0868 m_map.insert(info, new StructureView(this, info)); 0869 } 0870 0871 return m_map[info]; 0872 } 0873 0874 bool StructureWidget::viewExistsFor(KileDocument::Info *info) 0875 { 0876 if(!info) { 0877 return false; 0878 } 0879 else { 0880 return m_map.contains(info); 0881 } 0882 } 0883 0884 void StructureWidget::closeDocumentInfo(KileDocument::Info *docinfo) 0885 { 0886 m_docinfo = Q_NULLPTR; 0887 if(m_map.contains(docinfo)) { 0888 StructureView *data = m_map[docinfo]; 0889 m_map.remove(docinfo); 0890 delete data; 0891 } 0892 0893 if(m_map.isEmpty()) { 0894 m_default->activate(); 0895 } 0896 } 0897 0898 void StructureWidget::clear() 0899 { 0900 QMap<KileDocument::Info *, StructureView *>::iterator it; 0901 QMap<KileDocument::Info *, StructureView *>::iterator itend(m_map.end()); 0902 for (it = m_map.begin(); it != itend; ++it) { 0903 if(it.value()) { 0904 delete it.value(); 0905 } 0906 } 0907 0908 m_map.clear(); 0909 m_docinfo = Q_NULLPTR; 0910 0911 m_default->activate(); 0912 } 0913 0914 void StructureWidget::updateUrl(KileDocument::Info *docinfo) 0915 { 0916 StructureView *view = viewFor(docinfo); 0917 if(view) { 0918 view->updateRoot(); 0919 } 0920 } 0921 0922 void StructureWidget::update(KileDocument::Info *docinfo) 0923 { 0924 update(docinfo, false); 0925 } 0926 0927 void StructureWidget::update(KileDocument::Info *docinfo, bool forceParsing) 0928 { 0929 KILE_DEBUG_MAIN << "==KileWidget::StructureWidget::update(" << docinfo << ")============="; 0930 0931 if(!docinfo) { 0932 m_default->activate(); 0933 return; 0934 } 0935 0936 m_docinfo = docinfo; 0937 bool needParsing = forceParsing || m_docinfo->isDirty() || !viewExistsFor(docinfo); 0938 0939 //find structview-item for this docinfo 0940 StructureView *view = viewFor(m_docinfo); 0941 if(!view) { 0942 m_default->activate(); 0943 return; 0944 } 0945 0946 if(needParsing) { //need to reparse the doc 0947 m_docinfo->updateStruct(); 0948 } 0949 0950 KILE_DEBUG_MAIN << "activating view"; 0951 view->activate(); 0952 } 0953 0954 void StructureWidget::updateAfterParsing(KileDocument::Info *info, const std::list<KileParser::StructureViewItem*>& items) 0955 { 0956 KILE_DEBUG_MAIN; 0957 StructureView *view = viewFor(info); 0958 if(!view) { 0959 m_default->activate(); 0960 return; 0961 } 0962 0963 int xtop = view->horizontalScrollBar()->value(); 0964 int ytop = view->verticalScrollBar()->value(); 0965 // avoid flickering when parsing 0966 view->setUpdatesEnabled(false); 0967 view->cleanUp(); 0968 for(KileParser::StructureViewItem *item : items) { 0969 view->addItem(item->title, item->line, item->column, item->type, item->level, item->startline, item->startcol, item->pix, item->folder); 0970 } 0971 view->setUpdatesEnabled(true); 0972 view->showReferences(m_ki); 0973 view->horizontalScrollBar()->setValue(xtop); 0974 view->verticalScrollBar()->setValue(ytop); 0975 } 0976 0977 void StructureWidget::clean(KileDocument::Info *docinfo) 0978 { 0979 KILE_DEBUG_MAIN << "==void StructureWidget::clean()========"; 0980 StructureView *view = viewFor(docinfo); 0981 if(view) { 0982 view->cleanUp(); 0983 } 0984 } 0985 0986 void StructureWidget::updateReferences(KileDocument::Info *docinfo) 0987 { 0988 KILE_DEBUG_MAIN << "==void StructureView::updateReferences()========"; 0989 StructureView *view = viewFor(docinfo); 0990 if(view) { 0991 view->showReferences(m_ki); 0992 } 0993 } 0994 0995 ////////////////////// StructureWidget: find sectioning ////////////////////// 0996 0997 bool StructureWidget::findSectioning(StructureViewItem *refItem, KTextEditor::Document *doc, int row, int col, bool backwards, bool checkLevel, int §Row, int §Col) 0998 { 0999 KileDocument::TextInfo *docinfo = m_ki->docManager()->textInfoFor(doc); 1000 if(!docinfo) { 1001 return false; 1002 } 1003 1004 if( checkLevel && !refItem ) { // only allow a refItem == Q_NULLPTR if checkLevel is false 1005 return false; 1006 } 1007 1008 bool found = false; 1009 int foundRow, foundCol; 1010 StructureView *structurelist = viewFor(docinfo); 1011 QTreeWidgetItemIterator it(structurelist); 1012 while(*it) { 1013 StructureViewItem *item = dynamic_cast<StructureViewItem*>(*it); 1014 if (item && item->type() == KileStruct::Sect && (!checkLevel || item->level() <= refItem->level())) { 1015 foundRow = item->startline() - 1; 1016 foundCol = item->startcol() - 1; 1017 if(backwards) { 1018 if(foundRow < row || (foundRow==row && foundCol < col)) { 1019 sectRow = foundRow; 1020 sectCol = foundCol; 1021 found = true; 1022 } 1023 else { 1024 return found; 1025 } 1026 1027 } 1028 else if(!backwards && (foundRow > row || (foundRow == row && foundCol > col))) { 1029 sectRow = foundRow; 1030 sectCol = foundCol; 1031 return true; 1032 } 1033 } 1034 ++it; 1035 } 1036 1037 return found; 1038 } 1039 1040 void StructureWidget::handleDocumentParsingStarted() 1041 { 1042 setEnabled(false); 1043 // if a context menu is showing, we better close it 1044 // as the StructureViewItems it operates on will be deleted 1045 if(m_showingContextMenu) { 1046 m_showingContextMenu->close(); 1047 } 1048 } 1049 1050 void StructureWidget::handleDocumentParsingCompleted() 1051 { 1052 setEnabled(true); 1053 } 1054 } 1055