1 /***************************************************************************
2 * Copyright (C) 2005 by David Saxton *
3 * david@bluehaze.org *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 ***************************************************************************/
10
11 #include "asmformatter.h"
12 #include "asminfo.h"
13 #include "asmparser.h"
14 #include "debugmanager.h"
15 #include "docmanager.h"
16 #include "documentiface.h"
17 #include "filemetainfo.h"
18 #include "gpsimprocessor.h"
19 #include "ktechlab.h"
20 #include "language.h"
21 #include "languagemanager.h"
22 #include "microselectwidget.h"
23 #include "programmerdlg.h"
24 #include "symbolviewer.h"
25 #include "textdocument.h"
26 #include "textview.h"
27 #include "gpsimprocessor.h"
28
29 // #include <kate/katedocument.h>
30 #include <QAction>
31 #include <QDebug>
32 #include <QTemporaryFile>
33 #include <QDir>
34
35 #include <KLocalizedString>
36 #include <KMessageBox>
37 #include <KTextEditor/Document>
38 #include <KXMLGUIFactory>
39 #include <KTextEditor/Editor>
40
41
isUndoAvailable() const42 bool TextDocument::isUndoAvailable() const {
43 //return (m_doc->undoCount() != 0);
44 return true; // TODO FIXME fix undo/redo
45 }
isRedoAvailable() const46 bool TextDocument::isRedoAvailable() const {
47 //return (m_doc->redoCount() != 0);
48 return true; // TODO FIXME fix undo/redo
49
50 }
51
constructTextDocument(const QString & caption,const char * name)52 TextDocument *TextDocument::constructTextDocument( const QString& caption, const char *name )
53 {
54 TextDocument *textDocument = new TextDocument( caption, name);
55 if( textDocument->m_constructorSuccessful )
56 return textDocument;
57 delete textDocument;
58 return nullptr;
59 }
60
61
TextDocument(const QString & caption,const char * name)62 TextDocument::TextDocument( const QString &caption, const char *name )
63 : Document( caption, name ),
64 m_doc(nullptr)
65 {
66 m_constructorSuccessful = false;
67
68 #ifndef NO_GPSIM
69 m_bOwnDebugger = false;
70 b_lockSyncBreakpoints = false;
71 m_lastDebugLineAt = -1;
72 m_pDebugger = nullptr;
73 #endif
74
75 m_pLastTextOutputTarget = nullptr;
76 m_guessedCodeType = TextDocument::ct_unknown;
77 m_type = Document::dt_text;
78 //m_bookmarkActions.setAutoDelete(true); // TODO see if this genereates memory leaks
79 m_pDocumentIface = new TextDocumentIface(this);
80 KTextEditor::Editor* editor = KTextEditor::Editor::instance();
81 m_doc = editor->createDocument(this);
82
83 if(!m_doc)
84 {
85 KMessageBox::sorry( KTechlab::self(), i18n("Failed to create editor") );
86 return;
87 }
88 guessScheme();
89
90 connect( m_doc, SIGNAL(undoChanged()), this, SIGNAL(undoRedoStateChanged()) );
91 connect( m_doc, SIGNAL(undoChanged()), this, SLOT(slotSyncModifiedStates()) );
92 connect( m_doc, SIGNAL(textChanged(KTextEditor::Document *)), this, SLOT(slotSyncModifiedStates()) );
93 // connect( m_doc, SIGNAL(selectionChanged()), this, SLOT(slotSelectionmChanged()) ); // 2016.09.08 - moved to TextView
94 connect( m_doc, SIGNAL(marksChanged(KTextEditor::Document*)), this, SLOT(slotUpdateMarksInfo()) );
95
96 KTextEditor::MarkInterface *markIface = qobject_cast<KTextEditor::MarkInterface*>( m_doc );
97 if (!markIface) {
98 KMessageBox::sorry( KTechlab::self(), i18n("Failed to create MarkInterface") );
99 return;
100 }
101
102 markIface->setMarkDescription((KTextEditor::MarkInterface::MarkTypes)Breakpoint, i18n("Breakpoint"));
103 markIface->setMarkPixmap((KTextEditor::MarkInterface::MarkTypes)Breakpoint, *inactiveBreakpointPixmap());
104 markIface->setMarkPixmap((KTextEditor::MarkInterface::MarkTypes)ActiveBreakpoint, *activeBreakpointPixmap());
105 markIface->setMarkPixmap((KTextEditor::MarkInterface::MarkTypes)ReachedBreakpoint, *reachedBreakpointPixmap());
106 markIface->setMarkPixmap((KTextEditor::MarkInterface::MarkTypes)DisabledBreakpoint, *disabledBreakpointPixmap());
107 markIface->setMarkPixmap((KTextEditor::MarkInterface::MarkTypes)ExecutionPoint, *executionPointPixmap());
108 markIface->setEditableMarks( Bookmark | Breakpoint );
109
110 m_constructorSuccessful = true;
111 }
112
113
~TextDocument()114 TextDocument::~TextDocument()
115 {
116 if( !m_constructorSuccessful ) return;
117
118 debugStop();
119
120 if ( KTechlab::self() )
121 {
122 ViewList::iterator end = m_viewList.end();
123 for ( ViewList::iterator it = m_viewList.begin(); it != end; ++it )
124 {
125 if ( TextView * tv = dynamic_cast<TextView*>( (View*)*it) )
126 {
127 KTextEditor::View * kv = tv->kateView();
128 KTechlab::self()->factory()->removeClient( kv );
129 }
130 }
131 }
132
133 delete m_doc;
134 delete m_pDocumentIface;
135 }
136
137
fileClose()138 bool TextDocument::fileClose()
139 {
140 const QUrl u = url();
141 if ( !u.isEmpty() )
142 fileMetaInfo()->grabMetaInfo( u, this );
143
144 return Document::fileClose();
145 }
146
147
textView() const148 TextView* TextDocument::textView() const
149 {
150 return static_cast<TextView*>(activeView());
151 }
152
153
createView(ViewContainer * viewContainer,uint viewAreaId,const char * name)154 View * TextDocument::createView( ViewContainer *viewContainer, uint viewAreaId, const char *name )
155 {
156 TextView * textView = new TextView( this, viewContainer, viewAreaId, name );
157
158 fileMetaInfo()->initializeFromMetaInfo( url(), textView );
159
160 handleNewView(textView);
161 return textView;
162 }
163
164
createKateView(QWidget * parent,const char *)165 KTextEditor::View* TextDocument::createKateView( QWidget *parent, const char * /*name*/ )
166 {
167 //return static_cast<KTextEditor::View*>((m_doc->createView( parent, name ))->qt_cast("Kate::View"));
168 return m_doc->createView( parent /*, name */);
169 }
170
171
cut()172 void TextDocument::cut()
173 {
174 if (textView())
175 textView()->cut();
176 }
copy()177 void TextDocument::copy()
178 {
179 if (textView())
180 textView()->copy();
181 }
paste()182 void TextDocument::paste()
183 {
184 if (textView())
185 textView()->paste();
186 }
187
188
setText(const QString & text,bool asInitial)189 void TextDocument::setText( const QString & text, bool asInitial )
190 {
191 if ( asInitial )
192 {
193 disconnect( m_doc, SIGNAL(undoChanged()), this, SIGNAL(undoRedoStateChanged()) );
194 disconnect( m_doc, SIGNAL(undoChanged()), this, SLOT(slotSyncModifiedStates()) );
195 disconnect( m_doc, SIGNAL(textChanged(KTextEditor::Document *)), this, SLOT(slotSyncModifiedStates()) );
196 }
197
198 const ViewList::iterator end = m_viewList.end();
199 for ( ViewList::iterator it = m_viewList.begin(); it != end; ++it )
200 (static_cast<TextView*>((View*)*it))->saveCursorPosition();
201
202 m_doc->setText(text);
203
204 for ( ViewList::iterator it = m_viewList.begin(); it != end; ++it )
205 (static_cast<TextView*>((View*)*it))->restoreCursorPosition();
206
207 if ( asInitial )
208 {
209 //m_doc->clearUndo(); // TODO FIXME
210 //m_doc->clearRedo(); // TODO FIXME
211 qWarning() << "TextDocument::clearUndo TODO";
212 setModified(false);
213
214 connect( m_doc, SIGNAL(undoChanged()), this, SIGNAL(undoRedoStateChanged()) );
215 connect( m_doc, SIGNAL(undoChanged()), this, SLOT(slotSyncModifiedStates()) );
216 connect( m_doc, SIGNAL(textChanged(KTextEditor::Document *)), this, SLOT(slotSyncModifiedStates()) );
217 }
218 }
219
220
undo()221 void TextDocument::undo()
222 {
223 textView()->undo();
224 slotSyncModifiedStates();
225 }
226
227
redo()228 void TextDocument::redo()
229 {
230 textView()->redo();
231 slotSyncModifiedStates();
232 }
233
234
slotSyncModifiedStates()235 void TextDocument::slotSyncModifiedStates()
236 {
237 setModified( m_doc->isModified() );
238 }
setModified(bool modified)239 void TextDocument::setModified( bool modified )
240 {
241 if ( (modified == b_modified) && (modified == isModified()) ) {
242 return;
243 }
244 m_doc->setModified(modified);
245 b_modified = modified;
246
247 emit modifiedStateChanged();
248 }
249
250
guessScheme(bool allowDisable)251 void TextDocument::guessScheme( bool allowDisable )
252 {
253 // And specific file actions depending on the current type of file
254 QString fileName = url().fileName();
255 QString extension = fileName.right( fileName.length() - fileName.lastIndexOf('.') - 1 );
256
257 if ( extension == "asm" || extension == "src" || extension == "inc" )
258 slotInitLanguage(ct_asm);
259
260 else if ( extension == "hex" )
261 slotInitLanguage(ct_hex);
262
263 else if ( extension == "basic" || extension == "microbe" )
264 slotInitLanguage(ct_microbe);
265
266 else if ( extension == "c" )
267 slotInitLanguage(ct_c);
268
269 else if ( m_guessedCodeType != TextDocument::ct_unknown )
270 slotInitLanguage(m_guessedCodeType);
271
272 else if ( allowDisable && activeView() )
273 textView()->disableActions();
274 }
275
276
slotInitLanguage(CodeType type)277 void TextDocument::slotInitLanguage( CodeType type )
278 {
279 QString hlName;
280
281 switch (type)
282 {
283 case ct_asm:
284 hlName = "PicAsm";
285 break;
286
287 case ct_c:
288 hlName = "C";
289 break;
290
291 case ct_hex:
292 break;
293
294 case ct_microbe:
295 hlName = "Microbe";
296 break;
297
298 case ct_unknown:
299 break;
300 }
301
302 if ( !hlName.isEmpty() )
303 {
304 //int i = 0; // 2017.10.01 - comment out unused variable
305 //int hlModeCount = m_doc->hlModeCount();
306 QStringList hlModes = m_doc->highlightingModes();
307 //while ( i<hlModeCount && m_doc->hlModeName(i) != hlName )
308 // i++;
309 while (!hlModes.isEmpty()) {
310 if (hlModes.first() == hlName) {
311 break;
312 }
313 hlModes.removeFirst();
314 }
315
316 //m_doc->setHlMode(i);
317 if (!hlModes.isEmpty()) {
318 m_doc->setHighlightingMode(hlModes.first());
319 }
320 }
321
322 m_guessedCodeType = type;
323
324 ViewList::iterator end = m_viewList.end();
325 for ( ViewList::iterator it = m_viewList.begin(); it != end; ++it )
326 {
327 if ( TextView * tv = dynamic_cast<TextView*>( (View*)*it ) )
328 tv->initCodeActions();
329 }
330 }
331
332
formatAssembly()333 void TextDocument::formatAssembly()
334 {
335 AsmFormatter formatter;
336 //QStringList lines = QStringList::split( "\n", m_doc->text(), true ); // 2018.12.01
337 QStringList lines = m_doc->text().split("\n", QString::KeepEmptyParts);
338 setText( formatter.tidyAsm(lines), false );
339 setModified(true);
340 }
341
342
fileSave(const QUrl & url)343 void TextDocument::fileSave( const QUrl& url )
344 {
345 if ( m_doc->url() != url )
346 {
347 qCritical() << Q_FUNC_INFO << "Error: Kate::View url and passed url do not match; cannot save." << endl;
348 return;
349 }
350
351 if ( activeView() && (textView()->save()) )
352 saveDone();
353 }
354
355
fileSaveAs()356 void TextDocument::fileSaveAs()
357 {
358 if ( activeView() && (textView()->saveAs()) )
359 saveDone();
360
361 // Our modified state may not have changed, but we emit this to force the
362 // main window to update our caption.
363 emit modifiedStateChanged();
364 }
365
366
saveDone()367 void TextDocument::saveDone()
368 {
369 setURL( m_doc->url() );
370 guessScheme(false);
371 setModified(false);
372 emit modifiedStateChanged();
373 }
374
375
openURL(const QUrl & url)376 bool TextDocument::openURL( const QUrl& url )
377 {
378 m_doc->openUrl(url);
379 setURL(url);
380
381 fileMetaInfo()->initializeFromMetaInfo( url, this );
382 guessScheme();
383
384 #ifndef NO_GPSIM
385 DebugManager::self()->urlOpened( this );
386 #endif
387
388 return true;
389 }
390
391
setLastTextOutputTarget(TextDocument * target)392 void TextDocument::setLastTextOutputTarget( TextDocument * target )
393 {
394 m_pLastTextOutputTarget = target;
395 }
396
397
outputFilePath(const QString & ext)398 QString TextDocument::outputFilePath( const QString &ext )
399 {
400 QString filePath = url().path();
401 if ( filePath.isEmpty() )
402 {
403 QTemporaryFile f(QDir::tempPath() + QLatin1String("/ktechlab_XXXXXX") + ext);
404 f.setAutoRemove(false);
405 if (!f.open()) {
406 qWarning() << Q_FUNC_INFO << " Failed to open temporary file";
407 return QString();
408 }
409 QTextStream out(&f);
410 out << m_doc->text();
411 f.close();
412 DocManager::self()->associateDocument(QUrl::fromLocalFile(f.fileName()), this );
413 return f.fileName();
414 }
415 if ( isModified() )
416 {
417 fileSave();
418 }
419 return filePath;
420 }
421
422
slotConvertTo(QAction * action)423 void TextDocument::slotConvertTo( QAction *action )
424 {
425 int target = action->data().toInt();
426 switch ( (ConvertToTarget)target )
427 {
428 case TextDocument::MicrobeOutput:
429 break;
430
431 case TextDocument::AssemblyOutput:
432 convertToAssembly();
433 break;
434
435 case TextDocument::HexOutput:
436 convertToHex();
437 break;
438
439 case TextDocument::PICOutput:
440 convertToPIC();
441 break;
442 }
443 }
444
445
convertToAssembly()446 void TextDocument::convertToAssembly()
447 {
448 QString filePath;
449 bool showPICSelect = false;
450 ProcessOptions::ProcessPath::MediaType toType;
451
452 if ( m_guessedCodeType == TextDocument::ct_microbe )
453 {
454 toType = ProcessOptions::ProcessPath::AssemblyAbsolute;
455 filePath = outputFilePath(".microbe");
456 }
457
458 else if ( m_guessedCodeType == TextDocument::ct_hex )
459 {
460 toType = ProcessOptions::ProcessPath::Disassembly;
461 filePath = outputFilePath(".hex");
462 }
463
464 else if ( m_guessedCodeType == TextDocument::ct_c )
465 {
466 toType = ProcessOptions::ProcessPath::AssemblyRelocatable;
467 filePath = outputFilePath(".c");
468 showPICSelect = true;
469 }
470
471 else
472 {
473 qCritical() << "Could not get file type for converting to assembly!"<<endl;
474 return;
475 }
476
477 OutputMethodDlg dlg( i18n("Assembly Code Output"), url(), showPICSelect, KTechlab::self() );
478
479 if ( m_guessedCodeType == TextDocument::ct_c )
480 dlg.microSelect()->setAllowedAsmSet( AsmInfo::PIC14 | AsmInfo::PIC16 );
481
482 dlg.setOutputExtension(".asm");
483 dlg.setFilter( QString("*.asm *.src *.inc|%1 (*.asm, *.src, *.inc)\n*|%2").arg(i18n("Assembly Code")).arg(i18n("All Files")) );
484 const int accepted = dlg.exec();
485 if (accepted != QDialog::Accepted)
486 return;
487
488 ProcessOptions o( dlg.info() );
489 o.setTextOutputTarget( m_pLastTextOutputTarget, this, SLOT(setLastTextOutputTarget( TextDocument* )) );
490 o.setInputFiles(QStringList( filePath) );
491 o.setProcessPath( ProcessOptions::ProcessPath::path( ProcessOptions::guessMediaType(filePath), toType ) );
492 LanguageManager::self()->compile(o);
493 }
494
495
convertToHex()496 void TextDocument::convertToHex()
497 {
498 QString filePath;
499 bool showPICSelect = false;
500
501 if ( m_guessedCodeType == TextDocument::ct_microbe )
502 filePath = outputFilePath(".microbe");
503
504 else if ( m_guessedCodeType == TextDocument::ct_asm )
505 {
506 filePath = outputFilePath(".asm");
507 showPICSelect = true; // FIXME if we use shared libs, then we need the pic type
508 }
509 else if ( m_guessedCodeType == TextDocument::ct_c )
510 {
511 filePath = outputFilePath(".c");
512 showPICSelect = true;
513 }
514
515 else
516 {
517 qCritical() << "Could not get file type for converting to hex!"<<endl;
518 return;
519 }
520
521 OutputMethodDlg dlg( i18n("Hex Code Output"), url(), showPICSelect, KTechlab::self() );
522 dlg.setOutputExtension(".hex");
523 dlg.setFilter( QString("*.hex|Hex (*.hex)\n*|%1").arg(i18n("All Files")) );
524
525 if ( m_guessedCodeType == TextDocument::ct_c )
526 dlg.microSelect()->setAllowedAsmSet( AsmInfo::PIC14 | AsmInfo::PIC16 );
527
528 const int accepted = dlg.exec();
529 if (accepted != QDialog::Accepted)
530 return;
531
532 ProcessOptions o( dlg.info() );
533 o.setTextOutputTarget( m_pLastTextOutputTarget, this, SLOT(setLastTextOutputTarget( TextDocument* )) );
534 o.setInputFiles(QStringList(filePath));
535 o.setProcessPath( ProcessOptions::ProcessPath::path( ProcessOptions::guessMediaType(filePath), ProcessOptions::ProcessPath::Program ) );
536 LanguageManager::self()->compile(o);
537 }
538
539
convertToPIC()540 void TextDocument::convertToPIC()
541 {
542 QString filePath;
543
544 QString picID;
545
546 switch ( m_guessedCodeType )
547 {
548 case ct_microbe:
549 filePath = outputFilePath(".microbe");
550 break;
551
552 case ct_asm:
553 {
554 filePath = outputFilePath(".asm");
555 AsmParser p( filePath );
556 p.parse();
557 picID = p.picID();
558 break;
559 }
560
561 case ct_c:
562 filePath = outputFilePath(".c");
563 break;
564
565 case ct_hex:
566 filePath = outputFilePath(".hex");
567 break;
568
569 case ct_unknown:
570 qCritical() << "Could not get file type for converting to hex!"<<endl;
571 return;
572 }
573
574 ProgrammerDlg * dlg = new ProgrammerDlg( picID, (QWidget*)KTechlab::self(), "Programmer Dlg" );
575
576 if ( m_guessedCodeType == TextDocument::ct_c )
577 dlg->microSelect()->setAllowedAsmSet( AsmInfo::PIC14 | AsmInfo::PIC16 );
578
579 const int accepted = dlg->exec();
580 if (accepted != QDialog::Accepted) {
581 dlg->deleteLater();
582 return;
583 }
584
585 ProcessOptions o;
586 dlg->initOptions( & o );
587 o.setInputFiles( QStringList(filePath ));
588 o.setProcessPath( ProcessOptions::ProcessPath::path( ProcessOptions::guessMediaType(filePath), ProcessOptions::ProcessPath::Pic ) );
589 LanguageManager::self()->compile( o );
590
591 dlg->deleteLater();
592 }
593
594
print()595 void TextDocument::print()
596 {
597 //KTextEditor::printInterface(m_doc)->print (); // TODO FIXME
598 textView()->print();
599 }
600
601 // 2016.09.08 - moved to TextView
602 // void TextDocument::slotSelectionmChanged()
603 // {
604 // KTechlab::self()->actionByName( "edit_cut" )->setEnabled( /* m_doc->hasSelection () */ m_doc->activeView()->selection() );
605 // KTechlab::self()->actionByName( "edit_copy" )->setEnabled( /*m_doc->hasSelection () */ m_doc->activeView()->selection() );
606 // }
607
608
bookmarkList() const609 IntList TextDocument::bookmarkList() const
610 {
611 IntList bookmarkList;
612
613 typedef QHash<int, KTextEditor::Mark*> MarkList;
614 KTextEditor::MarkInterface *iface = qobject_cast<KTextEditor::MarkInterface*>( m_doc );
615 if (!iface) return IntList();
616 //MarkList markList = m_doc->marks();
617 const MarkList &markList = iface->marks();
618
619 // Find out what marks need adding to our internal lists
620 //for ( KTextEditor::Mark * mark = markList.first(); mark; mark = markList.next() )
621 for (MarkList::const_iterator itMark = markList.begin(); itMark != markList.end(); ++itMark)
622 {
623 const KTextEditor::Mark * mark = itMark.value();
624 if ( mark->type & Bookmark )
625 bookmarkList += mark->line;
626 }
627
628 return bookmarkList;
629 }
630
631
slotUpdateMarksInfo()632 void TextDocument::slotUpdateMarksInfo()
633 {
634 if ( !KTechlab::self() )
635 return;
636
637 if ( activeView() )
638 textView()->slotUpdateMarksInfo();
639
640 #ifndef NO_GPSIM
641 syncBreakpoints();
642 #endif
643
644 // Update our list of bookmarks in the menu
645 KTechlab::self()->unplugActionList("bookmark_actionlist");
646 m_bookmarkActions.clear();
647
648 //QPtrList<KTextEditor::Mark> markList = m_doc->marks();
649 typedef QHash<int, KTextEditor::Mark*> MarkList;
650 KTextEditor::MarkInterface *iface = qobject_cast<KTextEditor::MarkInterface*>( m_doc );
651 if (!iface) return ;
652 //MarkList markList = m_doc->marks();
653 MarkList markList = iface->marks();
654
655
656 // Find out what marks need adding to our internal lists
657 //for ( KTextEditor::Mark * mark = markList.first(); mark; mark = markList.next() )
658 //{
659 for (MarkList::iterator itMark = markList.begin(); itMark != markList.end(); ++itMark)
660 {
661 KTextEditor::Mark * mark = itMark.value();
662 if ( mark->type & Bookmark )
663 {
664 QString actionCaption = i18n("%1 - %2", QString::number( mark->line+1 ),
665 m_doc->text(KTextEditor::Range( mark->line, 0, mark->line, 100 /* FIXME arbitrary */)) );
666 QString actionName = QString("bookmark_%1").arg(QString::number(mark->line));
667 /*
668 QAction * a = new QAction( actionCaption,
669 0, this, SLOT(slotBookmarkRequested()), this,
670 actionName );
671 */
672 QAction * a = new QAction( actionCaption, this);
673 a->setObjectName(actionName.toLatin1().data());
674 connect(a, SIGNAL(triggered(bool)), this, SLOT(slotBookmarkRequested()));
675 m_bookmarkActions.append(a);
676 }
677 }
678
679 KTechlab::self()->plugActionList( "bookmark_actionlist", m_bookmarkActions );
680 }
681
682
slotBookmarkRequested()683 void TextDocument::slotBookmarkRequested()
684 {
685 const QObject * s = sender();
686 if (!s) return;
687
688 QString name = s->objectName();
689 if ( !name.startsWith("bookmark_") )
690 return;
691
692 name.remove("bookmark_");
693 int line = -1;
694 bool ok;
695 line = name.toInt(&ok);
696 if ( ok && line >= 0 && activeView() )
697 (static_cast<TextView*>(activeView()))->gotoLine(line);
698 }
699
700
setBookmarks(const IntList & lines)701 void TextDocument::setBookmarks( const IntList &lines )
702 {
703 clearBookmarks();
704 const IntList::const_iterator end = lines.end();
705 for ( IntList::const_iterator it = lines.begin(); it != end; ++it )
706 setBookmark( *it, true );
707 }
708
709
clearBookmarks()710 void TextDocument::clearBookmarks()
711 {
712 //QPtrList<KTextEditor::Mark> markList = m_doc->marks();
713 typedef QHash<int, KTextEditor::Mark*> MarkList;
714 KTextEditor::MarkInterface *iface = qobject_cast<KTextEditor::MarkInterface*>( m_doc );
715 if (!iface) return;
716 //MarkList markList = m_doc->marks();
717 MarkList markList = iface->marks();
718
719 // Find out what marks need adding to our internal lists
720 //for ( KTextEditor::Mark * mark = markList.first(); mark; mark = markList.next() )
721 //{
722 for (MarkList::iterator itMark = markList.begin(); itMark != markList.end(); ++itMark)
723 {
724 KTextEditor::Mark * mark = itMark.value();
725 if ( mark->type & Bookmark )
726 iface->removeMark( mark->line, Bookmark );
727 }
728
729 slotUpdateMarksInfo();
730 }
731
732
setBookmark(uint line,bool isBookmark)733 void TextDocument::setBookmark( uint line, bool isBookmark )
734 {
735 KTextEditor::MarkInterface *iface = qobject_cast<KTextEditor::MarkInterface*>( m_doc );
736 if (!iface) return;
737
738 if (isBookmark)
739 iface->addMark( line, Bookmark );
740
741 else
742 iface->removeMark( line, Bookmark );
743 }
744
745
setBreakpoints(const IntList & lines)746 void TextDocument::setBreakpoints( const IntList &lines )
747 {
748 #ifndef NO_GPSIM
749 clearBreakpoints();
750 const IntList::const_iterator end = lines.end();
751 for ( IntList::const_iterator it = lines.begin(); it != end; ++it )
752 setBreakpoint( *it, true );
753 #endif // !NO_GPSIM
754 }
755
756
breakpointList() const757 IntList TextDocument::breakpointList() const
758 {
759 IntList breakpointList;
760
761 #ifndef NO_GPSIM
762 //typedef QPtrList<KTextEditor::Mark> MarkList;
763 typedef QHash<int, KTextEditor::Mark*> MarkList;
764 KTextEditor::MarkInterface *iface = qobject_cast<KTextEditor::MarkInterface*>( m_doc );
765 if (!iface) return IntList();
766 //MarkList markList = m_doc->marks();
767 MarkList markList = iface->marks(); // note: this will copy
768
769
770 // Find out what marks need adding to our internal lists
771 //for ( KTextEditor::Mark * mark = markList.first(); mark; mark = markList.next() )
772 for (MarkList::iterator itMark = markList.begin(); itMark != markList.end(); ++itMark)
773 {
774 KTextEditor::Mark * mark = itMark.value();
775 if ( mark->type & Breakpoint )
776 breakpointList += mark->line;
777 }
778 #endif // !NO_GPSIM
779
780 return breakpointList;
781 }
782
783
setBreakpoint(uint line,bool isBreakpoint)784 void TextDocument::setBreakpoint( uint line, bool isBreakpoint )
785 {
786 #ifndef NO_GPSIM
787 KTextEditor::MarkInterface *iface = qobject_cast<KTextEditor::MarkInterface*>( m_doc );
788 if (!iface) return ;
789
790 if (isBreakpoint)
791 {
792 iface->addMark( line, Breakpoint );
793 if (m_pDebugger)
794 m_pDebugger->setBreakpoint( m_debugFile, line, true );
795 }
796 else
797 {
798 iface->removeMark( line, Breakpoint );
799 if (m_pDebugger)
800 m_pDebugger->setBreakpoint( m_debugFile, line, false );
801 }
802 #endif // !NO_GPSIM
803 }
804
805
debugRun()806 void TextDocument::debugRun()
807 {
808 #ifndef NO_GPSIM
809 if (m_pDebugger)
810 {
811 m_pDebugger->gpsim()->setRunning(true);
812 slotInitDebugActions();
813 return;
814 }
815
816 switch ( guessedCodeType() )
817 {
818 case ct_unknown:
819 KMessageBox::sorry( nullptr, i18n("Unknown code type."), i18n("Cannot debug") );
820 return;
821
822 case ct_hex:
823 KMessageBox::sorry( nullptr, i18n("Cannot debug hex."), i18n("Cannot debug") );
824 return;
825
826 case ct_microbe:
827 m_bLoadDebuggerAsHLL = true;
828 m_debugFile = outputFilePath(".microbe");
829 break;
830
831 case ct_asm:
832 m_bLoadDebuggerAsHLL = false;
833 m_debugFile = outputFilePath(".asm");
834 break;
835
836 case ct_c:
837 m_bLoadDebuggerAsHLL = true;
838 m_debugFile = outputFilePath(".c");
839 break;
840 }
841
842 m_symbolFile = GpsimProcessor::generateSymbolFile( m_debugFile, this, SLOT(slotCODCreationSucceeded()), SLOT(slotCODCreationFailed()) );
843 #endif // !NO_GPSIM
844 }
845
846
debugInterrupt()847 void TextDocument::debugInterrupt()
848 {
849 #ifndef NO_GPSIM
850 if (!m_pDebugger)
851 return;
852
853 m_pDebugger->gpsim()->setRunning(false);
854 slotInitDebugActions();
855 #endif // !NO_GPSIM
856 }
857
858
debugStop()859 void TextDocument::debugStop()
860 {
861 #ifndef NO_GPSIM
862 if ( !m_pDebugger || !m_bOwnDebugger )
863 return;
864
865 m_pDebugger->gpsim()->deleteLater();
866 m_pDebugger = nullptr;
867 slotDebugSetCurrentLine( SourceLine() );
868 slotInitDebugActions();
869 #endif // !NO_GPSIM
870 }
871
872
debugStep()873 void TextDocument::debugStep()
874 {
875 #ifndef NO_GPSIM
876 if (!m_pDebugger)
877 return;
878
879 m_pDebugger->stepInto();
880 #endif // !NO_GPSIM
881 }
882
883
debugStepOver()884 void TextDocument::debugStepOver()
885 {
886 #ifndef NO_GPSIM
887 if (!m_pDebugger)
888 return;
889
890 m_pDebugger->stepOver();
891 #endif // !NO_GPSIM
892 }
893
894
debugStepOut()895 void TextDocument::debugStepOut()
896 {
897 #ifndef NO_GPSIM
898 if (!m_pDebugger)
899 return;
900
901 m_pDebugger->stepOut();
902 #endif // !NO_GPSIM
903 }
904
905
slotDebugSetCurrentLine(const SourceLine & line)906 void TextDocument::slotDebugSetCurrentLine( const SourceLine & line )
907 {
908 #ifndef NO_GPSIM
909
910 KTextEditor::MarkInterface *iface = qobject_cast<KTextEditor::MarkInterface*>( m_doc );
911 if (!iface) return;
912
913 int textLine = line.line();
914
915 if ( DocManager::self()->findDocument(QUrl::fromLocalFile(line.fileName())) != this )
916 textLine = -1;
917
918 iface->removeMark( m_lastDebugLineAt, ExecutionPoint );
919 iface->addMark( textLine, ExecutionPoint );
920
921 if ( activeView() )
922 textView()->setCursorPosition( textLine, 0 );
923
924 m_lastDebugLineAt = textLine;
925 #endif // !NO_GPSIM
926 }
927
928
slotInitDebugActions()929 void TextDocument::slotInitDebugActions()
930 {
931 #ifndef NO_GPSIM
932 if ( m_pDebugger )
933 {
934 if ( m_pDebugger->gpsim()->isRunning() )
935 slotDebugSetCurrentLine( SourceLine() );
936 else
937 slotDebugSetCurrentLine( m_pDebugger->currentLine() );
938 }
939
940 if ( activeView() )
941 textView()->slotInitDebugActions();
942 #endif // !NO_GPSIM
943 }
944
945
slotCODCreationSucceeded()946 void TextDocument::slotCODCreationSucceeded()
947 {
948 #ifndef NO_GPSIM
949 GpsimProcessor * gpsim = new GpsimProcessor( m_symbolFile, this );
950
951 if (m_bLoadDebuggerAsHLL)
952 gpsim->setDebugMode( GpsimDebugger::HLLDebugger );
953 else
954 gpsim->setDebugMode( GpsimDebugger::AsmDebugger );
955
956 setDebugger( gpsim->currentDebugger(), true );
957 #endif // !NO_GPSIM
958 }
slotCODCreationFailed()959 void TextDocument::slotCODCreationFailed()
960 {
961 #ifndef NO_GPSIM
962 m_debugFile = QString::null;
963 m_symbolFile = QString::null;
964 #endif // !NO_GPSIM
965 }
966
967
slotDebuggerDestroyed()968 void TextDocument::slotDebuggerDestroyed()
969 {
970 #ifndef NO_GPSIM
971 slotDebugSetCurrentLine( SourceLine() );
972 m_pDebugger = nullptr;
973 m_debugFile = QString::null;
974 slotInitDebugActions();
975 #endif // !NO_GPSIM
976 }
977
978
979 #ifndef NO_GPSIM
clearBreakpoints()980 void TextDocument::clearBreakpoints()
981 {
982 //QPtrList<KTextEditor::Mark> markList = m_doc->marks();
983 //typedef QPtrList<KTextEditor::Mark> MarkList;
984 typedef QHash<int, KTextEditor::Mark*> MarkList;
985 KTextEditor::MarkInterface *iface = qobject_cast<KTextEditor::MarkInterface*>( m_doc );
986 if (!iface) return;
987 //MarkList markList = m_doc->marks();
988 MarkList markList = iface->marks(); // note: this will copy
989
990 // Find out what marks need adding to our internal lists
991 //for ( KTextEditor::Mark * mark = markList.first(); mark; mark = markList.next() )
992 for (MarkList::iterator itMark = markList.begin(); itMark != markList.end(); ++itMark)
993 {
994 KTextEditor::Mark * mark = itMark.value();
995 if ( mark->type & Bookmark )
996 iface->removeMark( mark->line, Breakpoint );
997 }
998
999 slotUpdateMarksInfo();
1000 }
1001
1002
syncBreakpoints()1003 void TextDocument::syncBreakpoints()
1004 {
1005 if (b_lockSyncBreakpoints)
1006 return;
1007
1008 // We don't really care about synching marks if we aren't debugging / aren't able to take use of the marks
1009 if (!m_pDebugger)
1010 return;
1011
1012 b_lockSyncBreakpoints = true;
1013
1014 //QPtrList<KTextEditor::Mark> markList = m_doc->marks();
1015 //typedef QPtrList<KTextEditor::Mark> MarkList;
1016 typedef QHash<int, KTextEditor::Mark*> MarkList;
1017 KTextEditor::MarkInterface *iface = qobject_cast<KTextEditor::MarkInterface*>( m_doc );
1018 if (!iface) return;
1019 //MarkList markList = m_doc->marks();
1020 MarkList markList = iface->marks(); // note: this will copy
1021
1022 IntList bpList;
1023
1024 // Find out what marks need adding to our internal lists
1025 //for ( KTextEditor::Mark * mark = markList.first(); mark; mark = markList.next() )
1026 for (MarkList::iterator itMark = markList.begin(); itMark != markList.end(); ++itMark)
1027 {
1028 KTextEditor::Mark *mark = itMark.value();
1029 const int line = mark->line;
1030
1031 if ( mark->type & Breakpoint )
1032 bpList.append(line);
1033
1034 if ( mark->type == ExecutionPoint )
1035 m_lastDebugLineAt = line;
1036 }
1037
1038 m_pDebugger->setBreakpoints( m_debugFile, bpList );
1039
1040 b_lockSyncBreakpoints = false;
1041 }
1042
1043
debuggerIsRunning() const1044 bool TextDocument::debuggerIsRunning() const
1045 {
1046 return m_pDebugger;
1047 }
1048
1049
debuggerIsStepping() const1050 bool TextDocument::debuggerIsStepping() const
1051 {
1052 return m_pDebugger && !m_pDebugger->gpsim()->isRunning();
1053 }
1054
1055
setDebugger(GpsimDebugger * debugger,bool ownDebugger)1056 void TextDocument::setDebugger( GpsimDebugger * debugger, bool ownDebugger )
1057 {
1058 if ( debugger == m_pDebugger )
1059 return;
1060
1061 // If we create a gpsim, then we may get called by DebugManager, which will
1062 // try to claim we don't own it. So if we have a symbol file waiting, thne
1063 // wait until we are called from its successful creation
1064 if ( !m_symbolFile.isEmpty() && !ownDebugger )
1065 return;
1066
1067 // Reset it for use next time
1068 m_symbolFile = QString::null;
1069
1070 if (m_bOwnDebugger)
1071 delete m_pDebugger;
1072
1073 m_pDebugger = debugger;
1074 m_bOwnDebugger = ownDebugger;
1075
1076 if (!m_pDebugger)
1077 return;
1078
1079 if ( m_debugFile.isEmpty() )
1080 m_debugFile = url().path();
1081
1082 connect( m_pDebugger, SIGNAL(destroyed()), this, SLOT(slotDebuggerDestroyed()) );
1083 connect( m_pDebugger->gpsim(), SIGNAL(runningStatusChanged(bool )), this, SLOT(slotInitDebugActions()) );
1084 connect( m_pDebugger, SIGNAL(lineReached(const SourceLine &)), this, SLOT(slotDebugSetCurrentLine(const SourceLine &)) );
1085 m_pDebugger->setBreakpoints( m_debugFile, breakpointList() );
1086
1087 slotInitDebugActions();
1088 if ( !m_pDebugger->gpsim()->isRunning() )
1089 slotDebugSetCurrentLine( m_pDebugger->currentLine() );
1090
1091 if ( this == dynamic_cast<TextDocument*>(DocManager::self()->getFocusedDocument()) )
1092 SymbolViewer::self()->setContext( m_pDebugger->gpsim() );
1093 }
1094 #endif // !NO_GPSIM
1095
1096
inactiveBreakpointPixmap()1097 const QPixmap* TextDocument::inactiveBreakpointPixmap()
1098 {
1099 const char*breakpoint_gr_xpm[]={
1100 "11 16 6 1",
1101 "c c #c6c6c6",
1102 "d c #2c2c2c",
1103 "# c #000000",
1104 ". c None",
1105 "a c #ffffff",
1106 "b c #555555",
1107 "...........",
1108 "...........",
1109 "...#####...",
1110 "..#aaaaa#..",
1111 ".#abbbbbb#.",
1112 "#abbbbbbbb#",
1113 "#abcacacbd#",
1114 "#abbbbbbbb#",
1115 "#abcacacbd#",
1116 "#abbbbbbbb#",
1117 ".#bbbbbbb#.",
1118 "..#bdbdb#..",
1119 "...#####...",
1120 "...........",
1121 "...........",
1122 "..........."};
1123 static QPixmap pixmap( breakpoint_gr_xpm );
1124 return &pixmap;
1125 }
1126
1127
activeBreakpointPixmap()1128 const QPixmap* TextDocument::activeBreakpointPixmap()
1129 {
1130 const char* breakpoint_xpm[]={
1131 "11 16 6 1",
1132 "c c #c6c6c6",
1133 ". c None",
1134 "# c #000000",
1135 "d c #840000",
1136 "a c #ffffff",
1137 "b c #ff0000",
1138 "...........",
1139 "...........",
1140 "...#####...",
1141 "..#aaaaa#..",
1142 ".#abbbbbb#.",
1143 "#abbbbbbbb#",
1144 "#abcacacbd#",
1145 "#abbbbbbbb#",
1146 "#abcacacbd#",
1147 "#abbbbbbbb#",
1148 ".#bbbbbbb#.",
1149 "..#bdbdb#..",
1150 "...#####...",
1151 "...........",
1152 "...........",
1153 "..........."};
1154 static QPixmap pixmap( breakpoint_xpm );
1155 return &pixmap;
1156 }
1157
1158
1159
reachedBreakpointPixmap()1160 const QPixmap* TextDocument::reachedBreakpointPixmap()
1161 {
1162 const char*breakpoint_bl_xpm[]={
1163 "11 16 7 1",
1164 "a c #c0c0ff",
1165 "# c #000000",
1166 "c c #0000c0",
1167 "e c #0000ff",
1168 "b c #dcdcdc",
1169 "d c #ffffff",
1170 ". c None",
1171 "...........",
1172 "...........",
1173 "...#####...",
1174 "..#ababa#..",
1175 ".#bcccccc#.",
1176 "#acccccccc#",
1177 "#bcadadace#",
1178 "#acccccccc#",
1179 "#bcadadace#",
1180 "#acccccccc#",
1181 ".#ccccccc#.",
1182 "..#cecec#..",
1183 "...#####...",
1184 "...........",
1185 "...........",
1186 "..........."};
1187 static QPixmap pixmap( breakpoint_bl_xpm );
1188 return &pixmap;
1189 }
1190
1191
disabledBreakpointPixmap()1192 const QPixmap* TextDocument::disabledBreakpointPixmap()
1193 {
1194 const char*breakpoint_wh_xpm[]={
1195 "11 16 7 1",
1196 "a c #c0c0ff",
1197 "# c #000000",
1198 "c c #0000c0",
1199 "e c #0000ff",
1200 "b c #dcdcdc",
1201 "d c #ffffff",
1202 ". c None",
1203 "...........",
1204 "...........",
1205 "...#####...",
1206 "..#ddddd#..",
1207 ".#ddddddd#.",
1208 "#ddddddddd#",
1209 "#ddddddddd#",
1210 "#ddddddddd#",
1211 "#ddddddddd#",
1212 "#ddddddddd#",
1213 ".#ddddddd#.",
1214 "..#ddddd#..",
1215 "...#####...",
1216 "...........",
1217 "...........",
1218 "..........."};
1219 static QPixmap pixmap( breakpoint_wh_xpm );
1220 return &pixmap;
1221 }
1222
1223
executionPointPixmap()1224 const QPixmap* TextDocument::executionPointPixmap()
1225 {
1226 const char*exec_xpm[]={
1227 "11 16 4 1",
1228 "a c #00ff00",
1229 "b c #000000",
1230 ". c None",
1231 "# c #00c000",
1232 "...........",
1233 "...........",
1234 "...........",
1235 "#a.........",
1236 "#aaa.......",
1237 "#aaaaa.....",
1238 "#aaaaaaa...",
1239 "#aaaaaaaaa.",
1240 "#aaaaaaa#b.",
1241 "#aaaaa#b...",
1242 "#aaa#b.....",
1243 "#a#b.......",
1244 "#b.........",
1245 "...........",
1246 "...........",
1247 "..........."};
1248 static QPixmap pixmap( exec_xpm );
1249 return &pixmap;
1250 }
1251