diff options
Diffstat (limited to 'dbaccess/source/ui/querydesign/ConnectionLine.cxx')
-rw-r--r-- | dbaccess/source/ui/querydesign/ConnectionLine.cxx | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/dbaccess/source/ui/querydesign/ConnectionLine.cxx b/dbaccess/source/ui/querydesign/ConnectionLine.cxx new file mode 100644 index 000000000000..91d67b82108c --- /dev/null +++ b/dbaccess/source/ui/querydesign/ConnectionLine.cxx @@ -0,0 +1,385 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_dbaccess.hxx" +#include "ConnectionLine.hxx" +#include "ConnectionLineData.hxx" +#include "TableWindow.hxx" +#include "TableWindowListBox.hxx" +#include "TableConnection.hxx" +#include <vcl/svapp.hxx> +#ifndef _INC_MATH +#include <math.h> +#endif +#include <osl/diagnose.h> +#include <vcl/lineinfo.hxx> + + +using namespace dbaui; +const long DESCRIPT_LINE_WIDTH = 15; +const long HIT_SENSITIVE_RADIUS = 5; + +namespace +{ + /** calcRect creates a new rectangle with the given points + @param _rBase the base point + @param _aVector the vector which will be added + */ + inline Rectangle calcRect(const Point& _rBase,const Point& _aVector) + { + return Rectangle( _rBase - _aVector, _rBase + _aVector ); + } + // ----------------------------------------------------------------------------- + /** GetTextPos calculate the rectangle for the connection to be drawn + @param _pWin the table window where to draw it + @param _aConnPos the connection point + @param _aDescrLinePos the description line pos + */ + Rectangle GetTextPos(const OTableWindow* _pWin, const Point& _aConnPos,const Point& _aDescrLinePos) + { + OTableWindowListBox* pListBox = _pWin ? _pWin->GetListBox() : NULL; + OSL_ENSURE(_pWin && pListBox, "OConnectionLine::GetSourceTextPos : invalid call !"); + + Rectangle aReturn; + if ( pListBox ) + { + const long nRowHeight = pListBox->GetEntryHeight(); + aReturn.Top() = _aConnPos.Y() - nRowHeight; + aReturn.Bottom() = aReturn.Top() + nRowHeight; + if (_aDescrLinePos.X() < _aConnPos.X()) + { + aReturn.Left() = _aDescrLinePos.X(); + aReturn.Right() = aReturn.Left() + _aConnPos.X() - _aDescrLinePos.X(); + } + else + { + aReturn.Left() = _aConnPos.X(); + aReturn.Right() = aReturn.Left() + _aDescrLinePos.X() - _aConnPos.X(); + } + } + + return aReturn; + } + // ----------------------------------------------------------------------------- + /** calcPointsYValue calculate the points Y value in relation to the listbox entry + @param _pWin the corresponding window + @param _pEntry the source or dest entry + @param _rNewConPos (in/out) the connection pos + @param _rNewDescrPos (in/out) the description pos + */ + void calcPointsYValue(const OTableWindow* _pWin,SvLBoxEntry* _pEntry,Point& _rNewConPos,Point& _rNewDescrPos) + { + const OTableWindowListBox* pListBox = _pWin->GetListBox(); + _rNewConPos.Y() = _pWin->GetPosPixel().Y(); + if ( _pEntry ) + { + const long nRowHeight = pListBox->GetEntryHeight(); + _rNewConPos.Y() += pListBox->GetPosPixel().Y(); + long nEntryPos = pListBox->GetEntryPosition( _pEntry ).Y(); + + if( nEntryPos >= 0 ) + { + _rNewConPos.Y() += nEntryPos; + _rNewConPos.Y() += (long)( 0.5 * nRowHeight ); + } + else + _rNewConPos.Y() -= (long)( 0.5 * nRowHeight ); + + long nListBoxBottom = _pWin->GetPosPixel().Y() + + pListBox->GetPosPixel().Y() + + pListBox->GetSizePixel().Height(); + if( _rNewConPos.Y() > nListBoxBottom ) + _rNewConPos.Y() = nListBoxBottom + 2; + } + else + _rNewConPos.Y() += static_cast<sal_Int32>(pListBox->GetPosPixel().Y()*0.5); + + _rNewDescrPos.Y() = _rNewConPos.Y(); + } + // ----------------------------------------------------------------------------- +} + +//======================================================================== +// class OConnectionLine +//======================================================================== +DBG_NAME(OConnectionLine) +//------------------------------------------------------------------------ +OConnectionLine::OConnectionLine( OTableConnection* _pConn, OConnectionLineDataRef _pLineData ) + : m_pTabConn( _pConn ) + ,m_pData( _pLineData ) +{ + DBG_CTOR(OConnectionLine,NULL); +} + +//------------------------------------------------------------------------ +OConnectionLine::OConnectionLine( const OConnectionLine& _rLine ) +{ + DBG_CTOR(OConnectionLine,NULL); + m_pData = new OConnectionLineData( *_rLine.GetData() ); + *this = _rLine; +} + +//------------------------------------------------------------------------ +OConnectionLine::~OConnectionLine() +{ + DBG_DTOR(OConnectionLine,NULL); +} + +//------------------------------------------------------------------------ +OConnectionLine& OConnectionLine::operator=( const OConnectionLine& rLine ) +{ + if( &rLine != this ) + { + // da mir die Daten nicht gehoeren, loesche ich die alten nicht + m_pData->CopyFrom(*rLine.GetData()); + // CopyFrom ist virtuell, damit ist es kein Problem, wenn m_pData von einem von OTableConnectionData abgeleiteten Typ ist + + m_pTabConn = rLine.m_pTabConn; + m_aSourceConnPos = rLine.m_aSourceConnPos; + m_aDestConnPos = rLine.m_aDestConnPos; + m_aSourceDescrLinePos = rLine.m_aSourceDescrLinePos; + m_aDestDescrLinePos = rLine.m_aDestDescrLinePos; + } + + return *this; +} + +//------------------------------------------------------------------------ +Rectangle OConnectionLine::GetBoundingRect() +{ + ////////////////////////////////////////////////////////////////////// + // Umgebendes Rechteck bestimmen + Rectangle aBoundingRect( Point(0,0), Point(0,0) ); + if( !IsValid() ) + return aBoundingRect; + + Point aTopLeft; + Point aBottomRight; + + if( m_aSourceDescrLinePos.Y() <= m_aDestDescrLinePos.Y() ) + { + aTopLeft.Y() = m_aSourceDescrLinePos.Y(); + aBottomRight.Y() = m_aDestDescrLinePos.Y(); + } + else + { + aTopLeft.Y() = m_aDestDescrLinePos.Y(); + aBottomRight.Y() = m_aSourceDescrLinePos.Y(); + } + + if( m_aSourceDescrLinePos.X() <= m_aDestDescrLinePos.X() ) + { + aTopLeft.X() = m_aSourceDescrLinePos.X(); + aBottomRight.X() = m_aDestDescrLinePos.X(); + } + else + { + aTopLeft.X() = m_aDestDescrLinePos.X(); + aBottomRight.X() = m_aSourceDescrLinePos.X(); + } + + const OTableWindow* pSourceWin = m_pTabConn->GetSourceWin(); + const OTableWindow* pDestWin = m_pTabConn->GetDestWin(); + ////////////////////////////////////////////////////////////////////// + // Linie verlaeuft in z-Form + if( pSourceWin == pDestWin || Abs(m_aSourceConnPos.X() - m_aDestConnPos.X()) > Abs(m_aSourceDescrLinePos.X() - m_aDestDescrLinePos.X()) ) + { + aTopLeft.X() -= DESCRIPT_LINE_WIDTH; + aBottomRight.X() += DESCRIPT_LINE_WIDTH; + } + + aBoundingRect = Rectangle( aTopLeft-Point(2,17), aBottomRight+Point(2,2) ); + + return aBoundingRect; +} +// ----------------------------------------------------------------------------- +void calcPointX1(const OTableWindow* _pWin,Point& _rNewConPos,Point& _rNewDescrPos) +{ + _rNewConPos.X() = _pWin->GetPosPixel().X() + _pWin->GetSizePixel().Width(); + _rNewDescrPos.X() = _rNewConPos.X(); + _rNewConPos.X() += DESCRIPT_LINE_WIDTH; +} +// ----------------------------------------------------------------------------- +void calcPointX2(const OTableWindow* _pWin,Point& _rNewConPos,Point& _rNewDescrPos) +{ + _rNewConPos.X() = _pWin->GetPosPixel().X(); + _rNewDescrPos.X() = _rNewConPos.X(); + _rNewConPos.X() -= DESCRIPT_LINE_WIDTH; +} +//------------------------------------------------------------------------ +sal_Bool OConnectionLine::RecalcLine() +{ + ////////////////////////////////////////////////////////////////////// + // Fenster und Entries muessen gesetzt sein + const OTableWindow* pSourceWin = m_pTabConn->GetSourceWin(); + const OTableWindow* pDestWin = m_pTabConn->GetDestWin(); + + if( !pSourceWin || !pDestWin ) + return sal_False; + + SvLBoxEntry* pSourceEntry = pSourceWin->GetListBox()->GetEntryFromText( GetData()->GetSourceFieldName() ); + SvLBoxEntry* pDestEntry = pDestWin->GetListBox()->GetEntryFromText( GetData()->GetDestFieldName() ); + + ////////////////////////////////////////////////////////////////////// + // X-Koordinaten bestimmen + Point aSourceCenter( 0, 0 ); + Point aDestCenter( 0, 0 ); + + aSourceCenter.X() = pSourceWin->GetPosPixel().X() + (long)( 0.5*pSourceWin->GetSizePixel().Width() ); + aDestCenter.X() = pDestWin->GetPosPixel().X() + (long)( 0.5*pDestWin->GetSizePixel().Width() ); + + const OTableWindow* pFirstWin = pDestWin; + const OTableWindow* pSecondWin = pSourceWin; + Point* pFirstConPos = &m_aDestConnPos; + Point* pFirstDescrPos = &m_aDestDescrLinePos; + Point* pSecondConPos = &m_aSourceConnPos; + Point* pSecondDescrPos = &m_aSourceDescrLinePos; + if( aDestCenter.X() > aSourceCenter.X() ) + { + pFirstWin = pSourceWin; + pSecondWin = pDestWin; + pFirstConPos = &m_aSourceConnPos; + pFirstDescrPos = &m_aSourceDescrLinePos; + pSecondConPos = &m_aDestConnPos; + pSecondDescrPos = &m_aDestDescrLinePos; + } + + if ( pFirstWin == pSecondWin && pSourceEntry != pDestEntry ) + calcPointX2(pFirstWin,*pFirstConPos,*pFirstDescrPos); + else + calcPointX1(pFirstWin,*pFirstConPos,*pFirstDescrPos); + calcPointX2(pSecondWin,*pSecondConPos,*pSecondDescrPos); + + ////////////////////////////////////////////////////////////////////// + // aSourceConnPosY bestimmen + calcPointsYValue(pSourceWin,pSourceEntry,m_aSourceConnPos,m_aSourceDescrLinePos); + + ////////////////////////////////////////////////////////////////////// + // aDestConnPosY bestimmen + calcPointsYValue(pDestWin,pDestEntry,m_aDestConnPos,m_aDestDescrLinePos); + + return sal_True; +} +// ----------------------------------------------------------------------------- + +//------------------------------------------------------------------------ +void OConnectionLine::Draw( OutputDevice* pOutDev ) +{ + const sal_uInt16 nRectSize = 3; + + ////////////////////////////////////////////////////////////////////// + // Neue Dimensionen berechnen + if( !RecalcLine() ) + return; + + ////////////////////////////////////////////////////////////////////// + // Zeichnen der Linien + if (m_pTabConn->IsSelected()) + pOutDev->SetLineColor(Application::GetSettings().GetStyleSettings().GetHighlightColor()); + else + pOutDev->SetLineColor(Application::GetSettings().GetStyleSettings().GetWindowTextColor()); + + LineInfo aLineInfo; + if ( m_pTabConn->IsSelected() ) + aLineInfo.SetWidth(3); + Polygon aPoly; + aPoly.Insert(0,m_aSourceDescrLinePos); + aPoly.Insert(1,m_aSourceConnPos); + aPoly.Insert(2,m_aDestConnPos); + aPoly.Insert(3,m_aDestDescrLinePos); + pOutDev->DrawPolyLine(aPoly,aLineInfo); + + ////////////////////////////////////////////////////////////////////// + // draw the connection rectangles + pOutDev->SetFillColor(Application::GetSettings().GetStyleSettings().GetWindowColor()); + + Point aVector(nRectSize,nRectSize); + pOutDev->DrawRect( calcRect(m_aSourceDescrLinePos,aVector) ); + pOutDev->DrawRect( calcRect( m_aDestDescrLinePos,aVector) ); +} +// ----------------------------------------------------------------------------- +sal_Bool OConnectionLine::IsValid() const +{ + return m_pData.is(); +} +//------------------------------------------------------------------------ +double dist_Euklid(const Point &p1, const Point& p2,const Point& pM, Point& q) +{ + Point v(p2 - p1); + Point w(pM - p1); + double a = sqrt((double)(v.X()*v.X() + v.Y()*v.Y())); + double l = (v.X() * w.Y() - v.Y() * w.X()) / a; + double a2 = w.X()*v.X()+w.Y()*v.Y(); + a = a2 / (a * a); + q.X() = long(p1.X() + a * v.X()); + q.Y() = long(p1.Y() + a * v.Y()); + return l; +} +//------------------------------------------------------------------------ +bool OConnectionLine::CheckHit( const Point& rMousePos ) const +{ + ////////////////////////////////////////////////////////////////////// + /* + Vorgehensweise beim HitTest: + Es wird der Abstand nach Euklid berechnet. + */ + Point q; + double l = fabs(dist_Euklid(m_aSourceConnPos,m_aDestConnPos,rMousePos,q)); + if( l < HIT_SENSITIVE_RADIUS) + { + if(::std::min(m_aSourceConnPos.X(),m_aDestConnPos.X()) <= q.X() && ::std::min(m_aSourceConnPos.Y(),m_aDestConnPos.Y()) <= q.Y() + && q.X() <= ::std::max(m_aDestConnPos.X(),m_aSourceConnPos.X()) && q.Y() <= ::std::max(m_aDestConnPos.Y(),m_aSourceConnPos.Y())) + return true; + } + + return false; +} +// ----------------------------------------------------------------------------- +Rectangle OConnectionLine::GetSourceTextPos() const +{ + return GetTextPos(m_pTabConn->GetSourceWin(),m_aSourceConnPos,m_aSourceDescrLinePos); +} +// ----------------------------------------------------------------------------- +Rectangle OConnectionLine::GetDestTextPos() const +{ + return GetTextPos(m_pTabConn->GetDestWin(),m_aDestConnPos,m_aDestDescrLinePos); +} +// ----------------------------------------------------------------------------- +Point OConnectionLine::getMidPoint() const +{ + Point aDest = m_aDestConnPos - m_aSourceConnPos; + aDest.X() /= 2; + aDest.Y() /= 2; + + return m_aSourceConnPos + aDest; +} +// ----------------------------------------------------------------------------- + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |