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