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