summaryrefslogtreecommitdiffstats
path: root/src/viewcontainer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/viewcontainer.cpp')
-rw-r--r--src/viewcontainer.cpp610
1 files changed, 610 insertions, 0 deletions
diff --git a/src/viewcontainer.cpp b/src/viewcontainer.cpp
new file mode 100644
index 0000000..4f145dd
--- /dev/null
+++ b/src/viewcontainer.cpp
@@ -0,0 +1,610 @@
+/***************************************************************************
+ * Copyright (C) 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 "docmanager.h"
+#include "document.h"
+#include "ktechlab.h"
+#include "view.h"
+#include "viewcontainer.h"
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include <ktabwidget.h>
+#include <qobjectlist.h>
+
+ViewContainer::ViewContainer( const QString & caption, KTechlab * ktechlab, QWidget * parent )
+ : QWidget( ktechlab ? ktechlab->tabWidget() : parent )
+{
+ b_deleted = false;
+ p_ktechlab = ktechlab;
+ if (ktechlab)
+ connect( ktechlab, SIGNAL(needUpdateCaptions()), this, SLOT(updateCaption()) );
+
+ QHBoxLayout *layout = new QHBoxLayout(this);
+ m_baseViewArea = new ViewArea( this, this, 0, "viewarea_0" );
+ connect( m_baseViewArea, SIGNAL(destroyed(QObject* )), this, SLOT(baseViewAreaDestroyed(QObject* )) );
+
+ layout->addWidget(m_baseViewArea);
+
+ m_activeViewArea = 0;
+ b_focused = false;
+
+ if (ktechlab)
+ ktechlab->tabWidget()->addTab( this, caption );
+
+ show();
+
+ if (ktechlab)
+ ktechlab->tabWidget()->setCurrentPage( ktechlab->tabWidget()->indexOf(this) );
+}
+
+
+ViewContainer::~ViewContainer()
+{
+ b_deleted = true;
+}
+
+
+void ViewContainer::setFocused()
+{
+ if (b_focused)
+ return;
+ b_focused = true;
+
+ View *view = activeView();
+ if (view)
+ view->setFocused();
+}
+
+
+void ViewContainer::setUnfocused()
+{
+ if (!b_focused)
+ return;
+ b_focused = false;
+
+ View *view = activeView();
+ if (view)
+ view->setUnfocused();
+}
+
+
+void ViewContainer::setActiveViewArea( uint id )
+{
+ if ( m_activeViewArea == int(id) )
+ return;
+
+ View *oldView = view(m_activeViewArea);
+ if (oldView)
+ oldView->setUnfocused();
+
+ m_activeViewArea = id;
+
+ ViewArea *va = viewArea(id);
+ if ( va && b_focused )
+ va->setFocus();
+
+ View *newView = view(id);
+ if ( newView && b_focused );
+ {
+ if (newView)
+ {
+ setCaption( newView->caption() );
+ newView->setFocused();
+ }
+ }
+}
+
+
+View *ViewContainer::view( uint id ) const
+{
+ ViewArea *va = viewArea(id);
+ if (!va)
+ return 0l;
+
+ // We do not want a recursive search as ViewAreas also hold other ViewAreas
+ QObjectList *l = va->queryList( "View", 0, false, false );
+ View *view = 0l;
+ if ( !l->isEmpty() )
+ view = dynamic_cast<View*>(l->first());
+ delete l;
+
+ return view;
+}
+
+
+ViewArea *ViewContainer::viewArea( uint id ) const
+{
+ if ( !m_viewAreaMap.contains(id) )
+ return 0l;
+
+ return m_viewAreaMap[id];
+}
+
+
+bool ViewContainer::closeViewContainer()
+{
+ bool didClose = true;
+ while ( didClose && !m_viewAreaMap.isEmpty() )
+ {
+ didClose = closeViewArea( m_viewAreaMap.begin().key() );
+ }
+
+ return m_viewAreaMap.isEmpty();
+}
+
+
+bool ViewContainer::closeViewArea( uint id )
+{
+ ViewArea *va = viewArea(id);
+ if ( !va )
+ return true;
+
+ bool doClose = false;
+ View *v = view(id);
+ if ( v && v->document() )
+ {
+ doClose = v->document()->numberOfViews() > 1;
+ if (!doClose)
+ doClose = v->document()->fileClose();
+ }
+ else
+ doClose = true;
+
+ if (!doClose)
+ return false;
+
+ m_viewAreaMap.remove(id);
+ va->deleteLater();
+
+ if ( m_activeViewArea == int(id) )
+ {
+ m_activeViewArea = -1;
+ findActiveViewArea();
+ }
+
+ return true;
+}
+
+
+int ViewContainer::createViewArea( int relativeViewArea, ViewArea::Position position )
+{
+ if ( relativeViewArea == -1 )
+ relativeViewArea = activeViewArea();
+
+ ViewArea *relative = viewArea(relativeViewArea);
+ if (!relative)
+ {
+ kdError() << k_funcinfo << "Could not find relative view area" << endl;
+ return -1;
+ }
+
+ uint id = uniqueNewId();
+// setActiveViewArea(id);
+
+ ViewArea *viewArea = relative->createViewArea( position, id );
+// ViewArea *viewArea = new ViewArea( m_splitter, id, (const char*)("viewarea_"+QString::number(id)) );
+ viewArea->show(); // remove?
+
+ return id;
+}
+
+
+void ViewContainer::setViewAreaId( ViewArea *viewArea, uint id )
+{
+ m_viewAreaMap[id] = viewArea;
+ m_usedIDs.append(id);
+}
+
+
+void ViewContainer::setViewAreaRemoved( uint id )
+{
+ if (b_deleted)
+ return;
+
+ ViewAreaMap::iterator it = m_viewAreaMap.find(id);
+ if ( it == m_viewAreaMap.end() )
+ return;
+
+ m_viewAreaMap.erase(it);
+
+ if ( m_activeViewArea == int(id) )
+ findActiveViewArea();
+}
+
+
+void ViewContainer::findActiveViewArea()
+{
+ if ( m_viewAreaMap.isEmpty() )
+ return;
+
+ setActiveViewArea( (--m_viewAreaMap.end()).key() );
+}
+
+
+void ViewContainer::baseViewAreaDestroyed( QObject *obj )
+{
+ if (!obj)
+ return;
+
+ if (!b_deleted)
+ {
+ b_deleted = true;
+ close();
+ deleteLater();
+ }
+}
+
+
+ViewContainer * ViewContainer::duplicateViewContainer()
+{
+ ViewContainer *viewContainer = new ViewContainer( caption(), p_ktechlab );
+ copyViewContainerIntoExisting(viewContainer);
+
+ p_ktechlab->addWindow(viewContainer);
+
+ return viewContainer;
+}
+
+
+void ViewContainer::copyViewContainerIntoExisting( ViewContainer *viewContainer )
+{
+ if (!viewContainer)
+ return;
+
+ const ViewAreaMap::iterator end = m_viewAreaMap.end();
+ for ( ViewAreaMap::iterator it = m_viewAreaMap.begin(); it != end; ++it )
+ {
+ View *oldView = view(it.key());
+ if (!oldView)
+ continue;
+
+ // See if there is an empty view container to be inserted into with id 0...
+ uint newId;
+ if ( viewContainer->view(0) )
+ newId = viewContainer->createViewArea( 0, ViewArea::Right );
+ else
+ newId = 0;
+
+ oldView->document()->createView( viewContainer, newId );
+ }
+}
+
+
+bool ViewContainer::canSaveUsefulStateInfo() const
+{
+ return m_baseViewArea && m_baseViewArea->canSaveUsefulStateInfo();
+}
+
+
+void ViewContainer::saveState( KConfig *config )
+{
+ if (!m_baseViewArea)
+ return;
+
+ config->writeEntry( "BaseViewArea", m_baseViewArea->id() );
+ m_baseViewArea->saveState(config);
+}
+
+
+void ViewContainer::restoreState( KConfig *config, const QString &groupName )
+{
+ config->setGroup(groupName);
+ int baseAreaId = config->readNumEntry("BaseViewArea");
+ m_baseViewArea->restoreState( config, baseAreaId, groupName );
+}
+
+
+int ViewContainer::uniqueParentId()
+{
+ int lowest = -1;
+ const IntList::iterator end = m_usedIDs.end();
+ for ( IntList::iterator it = m_usedIDs.begin(); it != end; ++it )
+ {
+ if ( *it < lowest )
+ lowest = *it;
+ }
+ int newId = lowest-1;
+ m_usedIDs.append(newId);
+ return newId;
+}
+
+
+int ViewContainer::uniqueNewId()
+{
+ int highest = 0;
+ const IntList::iterator end = m_usedIDs.end();
+ for ( IntList::iterator it = m_usedIDs.begin(); it != end; ++it )
+ {
+ if ( *it > highest )
+ highest = *it;
+ }
+ int newId = highest+1;
+ m_usedIDs.append(newId);
+ return newId;
+}
+
+
+void ViewContainer::setIdUsed( int id )
+{
+ m_usedIDs.append(id);
+}
+
+
+void ViewContainer::updateCaption()
+{
+ QString caption;
+
+ if ( !activeView() || !activeView()->document() )
+ caption = i18n("(empty)");
+
+ else
+ {
+ Document * doc = activeView()->document();
+ caption = doc->url().isEmpty() ? doc->caption() : doc->url().fileName();
+ if ( viewCount() > 1 )
+ caption += " ...";
+ }
+
+ setCaption(caption);
+ p_ktechlab->tabWidget()->setTabLabel( this, caption );
+}
+
+
+void ViewContainer::setKTechlabDeleted()
+{
+ p_ktechlab = 0l;
+ ViewAreaMap::iterator end = m_viewAreaMap.end();
+ for ( ViewAreaMap::iterator it = m_viewAreaMap.begin(); it != end; ++it )
+ {
+ if ( *it )
+ (*it)->setKTechlabDeleted();
+ }
+}
+
+
+
+
+
+ViewArea::ViewArea( QWidget *parent, ViewContainer *viewContainer, int id, const char *name )
+ : QSplitter( parent, name )
+{
+ p_viewContainer = viewContainer;
+ m_id = id;
+ p_view = 0l;
+ p_viewArea1 = 0l;
+ p_viewArea2 = 0l;
+ if (id >= 0)
+ p_viewContainer->setViewAreaId( this, uint(id) );
+ p_viewContainer->setIdUsed(id);
+ setOpaqueResize(KGlobalSettings::opaqueResize());
+}
+
+
+ViewArea::~ViewArea()
+{
+ if ( m_id >= 0 )
+ p_viewContainer->setViewAreaRemoved( uint(m_id) );
+}
+
+
+ViewArea *ViewArea::createViewArea( Position position, uint id )
+{
+ if (p_viewArea1 || p_viewArea2)
+ {
+ kdError() << k_funcinfo << "Attempting to create ViewArea when already containing ViewAreas!" << endl;
+ return 0l;
+ }
+ if (!p_view)
+ {
+ kdError() << k_funcinfo << "We don't have a view yet, so creating a new ViewArea is redundant" << endl;
+ return 0l;
+ }
+
+ setOrientation( ( position == Right ) ? Qt::Horizontal : Qt::Vertical );
+
+ p_viewArea1 = new ViewArea( this, p_viewContainer, m_id, (const char*)("viewarea_"+QString::number(m_id)) );
+ p_viewArea2 = new ViewArea( this, p_viewContainer, id, (const char*)("viewarea_"+QString::number(id)) );
+
+ connect( p_viewArea1, SIGNAL(destroyed(QObject* )), this, SLOT(viewAreaDestroyed(QObject* )) );
+ connect( p_viewArea2, SIGNAL(destroyed(QObject* )), this, SLOT(viewAreaDestroyed(QObject* )) );
+
+ p_view->reparent( p_viewArea1, QPoint(), true );
+ p_viewArea1->setView(p_view);
+ p_view = 0l;
+ m_id = p_viewContainer->uniqueParentId();
+
+ QValueList<int> splitPos;
+ int pos = ((orientation() == Qt::Horizontal) ? width()/2 : height()/2);
+ splitPos << pos << pos;
+ setSizes(splitPos);
+
+ p_viewArea1->show();
+ p_viewArea2->show();
+ return p_viewArea2;
+}
+
+
+void ViewArea::viewAreaDestroyed( QObject *obj )
+{
+ ViewArea *viewArea = static_cast<ViewArea*>(obj);
+
+ if ( viewArea == p_viewArea1 )
+ p_viewArea1 = 0l;
+
+ if ( viewArea == p_viewArea2 )
+ p_viewArea2 = 0l;
+
+ if ( !p_viewArea1 && !p_viewArea2 )
+ deleteLater();
+}
+
+
+void ViewArea::setView( View *view )
+{
+ if (!view)
+ return;
+ if (p_view)
+ {
+ kdError() << k_funcinfo << "Attempting to set already contained view!" << endl;
+ return;
+ }
+ p_view = view;
+ connect( view, SIGNAL(destroyed()), this, SLOT(viewDestroyed()) );
+}
+
+
+void ViewArea::viewDestroyed()
+{
+ if ( !p_view && !p_viewArea1 && !p_viewArea2 )
+ deleteLater();
+}
+
+
+void ViewArea::setKTechlabDeleted()
+{
+ if ( p_view )
+ p_view->setKTechlabDeleted();
+}
+
+
+bool ViewArea::canSaveUsefulStateInfo() const
+{
+ if ( p_viewArea1 && p_viewArea1->canSaveUsefulStateInfo() )
+ return true;
+
+ if ( p_viewArea2 && p_viewArea2->canSaveUsefulStateInfo() )
+ return true;
+
+ if ( p_view && p_view->document() && !p_view->document()->url().isEmpty() )
+ return true;
+
+ return false;
+}
+
+
+void ViewArea::saveState( KConfig *config )
+{
+ bool va1Ok = p_viewArea1 && p_viewArea1->canSaveUsefulStateInfo();
+ bool va2Ok = p_viewArea2 && p_viewArea2->canSaveUsefulStateInfo();
+
+ if ( va1Ok || va2Ok )
+ {
+ config->writeEntry( orientationKey(m_id), (orientation() == Qt::Horizontal) ? "LeftRight" : "TopBottom" );
+
+ QValueList<int> contains;
+ if (va1Ok)
+ contains << p_viewArea1->id();
+ if (va2Ok)
+ contains << p_viewArea2->id();
+
+ config->writeEntry( containsKey(m_id), contains );
+ if (va1Ok)
+ p_viewArea1->saveState(config);
+ if (va2Ok)
+ p_viewArea2->saveState(config);
+ }
+ else if ( p_view && !p_view->document()->url().isEmpty() )
+ {
+ config->writePathEntry( fileKey(m_id), p_view->document()->url().prettyURL() );
+ }
+}
+
+
+void ViewArea::restoreState( KConfig *config, int id, const QString &groupName )
+{
+ if (!config)
+ return;
+
+ if ( id != m_id )
+ {
+ if ( m_id >= 0 )
+ p_viewContainer->setViewAreaRemoved( uint(m_id) );
+
+ m_id = id;
+
+ if ( m_id >= 0 )
+ p_viewContainer->setViewAreaId( this, uint(m_id) );
+
+ p_viewContainer->setIdUsed(id);
+ }
+
+ config->setGroup(groupName);
+ if ( config->hasKey( orientationKey(id) ) )
+ {
+ QString orientation = config->readEntry( orientationKey(m_id) );
+ setOrientation( (orientation == "LeftRight") ? Qt::Horizontal : Qt::Vertical );
+ }
+
+ config->setGroup(groupName);
+ if ( config->hasKey( containsKey(m_id) ) )
+ {
+ typedef QValueList<int> IntList;
+ IntList contains = config->readIntListEntry( containsKey(m_id) );
+
+ if ( contains.isEmpty() || contains.size() > 2 )
+ kdError() << k_funcinfo << "Contained list has wrong size of " << contains.size() << endl;
+
+ else
+ {
+ if ( contains.size() >= 1 )
+ {
+ int viewArea1Id = contains[0];
+ p_viewArea1 = new ViewArea( this, p_viewContainer, viewArea1Id, (const char*)("viewarea_"+QString::number(viewArea1Id)) );
+ connect( p_viewArea1, SIGNAL(destroyed(QObject* )), this, SLOT(viewAreaDestroyed(QObject* )) );
+ p_viewArea1->restoreState( config, viewArea1Id, groupName );
+ p_viewArea1->show();
+ }
+
+ if ( contains.size() >= 2 )
+ {
+ int viewArea2Id = contains[1];
+ p_viewArea2 = new ViewArea( this, p_viewContainer, viewArea2Id, (const char*)("viewarea_"+QString::number(viewArea2Id)) );
+ connect( p_viewArea2, SIGNAL(destroyed(QObject* )), this, SLOT(viewAreaDestroyed(QObject* )) );
+ p_viewArea2->restoreState( config, viewArea2Id, groupName );
+ p_viewArea2->show();
+ }
+ }
+ }
+
+ config->setGroup(groupName);
+ if ( config->hasKey( fileKey(m_id) ) )
+ {
+ bool openedOk = DocManager::self()->openURL( config->readPathEntry( fileKey(m_id) ), this );
+ if (!openedOk)
+ deleteLater();
+ }
+}
+
+QString ViewArea::fileKey( int id )
+{
+ return QString("ViewArea ") + QString::number(id) + QString(" file");
+}
+QString ViewArea::containsKey( int id )
+{
+ return QString("ViewArea ") + QString::number(id) + QString(" contains");
+}
+QString ViewArea::orientationKey( int id )
+{
+ return QString("ViewArea ") + QString::number(id) + QString(" orientation");
+}
+
+
+
+
+ViewContainerDrag::ViewContainerDrag( ViewContainer *viewContainer )
+ : QStoredDrag( "dontcare", viewContainer)
+{
+ p_viewContainer = viewContainer;
+}
+
+#include "viewcontainer.moc"