Warning, file /sdk/ktechlab/src/textdocument.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /*************************************************************************** 0002 * Copyright (C) 2005 by David Saxton * 0003 * david@bluehaze.org * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 ***************************************************************************/ 0010 0011 #include "textdocument.h" 0012 #include "asmformatter.h" 0013 #include "asminfo.h" 0014 #include "asmparser.h" 0015 #include "debugmanager.h" 0016 #include "docmanager.h" 0017 #include "documentiface.h" 0018 #include "filemetainfo.h" 0019 #include "gpsimprocessor.h" 0020 #include "ktechlab.h" 0021 #include "language.h" 0022 #include "languagemanager.h" 0023 #include "microselectwidget.h" 0024 #include "programmerdlg.h" 0025 #include "symbolviewer.h" 0026 #include "textview.h" 0027 0028 // #include <kate/katedocument.h> 0029 #include <QAction> 0030 #include <QDir> 0031 #include <QTemporaryFile> 0032 0033 #include <KLocalizedString> 0034 #include <KMessageBox> 0035 #include <KTextEditor/Document> 0036 #include <KTextEditor/Editor> 0037 #include <KXMLGUIFactory> 0038 0039 #include <ktechlab_debug.h> 0040 0041 bool TextDocument::isUndoAvailable() const 0042 { 0043 // return (m_doc->undoCount() != 0); 0044 return true; // TODO FIXME fix undo/redo 0045 } 0046 bool TextDocument::isRedoAvailable() const 0047 { 0048 // return (m_doc->redoCount() != 0); 0049 return true; // TODO FIXME fix undo/redo 0050 } 0051 0052 TextDocument *TextDocument::constructTextDocument(const QString &caption) 0053 { 0054 TextDocument *textDocument = new TextDocument(caption); 0055 if (textDocument->m_constructorSuccessful) 0056 return textDocument; 0057 delete textDocument; 0058 return nullptr; 0059 } 0060 0061 TextDocument::TextDocument(const QString &caption) 0062 : Document(caption) 0063 , m_doc(nullptr) 0064 { 0065 m_constructorSuccessful = false; 0066 0067 #ifndef NO_GPSIM 0068 m_bOwnDebugger = false; 0069 b_lockSyncBreakpoints = false; 0070 m_lastDebugLineAt = -1; 0071 m_pDebugger = nullptr; 0072 #endif 0073 0074 m_pLastTextOutputTarget = nullptr; 0075 m_guessedCodeType = TextDocument::ct_unknown; 0076 m_type = Document::dt_text; 0077 // m_bookmarkActions.setAutoDelete(true); // TODO see if this genereates memory leaks 0078 m_pDocumentIface = new TextDocumentIface(this); 0079 KTextEditor::Editor *editor = KTextEditor::Editor::instance(); 0080 m_doc = editor->createDocument(this); 0081 0082 if (!m_doc) { 0083 KMessageBox::error(KTechlab::self(), i18n("Failed to create editor")); 0084 return; 0085 } 0086 guessScheme(); 0087 0088 connect(m_doc, SIGNAL(undoChanged()), this, SIGNAL(undoRedoStateChanged())); 0089 connect(m_doc, SIGNAL(undoChanged()), this, SLOT(slotSyncModifiedStates())); 0090 connect(m_doc, SIGNAL(textChanged(KTextEditor::Document *)), this, SLOT(slotSyncModifiedStates())); 0091 // connect( m_doc, SIGNAL(selectionChanged()), this, SLOT(slotSelectionmChanged()) ); // 2016.09.08 - moved to TextView 0092 connect(m_doc, SIGNAL(marksChanged(KTextEditor::Document *)), this, SLOT(slotUpdateMarksInfo())); 0093 0094 KTextEditor::MarkInterface *markIface = qobject_cast<KTextEditor::MarkInterface *>(m_doc); 0095 if (!markIface) { 0096 KMessageBox::error(KTechlab::self(), i18n("Failed to create MarkInterface")); 0097 return; 0098 } 0099 0100 markIface->setMarkDescription((KTextEditor::MarkInterface::MarkTypes)Breakpoint, i18n("Breakpoint")); 0101 markIface->setMarkPixmap((KTextEditor::MarkInterface::MarkTypes)Breakpoint, *inactiveBreakpointPixmap()); 0102 markIface->setMarkPixmap(KTextEditor::MarkInterface::BreakpointActive, *activeBreakpointPixmap()); 0103 markIface->setMarkPixmap(KTextEditor::MarkInterface::BreakpointReached, *reachedBreakpointPixmap()); 0104 markIface->setMarkPixmap(KTextEditor::MarkInterface::BreakpointDisabled, *disabledBreakpointPixmap()); 0105 markIface->setMarkPixmap(KTextEditor::MarkInterface::Execution, *executionPointPixmap()); 0106 markIface->setEditableMarks(KTextEditor::MarkInterface::Bookmark | Breakpoint); 0107 0108 m_constructorSuccessful = true; 0109 } 0110 0111 TextDocument::~TextDocument() 0112 { 0113 if (!m_constructorSuccessful) 0114 return; 0115 0116 debugStop(); 0117 0118 if (KTechlab::self()) { 0119 ViewList::iterator end = m_viewList.end(); 0120 for (ViewList::iterator it = m_viewList.begin(); it != end; ++it) { 0121 if (TextView *tv = dynamic_cast<TextView *>((View *)*it)) { 0122 KTextEditor::View *kv = tv->kateView(); 0123 KTechlab::self()->factory()->removeClient(kv); 0124 } 0125 } 0126 } 0127 0128 delete m_doc; 0129 delete m_pDocumentIface; 0130 } 0131 0132 bool TextDocument::fileClose() 0133 { 0134 const QUrl u = url(); 0135 if (!u.isEmpty()) 0136 fileMetaInfo()->grabMetaInfo(u, this); 0137 0138 return Document::fileClose(); 0139 } 0140 0141 TextView *TextDocument::textView() const 0142 { 0143 return static_cast<TextView *>(activeView()); 0144 } 0145 0146 View *TextDocument::createView(ViewContainer *viewContainer, uint viewAreaId) 0147 { 0148 TextView *textView = new TextView(this, viewContainer, viewAreaId); 0149 0150 fileMetaInfo()->initializeFromMetaInfo(url(), textView); 0151 0152 handleNewView(textView); 0153 return textView; 0154 } 0155 0156 KTextEditor::View *TextDocument::createKateView(QWidget *parent) 0157 { 0158 // return static_cast<KTextEditor::View*>((m_doc->createView( parent, name ))->qt_cast("Kate::View")); 0159 return m_doc->createView(parent); 0160 } 0161 0162 void TextDocument::cut() 0163 { 0164 if (textView()) 0165 textView()->cut(); 0166 } 0167 void TextDocument::copy() 0168 { 0169 if (textView()) 0170 textView()->copy(); 0171 } 0172 void TextDocument::paste() 0173 { 0174 if (textView()) 0175 textView()->paste(); 0176 } 0177 0178 void TextDocument::setText(const QString &text, bool asInitial) 0179 { 0180 if (asInitial) { 0181 disconnect(m_doc, SIGNAL(undoChanged()), this, SIGNAL(undoRedoStateChanged())); 0182 disconnect(m_doc, SIGNAL(undoChanged()), this, SLOT(slotSyncModifiedStates())); 0183 disconnect(m_doc, SIGNAL(textChanged(KTextEditor::Document *)), this, SLOT(slotSyncModifiedStates())); 0184 } 0185 0186 const ViewList::iterator end = m_viewList.end(); 0187 for (ViewList::iterator it = m_viewList.begin(); it != end; ++it) 0188 (static_cast<TextView *>((View *)*it))->saveCursorPosition(); 0189 0190 m_doc->setText(text); 0191 0192 for (ViewList::iterator it = m_viewList.begin(); it != end; ++it) 0193 (static_cast<TextView *>((View *)*it))->restoreCursorPosition(); 0194 0195 if (asInitial) { 0196 // m_doc->clearUndo(); // TODO FIXME 0197 // m_doc->clearRedo(); // TODO FIXME 0198 qCWarning(KTL_LOG) << "TextDocument::clearUndo TODO"; 0199 setModified(false); 0200 0201 connect(m_doc, SIGNAL(undoChanged()), this, SIGNAL(undoRedoStateChanged())); 0202 connect(m_doc, SIGNAL(undoChanged()), this, SLOT(slotSyncModifiedStates())); 0203 connect(m_doc, SIGNAL(textChanged(KTextEditor::Document *)), this, SLOT(slotSyncModifiedStates())); 0204 } 0205 } 0206 0207 void TextDocument::undo() 0208 { 0209 textView()->undo(); 0210 slotSyncModifiedStates(); 0211 } 0212 0213 void TextDocument::redo() 0214 { 0215 textView()->redo(); 0216 slotSyncModifiedStates(); 0217 } 0218 0219 void TextDocument::slotSyncModifiedStates() 0220 { 0221 setModified(m_doc->isModified()); 0222 } 0223 void TextDocument::setModified(bool modified) 0224 { 0225 if ((modified == b_modified) && (modified == isModified())) { 0226 return; 0227 } 0228 m_doc->setModified(modified); 0229 b_modified = modified; 0230 0231 emit modifiedStateChanged(); 0232 } 0233 0234 void TextDocument::guessScheme(bool allowDisable) 0235 { 0236 // And specific file actions depending on the current type of file 0237 QString fileName = url().fileName(); 0238 QString extension = fileName.right(fileName.length() - fileName.lastIndexOf('.') - 1); 0239 0240 if (extension == "asm" || extension == "src" || extension == "inc") 0241 slotInitLanguage(ct_asm); 0242 0243 else if (extension == "hex") 0244 slotInitLanguage(ct_hex); 0245 0246 else if (extension == "basic" || extension == "microbe") 0247 slotInitLanguage(ct_microbe); 0248 0249 else if (extension == "c") 0250 slotInitLanguage(ct_c); 0251 0252 else if (m_guessedCodeType != TextDocument::ct_unknown) 0253 slotInitLanguage(m_guessedCodeType); 0254 0255 else if (allowDisable && activeView()) 0256 textView()->disableActions(); 0257 } 0258 0259 void TextDocument::slotInitLanguage(CodeType type) 0260 { 0261 QString modeName; 0262 0263 switch (type) { 0264 case ct_asm: 0265 modeName = "PicAsm"; 0266 break; 0267 0268 case ct_c: 0269 modeName = "C"; 0270 break; 0271 0272 case ct_hex: 0273 break; 0274 0275 case ct_microbe: 0276 modeName = "Microbe"; 0277 break; 0278 0279 case ct_unknown: 0280 break; 0281 } 0282 0283 if (!modeName.isEmpty()) { 0284 const QStringList modes = m_doc->modes(); 0285 if (modes.contains(modeName)) { 0286 m_doc->setMode(modeName); 0287 } 0288 } 0289 0290 m_guessedCodeType = type; 0291 0292 ViewList::iterator end = m_viewList.end(); 0293 for (ViewList::iterator it = m_viewList.begin(); it != end; ++it) { 0294 if (TextView *tv = dynamic_cast<TextView *>((View *)*it)) 0295 tv->initCodeActions(); 0296 } 0297 } 0298 0299 void TextDocument::formatAssembly() 0300 { 0301 AsmFormatter formatter; 0302 // QStringList lines = QStringList::split( "\n", m_doc->text(), true ); // 2018.12.01 0303 #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) 0304 QStringList lines = m_doc->text().split("\n", Qt::KeepEmptyParts); 0305 #else 0306 QStringList lines = m_doc->text().split("\n", QString::KeepEmptyParts); 0307 #endif 0308 setText(formatter.tidyAsm(lines), false); 0309 setModified(true); 0310 } 0311 0312 void TextDocument::fileSave(const QUrl &url) 0313 { 0314 if (m_doc->url() != url) { 0315 qCCritical(KTL_LOG) << "Error: Kate::View url and passed url do not match; cannot save."; 0316 return; 0317 } 0318 0319 if (activeView() && (textView()->save())) 0320 saveDone(); 0321 } 0322 0323 void TextDocument::fileSaveAs() 0324 { 0325 if (activeView() && (textView()->saveAs())) 0326 saveDone(); 0327 0328 // Our modified state may not have changed, but we emit this to force the 0329 // main window to update our caption. 0330 emit modifiedStateChanged(); 0331 } 0332 0333 void TextDocument::saveDone() 0334 { 0335 setURL(m_doc->url()); 0336 guessScheme(false); 0337 setModified(false); 0338 emit modifiedStateChanged(); 0339 } 0340 0341 bool TextDocument::openURL(const QUrl &url) 0342 { 0343 m_doc->openUrl(url); 0344 setURL(url); 0345 0346 fileMetaInfo()->initializeFromMetaInfo(url, this); 0347 guessScheme(); 0348 0349 #ifndef NO_GPSIM 0350 DebugManager::self()->urlOpened(this); 0351 #endif 0352 0353 return true; 0354 } 0355 0356 void TextDocument::setLastTextOutputTarget(TextDocument *target) 0357 { 0358 m_pLastTextOutputTarget = target; 0359 } 0360 0361 QString TextDocument::outputFilePath(const QString &ext) 0362 { 0363 QString filePath = url().path(); 0364 if (filePath.isEmpty()) { 0365 QTemporaryFile f(QDir::tempPath() + QLatin1String("/ktechlab_XXXXXX") + ext); 0366 f.setAutoRemove(false); 0367 if (!f.open()) { 0368 qCWarning(KTL_LOG) << " Failed to open temporary file"; 0369 return QString(); 0370 } 0371 QTextStream out(&f); 0372 out << m_doc->text(); 0373 f.close(); 0374 DocManager::self()->associateDocument(QUrl::fromLocalFile(f.fileName()), this); 0375 return f.fileName(); 0376 } 0377 if (isModified()) { 0378 fileSave(); 0379 } 0380 return filePath; 0381 } 0382 0383 void TextDocument::slotConvertTo(QAction *action) 0384 { 0385 int target = action->data().toInt(); 0386 switch ((ConvertToTarget)target) { 0387 case TextDocument::MicrobeOutput: 0388 break; 0389 0390 case TextDocument::AssemblyOutput: 0391 convertToAssembly(); 0392 break; 0393 0394 case TextDocument::HexOutput: 0395 convertToHex(); 0396 break; 0397 0398 case TextDocument::PICOutput: 0399 convertToPIC(); 0400 break; 0401 } 0402 } 0403 0404 void TextDocument::convertToAssembly() 0405 { 0406 QString filePath; 0407 bool showPICSelect = false; 0408 ProcessOptions::ProcessPath::MediaType toType; 0409 0410 if (m_guessedCodeType == TextDocument::ct_microbe) { 0411 toType = ProcessOptions::ProcessPath::AssemblyAbsolute; 0412 filePath = outputFilePath(".microbe"); 0413 } 0414 0415 else if (m_guessedCodeType == TextDocument::ct_hex) { 0416 toType = ProcessOptions::ProcessPath::Disassembly; 0417 filePath = outputFilePath(".hex"); 0418 } 0419 0420 else if (m_guessedCodeType == TextDocument::ct_c) { 0421 toType = ProcessOptions::ProcessPath::AssemblyRelocatable; 0422 filePath = outputFilePath(".c"); 0423 showPICSelect = true; 0424 } 0425 0426 else { 0427 qCCritical(KTL_LOG) << "Could not get file type for converting to assembly!"; 0428 return; 0429 } 0430 0431 OutputMethodDlg dlg(i18n("Assembly Code Output"), url(), showPICSelect, KTechlab::self()); 0432 0433 if (m_guessedCodeType == TextDocument::ct_c) 0434 dlg.microSelect()->setAllowedAsmSet(AsmInfo::PIC14 | AsmInfo::PIC16); 0435 0436 dlg.setOutputExtension(".asm"); 0437 dlg.setFilter(QString("*.asm *.src *.inc|%1 (*.asm, *.src, *.inc)\n*|%2").arg(i18n("Assembly Code")).arg(i18n("All Files"))); 0438 const int accepted = dlg.exec(); 0439 if (accepted != QDialog::Accepted) 0440 return; 0441 0442 ProcessOptions o(dlg.info()); 0443 o.setTextOutputTarget(m_pLastTextOutputTarget, this, SLOT(setLastTextOutputTarget(TextDocument *))); 0444 o.setInputFiles(QStringList(filePath)); 0445 o.setProcessPath(ProcessOptions::ProcessPath::path(ProcessOptions::guessMediaType(filePath), toType)); 0446 LanguageManager::self()->compile(o); 0447 } 0448 0449 void TextDocument::convertToHex() 0450 { 0451 QString filePath; 0452 bool showPICSelect = false; 0453 0454 if (m_guessedCodeType == TextDocument::ct_microbe) 0455 filePath = outputFilePath(".microbe"); 0456 0457 else if (m_guessedCodeType == TextDocument::ct_asm) { 0458 filePath = outputFilePath(".asm"); 0459 showPICSelect = true; // FIXME if we use shared libs, then we need the pic type 0460 } else if (m_guessedCodeType == TextDocument::ct_c) { 0461 filePath = outputFilePath(".c"); 0462 showPICSelect = true; 0463 } 0464 0465 else { 0466 qCCritical(KTL_LOG) << "Could not get file type for converting to hex!"; 0467 return; 0468 } 0469 0470 OutputMethodDlg dlg(i18n("Hex Code Output"), url(), showPICSelect, KTechlab::self()); 0471 dlg.setOutputExtension(".hex"); 0472 dlg.setFilter(QString("*.hex|Hex (*.hex)\n*|%1").arg(i18n("All Files"))); 0473 0474 if (m_guessedCodeType == TextDocument::ct_c) 0475 dlg.microSelect()->setAllowedAsmSet(AsmInfo::PIC14 | AsmInfo::PIC16); 0476 0477 const int accepted = dlg.exec(); 0478 if (accepted != QDialog::Accepted) 0479 return; 0480 0481 ProcessOptions o(dlg.info()); 0482 o.setTextOutputTarget(m_pLastTextOutputTarget, this, SLOT(setLastTextOutputTarget(TextDocument *))); 0483 o.setInputFiles(QStringList(filePath)); 0484 o.setProcessPath(ProcessOptions::ProcessPath::path(ProcessOptions::guessMediaType(filePath), ProcessOptions::ProcessPath::Program)); 0485 LanguageManager::self()->compile(o); 0486 } 0487 0488 void TextDocument::convertToPIC() 0489 { 0490 QString filePath; 0491 0492 QString picID; 0493 0494 switch (m_guessedCodeType) { 0495 case ct_microbe: 0496 filePath = outputFilePath(".microbe"); 0497 break; 0498 0499 case ct_asm: { 0500 filePath = outputFilePath(".asm"); 0501 AsmParser p(filePath); 0502 p.parse(); 0503 picID = p.picID(); 0504 break; 0505 } 0506 0507 case ct_c: 0508 filePath = outputFilePath(".c"); 0509 break; 0510 0511 case ct_hex: 0512 filePath = outputFilePath(".hex"); 0513 break; 0514 0515 case ct_unknown: 0516 qCCritical(KTL_LOG) << "Could not get file type for converting to hex!"; 0517 return; 0518 } 0519 0520 ProgrammerDlg *dlg = new ProgrammerDlg(picID, (QWidget *)KTechlab::self()); 0521 dlg->setObjectName("Programmer Dlg"); 0522 0523 if (m_guessedCodeType == TextDocument::ct_c) 0524 dlg->microSelect()->setAllowedAsmSet(AsmInfo::PIC14 | AsmInfo::PIC16); 0525 0526 const int accepted = dlg->exec(); 0527 if (accepted != QDialog::Accepted) { 0528 dlg->deleteLater(); 0529 return; 0530 } 0531 0532 ProcessOptions o; 0533 dlg->initOptions(&o); 0534 o.setInputFiles(QStringList(filePath)); 0535 o.setProcessPath(ProcessOptions::ProcessPath::path(ProcessOptions::guessMediaType(filePath), ProcessOptions::ProcessPath::Pic)); 0536 LanguageManager::self()->compile(o); 0537 0538 dlg->deleteLater(); 0539 } 0540 0541 void TextDocument::print() 0542 { 0543 // KTextEditor::printInterface(m_doc)->print (); // TODO FIXME 0544 textView()->print(); 0545 } 0546 0547 // 2016.09.08 - moved to TextView 0548 // void TextDocument::slotSelectionmChanged() 0549 // { 0550 // KTechlab::self()->actionByName( "edit_cut" )->setEnabled( /* m_doc->hasSelection () */ m_doc->activeView()->selection() ); 0551 // KTechlab::self()->actionByName( "edit_copy" )->setEnabled( /*m_doc->hasSelection () */ m_doc->activeView()->selection() ); 0552 // } 0553 0554 IntList TextDocument::bookmarkList() const 0555 { 0556 IntList bookmarkList; 0557 0558 typedef QHash<int, KTextEditor::Mark *> MarkList; 0559 KTextEditor::MarkInterface *iface = qobject_cast<KTextEditor::MarkInterface *>(m_doc); 0560 if (!iface) 0561 return IntList(); 0562 // MarkList markList = m_doc->marks(); 0563 const MarkList &markList = iface->marks(); 0564 0565 // Find out what marks need adding to our internal lists 0566 // for ( KTextEditor::Mark * mark = markList.first(); mark; mark = markList.next() ) 0567 for (MarkList::const_iterator itMark = markList.begin(); itMark != markList.end(); ++itMark) { 0568 const KTextEditor::Mark *mark = itMark.value(); 0569 if (mark->type & KTextEditor::MarkInterface::Bookmark) 0570 bookmarkList += mark->line; 0571 } 0572 0573 return bookmarkList; 0574 } 0575 0576 void TextDocument::slotUpdateMarksInfo() 0577 { 0578 if (!KTechlab::self()) 0579 return; 0580 0581 if (activeView()) 0582 textView()->slotUpdateMarksInfo(); 0583 0584 #ifndef NO_GPSIM 0585 syncBreakpoints(); 0586 #endif 0587 0588 // Update our list of bookmarks in the menu 0589 KTechlab::self()->unplugActionList("bookmark_actionlist"); 0590 m_bookmarkActions.clear(); 0591 0592 // QPtrList<KTextEditor::Mark> markList = m_doc->marks(); 0593 typedef QHash<int, KTextEditor::Mark *> MarkList; 0594 KTextEditor::MarkInterface *iface = qobject_cast<KTextEditor::MarkInterface *>(m_doc); 0595 if (!iface) 0596 return; 0597 // MarkList markList = m_doc->marks(); 0598 MarkList markList = iface->marks(); 0599 0600 // Find out what marks need adding to our internal lists 0601 // for ( KTextEditor::Mark * mark = markList.first(); mark; mark = markList.next() ) 0602 //{ 0603 for (MarkList::iterator itMark = markList.begin(); itMark != markList.end(); ++itMark) { 0604 KTextEditor::Mark *mark = itMark.value(); 0605 if (mark->type & KTextEditor::MarkInterface::Bookmark) { 0606 QString actionCaption = i18n("%1 - %2", QString::number(mark->line + 1), m_doc->text(KTextEditor::Range(mark->line, 0, mark->line, 100 /* FIXME arbitrary */))); 0607 QString actionName = QString("bookmark_%1").arg(QString::number(mark->line)); 0608 /* 0609 QAction * a = new QAction( actionCaption, 0610 0, this, SLOT(slotBookmarkRequested()), this, 0611 actionName ); 0612 */ 0613 QAction *a = new QAction(actionCaption, this); 0614 a->setObjectName(actionName.toLatin1().data()); 0615 connect(a, SIGNAL(triggered(bool)), this, SLOT(slotBookmarkRequested())); 0616 m_bookmarkActions.append(a); 0617 } 0618 } 0619 0620 KTechlab::self()->plugActionList("bookmark_actionlist", m_bookmarkActions); 0621 } 0622 0623 void TextDocument::slotBookmarkRequested() 0624 { 0625 const QObject *s = sender(); 0626 if (!s) 0627 return; 0628 0629 QString name = s->objectName(); 0630 if (!name.startsWith("bookmark_")) 0631 return; 0632 0633 name.remove("bookmark_"); 0634 int line = -1; 0635 bool ok; 0636 line = name.toInt(&ok); 0637 if (ok && line >= 0 && activeView()) 0638 (static_cast<TextView *>(activeView()))->gotoLine(line); 0639 } 0640 0641 void TextDocument::setBookmarks(const IntList &lines) 0642 { 0643 clearBookmarks(); 0644 const IntList::const_iterator end = lines.end(); 0645 for (IntList::const_iterator it = lines.begin(); it != end; ++it) 0646 setBookmark(*it, true); 0647 } 0648 0649 void TextDocument::clearBookmarks() 0650 { 0651 // QPtrList<KTextEditor::Mark> markList = m_doc->marks(); 0652 typedef QHash<int, KTextEditor::Mark *> MarkList; 0653 KTextEditor::MarkInterface *iface = qobject_cast<KTextEditor::MarkInterface *>(m_doc); 0654 if (!iface) 0655 return; 0656 // MarkList markList = m_doc->marks(); 0657 MarkList markList = iface->marks(); 0658 0659 // Find out what marks need adding to our internal lists 0660 // for ( KTextEditor::Mark * mark = markList.first(); mark; mark = markList.next() ) 0661 //{ 0662 for (MarkList::iterator itMark = markList.begin(); itMark != markList.end(); ++itMark) { 0663 KTextEditor::Mark *mark = itMark.value(); 0664 if (mark->type & KTextEditor::MarkInterface::Bookmark) 0665 iface->removeMark(mark->line, KTextEditor::MarkInterface::Bookmark); 0666 } 0667 0668 slotUpdateMarksInfo(); 0669 } 0670 0671 void TextDocument::setBookmark(uint line, bool isBookmark) 0672 { 0673 KTextEditor::MarkInterface *iface = qobject_cast<KTextEditor::MarkInterface *>(m_doc); 0674 if (!iface) 0675 return; 0676 0677 if (isBookmark) 0678 iface->addMark(line, KTextEditor::MarkInterface::Bookmark); 0679 0680 else 0681 iface->removeMark(line, KTextEditor::MarkInterface::Bookmark); 0682 } 0683 0684 void TextDocument::setBreakpoints(const IntList &lines) 0685 { 0686 #ifndef NO_GPSIM 0687 clearBreakpoints(); 0688 const IntList::const_iterator end = lines.end(); 0689 for (IntList::const_iterator it = lines.begin(); it != end; ++it) 0690 setBreakpoint(*it, true); 0691 #else 0692 Q_UNUSED(lines); 0693 #endif // !NO_GPSIM 0694 } 0695 0696 IntList TextDocument::breakpointList() const 0697 { 0698 IntList breakpointList; 0699 0700 #ifndef NO_GPSIM 0701 // typedef QPtrList<KTextEditor::Mark> MarkList; 0702 typedef QHash<int, KTextEditor::Mark *> MarkList; 0703 KTextEditor::MarkInterface *iface = qobject_cast<KTextEditor::MarkInterface *>(m_doc); 0704 if (!iface) 0705 return IntList(); 0706 // MarkList markList = m_doc->marks(); 0707 MarkList markList = iface->marks(); // note: this will copy 0708 0709 // Find out what marks need adding to our internal lists 0710 // for ( KTextEditor::Mark * mark = markList.first(); mark; mark = markList.next() ) 0711 for (MarkList::iterator itMark = markList.begin(); itMark != markList.end(); ++itMark) { 0712 KTextEditor::Mark *mark = itMark.value(); 0713 if (mark->type & Breakpoint) 0714 breakpointList += mark->line; 0715 } 0716 #endif // !NO_GPSIM 0717 0718 return breakpointList; 0719 } 0720 0721 void TextDocument::setBreakpoint(uint line, bool isBreakpoint) 0722 { 0723 #ifndef NO_GPSIM 0724 KTextEditor::MarkInterface *iface = qobject_cast<KTextEditor::MarkInterface *>(m_doc); 0725 if (!iface) 0726 return; 0727 0728 if (isBreakpoint) { 0729 iface->addMark(line, Breakpoint); 0730 if (m_pDebugger) 0731 m_pDebugger->setBreakpoint(m_debugFile, line, true); 0732 } else { 0733 iface->removeMark(line, Breakpoint); 0734 if (m_pDebugger) 0735 m_pDebugger->setBreakpoint(m_debugFile, line, false); 0736 } 0737 #else 0738 Q_UNUSED(line); 0739 Q_UNUSED(isBreakpoint); 0740 #endif // !NO_GPSIM 0741 } 0742 0743 void TextDocument::debugRun() 0744 { 0745 #ifndef NO_GPSIM 0746 if (m_pDebugger) { 0747 m_pDebugger->gpsim()->setRunning(true); 0748 slotInitDebugActions(); 0749 return; 0750 } 0751 0752 switch (guessedCodeType()) { 0753 case ct_unknown: 0754 KMessageBox::error(nullptr, i18n("Unknown code type."), i18n("Cannot debug")); 0755 return; 0756 0757 case ct_hex: 0758 KMessageBox::error(nullptr, i18n("Cannot debug hex."), i18n("Cannot debug")); 0759 return; 0760 0761 case ct_microbe: 0762 m_bLoadDebuggerAsHLL = true; 0763 m_debugFile = outputFilePath(".microbe"); 0764 break; 0765 0766 case ct_asm: 0767 m_bLoadDebuggerAsHLL = false; 0768 m_debugFile = outputFilePath(".asm"); 0769 break; 0770 0771 case ct_c: 0772 m_bLoadDebuggerAsHLL = true; 0773 m_debugFile = outputFilePath(".c"); 0774 break; 0775 } 0776 0777 m_symbolFile = GpsimProcessor::generateSymbolFile(m_debugFile, this, SLOT(slotCODCreationSucceeded()), SLOT(slotCODCreationFailed())); 0778 #endif // !NO_GPSIM 0779 } 0780 0781 void TextDocument::debugInterrupt() 0782 { 0783 #ifndef NO_GPSIM 0784 if (!m_pDebugger) 0785 return; 0786 0787 m_pDebugger->gpsim()->setRunning(false); 0788 slotInitDebugActions(); 0789 #endif // !NO_GPSIM 0790 } 0791 0792 void TextDocument::debugStop() 0793 { 0794 #ifndef NO_GPSIM 0795 if (!m_pDebugger || !m_bOwnDebugger) 0796 return; 0797 0798 m_pDebugger->gpsim()->deleteLater(); 0799 m_pDebugger = nullptr; 0800 slotDebugSetCurrentLine(SourceLine()); 0801 slotInitDebugActions(); 0802 #endif // !NO_GPSIM 0803 } 0804 0805 void TextDocument::debugStep() 0806 { 0807 #ifndef NO_GPSIM 0808 if (!m_pDebugger) 0809 return; 0810 0811 m_pDebugger->stepInto(); 0812 #endif // !NO_GPSIM 0813 } 0814 0815 void TextDocument::debugStepOver() 0816 { 0817 #ifndef NO_GPSIM 0818 if (!m_pDebugger) 0819 return; 0820 0821 m_pDebugger->stepOver(); 0822 #endif // !NO_GPSIM 0823 } 0824 0825 void TextDocument::debugStepOut() 0826 { 0827 #ifndef NO_GPSIM 0828 if (!m_pDebugger) 0829 return; 0830 0831 m_pDebugger->stepOut(); 0832 #endif // !NO_GPSIM 0833 } 0834 0835 void TextDocument::slotDebugSetCurrentLine(const SourceLine &line) 0836 { 0837 #ifndef NO_GPSIM 0838 0839 KTextEditor::MarkInterface *iface = qobject_cast<KTextEditor::MarkInterface *>(m_doc); 0840 if (!iface) 0841 return; 0842 0843 int textLine = line.line(); 0844 0845 if (DocManager::self()->findDocument(QUrl::fromLocalFile(line.fileName())) != this) 0846 textLine = -1; 0847 0848 iface->removeMark(m_lastDebugLineAt, KTextEditor::MarkInterface::Execution); 0849 iface->addMark(textLine, KTextEditor::MarkInterface::Execution); 0850 0851 if (activeView()) 0852 textView()->setCursorPosition(textLine, 0); 0853 0854 m_lastDebugLineAt = textLine; 0855 #else 0856 Q_UNUSED(line); 0857 #endif // !NO_GPSIM 0858 } 0859 0860 void TextDocument::slotInitDebugActions() 0861 { 0862 #ifndef NO_GPSIM 0863 if (m_pDebugger) { 0864 if (m_pDebugger->gpsim()->isRunning()) 0865 slotDebugSetCurrentLine(SourceLine()); 0866 else 0867 slotDebugSetCurrentLine(m_pDebugger->currentLine()); 0868 } 0869 0870 if (activeView()) 0871 textView()->slotInitDebugActions(); 0872 #endif // !NO_GPSIM 0873 } 0874 0875 void TextDocument::slotCODCreationSucceeded() 0876 { 0877 #ifndef NO_GPSIM 0878 GpsimProcessor *gpsim = new GpsimProcessor(m_symbolFile, this); 0879 0880 if (m_bLoadDebuggerAsHLL) 0881 gpsim->setDebugMode(GpsimDebugger::HLLDebugger); 0882 else 0883 gpsim->setDebugMode(GpsimDebugger::AsmDebugger); 0884 0885 setDebugger(gpsim->currentDebugger(), true); 0886 #endif // !NO_GPSIM 0887 } 0888 void TextDocument::slotCODCreationFailed() 0889 { 0890 #ifndef NO_GPSIM 0891 m_debugFile = QString(); 0892 m_symbolFile = QString(); 0893 #endif // !NO_GPSIM 0894 } 0895 0896 void TextDocument::slotDebuggerDestroyed() 0897 { 0898 #ifndef NO_GPSIM 0899 slotDebugSetCurrentLine(SourceLine()); 0900 m_pDebugger = nullptr; 0901 m_debugFile = QString(); 0902 slotInitDebugActions(); 0903 #endif // !NO_GPSIM 0904 } 0905 0906 #ifndef NO_GPSIM 0907 void TextDocument::clearBreakpoints() 0908 { 0909 // QPtrList<KTextEditor::Mark> markList = m_doc->marks(); 0910 // typedef QPtrList<KTextEditor::Mark> MarkList; 0911 typedef QHash<int, KTextEditor::Mark *> MarkList; 0912 KTextEditor::MarkInterface *iface = qobject_cast<KTextEditor::MarkInterface *>(m_doc); 0913 if (!iface) 0914 return; 0915 // MarkList markList = m_doc->marks(); 0916 MarkList markList = iface->marks(); // note: this will copy 0917 0918 // Find out what marks need adding to our internal lists 0919 // for ( KTextEditor::Mark * mark = markList.first(); mark; mark = markList.next() ) 0920 for (MarkList::iterator itMark = markList.begin(); itMark != markList.end(); ++itMark) { 0921 KTextEditor::Mark *mark = itMark.value(); 0922 if (mark->type & KTextEditor::MarkInterface::Bookmark) 0923 iface->removeMark(mark->line, Breakpoint); 0924 } 0925 0926 slotUpdateMarksInfo(); 0927 } 0928 0929 void TextDocument::syncBreakpoints() 0930 { 0931 if (b_lockSyncBreakpoints) 0932 return; 0933 0934 // We don't really care about synching marks if we aren't debugging / aren't able to take use of the marks 0935 if (!m_pDebugger) 0936 return; 0937 0938 b_lockSyncBreakpoints = true; 0939 0940 // QPtrList<KTextEditor::Mark> markList = m_doc->marks(); 0941 // typedef QPtrList<KTextEditor::Mark> MarkList; 0942 typedef QHash<int, KTextEditor::Mark *> MarkList; 0943 KTextEditor::MarkInterface *iface = qobject_cast<KTextEditor::MarkInterface *>(m_doc); 0944 if (!iface) 0945 return; 0946 // MarkList markList = m_doc->marks(); 0947 MarkList markList = iface->marks(); // note: this will copy 0948 0949 IntList bpList; 0950 0951 // Find out what marks need adding to our internal lists 0952 // for ( KTextEditor::Mark * mark = markList.first(); mark; mark = markList.next() ) 0953 for (MarkList::iterator itMark = markList.begin(); itMark != markList.end(); ++itMark) { 0954 KTextEditor::Mark *mark = itMark.value(); 0955 const int line = mark->line; 0956 0957 if (mark->type & Breakpoint) 0958 bpList.append(line); 0959 0960 if (mark->type == KTextEditor::MarkInterface::Execution) 0961 m_lastDebugLineAt = line; 0962 } 0963 0964 m_pDebugger->setBreakpoints(m_debugFile, bpList); 0965 0966 b_lockSyncBreakpoints = false; 0967 } 0968 0969 bool TextDocument::debuggerIsRunning() const 0970 { 0971 return m_pDebugger; 0972 } 0973 0974 bool TextDocument::debuggerIsStepping() const 0975 { 0976 return m_pDebugger && !m_pDebugger->gpsim()->isRunning(); 0977 } 0978 0979 void TextDocument::setDebugger(GpsimDebugger *debugger, bool ownDebugger) 0980 { 0981 if (debugger == m_pDebugger) 0982 return; 0983 0984 // If we create a gpsim, then we may get called by DebugManager, which will 0985 // try to claim we don't own it. So if we have a symbol file waiting, thne 0986 // wait until we are called from its successful creation 0987 if (!m_symbolFile.isEmpty() && !ownDebugger) 0988 return; 0989 0990 // Reset it for use next time 0991 m_symbolFile = QString(); 0992 0993 if (m_bOwnDebugger) 0994 delete m_pDebugger; 0995 0996 m_pDebugger = debugger; 0997 m_bOwnDebugger = ownDebugger; 0998 0999 if (!m_pDebugger) 1000 return; 1001 1002 if (m_debugFile.isEmpty()) 1003 m_debugFile = url().path(); 1004 1005 connect(m_pDebugger, &GpsimDebugger::destroyed, this, &TextDocument::slotDebuggerDestroyed); 1006 connect(m_pDebugger->gpsim(), &GpsimProcessor::runningStatusChanged, this, &TextDocument::slotInitDebugActions); 1007 connect(m_pDebugger, &GpsimDebugger::lineReached, this, &TextDocument::slotDebugSetCurrentLine); 1008 m_pDebugger->setBreakpoints(m_debugFile, breakpointList()); 1009 1010 slotInitDebugActions(); 1011 if (!m_pDebugger->gpsim()->isRunning()) 1012 slotDebugSetCurrentLine(m_pDebugger->currentLine()); 1013 1014 if (this == dynamic_cast<TextDocument *>(DocManager::self()->getFocusedDocument())) 1015 SymbolViewer::self()->setContext(m_pDebugger->gpsim()); 1016 } 1017 #endif // !NO_GPSIM 1018 1019 const QPixmap *TextDocument::inactiveBreakpointPixmap() 1020 { 1021 const char *breakpoint_gr_xpm[] = {"11 16 6 1", "c c #c6c6c6", "d c #2c2c2c", "# c #000000", ". c None", "a c #ffffff", "b c #555555", "...........", "...........", "...#####...", "..#aaaaa#..", ".#abbbbbb#.", 1022 "#abbbbbbbb#", "#abcacacbd#", "#abbbbbbbb#", "#abcacacbd#", "#abbbbbbbb#", ".#bbbbbbb#.", "..#bdbdb#..", "...#####...", "...........", "...........", "..........."}; 1023 static QPixmap pixmap(breakpoint_gr_xpm); 1024 return &pixmap; 1025 } 1026 1027 const QPixmap *TextDocument::activeBreakpointPixmap() 1028 { 1029 const char *breakpoint_xpm[] = {"11 16 6 1", "c c #c6c6c6", ". c None", "# c #000000", "d c #840000", "a c #ffffff", "b c #ff0000", "...........", "...........", "...#####...", "..#aaaaa#..", ".#abbbbbb#.", 1030 "#abbbbbbbb#", "#abcacacbd#", "#abbbbbbbb#", "#abcacacbd#", "#abbbbbbbb#", ".#bbbbbbb#.", "..#bdbdb#..", "...#####...", "...........", "...........", "..........."}; 1031 static QPixmap pixmap(breakpoint_xpm); 1032 return &pixmap; 1033 } 1034 1035 const QPixmap *TextDocument::reachedBreakpointPixmap() 1036 { 1037 const char *breakpoint_bl_xpm[] = {"11 16 7 1", "a c #c0c0ff", "# c #000000", "c c #0000c0", "e c #0000ff", "b c #dcdcdc", "d c #ffffff", ". c None", "...........", "...........", "...#####...", "..#ababa#..", 1038 ".#bcccccc#.", "#acccccccc#", "#bcadadace#", "#acccccccc#", "#bcadadace#", "#acccccccc#", ".#ccccccc#.", "..#cecec#..", "...#####...", "...........", "...........", "..........."}; 1039 static QPixmap pixmap(breakpoint_bl_xpm); 1040 return &pixmap; 1041 } 1042 1043 const QPixmap *TextDocument::disabledBreakpointPixmap() 1044 { 1045 const char *breakpoint_wh_xpm[] = {"11 16 7 1", "a c #c0c0ff", "# c #000000", "c c #0000c0", "e c #0000ff", "b c #dcdcdc", "d c #ffffff", ". c None", "...........", "...........", "...#####...", "..#ddddd#..", 1046 ".#ddddddd#.", "#ddddddddd#", "#ddddddddd#", "#ddddddddd#", "#ddddddddd#", "#ddddddddd#", ".#ddddddd#.", "..#ddddd#..", "...#####...", "...........", "...........", "..........."}; 1047 static QPixmap pixmap(breakpoint_wh_xpm); 1048 return &pixmap; 1049 } 1050 1051 const QPixmap *TextDocument::executionPointPixmap() 1052 { 1053 const char *exec_xpm[] = {"11 16 4 1", "a c #00ff00", "b c #000000", ". c None", "# c #00c000", "...........", "...........", "...........", "#a.........", "#aaa.......", "#aaaaa.....", 1054 "#aaaaaaa...", "#aaaaaaaaa.", "#aaaaaaa#b.", "#aaaaa#b...", "#aaa#b.....", "#a#b.......", "#b.........", "...........", "...........", "..........."}; 1055 static QPixmap pixmap(exec_xpm); 1056 return &pixmap; 1057 }