You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ktechlab/src/viewcontainer.cpp

611 lines
13 KiB

/***************************************************************************
* Copyright (C) 2005 by David Saxton *
* david@bluehaze.org *
* *
* 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 <tdeconfig.h>
#include <kdebug.h>
#include <tdeglobalsettings.h>
#include <tdelocale.h>
#include <ktabwidget.h>
#include <tqobjectlist.h>
ViewContainer::ViewContainer( const TQString & caption, KTechlab * ktechlab, TQWidget * parent )
: TQWidget( ktechlab ? ktechlab->tabWidget() : parent )
{
b_deleted = false;
p_ktechlab = ktechlab;
if (ktechlab)
connect( ktechlab, TQT_SIGNAL(needUpdateCaptions()), this, TQT_SLOT(updateCaption()) );
TQHBoxLayout *layout = new TQHBoxLayout(this);
m_baseViewArea = new ViewArea( this, this, 0, "viewarea_0" );
connect( m_baseViewArea, TQT_SIGNAL(destroyed(TQObject* )), this, TQT_SLOT(baseViewAreaDestroyed(TQObject* )) );
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
TQObjectList *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_"+TQString::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( TQObject *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( TDEConfig *config )
{
if (!m_baseViewArea)
return;
config->writeEntry( "BaseViewArea", m_baseViewArea->id() );
m_baseViewArea->saveState(config);
}
void ViewContainer::restoreState( TDEConfig *config, const TQString &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()
{
TQString 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( TQWidget *parent, ViewContainer *viewContainer, int id, const char *name )
: TQSplitter( 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(TDEGlobalSettings::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_"+TQString::number(m_id)) );
p_viewArea2 = new ViewArea( this, p_viewContainer, id, (const char*)("viewarea_"+TQString::number(id)) );
connect( p_viewArea1, TQT_SIGNAL(destroyed(TQObject* )), this, TQT_SLOT(viewAreaDestroyed(TQObject* )) );
connect( p_viewArea2, TQT_SIGNAL(destroyed(TQObject* )), this, TQT_SLOT(viewAreaDestroyed(TQObject* )) );
p_view->reparent( p_viewArea1, TQPoint(), true );
p_viewArea1->setView(p_view);
p_view = 0l;
m_id = p_viewContainer->uniqueParentId();
TQValueList<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( TQObject *obj )
{
ViewArea *viewArea = static_cast<ViewArea*>(TQT_TQWIDGET(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, TQT_SIGNAL(destroyed()), this, TQT_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( TDEConfig *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" );
TQValueList<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( TDEConfig *config, int id, const TQString &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) ) )
{
TQString orientation = config->readEntry( orientationKey(m_id) );
setOrientation( (orientation == "LeftRight") ? Qt::Horizontal : Qt::Vertical );
}
config->setGroup(groupName);
if ( config->hasKey( containsKey(m_id) ) )
{
typedef TQValueList<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_"+TQString::number(viewArea1Id)) );
connect( p_viewArea1, TQT_SIGNAL(destroyed(TQObject* )), this, TQT_SLOT(viewAreaDestroyed(TQObject* )) );
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_"+TQString::number(viewArea2Id)) );
connect( p_viewArea2, TQT_SIGNAL(destroyed(TQObject* )), this, TQT_SLOT(viewAreaDestroyed(TQObject* )) );
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();
}
}
TQString ViewArea::fileKey( int id )
{
return TQString("ViewArea ") + TQString::number(id) + TQString(" file");
}
TQString ViewArea::containsKey( int id )
{
return TQString("ViewArea ") + TQString::number(id) + TQString(" contains");
}
TQString ViewArea::orientationKey( int id )
{
return TQString("ViewArea ") + TQString::number(id) + TQString(" orientation");
}
ViewContainerDrag::ViewContainerDrag( ViewContainer *viewContainer )
: TQStoredDrag( "dontcare", viewContainer)
{
p_viewContainer = viewContainer;
}
#include "viewcontainer.moc"