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_TABLEWINDOWLISTBOX_HXX 31 #include "TableWindowListBox.hxx" 32 #endif 33 #ifndef DBAUI_TABLEWINDOW_HXX 34 #include "TableWindow.hxx" 35 #endif 36 #ifndef DBAUI_QUERYDESIGNVIEW_HXX 37 #include "QueryDesignView.hxx" 38 #endif 39 #ifndef DBAUI_QUERYTABLEVIEW_HXX 40 #include "QueryTableView.hxx" 41 #endif 42 #ifndef DBAUI_QUERYCONTROLLER_HXX 43 #include "querycontroller.hxx" 44 #endif 45 #ifndef DBAUI_JOINEXCHANGE_HXX 46 #include "JoinExchange.hxx" 47 #endif 48 #ifndef _TOOLS_DEBUG_HXX 49 #include <tools/debug.hxx> 50 #endif 51 #ifndef _COM_SUN_STAR_SDBC_XDATABASEMETADATA_HPP_ 52 #include <com/sun/star/sdbc/XDatabaseMetaData.hpp> 53 #endif 54 #ifndef _SVX_DBEXCH_HRC 55 #include <svx/dbexch.hrc> 56 #endif 57 #ifndef _SV_SVAPP_HXX 58 #include <vcl/svapp.hxx> 59 #endif 60 61 using namespace dbaui; 62 using namespace ::com::sun::star::sdbc; 63 using namespace ::com::sun::star::uno; 64 using namespace ::com::sun::star::datatransfer; 65 66 OJoinExchangeData::OJoinExchangeData(OTableWindowListBox* pBox) 67 : pListBox(pBox) 68 , pEntry(pBox->FirstSelected()) 69 { } 70 71 const sal_uLong SCROLLING_TIMESPAN = 500; 72 const long LISTBOX_SCROLLING_AREA = 6; 73 //================================================================== 74 // class OTableWindowListBox 75 //================================================================== 76 DBG_NAME(OTableWindowListBox) 77 //------------------------------------------------------------------------------ 78 OTableWindowListBox::OTableWindowListBox( OTableWindow* pParent ) 79 :SvTreeListBox( pParent, WB_HASBUTTONS | WB_BORDER) 80 ,m_aMousePos( Point(0,0) ) 81 ,m_pTabWin( pParent ) 82 ,m_nDropEvent(0) 83 ,m_nUiEvent(0) 84 ,m_bReallyScrolled( sal_False ) 85 { 86 DBG_CTOR(OTableWindowListBox,NULL); 87 m_aScrollTimer.SetTimeout( SCROLLING_TIMESPAN ); 88 SetDoubleClickHdl( LINK(this, OTableWindowListBox, OnDoubleClick) ); 89 90 SetSelectionMode(SINGLE_SELECTION); 91 92 SetHighlightRange( ); 93 } 94 95 //------------------------------------------------------------------------------ 96 void OTableWindowListBox::dragFinished( ) 97 { 98 // first show the error msg when existing 99 m_pTabWin->getDesignView()->getController().showError(m_pTabWin->getDesignView()->getController().clearOccuredError()); 100 // second look for ui activities which should happen after d&d 101 if (m_nUiEvent) 102 Application::RemoveUserEvent(m_nUiEvent); 103 m_nUiEvent = Application::PostUserEvent(LINK(this, OTableWindowListBox, LookForUiHdl)); 104 } 105 106 //------------------------------------------------------------------------------ 107 OTableWindowListBox::~OTableWindowListBox() 108 { 109 DBG_DTOR(OTableWindowListBox,NULL); 110 if (m_nDropEvent) 111 Application::RemoveUserEvent(m_nDropEvent); 112 if (m_nUiEvent) 113 Application::RemoveUserEvent(m_nUiEvent); 114 if( m_aScrollTimer.IsActive() ) 115 m_aScrollTimer.Stop(); 116 m_pTabWin = NULL; 117 } 118 119 //------------------------------------------------------------------------------ 120 SvLBoxEntry* OTableWindowListBox::GetEntryFromText( const String& rEntryText ) 121 { 122 ////////////////////////////////////////////////////////////////////// 123 // Liste durchiterieren 124 SvTreeList* pTreeList = GetModel(); 125 SvLBoxEntry* pEntry = (SvLBoxEntry*)pTreeList->First(); 126 OJoinDesignView* pView = m_pTabWin->getDesignView(); 127 OJoinController& rController = pView->getController(); 128 129 sal_Bool bCase = sal_False; 130 try 131 { 132 Reference<XConnection> xConnection = rController.getConnection(); 133 if(xConnection.is()) 134 { 135 Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData(); 136 if(xMeta.is()) 137 bCase = xMeta->supportsMixedCaseQuotedIdentifiers(); 138 } 139 while( pEntry ) 140 { 141 if((bCase ? rEntryText == GetEntryText(pEntry) : rEntryText.EqualsIgnoreCaseAscii(GetEntryText(pEntry)))) 142 { 143 return pEntry; 144 } 145 pEntry = (SvLBoxEntry*)pTreeList->Next( pEntry ); 146 } 147 } 148 catch(SQLException&) 149 { 150 } 151 152 return NULL; 153 } 154 155 //------------------------------------------------------------------------------ 156 void OTableWindowListBox::NotifyScrolled() 157 { 158 m_bReallyScrolled = sal_True; 159 } 160 161 //------------------------------------------------------------------------------ 162 void OTableWindowListBox::NotifyEndScroll() 163 { 164 if (m_bReallyScrolled) 165 // die Verbindungen, die diese Tabelle eventuell hat, muessen neu gezeichnet werden 166 m_pTabWin->getTableView()->Invalidate(INVALIDATE_NOCHILDREN); 167 // ohne das INVALIDATE_NOCHILDREN wuerden auch alle Tabellen neu gezeichnet werden, 168 // sprich : es flackert 169 m_bReallyScrolled = sal_False; 170 } 171 172 //------------------------------------------------------------------------------ 173 long OTableWindowListBox::PreNotify(NotifyEvent& rNEvt) 174 { 175 sal_Bool bHandled = sal_False; 176 switch (rNEvt.GetType()) 177 { 178 case EVENT_KEYINPUT: 179 { 180 const KeyEvent* pKeyEvent = rNEvt.GetKeyEvent(); 181 const KeyCode& rCode = pKeyEvent->GetKeyCode(); 182 183 if (rCode.GetCode() != KEY_RETURN) 184 { 185 if(m_pTabWin) 186 { 187 bHandled = m_pTabWin->HandleKeyInput(*pKeyEvent); 188 // bHandled = sal_True; 189 } 190 break; 191 } 192 193 if (rCode.IsMod1() || rCode.IsMod2() || rCode.IsShift()) 194 break; 195 if (FirstSelected()) 196 static_cast<OTableWindow*>(Window::GetParent())->OnEntryDoubleClicked(FirstSelected()); 197 } 198 break; 199 } 200 201 if (!bHandled) 202 return SvTreeListBox::PreNotify(rNEvt); 203 return 1L; 204 } 205 206 //------------------------------------------------------------------------------ 207 IMPL_LINK( OTableWindowListBox, ScrollUpHdl, SvTreeListBox*, /*pBox*/ ) 208 { 209 SvLBoxEntry* pEntry = GetEntry( m_aMousePos ); 210 if( !pEntry ) 211 return 0; 212 213 if( pEntry != Last() ) 214 { 215 ScrollOutputArea( -1 ); 216 pEntry = GetEntry( m_aMousePos ); 217 Select( pEntry, sal_True ); 218 // m_aScrollTimer.Start(); 219 } 220 221 return 0; 222 } 223 224 //------------------------------------------------------------------------------ 225 IMPL_LINK( OTableWindowListBox, ScrollDownHdl, SvTreeListBox*, /*pBox*/ ) 226 { 227 SvLBoxEntry* pEntry = GetEntry( m_aMousePos ); 228 if( !pEntry ) 229 return 0; 230 231 if( pEntry != Last() ) 232 { 233 ScrollOutputArea( 1 ); 234 pEntry = GetEntry( m_aMousePos ); 235 Select( pEntry, sal_True ); 236 // m_aScrollTimer.Start(); 237 } 238 239 return 0; 240 } 241 242 //------------------------------------------------------------------------------ 243 void OTableWindowListBox::StartDrag( sal_Int8 /*nAction*/, const Point& /*rPosPixel*/ ) 244 { 245 OJoinTableView* pCont = m_pTabWin->getTableView(); 246 if (!pCont->getDesignView()->getController().isReadOnly() && pCont->getDesignView()->getController().isConnected()) 247 { 248 // #100271# OJ asterix was not allowed to be copied to selection browsebox 249 sal_Bool bFirstNotAllowed = FirstSelected() == First() && m_pTabWin->GetData()->IsShowAll(); 250 EndSelection(); 251 // create a description of the source 252 OJoinExchangeData jxdSource(this); 253 // put it into a exchange object 254 OJoinExchObj* pJoin = new OJoinExchObj(jxdSource,bFirstNotAllowed); 255 Reference< XTransferable > xEnsureDelete(pJoin); 256 pJoin->StartDrag(this, DND_ACTION_LINK, this); 257 } 258 } 259 260 //------------------------------------------------------------------------------ 261 sal_Int8 OTableWindowListBox::AcceptDrop( const AcceptDropEvent& _rEvt ) 262 { 263 sal_Int8 nDND_Action = DND_ACTION_NONE; 264 // check the format 265 if ( !OJoinExchObj::isFormatAvailable(GetDataFlavorExVector(),SOT_FORMATSTR_ID_SBA_TABID) // this means that the first entry is to be draged 266 && OJoinExchObj::isFormatAvailable(GetDataFlavorExVector(),SOT_FORMATSTR_ID_SBA_JOIN) ) 267 { // don't drop into the window if it's the drag source itself 268 269 270 // remove the selection if the dragging operation is leaving the window 271 if (_rEvt.mbLeaving) 272 SelectAll(sal_False); 273 else 274 { 275 // hit test 276 m_aMousePos = _rEvt.maPosPixel; 277 Size aOutputSize = GetOutputSizePixel(); 278 SvLBoxEntry* pEntry = GetEntry( m_aMousePos ); 279 if( !pEntry ) 280 return DND_ACTION_NONE; 281 282 // Scrolling Areas 283 Rectangle aBottomScrollArea( Point(0, aOutputSize.Height()-LISTBOX_SCROLLING_AREA), 284 Size(aOutputSize.Width(), LISTBOX_SCROLLING_AREA) ); 285 Rectangle aTopScrollArea( Point(0,0), Size(aOutputSize.Width(), LISTBOX_SCROLLING_AREA) ); 286 287 // Wenn Zeiger auf der oberen ScrollingArea steht, nach oben scrollen 288 if( aBottomScrollArea.IsInside(m_aMousePos) ) 289 { 290 if( !m_aScrollTimer.IsActive() ) 291 { 292 m_aScrollTimer.SetTimeoutHdl( LINK(this, OTableWindowListBox, ScrollUpHdl) ); 293 ScrollUpHdl( this ); 294 } 295 } 296 297 // Wenn Zeiger auf der oberen ScrollingArea steht, nach unten scrollen 298 else if( aTopScrollArea.IsInside(m_aMousePos) ) 299 { 300 if( !m_aScrollTimer.IsActive() ) 301 { 302 m_aScrollTimer.SetTimeoutHdl( LINK(this, OTableWindowListBox, ScrollDownHdl) ); 303 ScrollDownHdl( this ); 304 } 305 } 306 else 307 { 308 if( m_aScrollTimer.IsActive() ) 309 m_aScrollTimer.Stop(); 310 } 311 312 // Beim Drag automatisch den richtigen Eintrag selektieren 313 if ((FirstSelected() != pEntry) || (FirstSelected() && NextSelected(FirstSelected()))) 314 SelectAll(sal_False); 315 Select(pEntry, sal_True); 316 317 // Auf den ersten Eintrag (*) kann nicht gedroppt werden 318 if(!( m_pTabWin->GetData()->IsShowAll() && (pEntry==First()) )) 319 nDND_Action = DND_ACTION_LINK; 320 } 321 } 322 return nDND_Action; 323 } 324 // ----------------------------------------------------------------------------- 325 326 //------------------------------------------------------------------------------ 327 IMPL_LINK( OTableWindowListBox, LookForUiHdl, void *, /*EMPTY_ARG*/) 328 { 329 m_nUiEvent = 0; 330 m_pTabWin->getTableView()->lookForUiActivities(); 331 return 0L; 332 } 333 //------------------------------------------------------------------------------ 334 IMPL_LINK( OTableWindowListBox, DropHdl, void *, /*EMPTY_ARG*/) 335 { 336 // create the connection 337 m_nDropEvent = 0; 338 OSL_ENSURE(m_pTabWin,"No TableWindow!"); 339 try 340 { 341 OJoinTableView* pCont = m_pTabWin->getTableView(); 342 OSL_ENSURE(pCont,"No QueryTableView!"); 343 pCont->AddConnection(m_aDropInfo.aSource, m_aDropInfo.aDest); 344 } 345 catch(const SQLException& e) 346 { 347 // remember the exception so that we can show them later when d&d is finished 348 m_pTabWin->getDesignView()->getController().setErrorOccured(::dbtools::SQLExceptionInfo(e)); 349 } 350 return 0L; 351 } 352 //------------------------------------------------------------------------------ 353 sal_Int8 OTableWindowListBox::ExecuteDrop( const ExecuteDropEvent& _rEvt ) 354 { 355 TransferableDataHelper aDropped(_rEvt.maDropEvent.Transferable); 356 if ( OJoinExchObj::isFormatAvailable(aDropped.GetDataFlavorExVector())) 357 { // don't drop into the window if it's the drag source itself 358 m_aDropInfo.aSource = OJoinExchangeData(this); 359 m_aDropInfo.aDest = OJoinExchObj::GetSourceDescription(_rEvt.maDropEvent.Transferable); 360 361 if (m_nDropEvent) 362 Application::RemoveUserEvent(m_nDropEvent); 363 m_nDropEvent = Application::PostUserEvent(LINK(this, OTableWindowListBox, DropHdl)); 364 365 return DND_ACTION_LINK; 366 } 367 return DND_ACTION_NONE; 368 } 369 370 //------------------------------------------------------------------------------ 371 void OTableWindowListBox::LoseFocus() 372 { 373 if(m_pTabWin) 374 m_pTabWin->setActive(sal_False); 375 SvTreeListBox::LoseFocus(); 376 } 377 378 //------------------------------------------------------------------------------ 379 void OTableWindowListBox::GetFocus() 380 { 381 if(m_pTabWin) 382 m_pTabWin->setActive(); 383 384 if (GetCurEntry() != NULL) 385 { 386 if ( GetSelectionCount() == 0 || GetCurEntry() != FirstSelected() ) 387 { 388 if ( FirstSelected() ) 389 Select(FirstSelected(), sal_False); 390 Select(GetCurEntry(), sal_True); 391 } 392 else 393 ShowFocusRect(FirstSelected()); 394 } 395 SvTreeListBox::GetFocus(); 396 } 397 398 //------------------------------------------------------------------------------ 399 IMPL_LINK( OTableWindowListBox, OnDoubleClick, SvTreeListBox *, /*pBox*/ ) 400 { 401 // meinem Elter Bescheid sagen 402 Window* pParent = Window::GetParent(); 403 DBG_ASSERT(pParent != NULL, "OTableWindowListBox::OnDoubleClick : habe kein Parent !"); 404 405 static_cast<OTableWindow*>(pParent)->OnEntryDoubleClicked(GetHdlEntry()); 406 407 return 0; 408 } 409 // ----------------------------------------------------------------------------- 410 void OTableWindowListBox::Command(const CommandEvent& rEvt) 411 { 412 switch (rEvt.GetCommand()) 413 { 414 case COMMAND_CONTEXTMENU: 415 { 416 static_cast<OTableWindow*>(Window::GetParent())->Command(rEvt); 417 break; 418 } 419 default: 420 SvTreeListBox::Command(rEvt); 421 } 422 } 423 // ----------------------------------------------------------------------------- 424