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.
koffice/kivio/kiviopart/kivio_page.cpp

1680 lines
39 KiB

/*
* Kivio - Visual Modelling and Flowcharting
* Copyright (C) 2000-2001 theKompany.com & Dave Marotti
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <tqpainter.h>
#include <tqdrawutil.h>
#include <tqkeycode.h>
#include <tqregexp.h>
#include <tqpoint.h>
#include <tqcursor.h>
#include <tqptrstack.h>
#include <tqbuffer.h>
#include <tqmessagebox.h>
#include <tqclipboard.h>
#include <tqpicture.h>
#include <tqdom.h>
#include <tqtextstream.h>
#include <tqdragobject.h>
#include <tqmime.h>
#include <tqsortedlist.h>
#include <tqvaluelist.h>
#include <kdebug.h>
#include <klocale.h>
#include <kglobal.h>
#include <kmessagebox.h>
#include <KoUnit.h>
#include <KoPoint.h>
#include <KoRect.h>
#include <KoZoomHandler.h>
#include <kapplication.h>
#include <KoXmlWriter.h>
#include <KoXmlNS.h>
#include <KoDom.h>
#include <KoStore.h>
#include <KoOasisStyles.h>
#include <KoGenStyles.h>
#include "kivio_page.h"
#include "kivio_map.h"
#include "kivio_doc.h"
#include "kivio_canvas.h"
#include "kivio_view.h"
#include "kivio_config.h"
#include "kivio_common.h"
#include "kivio_connector_point.h"
#include "kivio_group_stencil.h"
#include "kivio_intra_stencil_data.h"
#include "kivio_layer.h"
#include "kivio_painter.h"
#include "kivio_stencil.h"
#include "kivio_1d_stencil.h"
#include "KIvioPageIface.h"
#include "kivio_command.h"
#include "kivioglobal.h"
#include "kiviodragobject.h"
#include <fixx11h.h> // for None
int KivioPage::s_id = 0L;
TQIntDict<KivioPage>* KivioPage::s_mapPages;
KivioPage::KivioPage( KivioMap *_map, const TQString &pageName, const char *_name )
: TQObject( _map, _name ),
m_pCurLayer(NULL)
{
if ( s_mapPages == 0L )
s_mapPages = new TQIntDict<KivioPage>;
m_id = s_id++;
s_mapPages->insert( m_id, this );
m_dcop = 0;
m_pMap = _map;
m_pDoc = _map->doc();
// Make sure the layers auto-delete themselves
m_pCurLayer = new KivioLayer(this);
m_pCurLayer->setName(i18n("Layer 1"));
m_lstLayers.append( m_pCurLayer );
m_lstLayers.setAutoDelete(true);
m_lstSelection.setAutoDelete(false);
m_strName = pageName;
setHidden(false);
// Get a unique name so that we can offer scripting
if ( !_name ) {
TQCString s;
s.sprintf("Page%i", s_id );
setName( s.data() );
}
m_pPageLayout = Kivio::Config::defaultPageLayout();
}
DCOPObject* KivioPage::dcopObject()
{
if ( !m_dcop )
m_dcop = new KIvioPageIface( this );
return m_dcop;
}
KivioPage::~KivioPage()
{
kdDebug(43000)<<" KivioPage::~KivioPage()************ :"<<this<<endl;
s_mapPages->remove(m_id);
delete m_dcop;
}
KivioPage* KivioPage::find( int _id )
{
if ( !s_mapPages )
return 0L;
return (*s_mapPages)[ _id ];
}
void KivioPage::print( TQPainter &/*painter*/, KPrinter */*_printer*/ )
{
}
void KivioPage::printPage( TQPainter &/*_painter*/, const TQRect& /*page_range*/, const TQRect& /*view*/ )
{
}
TQDomElement KivioPage::save( TQDomDocument& doc )
{
// Write the name and 'hide' flag first as attributes
TQDomElement page = doc.createElement( "KivioPage" );
page.setAttribute( "name", m_strName );
page.setAttribute( "hide", (int)m_bPageHide );
// Create a child element for the page layout
TQDomElement layoutE = saveLayout( doc );
page.appendChild( layoutE );
// Save guides
TQDomElement guidesElement = doc.createElement("GuidesLayout");
page.appendChild(guidesElement);
saveGuideLines(guidesElement);
// Iterate through all layers saving them as child elements
KivioLayer *pLayer = m_lstLayers.first();
while( pLayer )
{
TQDomElement layerE = pLayer->saveXML(doc);
if( layerE.isNull() )
{
kdDebug(43000) << "KivioPage::save() - Oh shit. KivioLayer::saveXML() returned a bad element!" << endl;
}
else
{
page.appendChild( layerE );
}
pLayer = m_lstLayers.next();
}
return page;
}
void KivioPage::saveOasis(KoStore* /*store*/, KoXmlWriter* docWriter, KoGenStyles* styles)
{
docWriter->startElement("draw:page");
docWriter->addAttribute("draw:name", m_strName);
if(m_pPageLayout == Kivio::Config::defaultPageLayout()) {
docWriter->addAttribute("draw:master-page-name", "Standard");
} else {
KoGenStyle pageLayout = m_pPageLayout.saveOasis();
TQString layoutName = styles->lookup(pageLayout, "PL");
KoGenStyle masterPage(KoGenStyle::STYLE_MASTER);
masterPage.addAttribute("style:page-layout-name", layoutName);
TQString masterName = styles->lookup(masterPage, "MP");
docWriter->addAttribute("draw:master-page-name", masterName);
}
// TODO OASIS: Save guidelines!
TQBuffer layerBuffer;
layerBuffer.open(IO_WriteOnly);
KoXmlWriter layerWriter(TQT_TQIODEVICE(&layerBuffer));
layerWriter.startElement("draw:layer-set");
// Iterate through all layers
KivioLayer* layer = m_lstLayers.first();
while(layer) {
layer->saveOasis(&layerWriter);
layer = m_lstLayers.next();
}
layerWriter.endElement(); // draw:layer-set
TQString layerSet = TQString::fromUtf8(layerBuffer.buffer(), layerBuffer.buffer().size());
KoGenStyle pageStyle(Kivio::STYLE_PAGE, "drawing-page");
pageStyle.addChildElement("draw:layer-set", layerSet);
TQString styleName = styles->lookup(pageStyle, "PS");
docWriter->addAttribute("draw:style-name", styleName);
docWriter->endElement(); // draw:page
}
TQDomElement KivioPage::saveLayout( TQDomDocument &doc )
{
TQDomElement e = doc.createElement("PageLayout");
Kivio::savePageLayout(e, m_pPageLayout);
return e;
}
bool KivioPage::loadLayout( const TQDomElement &e )
{
m_pPageLayout = Kivio::loadPageLayout(e);
return true;
}
bool KivioPage::isLoading()
{
return m_pDoc->isLoading();
}
bool KivioPage::loadXML( const TQDomElement& pageE )
{
m_strName = pageE.attribute("name");
if (m_strName.isEmpty())
return false;
m_bPageHide = (int)pageE.attribute("hide").toInt();
// Clear the layer list
KivioLayer *pLayer;
m_lstLayers.clear();
TQDomNode node = pageE.firstChild();
while( !node.isNull() )
{
if( node.nodeName() == "KivioLayer" )
{
pLayer = new KivioLayer(this);
if( pLayer->loadXML( node.toElement() )==false )
{
delete pLayer;
pLayer = NULL;
}
else
{
m_lstLayers.append( pLayer );
pLayer = NULL;
}
}
else if( node.nodeName() == "PageLayout" )
{
loadLayout( node.toElement() );
}
else if ( node.nodeName() == "GuidesLayout" ) {
loadGuideLines(node.toElement());
}
else
{
kdDebug(43000) << "KivioLayer::loadXML() - unknown node found, " << node.nodeName() << endl;
}
node = node.nextSibling();
}
m_pCurLayer = m_lstLayers.first();
if( !m_pCurLayer )
{
kdDebug(43000) << "KivioLayer::loadXML() - No layers loaded!! BIGGGGG PROBLEMS!" << endl;
}
// Now that we are done loading, fix all the connections
KivioLayer *pLayerBak;
pLayer = m_lstLayers.first();
while( pLayer )
{
pLayerBak = pLayer;
kdDebug(43000) << "KivioLayer::loadXML() - loading layer connections" << endl;
pLayer->searchForConnections(this);
m_lstLayers.find( pLayerBak );
pLayer = m_lstLayers.next();
}
return true;
}
bool KivioPage::loadOasis(const TQDomElement& page, KoOasisStyles& oasisStyles)
{
m_strName = page.attributeNS( KoXmlNS::draw, "name", TQString());
TQDomElement* masterPage = oasisStyles.masterPages()[page.attributeNS( KoXmlNS::draw, "master-page-name", TQString())];
if(!masterPage) {
kdDebug(430000) << "Couldn't find the master page! " << page.attributeNS( KoXmlNS::draw, "master-page-name", TQString()) << endl;
return false;
}
const TQDomElement *pageLayout = oasisStyles.findStyle(masterPage->attributeNS( KoXmlNS::style, "page-layout-name", TQString() ) );
if(!pageLayout) {
kdDebug(430000) << "Couldn't find the pagelayout!" << endl;
return false;
}
m_pPageLayout.loadOasis(*pageLayout);
if(m_pPageLayout.ptWidth <= 1e-13 || m_pPageLayout.ptHeight <= 1e-13) {
kdDebug(430000) << "Non valid pagelayout!" << endl;
return false;
}
const TQDomElement* style = oasisStyles.findStyle(page.attributeNS( KoXmlNS::draw, "style-name", TQString()) ); // Find the page style
if(!style) {
return false;
}
TQDomNode styleNode = KoDom::namedItemNS( *style, KoXmlNS::style, "properties");
styleNode = KoDom::namedItemNS( styleNode, KoXmlNS::draw, "layer-set");
TQDomNode currentNode = styleNode.firstChild();
// Load the layers
while(!currentNode.isNull()) {
if(currentNode.nodeName() == "draw:layer") {
KivioLayer* layer = new KivioLayer(this);
layer->loadOasis(currentNode.toElement());
m_lstLayers.append(layer);
}
currentNode = currentNode.nextSibling();
}
return true;
}
void KivioPage::update()
{
}
KivioPage* KivioPage::findPage( const TQString& name )
{
if (!m_pMap)
return 0L;
return m_pMap->findPage(name);
}
bool KivioPage::setPageName( const TQString& name, bool init )
{
if ( map()->findPage( name ) )
return false;
if ( m_strName == name )
return true;
TQString old_name = m_strName;
m_strName = name;
if (init)
return true;
emit m_pDoc->sig_pageNameChanged(this, old_name);
return true;
}
/**
* Paints the page.
*
* An important note is that layers are drawn first to last. So the last layer is the
* most visible.
*/
void KivioPage::paintContent( KivioPainter& painter, const TQRect& rect, bool transparent,
TQPoint p0, KoZoomHandler* zoom, bool drawConnectorTargets, bool drawSelection )
{
KivioLayer *pLayer = m_lstLayers.first();
while( pLayer )
{
if( pLayer->visible() )
{
pLayer->paintContent( painter, rect, transparent, p0, zoom );
}
pLayer = m_lstLayers.next();
}
// Now the second iteration - connection targets
// Only draw targets if the zoom is higher than a certain value
if(zoom->zoom() >= 50) {
if(drawConnectorTargets) {
m_pCurLayer->paintConnectorTargets( painter, rect, transparent, p0, zoom );
pLayer = m_lstLayers.first();
while(pLayer) {
if(pLayer->connectable() && (pLayer != m_pCurLayer)) {
pLayer->paintConnectorTargets( painter, rect, transparent, p0, zoom );
}
pLayer = m_lstLayers.next();
}
}
}
// Now the third iteration - selection handles
if(drawSelection) {
m_pCurLayer->paintSelectionHandles( painter, rect, transparent, p0, zoom );
}
}
void KivioPage::printContent( KivioPainter& painter, int xdpi, int ydpi )
{
if(!xdpi) {
xdpi = KoGlobal::dpiX();
}
if(!ydpi) {
ydpi = KoGlobal::dpiY();
}
KivioLayer *pLayer = m_lstLayers.first();
while( pLayer )
{
if( pLayer->visible() )
{
pLayer->printContent( painter, xdpi, ydpi );
}
pLayer = m_lstLayers.next();
}
}
void KivioPage::printContent(KivioPainter& painter, KoZoomHandler* zoomHandler)
{
KivioLayer *pLayer = m_lstLayers.first();
while( pLayer )
{
if(pLayer->visible())
{
pLayer->printContent(painter, zoomHandler);
}
pLayer = m_lstLayers.next();
}
}
void KivioPage::printSelected( KivioPainter& painter, int xdpi, int ydpi )
{
if(!xdpi) {
xdpi = KoGlobal::dpiX();
}
if(!ydpi) {
ydpi = KoGlobal::dpiY();
}
KivioStencil *pStencil;
KivioIntraStencilData data;
KoZoomHandler zoomHandler;
zoomHandler.setZoomAndResolution(100, xdpi, ydpi);
data.painter = &painter;
data.zoomHandler = &zoomHandler;
data.printing = true;
KivioLayer *pLayer = m_lstLayers.first();
while( pLayer )
{
if( pLayer->visible()==true )
{
pStencil = pLayer->firstStencil();
while( pStencil )
{
if(pStencil->isSelected())
{
pStencil->paint(&data);
}
pStencil = pLayer->nextStencil();
}
}
pLayer = m_lstLayers.next();
}
}
bool KivioPage::addStencil( KivioStencil *pStencil )
{
if(!pStencil) {
kdDebug(43000) << "KivioPage::addStencil() - Null stencil passed" << endl;
return false;
}
if(!m_pCurLayer) {
kdDebug(43000) << "KivioPage::addStencil() - NULL current layer" << endl;
return false;
}
KivioAddStencilCommand *cmd = new KivioAddStencilCommand(i18n("Add Stencil"), this, m_pCurLayer, pStencil );
m_pDoc->addCommand(cmd);
return m_pCurLayer->addStencil( pStencil );
}
void KivioPage::selectStencils( double x, double y, double w, double h )
{
// Iterate through all stencils of this layer
KivioStencil *pStencil = m_pCurLayer->stencilList()->first();
while(pStencil) {
// Is it in the rectangle?
if(pStencil->isInRect(KoRect(x, y, w, h))) {
selectStencil( pStencil );
}
pStencil = m_pCurLayer->stencilList()->next();
}
m_pDoc->slotSelectionChanged();
}
void KivioPage::selectStencil( KivioStencil *pStencil )
{
if(!pStencil) {
kdDebug(43000) << "KivioPage::selectStencil - AHHHH! NULL STENCIL!" << endl;
return;
}
// Don't allow reselection
if(m_lstSelection.findRef(pStencil) != -1) {
return;
}
kdDebug(43000) <<"KivioPage::selectStencil - Selecting stencil" << endl;
pStencil->select();
m_lstSelection.append(pStencil);
m_pDoc->slotSelectionChanged();
}
bool KivioPage::unselectStencil( KivioStencil *pStencil )
{
pStencil->unselect();
m_pDoc->slotSelectionChanged();
return m_lstSelection.removeRef( pStencil );
}
void KivioPage::selectAllStencils()
{
unselectAllStencils();
KivioStencil* pStencil = m_pCurLayer->stencilList()->first();
while(pStencil) {
pStencil->select();
m_lstSelection.append(pStencil);
pStencil = m_pCurLayer->stencilList()->next();
}
/*
* The following code is commented out because selections must
* remain in the current layer.
*/
/*
KivioLayer* pLayer = m_lstLayers.first();
while( pLayer )
{
if( pLayer->visible() )
{
pStencil = pLayer->stencilList()->first();
while( pStencil )
{
pStencil->select();
m_lstSelection.append(pStencil);
pStencil = pLayer->stencilList()->next();
}
}
pLayer = m_lstLayers.next();
}
*/
m_pDoc->slotSelectionChanged();
}
void KivioPage::unselectAllStencils()
{
KivioStencil* pStencil = m_lstSelection.first();
while(pStencil)
{
pStencil->unselect();
pStencil = m_lstSelection.next();
}
m_lstSelection.clear();
m_pDoc->slotSelectionChanged();
}
bool KivioPage::isStencilSelected(KivioStencil *pStencil)
{
return m_lstSelection.findRef( pStencil ) == -1;
}
/**
* Looks for stencils at a given point in the canvas
*
* @param pPoint The point to search with
*
* This will iterate through all visible layers and check
* for stencils. The first one it finds will be returned.
* If none are found, it will return NULL.
*/
KivioStencil *KivioPage::checkForStencil( KoPoint *pPoint, int *collisionType, double threshold, bool selectedOnly )
{
KivioStencil *pStencil;
int colType;
/*
* This code is commented out because selecting a stencil should only take place
* on the current layer. The following code searches all layers.
*/
// Start with the last layer since it is the top
/*
KivioLayer* pLayer = m_lstLayers.last();
while( pLayer )
{
pStencil = pLayer->checkForStencil( pPoint, &colType );
if( pStencil )
{
*collisionType = colType;
return pStencil;
}
pLayer = m_lstLayers.prev();
}
*/
pStencil = m_pCurLayer->checkForStencil( pPoint, &colType, threshold, selectedOnly );
if( pStencil )
{
*collisionType = colType;
return pStencil;
}
*collisionType = kctNone;
return NULL;
}
void KivioPage::deleteSelectedStencils()
{
// Make sure none of them have deletion protection
KivioStencil* pStencil = m_lstSelection.first();
while(pStencil) {
if(pStencil->protection()->at(kpDeletion)) {
KMessageBox::information(NULL, i18n("One of the selected stencils has protection from deletion and cannot be deleted."),
i18n("Protection From Deletion") );
return;
}
pStencil = m_lstSelection.next();
}
// Iterate through all items in the selection list
m_lstSelection.first();
pStencil = m_lstSelection.take();
KMacroCommand *macro = new KMacroCommand( i18n("Remove Stencil"));
bool createMacro = false;
while(pStencil) {
KivioRemoveStencilCommand *cmd =new KivioRemoveStencilCommand(i18n("Remove Stencil"), this, m_pCurLayer , pStencil );
createMacro = true;
macro->addCommand(cmd);
if(pStencil->type() == kstConnector) {
static_cast<Kivio1DStencil*>(pStencil)->disconnectFromTargets();
}
pStencil = m_lstSelection.take();
}
if (createMacro) {
macro->execute();
m_pDoc->addCommand( macro );
} else {
delete macro;
}
}
void KivioPage::groupSelectedStencils()
{
// Can't group 0 or 1 stencils
if(!m_pCurLayer || (m_lstSelection.count() <= 1)) {
return;
}
KivioGroupStencil* pGroup = new KivioGroupStencil();
// Iterate through all items in the selection list, taking them from the layer, then adding
// them to the group
KivioStencil* pStencil = m_pCurLayer->firstStencil();
KivioStencil* pTake = 0;
while(pStencil) {
if(pStencil->isSelected()) {
// Take the stencil out of it's layer
pTake = m_pCurLayer->takeStencil(pStencil);
if(!pTake) {
kdDebug(43000) << "KivioPage::groupSelectedStencil() - Failed to take() one of the selected stencils. CRAP!" << endl;
} else {
// Add it to the group
pGroup->addToGroup(pTake);
pStencil = m_pCurLayer->currentStencil();
}
} else {
pStencil = m_pCurLayer->nextStencil();
}
}
// Unselect the old ones
unselectAllStencils();
// Add the group as the selected stencil
m_pCurLayer->addStencil(pGroup);
selectStencil(pGroup);
KivioGroupCommand* cmd = new KivioGroupCommand(i18n("Group Selection"), this, m_pCurLayer, pGroup);
doc()->addCommand(cmd);
}
void KivioPage::ungroupSelectedStencils()
{
KivioStencil *pSelStencil, *pStencil;
TQPtrList<KivioStencil> *pList;
TQPtrList<KivioStencil> *pSelectThese = new TQPtrList<KivioStencil>;
KMacroCommand* macro = new KMacroCommand(i18n("Ungroup"));
bool ungrouped = false;
pSelectThese->setAutoDelete(false);
// Iterate through all selected stencils
pSelStencil = m_lstSelection.first();
while( pSelStencil )
{
// If there is a list, it is a group stencil
pList = pSelStencil->groupList();
if(pList)
{
pList->first();
pStencil = pList->first();
while( pStencil )
{
m_pCurLayer->addStencil( pStencil );
pSelectThese->append( pStencil );
pStencil = pList->next();
}
// Remove the current stencil from the selection list(the group we just disassembled)
m_lstSelection.take();
// Remove it permanently from the layer
if(!m_pCurLayer->takeStencil(pSelStencil))
{
kdDebug(43000) << "KivioPage::ungroupSelectedStencil() - Failed to locate the group shell for deletion"
<< endl;
}
KivioUnGroupCommand* cmd = new KivioUnGroupCommand(i18n("Ungroup"), this, m_pCurLayer,
static_cast<KivioGroupStencil*>(pSelStencil));
macro->addCommand(cmd);
ungrouped = true;
}
pSelStencil = m_lstSelection.next();
}
// Now iterate through the selectThese list and select
// those stencils
pStencil = pSelectThese->first();
while( pStencil )
{
selectStencil( pStencil );
if(pStencil->type() == kstConnector) {
pStencil->searchForConnections(this, 4.0);
}
pStencil = pSelectThese->next();
}
delete pSelectThese;
if(ungrouped) {
doc()->addCommand(macro);
} else {
delete macro;
}
}
void KivioPage::bringToFront()
{
KivioStencil *pStencil, *pMove;
KivioLayer *pLayer;
TQPtrList <KivioStencil> newList;
pLayer = m_pCurLayer;
newList.setAutoDelete(false);
/*
* We iterate through all stencils since order must be maintained
* amongst the selection during the move.
*/
pStencil = pLayer->firstStencil();
while( pStencil )
{
if( isStencilSelected( pStencil )==true )
{
pMove = pLayer->takeStencil();
if( pMove )
{
newList.append(pMove);
pStencil = pLayer->currentStencil();
}
else // In the case of error, the outside else won't execute
{
pStencil = pLayer->nextStencil();
}
}
else
{
pStencil = pLayer->nextStencil();
}
}
// push them back in, in reverse order
pStencil = newList.last();
while( pStencil )
{
pLayer->stencilList()->insert(0, pStencil);
pStencil = newList.prev();
}
}
void KivioPage::sendToBack()
{
KivioStencil *pStencil, *pMove;
KivioLayer *pLayer;
TQPtrList <KivioStencil> newList;
pLayer = m_pCurLayer;
newList.setAutoDelete(false);
/*
* We iterate through all stencils since order must be maintained
* amongst the selection during the move.
*/
pStencil = pLayer->firstStencil();
while( pStencil )
{
if( isStencilSelected( pStencil )==true )
{
pMove = pLayer->takeStencil();
if( pMove )
{
newList.append(pMove);
pStencil = pLayer->currentStencil();
}
else // In the case of error, the outside else won't execute
{
pStencil = pLayer->nextStencil();
}
}
else
{
pStencil = pLayer->nextStencil();
}
}
// push them back in, in reverse order
pStencil = newList.first();
while( pStencil )
{
pLayer->stencilList()->append(pStencil);
pStencil = newList.next();
}
}
void KivioPage::copy()
{
if(m_lstSelection.count() <= 0) {
return;
}
// push to clipbaord
KivioDragObject* kdo = new KivioDragObject();
kdo->setStencilList(m_lstSelection);
kdo->setStencilRect(getRectForAllSelectedStencils());
TQApplication::clipboard()->setData(kdo, TQClipboard::Clipboard);
}
void KivioPage::cut()
{
KivioStencil *pStencil;
KivioLayer *pLayer;
bool safe=true;
if( m_lstSelection.count() <= 0 )
return;
pLayer = m_pCurLayer;
// Make sure none of them are protected from deletion
pStencil = pLayer->firstStencil();
while( pStencil )
{
if( isStencilSelected( pStencil )==true )
{
if( pStencil->protection()->at(kpDeletion)==true )
{
safe=false;
}
}
pStencil = pLayer->nextStencil();
}
if( safe==false )
{
KMessageBox::information(NULL, i18n("One of the stencils has protection from deletion. You cannot cut or delete this stencil."), i18n("Protection From Delete") );
return;
}
copy();
deleteSelectedStencils();
}
void KivioPage::paste(KivioView* view)
{
TQPtrList<KivioStencil> list;
list.setAutoDelete(false);
KivioDragObject kdo;
if(kdo.decode(TQApplication::clipboard()->data(TQClipboard::Clipboard), list, this)) {
unselectAllStencils();
KivioStencil* stencil = list.first();
while(stencil) {
addStencil(stencil);
selectStencil(stencil);
stencil = list.next();
}
view->canvasWidget()->startPasteMoving();
}
}
int KivioPage::generateStencilIds(int next)
{
KivioLayer *pLayer;
pLayer = m_lstLayers.first();
while( pLayer )
{
next = pLayer->generateStencilIds( next );
pLayer = m_lstLayers.next();
}
return next;
}
KivioLayer *KivioPage::firstLayer()
{
return m_lstLayers.first();
}
KivioLayer *KivioPage::nextLayer()
{
return m_lstLayers.next();
}
KivioLayer *KivioPage::prevLayer()
{
return m_lstLayers.prev();
}
KivioLayer *KivioPage::lastLayer()
{
return m_lstLayers.last();
}
bool KivioPage::removeCurrentLayer()
{
KivioLayer *pLayer;
// NOOOOOOO!
if( m_lstLayers.count() <= 1 )
return false;
pLayer = m_lstLayers.first();
if( pLayer != m_pCurLayer )
{
if( m_lstLayers.find( m_pCurLayer )==false )
{
kdDebug(43000) << "KivioLayer::removeCurrentLayer() - Couldn't find current layer in the list. Bad!" << endl;
return false;
}
}
pLayer = m_lstLayers.next();
if( !pLayer )
{
(void)m_lstLayers.last();
pLayer = m_lstLayers.prev();
}
if( !pLayer )
{
kdDebug(43000) << "KivioLayer::removeCurrentLayer() - Couldn't find a next layer." << endl;
return false;
}
KivioRemoveLayerCommand * cmd = new KivioRemoveLayerCommand( i18n("Remove Layer"), this , m_pCurLayer , m_lstLayers.findRef(m_pCurLayer) );
doc()->addCommand( cmd );
takeLayer( m_pCurLayer );
/*
if( m_lstLayers.remove( m_pCurLayer )==false )
{
kdDebug(43000) << "KivioLayer::removeCurrentLayer() - Couldn't find current layer in the list. Bad!" << endl;
return false;
}
*/
m_pCurLayer = pLayer;
return true;
}
void KivioPage::takeLayer( KivioLayer *pLayer )
{
int pos=m_lstLayers.findRef(pLayer);
m_lstLayers.take( pos );
}
void KivioPage::addLayer( KivioLayer *pLayer )
{
m_lstLayers.append( pLayer );
}
void KivioPage::insertLayer( int position, KivioLayer *pLayer )
{
m_lstLayers.insert( position, pLayer );
}
KivioLayer *KivioPage::layerAt( int pos )
{
return m_lstLayers.at(pos);
}
void KivioPage::alignStencils(AlignData d)
{
KivioStencil* pStencil = m_lstSelection.first();
if(!pStencil)
return;
if (d.v != AlignData::None || d.h != AlignData::None) {
KMacroCommand *macro = new KMacroCommand(i18n("Move Stencil"));
double x = pStencil->x();
double y = pStencil->y();
double w = pStencil->w();
double h = pStencil->h();
while( pStencil )
{
KoRect oldRect = pStencil->rect();
switch (d.v) {
case AlignData::Top:
pStencil->setY(y);
break;
case AlignData::Center:
pStencil->setY(y+h/2-pStencil->h()/2);
break;
case AlignData::Bottom:
pStencil->setY(y+h-pStencil->h());
break;
default:
break;
}
switch (d.h) {
case AlignData::Left:
pStencil->setX(x);
break;
case AlignData::Center:
pStencil->setX(x+w/2-pStencil->w()/2);
break;
case AlignData::Right:
pStencil->setX(x+w-pStencil->w());
break;
default:
break;
}
KivioMoveStencilCommand * cmd = new KivioMoveStencilCommand( i18n("Move Stencil"),
pStencil, oldRect, pStencil->rect(), this);
macro->addCommand(cmd);
pStencil = m_lstSelection.next();
}
m_pDoc->addCommand(macro);
}
if (d.centerOfPage) {
KMacroCommand *macro = new KMacroCommand(i18n("Move Stencil"));
double w = m_pPageLayout.ptWidth;
double h = m_pPageLayout.ptHeight;
KoRect r = getRectForAllSelectedStencils();
double dx = ((w - r.width()) / 2.0) - r.x();
double dy = ((h - r.height()) / 2.0) - r.y();
pStencil = m_lstSelection.first();
while( pStencil )
{
KoRect oldRect = pStencil->rect();
pStencil->setPosition(pStencil->x() + dx, pStencil->y() + dy);
KivioMoveStencilCommand * cmd = new KivioMoveStencilCommand( i18n("Move Stencil"),
pStencil, oldRect, pStencil->rect(), this);
macro->addCommand(cmd);
pStencil = m_lstSelection.next();
}
m_pDoc->addCommand(macro);
}
}
class XYSortedStencilList : public TQPtrList<KivioStencil>
{
public:
XYSortedStencilList(bool sortX) :xsort(sortX) {};
protected:
int compareItems(TQPtrCollection::Item i1, TQPtrCollection::Item i2)
{
KivioStencil* s1 = (KivioStencil*)i1;
KivioStencil* s2 = (KivioStencil*)i2;
if (xsort) {
if (s1->x() > s2->x())
return 1;
if (s1->x() < s2->x())
return -1;
return 0;
}
if (s1->y() > s2->y())
return 1;
if (s1->y() < s2->y())
return -1;
return 0;
}
private:
bool xsort;
};
void KivioPage::distributeStencils(DistributeData d)
{
double x = 0.0;
double y = 0.0;
double x1 = 0.0;
double y1 = 0.0;
KivioStencil* pStencil = m_lstSelection.first();
if (!pStencil)
return;
XYSortedStencilList xSortList(true);
XYSortedStencilList ySortList(false);
TQValueList<KoRect> oldRects;
while( pStencil )
{
xSortList.append(pStencil);
ySortList.append(pStencil);
oldRects.append(pStencil->rect());
pStencil = m_lstSelection.next();
}
xSortList.sort();
ySortList.sort();
switch (d.extent) {
case DistributeData::Page:
x = m_pPageLayout.ptLeft;
y = m_pPageLayout.ptTop;
x1 = m_pPageLayout.ptWidth - m_pPageLayout.ptRight;
y1 = m_pPageLayout.ptHeight - m_pPageLayout.ptBottom;
break;
case DistributeData::Selection:
pStencil = m_lstSelection.first();
x = pStencil->x();
y = pStencil->x();
x1 = x + pStencil->w();
y1 = y + pStencil->h();
while( pStencil )
{
x = TQMIN(x,pStencil->x());
y = TQMIN(y,pStencil->y());
x1 = TQMAX(x1,pStencil->x() + pStencil->w());
y1 = TQMAX(y1,pStencil->y() + pStencil->h());
pStencil = m_lstSelection.next();
}
break;
default:
break;
}
/*****************************************************/
KivioStencil* firstx = xSortList.first();
KivioStencil* lastx = xSortList.last();
double countx = (double)(xSortList.count()-1);
double distx = 0.0;
switch (d.h) {
case DistributeData::Left:
x1 = x1 - lastx->w();
distx = (x1 - x)/countx;
break;
case DistributeData::Center:
x = x + firstx->w()/2;
x1 = x1 - lastx->w()/2;
distx = (x1 - x)/countx;
break;
case DistributeData::Spacing: {
double allw = 0.0;
pStencil = xSortList.first();
while( pStencil )
{
allw = allw + pStencil->w();
pStencil = xSortList.next();
}
distx = (x1-x-allw)/countx;
break; }
case DistributeData::Right:
x = x + firstx->w();
distx = (x1 - x)/countx;
break;
default:
break;
}
double xx = x;
switch (d.h) {
case DistributeData::Center:
pStencil = xSortList.first();
while( pStencil )
{
pStencil->setX(xx - pStencil->w()/2);
xx = xx + distx;
pStencil = xSortList.next();
}
break;
case DistributeData::Right:
pStencil = xSortList.first();
while( pStencil )
{
pStencil->setX(xx - pStencil->w());
xx = xx + distx;
pStencil = xSortList.next();
}
break;
case DistributeData::Left:
pStencil = xSortList.first();
while( pStencil )
{
pStencil->setX(xx);
xx = xx + distx;
pStencil = xSortList.next();
}
break;
case DistributeData::Spacing:
pStencil = xSortList.first();
while( pStencil )
{
pStencil->setX(xx);
xx = xx + pStencil->w() + distx;
pStencil = xSortList.next();
}
break;
default:
break;
}
/*****************************************************/
KivioStencil* firsty = ySortList.first();
KivioStencil* lasty = ySortList.last();
double county = (double)(ySortList.count()-1);
double disty = 0.0;
switch (d.v) {
case DistributeData::Top:
y1 = y1 - lasty->h();
disty = (y1 - y)/county;
break;
case DistributeData::Center:
y = y + firsty->h()/2;
y1 = y1 - lasty->h()/2;
disty = (y1 - y)/countx;
break;
case DistributeData::Spacing: {
double allh = 0.0;
pStencil = ySortList.first();
while( pStencil )
{
allh = allh + pStencil->h();
pStencil = ySortList.next();
}
disty = (y1-y-allh)/county;
break; }
case DistributeData::Bottom:
y = y + firsty->h();
disty = (y1 - y)/county;
break;
default:
break;
}
double yy = y;
switch (d.v) {
case DistributeData::Center:
pStencil = ySortList.first();
while( pStencil )
{
pStencil->setY(yy - pStencil->h()/2);
yy = yy + disty;
pStencil = ySortList.next();
}
break;
case DistributeData::Bottom:
pStencil = ySortList.first();
while( pStencil )
{
pStencil->setY(yy - pStencil->h());
yy = yy + disty;
pStencil = ySortList.next();
}
break;
case DistributeData::Top:
pStencil = ySortList.first();
while( pStencil )
{
pStencil->setY(yy);
yy = yy + disty;
pStencil = ySortList.next();
}
break;
case DistributeData::Spacing:
pStencil = ySortList.first();
while( pStencil )
{
pStencil->setY(yy);
yy = yy + pStencil->h() + disty;
pStencil = ySortList.next();
}
break;
default:
break;
}
if(d.v != DistributeData::None || d.h != DistributeData::None) {
KMacroCommand *macro = new KMacroCommand(i18n("Move Stencil"));
TQValueListIterator<KoRect> it;
pStencil = m_lstSelection.first();
for(it = oldRects.begin(); it != oldRects.end(); ++it) {
KivioMoveStencilCommand * cmd = new KivioMoveStencilCommand(i18n("Move Stencil"),
pStencil, (*it), pStencil->rect(), this);
macro->addCommand( cmd);
pStencil = m_lstSelection.next();
}
m_pDoc->addCommand( macro );
}
}
/**
* Returns a rectangle representing the bounds of all the selected stencils (in points).
*/
KoRect KivioPage::getRectForAllSelectedStencils()
{
KoRect rTotal, r;
KivioStencil *pStencil = m_lstSelection.first();
// Get the rect of the first selected stencil
if( pStencil )
{
rTotal = pStencil->rect();
pStencil = m_lstSelection.next();
}
// iterate through all the stencils uniting the rectangles
while( pStencil )
{
r = pStencil->rect();
rTotal = rTotal.unite( r );
pStencil = m_lstSelection.next();
}
return rTotal;
}
/**
* Returns a rectangle representing the bounds of all the selected stencils (in points).
*/
KoRect KivioPage::getRectForAllStencils()
{
KoRect rTotal, r;
bool firstTime = true;
KivioLayer *pLayer;
KivioStencil *pStencil;
pLayer = m_lstLayers.first();
while( pLayer )
{
pStencil = pLayer->firstStencil();
while( pStencil )
{
if( firstTime==true )
{
rTotal = pStencil->rect();
firstTime = false;
}
else
{
r = pStencil->rect();
rTotal = rTotal.unite( r );
}
pStencil = pLayer->nextStencil();
}
pLayer = m_lstLayers.next();
}
return rTotal;
}
void KivioPage::setPaperLayout(const KoPageLayout &l)
{
m_pPageLayout = l;
doc()->updateView(this);
emit sig_pageLayoutChanged(m_pPageLayout);
}
KivioConnectorTarget *KivioPage::connectPointToTarget( KivioConnectorPoint *p, double /*thresh*/)
{
double oldX, oldY;
KivioLayer *pLayer, *pCurLayer;
bool doneSearching = false;
KivioConnectorTarget *pTarget;
if( !p )
return NULL;
if( p->connectable()==false )
return NULL;
oldX = p->x();
oldY = p->y();
pCurLayer = curLayer();
pLayer = firstLayer();
while( pLayer && doneSearching==false )
{
if( pLayer != pCurLayer )
{
if( pLayer->connectable()==false || pLayer->visible()==false )
{
pLayer = nextLayer();
continue;
}
}
if( (pTarget=pLayer->connectPointToTarget(p, 8.0f )) )
{
return pTarget;
}
pLayer = nextLayer();
}
return NULL;
}
KoPoint KivioPage::snapToTarget( const KoPoint& p, double thresh, bool& hit )
{
KivioLayer *pLayer, *pCurLayer;
KoPoint retVal = p;
pCurLayer = curLayer();
pLayer = firstLayer();
while( pLayer && !hit )
{
if( pLayer != pCurLayer )
{
if( pLayer->connectable()==false || pLayer->visible()==false )
{
pLayer = nextLayer();
continue;
}
}
retVal = pLayer->snapToTarget(p, thresh, hit);
pLayer = nextLayer();
}
return retVal;
}
void KivioPage::setHidePage(bool _hide)
{
setHidden(_hide);
if(_hide)
emit sig_PageHidden(this);
else
emit sig_PageShown(this);
}
void KivioPage::setPaintSelected(bool paint)
{
KivioStencil *pStencil = m_lstSelection.first();
while( pStencil )
{
pStencil->setHidden(!paint);
pStencil = m_lstSelection.next();
}
}
bool KivioPage::checkForStencilTypeInSelection(KivioStencilType type)
{
KivioStencil *pStencil = m_lstSelection.first();
while( pStencil )
{
if(pStencil->type() == type) {
return true;
}
pStencil = m_lstSelection.next();
}
return false;
}
bool KivioPage::checkForTextBoxesInSelection()
{
KivioStencil *pStencil = m_lstSelection.first();
while(pStencil) {
if(pStencil->hasTextBox()) {
return true;
}
pStencil = m_lstSelection.next();
}
return false;
}
void KivioPage::setGuideLines(const TQValueList<double> hGuideLines, const TQValueList<double> vGuideLines)
{
m_hGuideLines = hGuideLines;
m_vGuideLines = vGuideLines;
}
void KivioPage::saveGuideLines(TQDomElement& element)
{
TQValueList<double>::iterator it;
TQValueList<double>::iterator itEnd = m_hGuideLines.end();
for(it = m_hGuideLines.begin(); it != itEnd; ++it) {
TQDomElement e = element.ownerDocument().createElement("Guideline");
element.appendChild(e);
XmlWriteDouble(e, "pos", *it);
XmlWriteInt(e, "orient", (int)Qt::Horizontal);
}
itEnd = m_vGuideLines.end();
for(it = m_vGuideLines.begin(); it != itEnd; ++it) {
TQDomElement e = element.ownerDocument().createElement("Guideline");
element.appendChild(e);
XmlWriteDouble(e, "pos", *it);
XmlWriteInt(e, "orient", (int)Qt::Vertical);
}
}
void KivioPage::loadGuideLines(const TQDomElement& element)
{
m_hGuideLines.clear();
m_vGuideLines.clear();
TQDomElement e = element.firstChild().toElement();
for( ; !e.isNull(); e = e.nextSibling().toElement() )
{
double pos = XmlReadDouble(e, "pos", 0.0);
Qt::Orientation orient = (Qt::Orientation)XmlReadInt(e, "orient", 0);
addGuideLine(orient, pos);
}
}
void KivioPage::addGuideLine(Qt::Orientation orientation, double position)
{
if(orientation == Qt::Horizontal) {
m_hGuideLines.append(position);
} else {
m_vGuideLines.append(position);
}
}
#include "kivio_page.moc"