1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_dbaccess.hxx" 30 #ifndef DBAUI_CONNECTIONLINE_HXX 31 #include "ConnectionLine.hxx" 32 #endif 33 #ifndef DBAUI_CONNECTIONLINEDATA_HXX 34 #include "ConnectionLineData.hxx" 35 #endif 36 #ifndef DBAUI_TABLEWINDOW_HXX 37 #include "TableWindow.hxx" 38 #endif 39 #ifndef DBAUI_TABLEWINDOWLISTBOX_HXX 40 #include "TableWindowListBox.hxx" 41 #endif 42 #ifndef DBAUI_TABLECONNECTION_HXX 43 #include "TableConnection.hxx" 44 #endif 45 #ifndef _SV_SVAPP_HXX 46 #include <vcl/svapp.hxx> 47 #endif 48 #ifndef _INC_MATH 49 #include <math.h> 50 #endif 51 #ifndef _TOOLS_DEBUG_HXX 52 #include <tools/debug.hxx> 53 #endif 54 #include <vcl/lineinfo.hxx> 55 56 57 using namespace dbaui; 58 const long DESCRIPT_LINE_WIDTH = 15; 59 const long HIT_SENSITIVE_RADIUS = 5; 60 61 namespace 62 { 63 /** calcRect creates a new rectangle with the given points 64 @param _rBase the base point 65 @param _aVector the vector which will be added 66 */ 67 inline Rectangle calcRect(const Point& _rBase,const Point& _aVector) 68 { 69 return Rectangle( _rBase - _aVector, _rBase + _aVector ); 70 } 71 // ----------------------------------------------------------------------------- 72 /** GetTextPos calculate the rectangle for the connection to be drawn 73 @param _pWin the table window where to draw it 74 @param _aConnPos the connection point 75 @param _aDescrLinePos the description line pos 76 */ 77 Rectangle GetTextPos(const OTableWindow* _pWin, const Point& _aConnPos,const Point& _aDescrLinePos) 78 { 79 OTableWindowListBox* pListBox = _pWin ? _pWin->GetListBox() : NULL; 80 DBG_ASSERT(_pWin && pListBox, "OConnectionLine::GetSourceTextPos : invalid call !"); 81 82 Rectangle aReturn; 83 if ( pListBox ) 84 { 85 const long nRowHeight = pListBox->GetEntryHeight(); 86 aReturn.Top() = _aConnPos.Y() - nRowHeight; 87 aReturn.Bottom() = aReturn.Top() + nRowHeight; 88 if (_aDescrLinePos.X() < _aConnPos.X()) 89 { 90 aReturn.Left() = _aDescrLinePos.X(); 91 aReturn.Right() = aReturn.Left() + _aConnPos.X() - _aDescrLinePos.X(); 92 } 93 else 94 { 95 aReturn.Left() = _aConnPos.X(); 96 aReturn.Right() = aReturn.Left() + _aDescrLinePos.X() - _aConnPos.X(); 97 } 98 } 99 100 return aReturn; 101 } 102 // ----------------------------------------------------------------------------- 103 /** calcPointsYValue calculate the points Y value in relation to the listbox entry 104 @param _pWin the corresponding window 105 @param _pEntry the source or dest entry 106 @param _rNewConPos (in/out) the connection pos 107 @param _rNewDescrPos (in/out) the description pos 108 */ 109 void calcPointsYValue(const OTableWindow* _pWin,SvLBoxEntry* _pEntry,Point& _rNewConPos,Point& _rNewDescrPos) 110 { 111 const OTableWindowListBox* pListBox = _pWin->GetListBox(); 112 _rNewConPos.Y() = _pWin->GetPosPixel().Y(); 113 if ( _pEntry ) 114 { 115 const long nRowHeight = pListBox->GetEntryHeight(); 116 _rNewConPos.Y() += pListBox->GetPosPixel().Y(); 117 long nEntryPos = pListBox->GetEntryPosition( _pEntry ).Y(); 118 119 if( nEntryPos >= 0 ) 120 { 121 _rNewConPos.Y() += nEntryPos; 122 _rNewConPos.Y() += (long)( 0.5 * nRowHeight ); 123 } 124 else 125 _rNewConPos.Y() -= (long)( 0.5 * nRowHeight ); 126 127 long nListBoxBottom = _pWin->GetPosPixel().Y() 128 + pListBox->GetPosPixel().Y() 129 + pListBox->GetSizePixel().Height(); 130 if( _rNewConPos.Y() > nListBoxBottom ) 131 _rNewConPos.Y() = nListBoxBottom + 2; 132 } 133 else 134 _rNewConPos.Y() += static_cast<sal_Int32>(pListBox->GetPosPixel().Y()*0.5); 135 136 _rNewDescrPos.Y() = _rNewConPos.Y(); 137 } 138 // ----------------------------------------------------------------------------- 139 } 140 141 //======================================================================== 142 // class OConnectionLine 143 //======================================================================== 144 DBG_NAME(OConnectionLine) 145 //------------------------------------------------------------------------ 146 OConnectionLine::OConnectionLine( OTableConnection* _pConn, OConnectionLineDataRef _pLineData ) 147 : m_pTabConn( _pConn ) 148 ,m_pData( _pLineData ) 149 { 150 DBG_CTOR(OConnectionLine,NULL); 151 } 152 153 //------------------------------------------------------------------------ 154 OConnectionLine::OConnectionLine( const OConnectionLine& _rLine ) 155 { 156 DBG_CTOR(OConnectionLine,NULL); 157 m_pData = new OConnectionLineData( *_rLine.GetData() ); 158 *this = _rLine; 159 } 160 161 //------------------------------------------------------------------------ 162 OConnectionLine::~OConnectionLine() 163 { 164 DBG_DTOR(OConnectionLine,NULL); 165 } 166 167 //------------------------------------------------------------------------ 168 OConnectionLine& OConnectionLine::operator=( const OConnectionLine& rLine ) 169 { 170 if( &rLine != this ) 171 { 172 // da mir die Daten nicht gehoeren, loesche ich die alten nicht 173 m_pData->CopyFrom(*rLine.GetData()); 174 // CopyFrom ist virtuell, damit ist es kein Problem, wenn m_pData von einem von OTableConnectionData abgeleiteten Typ ist 175 176 m_pTabConn = rLine.m_pTabConn; 177 m_aSourceConnPos = rLine.m_aSourceConnPos; 178 m_aDestConnPos = rLine.m_aDestConnPos; 179 m_aSourceDescrLinePos = rLine.m_aSourceDescrLinePos; 180 m_aDestDescrLinePos = rLine.m_aDestDescrLinePos; 181 } 182 183 return *this; 184 } 185 186 //------------------------------------------------------------------------ 187 Rectangle OConnectionLine::GetBoundingRect() 188 { 189 ////////////////////////////////////////////////////////////////////// 190 // Umgebendes Rechteck bestimmen 191 Rectangle aBoundingRect( Point(0,0), Point(0,0) ); 192 if( !IsValid() ) 193 return aBoundingRect; 194 195 Point aTopLeft; 196 Point aBottomRight; 197 198 if( m_aSourceDescrLinePos.Y() <= m_aDestDescrLinePos.Y() ) 199 { 200 aTopLeft.Y() = m_aSourceDescrLinePos.Y(); 201 aBottomRight.Y() = m_aDestDescrLinePos.Y(); 202 } 203 else 204 { 205 aTopLeft.Y() = m_aDestDescrLinePos.Y(); 206 aBottomRight.Y() = m_aSourceDescrLinePos.Y(); 207 } 208 209 if( m_aSourceDescrLinePos.X() <= m_aDestDescrLinePos.X() ) 210 { 211 aTopLeft.X() = m_aSourceDescrLinePos.X(); 212 aBottomRight.X() = m_aDestDescrLinePos.X(); 213 } 214 else 215 { 216 aTopLeft.X() = m_aDestDescrLinePos.X(); 217 aBottomRight.X() = m_aSourceDescrLinePos.X(); 218 } 219 220 const OTableWindow* pSourceWin = m_pTabConn->GetSourceWin(); 221 const OTableWindow* pDestWin = m_pTabConn->GetDestWin(); 222 ////////////////////////////////////////////////////////////////////// 223 // Linie verlaeuft in z-Form 224 if( pSourceWin == pDestWin || Abs(m_aSourceConnPos.X() - m_aDestConnPos.X()) > Abs(m_aSourceDescrLinePos.X() - m_aDestDescrLinePos.X()) ) 225 { 226 aTopLeft.X() -= DESCRIPT_LINE_WIDTH; 227 aBottomRight.X() += DESCRIPT_LINE_WIDTH; 228 } 229 230 aBoundingRect = Rectangle( aTopLeft-Point(2,17), aBottomRight+Point(2,2) ); 231 232 return aBoundingRect; 233 } 234 // ----------------------------------------------------------------------------- 235 void calcPointX1(const OTableWindow* _pWin,Point& _rNewConPos,Point& _rNewDescrPos) 236 { 237 _rNewConPos.X() = _pWin->GetPosPixel().X() + _pWin->GetSizePixel().Width(); 238 _rNewDescrPos.X() = _rNewConPos.X(); 239 _rNewConPos.X() += DESCRIPT_LINE_WIDTH; 240 } 241 // ----------------------------------------------------------------------------- 242 void calcPointX2(const OTableWindow* _pWin,Point& _rNewConPos,Point& _rNewDescrPos) 243 { 244 _rNewConPos.X() = _pWin->GetPosPixel().X(); 245 _rNewDescrPos.X() = _rNewConPos.X(); 246 _rNewConPos.X() -= DESCRIPT_LINE_WIDTH; 247 } 248 //------------------------------------------------------------------------ 249 sal_Bool OConnectionLine::RecalcLine() 250 { 251 ////////////////////////////////////////////////////////////////////// 252 // Fenster und Entries muessen gesetzt sein 253 const OTableWindow* pSourceWin = m_pTabConn->GetSourceWin(); 254 const OTableWindow* pDestWin = m_pTabConn->GetDestWin(); 255 256 if( !pSourceWin || !pDestWin ) 257 return sal_False; 258 259 SvLBoxEntry* pSourceEntry = pSourceWin->GetListBox()->GetEntryFromText( GetData()->GetSourceFieldName() ); 260 SvLBoxEntry* pDestEntry = pDestWin->GetListBox()->GetEntryFromText( GetData()->GetDestFieldName() ); 261 262 ////////////////////////////////////////////////////////////////////// 263 // X-Koordinaten bestimmen 264 Point aSourceCenter( 0, 0 ); 265 Point aDestCenter( 0, 0 ); 266 267 aSourceCenter.X() = pSourceWin->GetPosPixel().X() + (long)( 0.5*pSourceWin->GetSizePixel().Width() ); 268 aDestCenter.X() = pDestWin->GetPosPixel().X() + (long)( 0.5*pDestWin->GetSizePixel().Width() ); 269 270 const OTableWindow* pFirstWin = pDestWin; 271 const OTableWindow* pSecondWin = pSourceWin; 272 Point* pFirstConPos = &m_aDestConnPos; 273 Point* pFirstDescrPos = &m_aDestDescrLinePos; 274 Point* pSecondConPos = &m_aSourceConnPos; 275 Point* pSecondDescrPos = &m_aSourceDescrLinePos; 276 if( aDestCenter.X() > aSourceCenter.X() ) 277 { 278 pFirstWin = pSourceWin; 279 pSecondWin = pDestWin; 280 pFirstConPos = &m_aSourceConnPos; 281 pFirstDescrPos = &m_aSourceDescrLinePos; 282 pSecondConPos = &m_aDestConnPos; 283 pSecondDescrPos = &m_aDestDescrLinePos; 284 } 285 286 if ( pFirstWin == pSecondWin && pSourceEntry != pDestEntry ) 287 calcPointX2(pFirstWin,*pFirstConPos,*pFirstDescrPos); 288 else 289 calcPointX1(pFirstWin,*pFirstConPos,*pFirstDescrPos); 290 calcPointX2(pSecondWin,*pSecondConPos,*pSecondDescrPos); 291 292 ////////////////////////////////////////////////////////////////////// 293 // aSourceConnPosY bestimmen 294 calcPointsYValue(pSourceWin,pSourceEntry,m_aSourceConnPos,m_aSourceDescrLinePos); 295 296 ////////////////////////////////////////////////////////////////////// 297 // aDestConnPosY bestimmen 298 calcPointsYValue(pDestWin,pDestEntry,m_aDestConnPos,m_aDestDescrLinePos); 299 300 return sal_True; 301 } 302 // ----------------------------------------------------------------------------- 303 304 //------------------------------------------------------------------------ 305 void OConnectionLine::Draw( OutputDevice* pOutDev ) 306 { 307 const sal_uInt16 nRectSize = 3; 308 309 ////////////////////////////////////////////////////////////////////// 310 // Neue Dimensionen berechnen 311 if( !RecalcLine() ) 312 return; 313 314 ////////////////////////////////////////////////////////////////////// 315 // Zeichnen der Linien 316 if (m_pTabConn->IsSelected()) 317 pOutDev->SetLineColor(Application::GetSettings().GetStyleSettings().GetHighlightColor()); 318 else 319 pOutDev->SetLineColor(Application::GetSettings().GetStyleSettings().GetWindowTextColor()); 320 321 LineInfo aLineInfo; 322 if ( m_pTabConn->IsSelected() ) 323 aLineInfo.SetWidth(3); 324 Polygon aPoly; 325 aPoly.Insert(0,m_aSourceDescrLinePos); 326 aPoly.Insert(1,m_aSourceConnPos); 327 aPoly.Insert(2,m_aDestConnPos); 328 aPoly.Insert(3,m_aDestDescrLinePos); 329 pOutDev->DrawPolyLine(aPoly,aLineInfo); 330 331 ////////////////////////////////////////////////////////////////////// 332 // draw the connection rectangles 333 pOutDev->SetFillColor(Application::GetSettings().GetStyleSettings().GetWindowColor()); 334 335 Point aVector(nRectSize,nRectSize); 336 pOutDev->DrawRect( calcRect(m_aSourceDescrLinePos,aVector) ); 337 pOutDev->DrawRect( calcRect( m_aDestDescrLinePos,aVector) ); 338 } 339 // ----------------------------------------------------------------------------- 340 sal_Bool OConnectionLine::IsValid() const 341 { 342 return m_pData.isValid(); 343 } 344 //------------------------------------------------------------------------ 345 double dist_Euklid(const Point &p1, const Point& p2,const Point& pM, Point& q) 346 { 347 Point v(p2 - p1); 348 Point w(pM - p1); 349 double a = sqrt((double)(v.X()*v.X() + v.Y()*v.Y())); 350 double l = (v.X() * w.Y() - v.Y() * w.X()) / a; 351 double a2 = w.X()*v.X()+w.Y()*v.Y(); 352 a = a2 / (a * a); 353 q.X() = long(p1.X() + a * v.X()); 354 q.Y() = long(p1.Y() + a * v.Y()); 355 return l; 356 } 357 //------------------------------------------------------------------------ 358 bool OConnectionLine::CheckHit( const Point& rMousePos ) const 359 { 360 ////////////////////////////////////////////////////////////////////// 361 /* 362 Vorgehensweise beim HitTest: 363 Es wird der Abstand nach Euklid berechnet. 364 */ 365 Point q; 366 double l = fabs(dist_Euklid(m_aSourceConnPos,m_aDestConnPos,rMousePos,q)); 367 if( l < HIT_SENSITIVE_RADIUS) 368 { 369 if(::std::min(m_aSourceConnPos.X(),m_aDestConnPos.X()) <= q.X() && ::std::min(m_aSourceConnPos.Y(),m_aDestConnPos.Y()) <= q.Y() 370 && q.X() <= ::std::max(m_aDestConnPos.X(),m_aSourceConnPos.X()) && q.Y() <= ::std::max(m_aDestConnPos.Y(),m_aSourceConnPos.Y())) 371 return true; 372 } 373 374 return false; 375 } 376 // ----------------------------------------------------------------------------- 377 Rectangle OConnectionLine::GetSourceTextPos() const 378 { 379 return GetTextPos(m_pTabConn->GetSourceWin(),m_aSourceConnPos,m_aSourceDescrLinePos); 380 } 381 // ----------------------------------------------------------------------------- 382 Rectangle OConnectionLine::GetDestTextPos() const 383 { 384 return GetTextPos(m_pTabConn->GetDestWin(),m_aDestConnPos,m_aDestDescrLinePos); 385 } 386 // ----------------------------------------------------------------------------- 387 Point OConnectionLine::getMidPoint() const 388 { 389 Point aDest = m_aDestConnPos - m_aSourceConnPos; 390 aDest.X() /= 2; 391 aDest.Y() /= 2; 392 393 return m_aSourceConnPos + aDest; 394 } 395 // ----------------------------------------------------------------------------- 396 397 398