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