/*************************************************************************** * Copyright (C) 2005-2006 Nicolas Hadacek * * Copyright (C) 2003-2004 Alain Gibaud * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "editor_manager.h" #include #include #include #include #include #include #include #include "text_editor.h" #include "hex_editor.h" #include "object_view.h" #include "new_dialogs.h" #include "main_global.h" #include "gui_debug_manager.h" #include "common/gui/purl_gui.h" #include "device_gui.h" #include "register_view.h" #include "device_editor.h" #include "project_manager.h" #include "global_config.h" #include "project.h" //----------------------------------------------------------------------------- SwitchToDialog::SwitchToDialog(const TQStringList &names, TQWidget *tqparent) : Dialog(tqparent, "switch_to_dialog", true, i18n("Switch to editor"), Ok | Cancel, Ok, false) { TQVBoxLayout *top = new TQVBoxLayout(mainWidget(), 10, 10); _edit = new KLineEdit(mainWidget()); _edit->setCompletedItems(names); top->addWidget(_edit); } //----------------------------------------------------------------------------- void EditorTabBar::paintLabel(TQPainter *p, const TQRect &br, TQTab *t, bool has_focus) const { TQFont f = p->font(); f.setItalic(_readOnly[t]); p->setFont(f); TQTabBar::paintLabel(p, br, t, has_focus); } //----------------------------------------------------------------------------- TQString EditorHistory::goBack() { if ( !hasBack() ) return TQString(); _current--; return _names[_current]; } TQString EditorHistory::goForward() { if ( !hasForward() ) return TQString(); _current++; return _names[_current]; } void EditorHistory::add(const TQString &name) { if ( _names.count()!=0 ) { _current = TQMIN(_current, _names.count()-1); if ( _names[_current]==name ) return; if ( _current!=0 && _names[_current-1]==name ) { _current--; return; } _current++; if ( _current<_names.count() && _names[_current]==name ) return; } _names.resize(_current+1); _names[_current] = name; } void EditorHistory::closedLast() { if ( _names.count()==0 ) return; _names.resize(_current); if ( _current!=0 ) _current--; } //----------------------------------------------------------------------------- const char * const EditorManager::EDITOR_TAGS[Nb_EditorTypes] = { "device", "registers" }; EditorManager::EditorManager(TQWidget *tqparent) : TabWidget(tqparent, "editor_manager"), _current(0) { setTabBar(new EditorTabBar(this)); connect(this, TQT_SIGNAL(currentChanged(TQWidget *)), TQT_SLOT(showEditor(TQWidget *))); setHoverCloseButton(readConfigEntry(BaseGlobalConfig::ShowTabCloseButton).toBool()); setHoverCloseButtonDelayed(false); } bool EditorManager::openFile(const PURL::Url &url) { if ( url.isEmpty() ) return false; Editor *e = findEditor(url); if (e) { // document already loaded if ( !MessageBox::askContinue(i18n("File \"%1\" already loaded. Reload?").tqarg(url.kurl().prettyURL()), i18n("Warning"), i18n("Reload")) ) return true; if ( !e->slotLoad() ) { closeEditor(e, false); return false; } return true; } if ( !openEditor(url) ) { static_cast< KRecentFilesAction *>(Main::action("file_open_recent"))->removeURL(url.kurl()); return false; } static_cast(Main::action("file_open_recent"))->addURL(url.kurl()); return true; } void EditorManager::connectEditor(Editor *editor) { disconnectEditor(currentEditor()); if ( editor==0 ) return; editor->addGui(); connect(editor, TQT_SIGNAL(modified()), TQT_SLOT(modifiedSlot())); connect(editor, TQT_SIGNAL(guiChanged()), TQT_SIGNAL(guiChanged())); connect(editor, TQT_SIGNAL(dropEventPass(TQDropEvent *)), TQT_SLOT(slotDropEvent(TQDropEvent *))); connect(editor, TQT_SIGNAL(statusTextChanged(const TQString &)), TQT_SIGNAL(statusChanged(const TQString &))); } void EditorManager::modifiedSlot() { emit modified(currentEditor()->url()); } void EditorManager::disconnectEditor(Editor *editor) { if ( editor==0 ) return; editor->disconnect(this); editor->removeGui(); } TQString EditorManager::title(const Editor &e) const { return (e.url().isEmpty() ? "<" + e.name() + ">" : e.url().filename()); } void EditorManager::updateTitles() { KIconLoader loader; TQPixmap def = loader.loadIcon("piklab", KIcon::Small); TQPixmap modified = loader.loadIcon("filesave", KIcon::Small); TQPixmap chip = loader.loadIcon("piklab_chip", KIcon::Small); TQValueList::iterator it = _editors.begin(); for (; it!=_editors.end(); ++it) { static_cast(tabBar())->setReadOnly(indexOf(*it), (*it)->isReadOnly()); TQPixmap pixmap; if ( (*it)->isModified() ) pixmap = modified; else if ( ::tqqt_cast< ::DeviceEditor *>(*it)==0 ) pixmap = PURL::icon((*it)->fileType()); else pixmap = chip; changeTab(*it, pixmap.isNull() ? def : pixmap, title(**it)); } } bool EditorManager::closeCurrentEditor() { if ( !closeEditor(_current, true) ) return false; emit guiChanged(); return true; } bool EditorManager::closeAllEditors() { if ( currentEditor()==0 ) return true; while ( currentEditor() ) if ( !closeEditor(currentEditor(), true) ) break; emit guiChanged(); return ( currentEditor()==0 ); } bool EditorManager::closeAllOtherEditors() { if ( nbEditors()==1 ) return true; TQValueList list = _editors; list.remove(currentEditor()); TQValueList::iterator it = list.begin(); bool ok = true; for (; it!=list.end(); ++it) { if ( !closeEditor(*it, true) ) { ok = false; break; } } emit guiChanged(); return ok; } bool EditorManager::closeEditor(const PURL::Url &url) { Editor *e = findEditor(url); if ( e==0 ) return true; if ( !closeEditor(e, true) ) return false; emit guiChanged(); return true; } void EditorManager::closeRequest(int i) { closeEditor(static_cast(page(i)), true); emit guiChanged(); } bool EditorManager::closeEditor(Editor *e, bool ask) { if ( e==0 ) return true; if ( ask && !e->checkSaved() ) return false; removePage(e); _editors.remove(e); Editor *g = static_cast(currentPage()); changeToEditor(g); saveBookmarks(*e); delete e; return true; } void EditorManager::saveBookmarks(const Editor &e) { if ( Main::project()==0 ) return; TQValueList lines = e.bookmarkLines(); Main::project()->setBookmarkLines(e.url(), lines); } void EditorManager::restoreBookmarks(Editor &e) { if ( Main::project()==0 ) return; TQValueList lines = Main::project()->bookmarkLines(e.url()); e.setBookmarkLines(lines); } void EditorManager::showEditor(Editor *e) { changeToEditor(e); emit guiChanged(); } void EditorManager::changeToEditor(Editor *e) { if ( e==_current ) return; connectEditor(e); _current = e; if (e) { showPage(e); e->clearFocus(); // force a got focus signal e->setFocus(); e->statusChanged(); _history.add(name(*e)); } else { emit statusChanged(TQString()); _history.closedLast(); } } Editor *EditorManager::findEditor(const TQString &tag) { TQValueList::iterator it = _editors.begin(); for (; it!=_editors.end(); ++it) if ( (*it)->tag()==tag ) return *it; return 0; } Editor *EditorManager::findEditor(const PURL::Url &url) { TQValueList::iterator it = _editors.begin(); for (; it!=_editors.end(); ++it) if ( (*it)->url()==url ) return *it; return 0; } Editor *EditorManager::createEditor(PURL::FileType type, const PURL::Url &url) { Editor *e = findEditor(url); if (e) closeEditor(e, false); switch (type.type()) { case PURL::Hex: e = new HexEditor(this); break; case PURL::CSource: case PURL::CppSource: case PURL::CHeader: case PURL::AsmGPAsm: case PURL::AsmPIC30: case PURL::AsmPICC: case PURL::Inc: case PURL::JalSource: case PURL::BasicSource: e = new TextEditor(true, this); break; case PURL::Lkr: case PURL::Gld: case PURL::Map: case PURL::Lst: case PURL::Cod: case PURL::Unknown: e = new TextEditor(false, this); break; case PURL::Coff: if ( Main::project()==0 ) { if ( Main::deviceData()==0 ) return 0; e = new Coff::CoffEditor(url, *Main::deviceData(), this); } else { if ( Debugger::manager->coff()==0 ) return 0; e = new Coff::CoffEditor(*Debugger::manager->coff(), this); } static_cast(e)->setView(&Main::compileLog()); break; case PURL::Object: e = new Coff::ObjectEditor(url, this); static_cast(e)->setView(&Main::compileLog()); break; case PURL::Library: e = new Coff::LibraryEditor(url, this); static_cast(e)->setView(&Main::compileLog()); break; case PURL::Elf: case PURL::Project: case PURL::PikdevProject: case PURL::Nb_FileTypes: break; } return e; } void EditorManager::addEditor(Editor *e) { TQValueList::iterator it = _editors.begin(); for (; it!=_editors.end(); ++it) if ( *it==e ) return; _editors.append(e); addTab(e, TQString()); setTabEnabled(e, true); restoreBookmarks(*e); showEditor(e); } void EditorManager::slotDropEvent(TQDropEvent *event) { TQStringList urls; if ( !TQUriDrag::decodeLocalFiles(event, urls)) return; TQStringList::const_iterator it = urls.begin(); for(; it!=urls.end(); ++it) openEditor(PURL::Url::fromPathOrUrl(*it)); } Editor *EditorManager::openEditor(const PURL::Url &url) { Editor *e = findEditor(url); if ( e==0 ) { e = createEditor(url.fileType(), url); if ( e==0 ) return 0; if ( !e->open(url) ) { closeEditor(e, false); return 0; } addEditor(e); } else showEditor(e); return e; } void EditorManager::saveAllFiles() { TQValueList::iterator it = _editors.begin(); for (; it!=_editors.end(); ++it) { if ( !(*it)->isModified() ) continue; (*it)->save(); } emit guiChanged(); } PURL::UrlList EditorManager::files() const { PURL::UrlList names; TQValueList::const_iterator it = _editors.begin(); for(; it!=_editors.end(); ++it) { if ( (*it)->url().isEmpty() ) continue; names.push_back((*it)->url()); } return names; } void EditorManager::contextMenu(int i, const TQPoint &p) { Editor *editor = static_cast(page(i)); if ( editor==0 ) return; KIconLoader loader; TQPixmap closeIcon = loader.loadIcon("fileclose", KIcon::Small); TQPixmap saveIcon = loader.loadIcon("filesave", KIcon::Small); TQPixmap saveAsIcon = loader.loadIcon("filesaveas", KIcon::Small); TQPixmap reloadIcon = loader.loadIcon("reload", KIcon::Small); KPopupMenu *popup = new KPopupMenu; popup->insertTitle(title(*editor)); popup->insertItem(closeIcon, i18n("Close"), 1); if ( nbEditors()>1 ) popup->insertItem(i18n("Close All Others"), 2); if ( editor->isModified() ) popup->insertItem(saveIcon, i18n("Save"), 3); popup->insertItem(saveAsIcon, i18n("Save As..."), 4); if ( !editor->url().isEmpty() ) popup->insertItem(reloadIcon, i18n("Reload"), 5); switch (popup->exec(p)) { case 1: closeEditor(editor, true); break; case 2: closeAllOtherEditors(); break; case 3: editor->save(); break; case 4: editor->saveAs(); break; case 5: editor->reload(); break; } emit guiChanged(); delete popup; } void EditorManager::switchHeaderImplementation() { if ( currentEditor()==0 ) return; PURL::Url url = currentEditor()->url(); PURL::FileType type = url.fileType(); PURL::SourceFamily source = type.data().sourceFamily; if ( type.data().group==PURL::Source ) type = source.data().headerType; else { Q_ASSERT( type.data().group==PURL::Source ); type = Main::toolGroup().implementationType(source.data().toolType); } if ( type==PURL::Nb_FileTypes ) return; url = url.toFileType(type); if ( !url.exists() ) return; openEditor(url); } void EditorManager::switchToEditor() { TQStringList names; for (uint i=0; i<_editors.count(); i++) names.append(title(*_editors[i])); SwitchToDialog dialog(names, this); if ( dialog.exec()!=TQDialog::Accepted ) return; for (uint i=0; i(e)->setDevice(false); static_cast(e)->setDevice(true); // #### needed to fix GUI glitch ??? created = true; } break; } case RegisterEditor: { e = findEditor(tag); if ( e==0 ) { ::PBusyCursor bc; e = new Register::MainView(i18n("Registers"), tag); static_cast(Debugger::manager)->addRegisterView(*static_cast(e)); created = true; } break; } case Nb_EditorTypes: Q_ASSERT(false); break; } if ( e==0 ) return 0; if (created) { if ( !e->slotLoad() ) { delete e; return 0; } addEditor(e); } else showEditor(e); return e; }