summaryrefslogtreecommitdiffstats
path: root/src/ktechlab.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ktechlab.cpp')
-rw-r--r--src/ktechlab.cpp1232
1 files changed, 1232 insertions, 0 deletions
diff --git a/src/ktechlab.cpp b/src/ktechlab.cpp
new file mode 100644
index 0000000..cc89ffb
--- /dev/null
+++ b/src/ktechlab.cpp
@@ -0,0 +1,1232 @@
+/***************************************************************************
+ * Copyright (C) 2003-2005 by David Saxton *
+ * *
+ * 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 "circuitdocument.h"
+#include "config.h"
+#include "contexthelp.h"
+#include "docmanager.h"
+#include "filemetainfo.h"
+#include "flowcodedocument.h"
+#include "itemeditor.h"
+#include "itemgroup.h"
+#include "iteminterface.h"
+#include "itemlibrary.h"
+#include "ktechlab.h"
+#include "core/ktlconfig.h"
+#include "languagemanager.h"
+#include "mechanicsdocument.h"
+#include "microlibrary.h"
+#include "newfiledlg.h"
+#include "oscilloscope.h"
+#include "projectmanager.h"
+#include "recentfilesaction.h"
+#include "settingsdlg.h"
+#include "subcircuits.h"
+#include "symbolviewer.h"
+#include "textdocument.h"
+#include "textview.h"
+#include "viewcontainer.h"
+
+#include <qdockarea.h>
+#include <qtimer.h>
+#include <qtoolbutton.h>
+#include <qwhatsthis.h>
+
+#include <kaccel.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kedittoolbar.h>
+#include <kfiledialog.h>
+#include <kiconloader.h>
+#include <kio/netaccess.h>
+#include <kkeydialog.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kpopupmenu.h>
+#include <kstandarddirs.h>
+#include <ktabwidget.h>
+#include <kurldrag.h>
+#include <kwin.h>
+
+KTechlab::KTechlab()
+ : KateMDI::MainWindow( 0, "KTechlab" )
+{
+ QTime ct;
+ ct.start();
+
+ m_bIsShown = false;
+ m_pContainerDropSource = 0l;
+ m_pContainerDropReceived = 0l;
+ m_pContextMenuContainer = 0l;
+ m_pFocusedContainer = 0l;
+ m_pToolBarOverlayLabel = 0l;
+
+ m_pUpdateCaptionsTimer = new QTimer( this );
+ connect( m_pUpdateCaptionsTimer, SIGNAL(timeout()), this, SLOT(slotUpdateCaptions()) );
+
+ setMinimumSize( 400, 400 );
+
+ DocManager::self(this);
+ ItemInterface::self(this);
+
+ setupTabWidget();
+ setupToolDocks();
+ setupActions();
+ setupView();
+ readProperties( KGlobal::config() );
+
+// kdDebug() << "Constructor time: " << ct.elapsed() << endl;
+}
+
+
+KTechlab::~KTechlab()
+{
+ fileMetaInfo()->saveAllMetaInfo();
+
+ delete fileMetaInfo();
+ delete itemLibrary(); // This better be the last time the item library is used!
+ delete subcircuits();
+}
+
+
+void KTechlab::show()
+{
+ KateMDI::MainWindow::show();
+ m_bIsShown = true;
+}
+
+
+void KTechlab::load( const KURL & url )
+{
+ if ( url.url().endsWith( ".ktechlab", false ) )
+ {
+ // This is a ktechlab project; it has to be handled separetly from a
+ // normal file.
+
+ ProjectManager::self()->slotOpenProject( url );
+ return;
+ }
+
+
+ QString target;
+ // the below code is what you should normally do. in this
+ // example case, we want the url to our own. you probably
+ // want to use this code instead for your app
+
+ // download the contents
+ if ( !KIO::NetAccess::download( url, target, this ) )
+ {
+ // If the file could not be downloaded, for example does not
+ // exist on disk, NetAccess will tell us what error to use
+ KMessageBox::error(this, KIO::NetAccess::lastErrorString());
+
+ return;
+ }
+
+ addRecentFile(url);
+
+ // set our caption
+ setCaption( url.prettyURL() );
+
+ // load in the file (target is always local)
+ DocManager::self()->openURL( target );
+
+ // and remove the temp file
+ KIO::NetAccess::removeTempFile( target );
+}
+
+
+QStringList KTechlab::recentFiles()
+{
+ return m_recentFiles->items();
+}
+
+
+void KTechlab::setupToolDocks()
+{
+#if defined(KDE_MAKE_VERSION)
+# if KDE_VERSION >= KDE_MAKE_VERSION(3,3,0)
+ setToolViewStyle( KMultiTabBar::KDEV3ICON );
+# endif
+#endif
+
+ QPixmap pm;
+ KIconLoader * loader = KGlobal::iconLoader();
+ KateMDI::ToolView * tv = 0l;
+
+ tv = createToolView( ProjectManager::toolViewIdentifier(),
+ KMultiTabBar::Left,
+ loader->loadIcon( "attach", KIcon::Small ),
+ i18n("Project") );
+ ProjectManager::self( this, tv );
+
+ pm.load( locate( "appdata", "icons/circuit.png" ) );
+ tv = createToolView( ComponentSelector::toolViewIdentifier(),
+ KMultiTabBar::Left,
+ pm,
+ i18n("Components") );
+ ComponentSelector::self(tv);
+
+ // Create an instance of the subcircuits interface, now that we have created the component selector
+ subcircuits();
+ Subcircuits::loadSubcircuits();
+
+ pm.load( locate( "appdata", "icons/flowcode.png" ) );
+ tv = createToolView( FlowPartSelector::toolViewIdentifier(),
+ KMultiTabBar::Left,
+ pm,
+ i18n("Flow Parts") );
+ FlowPartSelector::self(tv);
+
+#ifdef MECHANICS
+ pm.load( locate( "appdata", "icons/mechanics.png" ) );
+ tv = createToolView( MechanicsSelector::toolViewIdentifier(),
+ KMultiTabBar::Left,
+ pm,
+ i18n("Mechanics") );
+ MechanicsSelector::self(tv);
+#endif
+
+ pm.load( locate( "appdata", "icons/item.png" ) );
+ tv = createToolView( ItemEditor::toolViewIdentifier(),
+ KMultiTabBar::Right,
+ pm,
+ i18n("Item Editor") );
+ ItemEditor::self(tv);
+
+ tv = createToolView( ContextHelp::toolViewIdentifier(),
+ KMultiTabBar::Right,
+ loader->loadIcon( "contents", KIcon::Small ),
+ i18n("Context Help") );
+ ContextHelp::self(tv);
+
+ tv = createToolView( LanguageManager::toolViewIdentifier(),
+ KMultiTabBar::Bottom,
+ loader->loadIcon( "log", KIcon::Small ),
+ i18n("Messages") );
+ LanguageManager::self( tv, this );
+
+#ifndef NO_GPSIM
+ tv = createToolView( SymbolViewer::toolViewIdentifier(),
+ KMultiTabBar::Right,
+ loader->loadIcon( "blockdevice", KIcon::Small ),
+ i18n("Symbol Viewer") );
+ SymbolViewer::self(tv);
+#endif
+
+ addOscilloscopeAsToolView(this);
+}
+
+
+void KTechlab::addWindow( ViewContainer * vc )
+{
+ if ( vc && !m_viewContainerList.contains(vc) )
+ {
+ m_viewContainerList << vc;
+ connect( vc, SIGNAL(destroyed(QObject* )), this, SLOT(slotViewContainerDestroyed(QObject* )) );
+ }
+
+ m_viewContainerList.remove((ViewContainer*)0);
+ slotUpdateTabWidget();
+ slotDocModifiedChanged();
+}
+
+
+void KTechlab::setupView()
+{
+ setAcceptDrops(true);
+ setStandardToolBarMenuEnabled(true);
+ setXMLFile("ktechlabui.rc");
+ createShellGUI(true);
+ action("newfile_popup")->plug( toolBar("mainToolBar"), 0 );
+ action("file_new")->unplug( toolBar("mainToolBar") );
+ statusBar()->show();
+}
+
+
+void KTechlab::overlayToolBarScreenshot()
+{
+ if ( !m_pToolBarOverlayLabel )
+ {
+ m_pToolBarOverlayLabel = new QLabel( 0, 0, WStyle_StaysOnTop | WStyle_Customize | WStyle_NoBorder | WNoAutoErase | WType_Popup );
+ m_pToolBarOverlayLabel->hide();
+ m_pToolBarOverlayLabel->setBackgroundMode( NoBackground );
+ }
+
+ if ( !m_bIsShown )
+ {
+ // The window isn't visible yet, so there's nothing to overlay (and if we tried,
+ // it would appear as a strange floating toolbar).
+ return;
+ }
+
+ if ( m_pToolBarOverlayLabel->isShown() )
+ {
+ // This is to avoid successive calls to removeGUIClient when we have
+ // already popped it up for the first call, and don't want to take
+ // another screenshot (as that would be without the toolbar).
+ return;
+ }
+
+ QPtrListIterator<KToolBar> toolBarIterator();
+
+// QWidget * toolsWidget = toolBar( "toolsToolBar" );
+// QWidget * debugWidget = toolBar( "debugTB" );
+
+ KToolBar * toolsWidget = static_cast<KToolBar*>(child( "toolsToolBar", "KToolBar" ));
+ KToolBar * debugWidget = static_cast<KToolBar*>(child( "debugTB", "KToolBar" ));
+
+ if ( !toolsWidget && !debugWidget )
+ return;
+
+ QWidget * parent = static_cast<QWidget*>(toolsWidget ? toolsWidget->parent() : debugWidget->parent());
+
+ QRect grabRect;
+
+ // 128 is a sanity check (widget can do strange things when being destroyed)
+
+ if ( toolsWidget && toolsWidget->height() <= 128 )
+ grabRect |= toolsWidget->geometry();
+ if ( debugWidget && debugWidget->height() <= 128 )
+ grabRect |= debugWidget->geometry();
+
+ if ( !grabRect.isValid() )
+ return;
+
+ QPixmap shot = QPixmap::grabWidget( parent, grabRect.x(), grabRect.y(), grabRect.width(), grabRect.height() );
+
+ m_pToolBarOverlayLabel->move( parent->mapToGlobal( grabRect.topLeft() ) );
+ m_pToolBarOverlayLabel->setFixedSize( grabRect.size() );
+ m_pToolBarOverlayLabel->setPixmap( shot );
+ m_pToolBarOverlayLabel->show();
+
+ QTimer::singleShot( 100, this, SLOT( hideToolBarOverlay() ) );
+}
+
+
+void KTechlab::hideToolBarOverlay()
+{
+ if ( !m_pToolBarOverlayLabel )
+ return;
+
+// QWidget * hiddenWidget = toolBar( "toolsToolBar" );
+// if ( !hiddenWidget )
+// return;
+
+// hiddenWidget->setBackgroundMode( NoBackground );
+// hiddenWidget->setWFlags( WNoAutoErase );
+// hiddenWidget->setUpdatesEnabled( false );
+
+ m_pToolBarOverlayLabel->hide();
+}
+
+
+void KTechlab::addNoRemoveGUIClient( KXMLGUIClient * client )
+{
+ if ( client && !m_noRemoveGUIClients.contains( client ) )
+ m_noRemoveGUIClients << client;
+}
+
+
+void KTechlab::removeGUIClients()
+{
+ QValueList<KXMLGUIClient*> clientsToRemove;
+
+ QPtrList<KXMLGUIClient> clients = factory()->clients();
+ for ( KXMLGUIClient * client = clients.first(); client; client = clients.next() )
+ {
+ if ( client && client != this && !m_noRemoveGUIClients.contains( client ) )
+ clientsToRemove << client;
+ }
+
+ if ( clients.isEmpty() )
+ return;
+
+ overlayToolBarScreenshot();
+
+ QValueList<KXMLGUIClient*>::iterator end = clientsToRemove.end();
+ for ( QValueList<KXMLGUIClient*>::iterator it = clientsToRemove.begin(); it != end; ++it )
+ factory()->removeClient(*it);
+}
+
+
+void KTechlab::setupTabWidget()
+{
+ m_pViewContainerTabWidget = new KTabWidget(centralWidget());
+ connect( tabWidget(), SIGNAL(currentChanged(QWidget* )), this, SLOT(slotViewContainerActivated(QWidget* )) );
+ connect( tabWidget(), SIGNAL(testCanDecode(const QDragMoveEvent*, bool& )), this, SLOT(slotTabDragEvent(const QDragMoveEvent*, bool& )) );
+ connect( tabWidget(), SIGNAL(initiateDrag(QWidget* )), this, SLOT(slotTabDragInitiate(QWidget* )) );
+ connect( tabWidget(), SIGNAL(receivedDropEvent(QDropEvent* )), this, SLOT(slotTabReceivedDropEvent(QDropEvent* )) );
+ connect( tabWidget(), SIGNAL(receivedDropEvent(QWidget*, QDropEvent* )), this, SLOT(slotTabReceivedDropEvent(QWidget*, QDropEvent* )) );
+
+ KConfig *config = kapp->config();
+ config->setGroup("UI");
+
+ bool CloseOnHover = config->readBoolEntry( "CloseOnHover", false );
+ tabWidget()->setHoverCloseButton( CloseOnHover );
+
+ bool CloseOnHoverDelay = config->readBoolEntry( "CloseOnHoverDelay", false );
+ tabWidget()->setHoverCloseButtonDelayed( CloseOnHoverDelay );
+
+// bool openNewTabAfterCurrent = config->readBoolEntry( "OpenNewTabAfterCurrent", false );
+// bool showTabIcons = config->readBoolEntry( "ShowTabIcons", true );
+
+ if (config->readBoolEntry( "ShowCloseTabsButton", true ))
+ {
+ QToolButton *but = new QToolButton(tabWidget());
+ but->setIconSet(SmallIcon("tab_remove"));
+ but->adjustSize();
+ but->hide();
+ connect( but, SIGNAL(clicked()), this, SLOT(slotViewContainerClose()) );
+ tabWidget()->setCornerWidget(but, TopRight);
+ }
+// tabWidget()->setTabReorderingEnabled(true);
+// connect(tabWidget(), SIGNAL(movedTab(int, int)), this, SLOT(tabMoved(int, int)));
+ connect(tabWidget(), SIGNAL(contextMenu(QWidget*,const QPoint &)), this, SLOT(slotTabContext(QWidget*,const QPoint &)));
+ //END Tab bar stuff
+}
+
+
+void KTechlab::slotUpdateTabWidget()
+{
+ m_viewContainerList.remove( (ViewContainer*)0 );
+
+ bool noWindows = m_viewContainerList.isEmpty();
+
+ if ( QWidget * button = tabWidget()->cornerWidget(TopRight) )
+ button->setHidden( noWindows );
+
+ if ( noWindows )
+ setCaption( 0 );
+}
+
+
+void KTechlab::setupActions()
+{
+ KActionCollection *ac = actionCollection();
+
+ KStdAction::openNew( this, SLOT(slotFileNew()), ac );
+ KStdAction::open( this, SLOT(slotFileOpen()), ac );
+ KStdAction::save( this, SLOT(slotFileSave()), ac );
+ KStdAction::saveAs( this, SLOT(slotFileSaveAs()), ac );
+ KStdAction::close( this, SLOT(slotViewClose()), ac );
+ KStdAction::print( this, SLOT(slotFilePrint()), ac );
+ KStdAction::quit( this, SLOT(slotFileQuit()), ac );
+ KStdAction::undo( this, SLOT(slotEditUndo()), ac );
+ KStdAction::redo( this, SLOT(slotEditRedo()), ac );
+ KStdAction::cut( this, SLOT(slotEditCut()), ac );
+ KStdAction::copy( this, SLOT(slotEditCopy()), ac );
+ KStdAction::paste( this, SLOT(slotEditPaste()), ac );
+ KStdAction::keyBindings( this, SLOT(slotOptionsConfigureKeys()), ac );
+ KStdAction::configureToolbars( this, SLOT(slotOptionsConfigureToolbars()), ac );
+ KStdAction::preferences( this, SLOT(slotOptionsPreferences()), ac );
+
+ //BEGIN New file popup
+ KToolBarPopupAction *p = new KToolBarPopupAction( i18n("&New"), "filenew", KStdAccel::shortcut(KStdAccel::New), this, SLOT(slotFileNew()), ac, "newfile_popup" );
+ p->popupMenu()->insertTitle( i18n("New File") );
+ (new KAction( i18n("Assembly"), "source", 0, this, SLOT(slotFileNewAssembly()), ac, "newfile_asm" ))->plug( p->popupMenu() );
+ (new KAction( i18n("C source"), "source_c", 0, this, SLOT(slotFileNewC()), ac, "newfile_c" ))->plug( p->popupMenu() );
+ (new KAction( i18n("Circuit"), "ktechlab_circuit", 0, this, SLOT(slotFileNewCircuit()), ac, "newfile_circuit" ))->plug( p->popupMenu() );
+ (new KAction( i18n("FlowCode"), "ktechlab_flowcode", 0, this, SLOT(slotFileNewFlowCode()), ac, "newfile_flowcode" ))->plug( p->popupMenu() );
+#ifdef MECHANICS
+ (new KAction( i18n("Mechanics"), "ktechlab_mechanics", 0, this, SLOT(slotFileNewMechanics()), ac, "newfile_mechanics" ))->plug( p->popupMenu() );
+#endif
+ (new KAction( "Microbe", "ktechlab_microbe", 0, this, SLOT(slotFileNewMicrobe()), ac, "newfile_microbe" ))->plug( p->popupMenu() );
+ //END New File popup
+
+
+// m_recentFiles = KStdAction::openRecent( this, SLOT(load(const KURL&)), ac );
+ m_recentFiles = new RecentFilesAction( "Recent Files", i18n("Open Recent"), this, SLOT(load(const KURL &)), ac, "file_open_recent" );
+ m_statusbarAction = KStdAction::showStatusbar( this, SLOT(slotOptionsShowStatusbar()), ac );
+
+ //BEGIN Project Actions
+ ProjectManager *pm = ProjectManager::self(this);
+ new KAction( i18n("New Project.."), "window_new", 0, pm, SLOT(slotNewProject()), ac, "project_new" );
+ new KAction( i18n("Open Project..."), "project_open", 0, pm, SLOT(slotOpenProject()), ac, "project_open" );
+// m_recentProjects = new KRecentFilesAction( i18n("Open &Recent Project..."), 0, ProjectManager::self(), SLOT(slotOpenProject(const KURL&)), ac, "project_open_recent" );
+ m_recentProjects = new RecentFilesAction( "Recent Projects", i18n("Open &Recent Project..."), ProjectManager::self(), SLOT(slotOpenProject(const KURL&)), ac, "project_open_recent" );
+ new KAction( i18n("Export to Makefile..."), "fileexport", 0, pm, SLOT(slotExportToMakefile()), ac, "project_export_makefile" );
+ new KAction( i18n("Create Subproject..."), 0, 0, pm, SLOT(slotCreateSubproject()), ac, "project_create_subproject" );
+ new KAction( i18n("Add Existing File..."), "fileopen", 0, pm, SLOT(slotAddFile()), ac, "project_add_existing_file" );
+ new KAction( i18n("Add Current File..."), "fileimport", 0, pm, SLOT(slotAddCurrentFile()), ac, "project_add_current_file" );
+// new KAction( i18n("Project Options"), "configure", 0, pm, SLOT(slotProjectOptions()), ac, "project_options" );
+ new KAction( i18n("Close Project"), "fileclose", 0, pm, SLOT(slotCloseProject()), ac, "project_close" );
+ new KAction( i18n("Remove from Project"), "editdelete", 0, pm, SLOT(slotRemoveSelected()), ac, "project_remove_selected" );
+ new KAction( i18n("Insert Existing File..."), "fileopen", 0, pm, SLOT(slotSubprojectAddExistingFile()), ac, "subproject_add_existing_file" );
+ new KAction( i18n("Insert Current File..."), "fileimport", 0, pm, SLOT(slotSubprojectAddCurrentFile()),ac, "subproject_add_current_file" );
+ new KAction( i18n("Linker Options..."), "configure", 0, pm, SLOT(slotSubprojectLinkerOptions()), ac, "project_item_linker_options" );
+ new KAction( i18n("Build..."), "launch", 0, pm, SLOT(slotItemBuild()), ac, "project_item_build" );
+ new KAction( i18n("Upload..."), "convert_to_pic", 0, pm, SLOT(slotItemUpload()), ac, "project_item_upload" );
+ new KAction( i18n("Processing Options..."), "configure", 0, pm, SLOT(slotItemProcessingOptions()), ac, "project_item_processing_options" );
+ //END Project Actions
+
+ new KAction( i18n("Split View Left/Right"), "view_right", Qt::CTRL|Qt::SHIFT|Qt::Key_L, this, SLOT(slotViewSplitLeftRight()), ac, "view_split_leftright" );
+ new KAction( i18n("Split View Top/Bottom"), "view_bottom", Qt::CTRL|Qt::SHIFT|Qt::Key_T, this, SLOT(slotViewSplitTopBottom()), ac, "view_split_topbottom" );
+
+ KToggleAction * ta = new KToggleAction( i18n("Run Simulation"), "player_play", Qt::Key_F10, 0, 0, ac, "simulation_run" );
+ ta->setChecked(true);
+ connect( ta, SIGNAL(toggled(bool )), Simulator::self(), SLOT(slotSetSimulating(bool )) );
+#if defined(KDE_MAKE_VERSION)
+# if KDE_VERSION >= KDE_MAKE_VERSION(3,3,0)
+ ta->setCheckedState( KGuiItem( i18n("Pause Simulation"), "player_pause", 0 ) );
+# endif
+#endif
+
+ // We can call slotCloseProject now that the actions have been created
+ ProjectManager::self(this)->updateActions();
+
+ DocManager::self(this)->disableContextActions();
+}
+
+
+void KTechlab::slotViewContainerActivated( QWidget * viewContainer )
+{
+ if (m_pFocusedContainer)
+ m_pFocusedContainer->setUnfocused();
+
+ m_pFocusedContainer = dynamic_cast<ViewContainer*>(viewContainer);
+ if ( !m_pFocusedContainer )
+ return;
+
+ m_pFocusedContainer->setFocused();
+}
+
+
+void KTechlab::slotViewContainerDestroyed( QObject * object )
+{
+ m_viewContainerList.remove( static_cast<ViewContainer*>(object) );
+ m_viewContainerList.remove( (ViewContainer*)0 );
+ slotUpdateTabWidget();
+}
+
+
+void KTechlab::slotTabDragEvent( const QDragMoveEvent *e, bool &accept )
+{
+ // Hmm...this function doesn't actually seem to get called. Instead,
+ // KTabBar just seems to go straight to slotTabDragInitiate.
+ Q_UNUSED(e);
+ accept = true;
+}
+
+
+void KTechlab::slotTabDragInitiate( QWidget *widget )
+{
+ ViewContainer *viewContainer = dynamic_cast<ViewContainer*>(widget);
+ if (!viewContainer)
+ return;
+ QDragObject *dragObject = new ViewContainerDrag(viewContainer);
+ dragObject->drag();
+}
+
+
+void KTechlab::slotTabReceivedDropEvent( QDropEvent *e )
+{
+ if (!e)
+ return;
+ ViewContainer *viewContainerSource = dynamic_cast<ViewContainer*>(e->source());
+ if (!viewContainerSource)
+ {
+ e->ignore();
+ return;
+ }
+ e->accept(true);
+ viewContainerSource->duplicateViewContainer();
+}
+
+
+void KTechlab::slotTabReceivedDropEvent( QWidget *widget, QDropEvent *e )
+{
+ if (!e)
+ return;
+ m_pContainerDropSource = dynamic_cast<ViewContainer*>(e->source());
+ m_pContainerDropReceived = dynamic_cast<ViewContainer*>(widget);
+ if ( !m_pContainerDropSource || !m_pContainerDropReceived || (m_pContainerDropSource == m_pContainerDropReceived) )
+ {
+ e->ignore();
+ return;
+ }
+ e->accept(true);
+
+ KPopupMenu dropMenu;
+ dropMenu.insertItem( KGlobal::iconLoader()->loadIcon( "goto", KIcon::Small ), i18n("&Insert Into"), 0 );
+ dropMenu.insertItem( KGlobal::iconLoader()->loadIcon( "editcopy", KIcon::Small ), i18n("&Copy Into"), 1 );
+ dropMenu.insertSeparator();
+ dropMenu.insertItem( KGlobal::iconLoader()->loadIcon( "stop", KIcon::Small ), i18n("C&ancel"), 2 );
+
+ connect( &dropMenu, SIGNAL(activated(int)), this, SLOT(slotDragContextActivated(int)) );
+// dropMenu.exec(e->pos() + widget->pos() );
+ dropMenu.exec( QCursor::pos() );
+}
+
+
+void KTechlab::slotDragContextActivated( int id )
+{
+ if ( !m_pContainerDropSource || !m_pContainerDropReceived )
+ return;
+
+ switch (id)
+ {
+ case 0:
+ m_pContainerDropSource->copyViewContainerIntoExisting(m_pContainerDropReceived);
+ m_pContainerDropSource->closeViewContainer();
+ break;
+ case 1:
+ m_pContainerDropSource->copyViewContainerIntoExisting(m_pContainerDropReceived);
+ break;
+ case 2:
+ default:
+ break;
+ }
+}
+
+
+KAction * KTechlab::action( const QString & name ) const
+{
+ KAction * action = actionCollection()->action(name);
+ if ( !action )
+ kdError() << k_funcinfo << "No such action: " << name << endl;
+ return action;
+}
+
+
+void KTechlab::saveProperties( KConfig *conf )
+{
+ // Dumbass KMainWindow - can't handle my width/height correctly. Whoever thought of the "+1" hack anyway?!
+ conf->setGroup("UI");
+ conf->writeEntry( "Width", width() );
+ conf->writeEntry( "Height", height() );
+ conf->writeEntry( "WinState", KWin::windowInfo( winId(), NET::WMState ).state() );
+
+#ifndef NO_GPSIM
+ SymbolViewer::self()->saveProperties( conf );
+#endif
+
+ if ( ProjectManager::self()->currentProject() )
+ {
+ conf->setGroup("Project");
+ conf->writePathEntry( "Open", ProjectManager::self()->currentProject()->url().prettyURL() );
+ }
+ else
+ conf->deleteGroup("Project");
+
+ //BEGIN Open Views State
+ // Remvoe old entries describing the save state - we don't want a horrible mish-mash of saved states
+ const QStringList groupList = conf->groupList();
+ const QStringList::const_iterator groupListEnd = groupList.end();
+ for ( QStringList::const_iterator it = groupList.begin(); it != groupListEnd; ++it )
+ {
+ if ( (*it).startsWith("ViewContainer") )
+ conf->deleteGroup(*it);
+ }
+
+ uint viewContainerId = 1;
+ const ViewContainerList::iterator vcEnd = m_viewContainerList.end();
+ for ( ViewContainerList::iterator it = m_viewContainerList.begin(); it != vcEnd; ++it )
+ {
+ if ( !(*it) || !(*it)->canSaveUsefulStateInfo() )
+ continue;
+
+ // To make sure the ViewContainers are restored in the right order, we must create them in alphabetical order,
+ // as KConfig stores them as such...
+ const QString id = QString::number(viewContainerId++).rightJustify( 4, '0' );
+
+ conf->setGroup( "ViewContainer " + id );
+ (*it)->saveState(conf);
+ }
+ //END Open Views State
+
+ saveSession( conf, "KateMDI" );
+ // Piss off KMainWindow
+ conf->setGroup("KateMDI");
+ int scnum = QApplication::desktop()->screenNumber(parentWidget());
+ QRect desk = QApplication::desktop()->screenGeometry(scnum);
+ conf->deleteEntry( QString::fromLatin1("Width %1").arg(desk.width()) );
+ conf->deleteEntry( QString::fromLatin1("Height %1").arg(desk.height()) );
+
+ conf->sync();
+}
+
+
+void KTechlab::readProperties( KConfig *conf )
+{
+ startRestore( conf, "KateMDI" );
+
+ m_recentFiles->loadEntries();
+ m_recentProjects->loadEntries();
+
+ //BEGIN Restore Open Views
+ if ( KTLConfig::restoreDocumentsOnStartup() )
+ {
+ // If we have a lot of views open from last time, then opening them will take a long time.
+ // So we want to enter the qt event loop to finish drawing the window et al before adding the views.
+ qApp->processEvents();
+
+ const QStringList groupList = conf->groupList();
+ const QStringList::const_iterator groupListEnd = groupList.end();
+ for ( QStringList::const_iterator it = groupList.begin(); it != groupListEnd; ++it )
+ {
+ if ( (*it).startsWith("ViewContainer") )
+ {
+ ViewContainer *viewContainer = new ViewContainer( *it, this );
+
+ conf->setGroup(*it);
+ viewContainer->restoreState( conf, *it );
+
+ addWindow( viewContainer );
+ }
+ }
+ }
+ //END Restore Open Views
+
+ conf->setGroup("Project");
+ if ( conf->readPathEntry("Open") != QString::null )
+ ProjectManager::self()->slotOpenProject( KURL( conf->readPathEntry("Open") ) );
+
+#ifndef NO_GPSIM
+ SymbolViewer::self()->readProperties( conf );
+#endif
+
+ finishRestore();
+
+ // Dumbass KMainWindow - can't handle my width/height correctly. Whoever thought of the "+1" hack anyway?!
+ conf->setGroup("UI");
+ resize( conf->readNumEntry( "Width", 800 ), conf->readNumEntry( "Height", 500 ) );
+ KWin::setState( winId(), conf->readLongNumEntry( "WinState", NET::Max ) );
+}
+
+
+void KTechlab::dragEnterEvent(QDragEnterEvent *event)
+{
+ // accept uri drops only
+ event->accept(KURLDrag::canDecode(event));
+}
+
+
+void KTechlab::dropEvent(QDropEvent *event)
+{
+ // this is a very simplistic implementation of a drop event. we
+ // will only accept a dropped URL. the Qt dnd code can do *much*
+ // much more, so please read the docs there
+ KURL::List urls;
+
+ // see if we can decode a URI.. if not, just ignore it
+ if (KURLDrag::decode(event, urls) && !urls.isEmpty())
+ {
+ // okay, we have a URI.. process it
+ const KURL &url = urls.first();
+
+ // load in the file
+ load(url);
+ }
+}
+
+
+void KTechlab::slotOptionsShowStatusbar()
+{
+ // this is all very cut and paste code for showing/hiding the
+ // statusbar
+ if (m_statusbarAction->isChecked())
+ statusBar()->show();
+ else
+ statusBar()->hide();
+}
+
+
+void KTechlab::slotOptionsConfigureKeys()
+{
+// KKeyDialog::configureKeys(actionCollection(), "ktechlabui.rc");
+ KKeyDialog::configure( actionCollection(), this, true );
+}
+
+
+void KTechlab::slotOptionsConfigureToolbars()
+{
+ KEditToolbar *dlg = new KEditToolbar(guiFactory());
+
+ if (dlg->exec())
+ {
+ createShellGUI( false );
+ createShellGUI( true );
+ }
+
+ delete dlg;
+}
+
+
+void KTechlab::slotOptionsPreferences()
+{
+ // An instance of your dialog could be already created and could be cached,
+ // in which case you want to display the cached dialog instead of creating
+ // another one
+ if ( KConfigDialog::showDialog( "settings" ) )
+ return;
+
+ // KConfigDialog didn't find an instance of this dialog, so lets create it:
+ SettingsDlg* dialog = new SettingsDlg( this, "settings", KTLConfig::self() );
+
+ // User edited the configuration - update your local copies of the
+ // configuration data
+ connect( dialog, SIGNAL(settingsChanged()), this, SLOT(slotUpdateConfiguration()) );
+ dialog->show();
+}
+
+
+void KTechlab::slotUpdateConfiguration()
+{
+ emit configurationChanged();
+}
+
+
+void KTechlab::slotChangeStatusbar( const QString & text )
+{
+ // Avoid flicker by repeatedly displaying the same message, as QStatusBar does not check for this
+ if ( m_lastStatusBarMessage == text )
+ return;
+
+ statusBar()->message(text);
+ m_lastStatusBarMessage = text;
+}
+
+
+void KTechlab::slotTabContext( QWidget* widget,const QPoint & pos )
+{
+ // Shamelessly stolen from KDevelop...
+
+ KPopupMenu * tabMenu = new KPopupMenu;
+ tabMenu->insertTitle( (dynamic_cast<ViewContainer*>(widget))->caption() );
+
+ //Find the document on whose tab the user clicked
+ m_pContextMenuContainer = 0l;
+
+ m_viewContainerList.remove((ViewContainer*)0l);
+
+ const ViewContainerList::iterator vcEnd = m_viewContainerList.end();
+ for ( ViewContainerList::iterator it = m_viewContainerList.begin(); it != vcEnd; ++it )
+ {
+ ViewContainer * viewContainer = *it;
+ if ( viewContainer == widget )
+ {
+ m_pContextMenuContainer = viewContainer;
+
+ tabMenu->insertItem( i18n("Close"), 0 );
+
+ View *view = (viewContainer->viewCount() == 1) ? viewContainer->activeView() : 0l;
+
+ if ( view && view->document()->isModified() )
+ tabMenu->insertItem( i18n("Save"), 1 );
+
+ if ( view && !view->document()->url().isEmpty() )
+ tabMenu->insertItem( i18n("Reload"), 2 );
+
+ if ( m_viewContainerList.count() > 1 )
+ tabMenu->insertItem( i18n("Close All Others"), 4 );
+
+ }
+ }
+
+ connect( tabMenu, SIGNAL( activated(int) ), this, SLOT(slotTabContextActivated(int)) );
+
+ tabMenu->exec(pos);
+ delete tabMenu;
+}
+
+
+void KTechlab::slotTabContextActivated( int id )
+{
+ // Shamelessly stolen from KDevelop...
+
+ if( !m_pContextMenuContainer )
+ return;
+
+ View *view = m_pContextMenuContainer->activeView();
+ if (!view)
+ return;
+ QGuardedPtr<Document> document = view->document();
+
+ switch(id)
+ {
+ case 0:
+ {
+ m_pContextMenuContainer->closeViewContainer();
+ break;
+ }
+ case 1:
+ document->fileSave();
+ break;
+ case 2:
+ {
+ KURL url = document->url();
+ if ( document->fileClose() )
+ {
+ delete document;
+ DocManager::self()->openURL(url);
+ }
+ break;
+ }
+ case 4:
+ {
+ const ViewContainerList::iterator vcEnd = m_viewContainerList.end();
+ for ( ViewContainerList::iterator it = m_viewContainerList.begin(); it != vcEnd; ++it )
+ {
+ ViewContainer *viewContainer = *it;
+ if ( viewContainer && viewContainer != m_pContextMenuContainer )
+ {
+ if ( !viewContainer->closeViewContainer() )
+ return;
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+
+
+void KTechlab::slotFileNewAssembly()
+{
+ TextDocument *document = DocManager::self()->createTextDocument();
+ if (document)
+ document->slotInitLanguage( TextDocument::ct_asm );
+}
+void KTechlab::slotFileNewMicrobe()
+{
+ TextDocument *document = DocManager::self()->createTextDocument();
+ if (document)
+ document->slotInitLanguage( TextDocument::ct_microbe );
+}
+void KTechlab::slotFileNewC()
+{
+ TextDocument *document = DocManager::self()->createTextDocument();
+ if (document)
+ document->slotInitLanguage( TextDocument::ct_c );
+}
+void KTechlab::slotFileNewCircuit()
+{
+ DocManager::self()->createCircuitDocument();
+}
+void KTechlab::slotFileNewFlowCode()
+{
+ slotFileNew();
+}
+void KTechlab::slotFileNewMechanics()
+{
+ DocManager::self()->createMechanicsDocument();
+}
+
+void KTechlab::slotFileNew()
+{
+ NewFileDlg *newFileDlg = new NewFileDlg(this);
+
+ newFileDlg->exec();
+
+ bool addToProject = newFileDlg->addToProject();
+ bool accepted = newFileDlg->accepted();
+ int finalType = newFileDlg->fileType();
+ QString microID = newFileDlg->microID();
+ int codeType = newFileDlg->codeType();
+
+ delete newFileDlg;
+ if (!accepted)
+ return;
+
+ Document *created = 0l;
+
+ if ( finalType == Document::dt_circuit )
+ created = DocManager::self()->createCircuitDocument();
+
+ else if ( finalType == Document::dt_flowcode )
+ {
+ FlowCodeDocument * fcd = DocManager::self()->createFlowCodeDocument();
+ fcd->setPicType(microID);
+ created = fcd;
+ }
+
+ else if ( finalType == Document::dt_mechanics )
+ created = DocManager::self()->createMechanicsDocument();
+
+ else
+ {
+ // Presumably a text document
+ TextDocument * textDocument = DocManager::self()->createTextDocument();
+
+ if (textDocument)
+ textDocument->slotInitLanguage( (TextDocument::CodeType)codeType );
+
+ created = textDocument;
+ }
+
+ if ( created && addToProject )
+ created->setAddToProjectOnSave(true);
+}
+
+void KTechlab::slotFileOpen()
+{
+ // this slot is called whenever the File->Open menu is selected,
+ // the Open shortcut is pressed (usually CTRL+O) or the Open toolbar
+ // button is clicked
+
+ // standard filedialog
+ KURL::List urls = getFileURLs();
+ const KURL::List::iterator end = urls.end();
+ for ( KURL::List::iterator it = urls.begin(); it != end; ++ it)
+ load(*it);
+}
+
+void KTechlab::addRecentFile( const KURL &url )
+{
+ m_recentFiles->addURL( url );
+ emit recentFileAdded(url);
+}
+
+
+KURL::List KTechlab::getFileURLs()
+{
+ return KFileDialog::getOpenURLs(
+ QString::null,
+ "*|All Files\n"
+ "*.asm *.src *.inc|Assembly Code (*.asm, *.src, *.inc)\n"
+ "*.hex|Intel Hex (*.hex)\n"
+ "*.circuit|Circuit (*.circuit)\n"
+ "*.flowcode|FlowCode (*.flowcode)\n"
+ "*.basic *.microbe|Microbe (*.microbe, *.basic)\n"
+ "*.mechanics|Mechanics (*.mechanics)\n",
+ 0L,
+ i18n("Open Location") );
+}
+
+
+void KTechlab::slotDocModifiedChanged()
+{
+ //BEGIN Set tab icons
+ KIconLoader *loader = KGlobal::iconLoader();
+ const ViewContainerList::iterator vcEnd = m_viewContainerList.end();
+ for ( ViewContainerList::iterator it = m_viewContainerList.begin(); it != vcEnd; ++it )
+ {
+ ViewContainer * vc = *it;
+ if ( !vc || !vc->activeView() || !vc->activeView()->document() )
+ continue;
+
+ QString iconName;
+
+ if ( vc->activeView()->document()->isModified() )
+ iconName = "filesave";
+
+ else switch ( vc->activeView()->document()->type() )
+ {
+ case Document::dt_circuit:
+ iconName = "ktechlab_circuit";
+ break;
+
+ case Document::dt_flowcode:
+ iconName = "ktechlab_flowcode";
+ break;
+
+ case Document::dt_mechanics:
+ iconName = "ktechlab_mechanics";
+ break;
+
+ case Document::dt_text:
+ iconName = "txt";
+ break;
+
+ case Document::dt_pinMapEditor:
+ break;
+
+ case Document::dt_none:
+ iconName = "unknown";
+ break;
+ }
+
+ tabWidget()->setTabIconSet( vc, loader->loadIcon( iconName, KIcon::Small ) );
+ }
+ //END Set tab icons
+}
+
+
+void KTechlab::requestUpdateCaptions()
+{
+ m_pUpdateCaptionsTimer->start( 0, true );
+}
+
+
+void KTechlab::slotUpdateCaptions()
+{
+ //BEGIN Set KTechlab caption
+ Document *document = DocManager::self()->getFocusedDocument();
+ QString newCaption;
+ if ( document )
+ {
+ KURL url = document->url();
+ if ( url.isEmpty() )
+ newCaption = document->caption();
+ else
+ {
+ if ( url.isLocalFile() && url.ref().isNull() && url.query().isNull() )
+ newCaption = url.path();
+ else
+ newCaption = url.prettyURL();
+ }
+ }
+ else
+ newCaption = "";
+
+ if (newCaption != caption().remove(" - KTechlab"))
+ setCaption(newCaption);
+ //END Set KTechlab caption
+
+
+ //BEGIN Set tab captions
+ emit needUpdateCaptions();
+
+ if ( document && document->activeView() && document->activeView()->viewContainer() )
+ {
+ document->activeView()->viewContainer()->updateCaption();
+ }
+ //END Set tab captions
+}
+
+
+void KTechlab::slotDocUndoRedoChanged()
+{
+ Document *document = DocManager::self()->getFocusedDocument();
+ if (!document)
+ return;
+
+ action("edit_undo")->setEnabled( document->isUndoAvailable() );
+ action("edit_redo")->setEnabled( document->isRedoAvailable() );
+}
+
+void KTechlab::slotFileSave()
+{
+ Document *document = DocManager::self()->getFocusedDocument();
+ if (document)
+ document->fileSave();
+}
+
+void KTechlab::slotFileSaveAs()
+{
+ Document *document = DocManager::self()->getFocusedDocument();
+ if (document)
+ document->fileSaveAs();
+}
+
+void KTechlab::slotFilePrint()
+{
+ Document *document = DocManager::self()->getFocusedDocument();
+ if (document)
+ document->print();
+}
+
+
+bool KTechlab::queryClose()
+{
+ saveProperties( KGlobal::config() );
+
+ if ( DocManager::self()->closeAll() && ProjectManager::self()->slotCloseProject() )
+ {
+ ViewContainerList::iterator end = m_viewContainerList.end();
+ for ( ViewContainerList::iterator it = m_viewContainerList.begin(); it != end; ++it )
+ {
+ if ( *it )
+ (*it)->setKTechlabDeleted();
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+void KTechlab::slotFileQuit()
+{
+ // close the first window, the list makes the next one the first again.
+ // This ensures that queryClose() is called on each window to ask for closing
+ KMainWindow* w;
+ if(memberList)
+ {
+ for( w=memberList->first(); w!=0; w=memberList->next() )
+ {
+ // only close the window if the closeEvent is accepted. If the user presses Cancel on the saveModified() dialog,
+ // the window and the application stay open.
+ if( !w->close() ) break;
+ }
+ }
+
+ slotChangeStatusbar( i18n("Exiting...") );
+}
+
+void KTechlab::slotEditUndo()
+{
+ Document *document = DocManager::self()->getFocusedDocument();
+ if (document)
+ document->undo();
+}
+
+void KTechlab::slotEditRedo()
+{
+ Document *document = DocManager::self()->getFocusedDocument();
+ if (document)
+ document->redo();
+}
+
+void KTechlab::slotEditCut()
+{
+ Document *document = DocManager::self()->getFocusedDocument();
+ if (document)
+ document->cut();
+}
+
+void KTechlab::slotEditCopy()
+{
+ Document *document = DocManager::self()->getFocusedDocument();
+ if (document)
+ document->copy();
+}
+
+void KTechlab::slotEditPaste()
+{
+ Document *document = DocManager::self()->getFocusedDocument();
+ if (document)
+ document->paste();
+}
+
+void KTechlab::slotViewContainerClose()
+{
+ if (m_pFocusedContainer)
+ m_pFocusedContainer->closeViewContainer();
+}
+void KTechlab::slotViewClose()
+{
+ View *view = DocManager::self()->getFocusedView();
+ if (view)
+ view->closeView();
+}
+void KTechlab::slotViewSplitLeftRight()
+{
+ View *view = DocManager::self()->getFocusedView();
+ if (!view)
+ return;
+ ViewContainer *vc = view->viewContainer();
+ uint vaId = vc->createViewArea( view->viewAreaId(), ViewArea::Right );
+ view->document()->createView( vc, vaId );
+}
+void KTechlab::slotViewSplitTopBottom()
+{
+ View *view = DocManager::self()->getFocusedView();
+ if (!view)
+ return;
+ ViewContainer *vc = view->viewContainer();
+ uint vaId = vc->createViewArea( view->viewAreaId(), ViewArea::Bottom );
+ view->document()->createView( vc, vaId );
+}
+
+#include "ktechlab.moc"