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_svtools.hxx"
26 #include <svtools/roadmap.hxx>
27 
28 #ifndef _STRING_HXX
29 #define _STRING_HXX
30 #endif
31 
32 #include <vector>
33 #include <algorithm>
34 #include <vcl/bitmap.hxx>
35 #include <tools/color.hxx>
36 #include <memory>
37 
38 #define ROADMAP_INDENT_X        4
39 #define ROADMAP_INDENT_Y        27
40 #define ROADMAP_ITEM_DISTANCE_Y 6
41 #define RMINCOMPLETE        -1
42 #define NADDITEM            1
43 #define INCOMPLETELABEL     ::String::CreateFromAscii("...")        // TODO: Cast to String
44 
45 //.........................................................................
46 namespace svt
47 {
48 //.........................................................................
49 
50     typedef std::vector< ::rtl::OUString > S_Vector;
51     typedef std::vector< RoadmapItem* > HL_Vector;
52 
53 	//=====================================================================
54 	//= ColorChanger
55 	//=====================================================================
56 	class IDLabel :  public FixedText
57 	{
58 	public:
59 		IDLabel( Window* _pParent, WinBits _nWinStyle = 0 );
60 		~IDLabel( );
61 		virtual void	DataChanged( const DataChangedEvent& rDCEvt );
62 	};
63 
64 	//=====================================================================
65 	//= ColorChanger
66 	//=====================================================================
67 	class ColorChanger
68 	{
69 	protected:
70 		OutputDevice*	m_pDev;
71 
72 	public:
ColorChanger(OutputDevice * _pDev,const Color & _rNewLineColor,const Color & _rNewFillColor)73 		ColorChanger( OutputDevice* _pDev, const Color& _rNewLineColor, const Color& _rNewFillColor )
74 			:m_pDev( _pDev )
75 		{
76 			m_pDev->Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
77 			m_pDev->SetLineColor( _rNewLineColor );
78 			m_pDev->SetFillColor( _rNewFillColor );
79 		}
80 
~ColorChanger()81 		~ColorChanger()
82 		{
83 			m_pDev->Pop();
84 		}
85 	};
86 
87 	//=====================================================================
88 	//= RoadmapItem
89 	//=====================================================================
90 	class RoadmapItem : public RoadmapTypes
91 	{
92 	private:
93 		IDLabel*                mpID;
94 		HyperLabel*             mpDescription;
95         const Size              m_aItemPlayground;
96 
97 	public:
98 		RoadmapItem( ORoadmap& _rParent, const Size& _rItemPlayground );
99 		~RoadmapItem( );
100 
101         void					SetID( sal_Int16 _ID );
102         sal_Int16				GetID() const;
103 
104         void					SetIndex( ItemIndex _Index );
105         ItemIndex               GetIndex() const;
106 
107         void					SetLabel( const ::rtl::OUString& _rText );
108         ::rtl::OUString			GetLabel( );
109 
110 		void					Update( ItemIndex _RMIndex, const ::rtl::OUString& _rText );
111 
112         void					SetPosition( RoadmapItem* OldHyperLabel );
113 
114 		void					ToggleBackgroundColor( const Color& _rGBColor );
115         void					SetInteractive( sal_Bool _bInteractive );
116 
117         void					SetClickHdl( const Link& rLink );
118         const Link&				GetClickHdl() const;
119 		void					SetZOrder( RoadmapItem* pRefRoadmapHyperLabel, sal_uInt16 nFlags );
120 		void					Enable( sal_Bool bEnable = sal_True);
121 		sal_Bool					IsEnabled() const;
122 		void					GrabFocus();
123 
124         bool                    Contains( const Window* _pWindow ) const;
125 
GetDescriptionHyperLabel() const126 		HyperLabel*				GetDescriptionHyperLabel() const { return mpDescription; }
127 
128     private:
129         void                    ImplUpdateIndex( const ItemIndex _nIndex );
130         void                    ImplUpdatePosSize();
131 	};
132 
133 	//=====================================================================
134 	//= RoadmapImpl
135 	//=====================================================================
136     class RoadmapImpl : public RoadmapTypes
137 	{
138 	protected:
139         const ORoadmap&     m_rAntiImpl;
140         Link                m_aSelectHdl;
141 		BitmapEx	        m_aPicture;
142         HL_Vector           m_aRoadmapSteps;
143         ItemId              m_iCurItemID;
144         sal_Bool            m_bInteractive;
145         sal_Bool            m_bComplete;
146         Size                m_aItemSizePixel;
147 
148 	public:
RoadmapImpl(const ORoadmap & _rAntiImpl)149         RoadmapImpl( const ORoadmap& _rAntiImpl )
150             :m_rAntiImpl( _rAntiImpl )
151             ,m_iCurItemID( -1 )
152             ,m_bInteractive( sal_True )
153             ,m_bComplete( sal_True )
154         {
155         }
156 
157         RoadmapItem* InCompleteHyperLabel;
158 
addHyperLabel(RoadmapItem * _rRoadmapStep)159         void			    addHyperLabel( RoadmapItem*  _rRoadmapStep ) { m_aRoadmapSteps.push_back(_rRoadmapStep); }
160 
getHyperLabels()161         HL_Vector&	        getHyperLabels() { return m_aRoadmapSteps; }
getHyperLabels() const162 		const HL_Vector&	getHyperLabels() const { return m_aRoadmapSteps; }
163 
insertHyperLabel(ItemIndex _Index,RoadmapItem * _rRoadmapStep)164         void                insertHyperLabel( ItemIndex _Index, RoadmapItem* _rRoadmapStep ) { m_aRoadmapSteps.insert( m_aRoadmapSteps.begin() + _Index, _rRoadmapStep ); }
165 
getItemCount() const166         ItemIndex           getItemCount() const { return m_aRoadmapSteps.size();}
167 
setCurItemID(ItemId i)168         void                setCurItemID( ItemId i ) {m_iCurItemID = i; }
getCurItemID() const169         ItemId              getCurItemID() const { return m_iCurItemID; }
170 
setInteractive(const sal_Bool _bInteractive)171         void                setInteractive(const sal_Bool _bInteractive) {m_bInteractive = _bInteractive; }
isInteractive() const172         sal_Bool            isInteractive() const { return m_bInteractive; };
173 
setComplete(const sal_Bool _bComplete)174         void                setComplete(const sal_Bool _bComplete) {m_bComplete = _bComplete; }
isComplete() const175         sal_Bool            isComplete() const { return m_bComplete; };
176 
setPicture(const BitmapEx & _rPic)177 		void			    setPicture( const BitmapEx& _rPic ) { m_aPicture = _rPic; }
getPicture() const178 		const BitmapEx&	    getPicture( ) const { return m_aPicture; }
179 
setSelectHdl(const Link & _rHdl)180         void			    setSelectHdl( const Link& _rHdl ) { m_aSelectHdl = _rHdl; }
getSelectHdl() const181 		const Link&	        getSelectHdl( ) const { return m_aSelectHdl; }
182 
183         void                initItemSize();
getItemSize() const184         const Size&         getItemSize() const { return m_aItemSizePixel; }
185 
removeHyperLabel(ItemIndex _Index)186         void removeHyperLabel( ItemIndex _Index )
187         {
188             if ( ( _Index > -1 ) && ( _Index < getItemCount() ) )
189             {
190                 delete m_aRoadmapSteps[_Index];
191                 m_aRoadmapSteps.erase( m_aRoadmapSteps.begin() + _Index);
192             }
193         }
194 	};
195 
196 
197 	//=====================================================================
198 	//= Roadmap
199 	//=====================================================================
200 	//---------------------------------------------------------------------
initItemSize()201     void RoadmapImpl::initItemSize()
202     {
203         Size aLabelSize( m_rAntiImpl.GetOutputSizePixel() );
204         aLabelSize.Height() = m_rAntiImpl.LogicToPixel( Size( 0, LABELBASEMAPHEIGHT ), MAP_APPFONT ).Height();
205         aLabelSize.Width() -= m_rAntiImpl.LogicToPixel( Size( 2 * ROADMAP_INDENT_X, 0 ), MAP_APPFONT ).Width();
206         m_aItemSizePixel = aLabelSize;
207     }
208 
209 	//=====================================================================
210 	//= Roadmap
211 	//=====================================================================
212 	//---------------------------------------------------------------------
ORoadmap(Window * _pParent,const ResId & _rId)213 	ORoadmap::ORoadmap( Window* _pParent, const ResId& _rId )
214         :Control( _pParent, _rId )
215 		,m_pImpl( new RoadmapImpl( *this ) )
216 	{
217 		implInit();
218 	}
219 
220 	//---------------------------------------------------------------------
ORoadmap(Window * _pParent,WinBits _nWinStyle)221 	ORoadmap::ORoadmap( Window* _pParent, WinBits _nWinStyle )
222 		:Control( _pParent, _nWinStyle )
223 		,m_pImpl( new RoadmapImpl( *this ) )
224 
225     {
226         implInit();
227 	}
228 
229 	//---------------------------------------------------------------------
implInit()230 	void ORoadmap::implInit()
231 	{
232 		const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
233 		Color aTextColor = rStyleSettings.GetFieldTextColor();
234         Font aFont = GetFont( );
235 		aFont.SetColor( aTextColor );
236 		aFont.SetWeight( WEIGHT_BOLD );
237         aFont.SetUnderline( UNDERLINE_SINGLE );
238 		SetFont( aFont );
239 		SetBackground( Wallpaper( rStyleSettings.GetFieldColor() ) );
240         m_pImpl->InCompleteHyperLabel = NULL;
241         m_pImpl->setCurItemID(-1 );
242         m_pImpl->setComplete( sal_True );
243 
244         // Roadmap control should be reachable as one unit with a Tab key
245         // the next Tab key should spring out of the control.
246         // To reach it the control itself should get focus and set it
247         // on entries. The entries themself should not be reachable with
248         // the Tab key directly. So each entry should have WB_NOTABSTOP.
249         //
250         // In other words the creator should create the control with the following
251         // flags:
252         // SetStyle( ( GetStyle() | WB_TABSTOP ) & ~WB_DIALOGCONTROL );
253 
254 // TODO: if somebody sets a new font from outside (OutputDevice::SetFont), we would have to react
255 // on this with calculating a new bold font.
256 // Unfortunately, the OutputDevice does not offer a notify mechanism for a changed font.
257 // So settings the font from outside is simply a forbidded scenario at the moment
258         EnableMapMode( sal_False );
259 	}
260 
261 	//---------------------------------------------------------------------
~ORoadmap()262 	ORoadmap::~ORoadmap( )
263 	{
264         HL_Vector aItemsCopy = m_pImpl->getHyperLabels();
265         m_pImpl->getHyperLabels().clear();
266         for ( HL_Vector::iterator i = aItemsCopy.begin(); i< aItemsCopy.end(); ++i )
267         {
268             delete *i;
269         }
270         if ( ! m_pImpl->isComplete() )
271             delete m_pImpl->InCompleteHyperLabel;
272 		delete m_pImpl;
273         m_pImpl = NULL;
274     }
275 
276 
GetCurrentRoadmapItemID() const277     RoadmapTypes::ItemId ORoadmap::GetCurrentRoadmapItemID() const
278     {
279         return m_pImpl->getCurItemID();
280     }
281 
282 
GetPreviousHyperLabel(ItemIndex _Index)283 	RoadmapItem* ORoadmap::GetPreviousHyperLabel( ItemIndex _Index)
284 	{
285 		RoadmapItem* pOldItem = NULL;
286 		if ( _Index > 0 )
287 			pOldItem = m_pImpl->getHyperLabels().at( _Index - 1 );
288 		return pOldItem;
289 	}
290 
291 
292    	//---------------------------------------------------------------------
293 
InsertHyperLabel(ItemIndex _Index,const::rtl::OUString & _sLabel,ItemId _RMID,sal_Bool _bEnabled)294     RoadmapItem* ORoadmap::InsertHyperLabel( ItemIndex _Index, const ::rtl::OUString& _sLabel, ItemId _RMID, sal_Bool _bEnabled)
295     {
296         if ( m_pImpl->getItemCount() == 0 )
297             m_pImpl->initItemSize();
298 
299         RoadmapItem* pItem = NULL;
300         RoadmapItem* pOldItem = GetPreviousHyperLabel( _Index );
301 
302         pItem = new RoadmapItem( *this, m_pImpl->getItemSize() );
303         if ( _RMID != RMINCOMPLETE )
304         {
305             pItem->SetInteractive( m_pImpl->isInteractive() );
306             m_pImpl->insertHyperLabel( _Index, pItem );
307         }
308         else
309         {
310             pItem->SetInteractive( sal_False );
311 		}
312         pItem->SetPosition( pOldItem );
313         pItem->Update( _Index, _sLabel );
314         pItem->SetClickHdl(LINK( this, ORoadmap, ImplClickHdl ) );
315         pItem->SetID( _RMID );
316         pItem->SetIndex( _Index );
317         if (!_bEnabled)
318             pItem->Enable( _bEnabled );
319         return pItem;
320     }
321 
322 	//---------------------------------------------------------------------
SetRoadmapBitmap(const BitmapEx & _rBmp,sal_Bool _bInvalidate)323 	void ORoadmap::SetRoadmapBitmap( const BitmapEx& _rBmp, sal_Bool _bInvalidate )
324 	{
325 		m_pImpl->setPicture( _rBmp );
326 		if ( _bInvalidate )
327 			Invalidate( );
328 	}
329 
330 	//---------------------------------------------------------------------
GetRoadmapBitmap() const331 	const BitmapEx& ORoadmap::GetRoadmapBitmap( ) const
332 	{
333 		return m_pImpl->getPicture( );
334 	}
335 
336 	//---------------------------------------------------------------------
SetRoadmapInteractive(sal_Bool _bInteractive)337     void ORoadmap::SetRoadmapInteractive( sal_Bool _bInteractive )
338     {
339         m_pImpl->setInteractive( _bInteractive );
340 
341         const HL_Vector& rItems = m_pImpl->getHyperLabels();
342         for (   HL_Vector::const_iterator i = rItems.begin();
343                 i < rItems.end();
344                 ++i
345             )
346         {
347             (*i)->SetInteractive( _bInteractive );
348         }
349     }
350 
351 	//---------------------------------------------------------------------
IsRoadmapInteractive()352     sal_Bool ORoadmap::IsRoadmapInteractive()
353     {
354         return m_pImpl->isInteractive();
355     }
356 
357 	//---------------------------------------------------------------------
SetRoadmapComplete(sal_Bool _bComplete)358     void ORoadmap::SetRoadmapComplete( sal_Bool _bComplete )
359     {
360         sal_Bool bWasComplete = m_pImpl->isComplete();
361         m_pImpl->setComplete( _bComplete );
362         if ( _bComplete )
363         {
364             if ( m_pImpl->InCompleteHyperLabel != NULL)
365             {
366                 delete m_pImpl->InCompleteHyperLabel;
367                 m_pImpl->InCompleteHyperLabel = NULL;
368             }
369         }
370         else if ( bWasComplete )
371             m_pImpl->InCompleteHyperLabel = InsertHyperLabel( m_pImpl->getItemCount(), ::String::CreateFromAscii( "..." ), RMINCOMPLETE );
372     }
373 
374 	//---------------------------------------------------------------------
UpdatefollowingHyperLabels(ItemIndex _nIndex)375     void ORoadmap::UpdatefollowingHyperLabels( ItemIndex _nIndex )
376     {
377         const HL_Vector& rItems = m_pImpl->getHyperLabels();
378         if ( _nIndex < (ItemIndex)rItems.size() )
379         {
380             RoadmapItem* pItem = NULL;
381             for (   HL_Vector::const_iterator i = rItems.begin() + _nIndex;
382                     i< rItems.end();
383                     ++i, ++_nIndex
384                 )
385             {
386                 pItem = *i;
387 
388                 pItem->SetIndex( _nIndex );
389                 pItem->SetPosition( GetPreviousHyperLabel( _nIndex ) );
390             }
391         }
392         if ( ! m_pImpl->isComplete() )
393         {
394 	        RoadmapItem* pOldItem = GetPreviousHyperLabel( m_pImpl->getItemCount() );
395             m_pImpl->InCompleteHyperLabel->SetPosition( pOldItem );
396             m_pImpl->InCompleteHyperLabel->Update( m_pImpl->getItemCount(), ::String::CreateFromAscii("...") );
397         }
398     }
399 
400 	//---------------------------------------------------------------------
ReplaceRoadmapItem(ItemIndex _Index,const::rtl::OUString & _RoadmapItem,ItemId _RMID,sal_Bool _bEnabled)401     void ORoadmap::ReplaceRoadmapItem( ItemIndex _Index, const ::rtl::OUString& _RoadmapItem, ItemId _RMID, sal_Bool _bEnabled )
402     {
403         RoadmapItem* pItem = GetByIndex( _Index);
404         if ( pItem != NULL )
405         {
406             pItem->Update( _Index,  _RoadmapItem );
407             pItem->SetID( _RMID );
408             pItem->Enable( _bEnabled );
409         }
410     }
411 
412 	//---------------------------------------------------------------------
GetItemCount() const413     RoadmapTypes::ItemIndex ORoadmap::GetItemCount() const
414     {
415         return m_pImpl->getItemCount();
416     }
417 
418 	//---------------------------------------------------------------------
GetItemID(ItemIndex _nIndex) const419     RoadmapTypes::ItemId ORoadmap::GetItemID( ItemIndex _nIndex ) const
420     {
421         const RoadmapItem* pHyperLabel = GetByIndex( _nIndex );
422         if ( pHyperLabel )
423             return pHyperLabel->GetID();
424         return -1;
425     }
426 
427 	//---------------------------------------------------------------------
GetItemIndex(ItemId _nID) const428     RoadmapTypes::ItemIndex ORoadmap::GetItemIndex( ItemId _nID ) const
429     {
430         ItemId nLocID = 0;
431         const HL_Vector& rItems = m_pImpl->getHyperLabels();
432         for (   HL_Vector::const_iterator i = rItems.begin();
433                 i < rItems.end();
434                 ++i
435             )
436         {
437             nLocID = (*i)->GetID();
438             if ( nLocID == _nID )
439                 return ItemIndex( i - rItems.begin() );
440         }
441         return -1;
442     }
443 
444 	//---------------------------------------------------------------------
InsertRoadmapItem(ItemIndex _Index,const::rtl::OUString & _RoadmapItem,ItemId _nUniqueId,sal_Bool _bEnabled)445     void ORoadmap::InsertRoadmapItem( ItemIndex _Index, const ::rtl::OUString& _RoadmapItem, ItemId _nUniqueId, sal_Bool _bEnabled )
446     {
447         InsertHyperLabel( _Index, _RoadmapItem, _nUniqueId, _bEnabled );
448             // Todo: YPos is superfluous, if items are always appended
449         UpdatefollowingHyperLabels( _Index + 1 );
450     }
451 
452 	//---------------------------------------------------------------------
DeleteRoadmapItem(ItemIndex _Index)453     void ORoadmap::DeleteRoadmapItem( ItemIndex _Index )
454     {
455         if ( m_pImpl->getItemCount() > 0 && ( _Index > -1)  &&  ( _Index < m_pImpl->getItemCount() ) )
456         {
457             m_pImpl->removeHyperLabel( _Index );
458             UpdatefollowingHyperLabels( _Index );
459         }
460     }
461 
462 	//---------------------------------------------------------------------
IsRoadmapComplete() const463     sal_Bool ORoadmap::IsRoadmapComplete( ) const
464     {
465         return m_pImpl->isComplete();
466     }
467 
468 	//---------------------------------------------------------------------
IsRoadmapItemEnabled(ItemId _nItemId,ItemIndex _nStartIndex) const469     sal_Bool ORoadmap::IsRoadmapItemEnabled( ItemId _nItemId, ItemIndex _nStartIndex  ) const
470     {
471         const RoadmapItem* _pLabelItem = GetByID( _nItemId, _nStartIndex  );
472         return _pLabelItem ? _pLabelItem->IsEnabled() : sal_False;
473     }
474 
475 	//---------------------------------------------------------------------
EnableRoadmapItem(ItemId _nItemId,sal_Bool _bEnable,ItemIndex _nStartIndex)476     void ORoadmap::EnableRoadmapItem( ItemId _nItemId, sal_Bool _bEnable, ItemIndex _nStartIndex )
477     {
478         RoadmapItem* pItem = GetByID( _nItemId, _nStartIndex );
479         if ( pItem != NULL )
480             pItem->Enable( _bEnable );
481     }
482 
483 	//---------------------------------------------------------------------
ChangeRoadmapItemLabel(ItemId _nID,const::rtl::OUString & _sLabel,ItemIndex _nStartIndex)484     void ORoadmap::ChangeRoadmapItemLabel( ItemId _nID, const ::rtl::OUString& _sLabel, ItemIndex _nStartIndex )
485     {
486         RoadmapItem* pItem = GetByID( _nID, _nStartIndex );
487         if ( pItem != NULL )
488 		{
489             pItem->Update( pItem->GetIndex(), _sLabel );
490 
491             const HL_Vector& rItems = m_pImpl->getHyperLabels();
492 			for (   HL_Vector::const_iterator i = rItems.begin() + _nStartIndex;
493                     i < rItems.end();
494                     ++i
495                 )
496 			{
497 				(*i)->SetPosition( GetPreviousHyperLabel( i - rItems.begin() ) );
498 			}
499 		}
500     }
501 
502 	//---------------------------------------------------------------------
503 
GetRoadmapItemLabel(ItemId _nID,ItemIndex _nStartIndex)504     ::rtl::OUString ORoadmap::GetRoadmapItemLabel( ItemId _nID, ItemIndex _nStartIndex )
505     {
506         RoadmapItem* pItem = GetByID( _nID, _nStartIndex );
507         if ( pItem != NULL )
508             return pItem->GetLabel();
509         else
510             return ::rtl::OUString();
511     }
512 
513 	//---------------------------------------------------------------------
ChangeRoadmapItemID(ItemId _nID,ItemId _NewID,ItemIndex _nStartIndex)514     void ORoadmap::ChangeRoadmapItemID( ItemId _nID, ItemId _NewID, ItemIndex _nStartIndex )
515     {
516         RoadmapItem* pItem = GetByID( _nID, _nStartIndex );
517         if ( pItem != NULL )
518             pItem->SetID( _NewID );
519     }
520 
521 	//---------------------------------------------------------------------
GetByID(ItemId _nID,ItemIndex _nStartIndex)522     RoadmapItem* ORoadmap::GetByID( ItemId _nID, ItemIndex _nStartIndex)
523     {
524         ItemId nLocID = 0;
525         const HL_Vector& rItems = m_pImpl->getHyperLabels();
526         for (   HL_Vector::const_iterator i = rItems.begin() + _nStartIndex;
527                 i < rItems.end();
528                 ++i
529             )
530         {
531             nLocID = (*i)->GetID();
532             if ( nLocID == _nID )
533                 return *i;
534         }
535         return NULL;
536     }
537 
538 	//---------------------------------------------------------------------
GetByID(ItemId _nID,ItemIndex _nStartIndex) const539     const RoadmapItem* ORoadmap::GetByID( ItemId _nID, ItemIndex _nStartIndex  ) const
540     {
541         return const_cast< ORoadmap* >( this )->GetByID( _nID, _nStartIndex );
542     }
543 
544 	//---------------------------------------------------------------------
GetByIndex(ItemIndex _nItemIndex)545     RoadmapItem* ORoadmap::GetByIndex( ItemIndex _nItemIndex)
546     {
547         const HL_Vector& rItems = m_pImpl->getHyperLabels();
548         if ( ( _nItemIndex > -1 ) && ( _nItemIndex < (ItemIndex)rItems.size() ) )
549         {
550             return rItems.at( _nItemIndex );
551         }
552         return NULL;
553     }
554 
555     //---------------------------------------------------------------------
GetByIndex(ItemIndex _nItemIndex) const556     const RoadmapItem* ORoadmap::GetByIndex( ItemIndex _nItemIndex ) const
557     {
558         return const_cast< ORoadmap* >( this )->GetByIndex( _nItemIndex );
559     }
560 
561 	//---------------------------------------------------------------------
GetNextAvailableItemId(ItemIndex _nNewIndex)562     RoadmapTypes::ItemId ORoadmap::GetNextAvailableItemId( ItemIndex _nNewIndex )
563     {
564         RoadmapItem* pItem = NULL;
565 
566         ItemIndex searchIndex = ++_nNewIndex;
567         while ( searchIndex < m_pImpl->getItemCount() )
568         {
569             pItem = GetByIndex( searchIndex );
570             if ( pItem->IsEnabled() )
571                 return pItem->GetID( );
572 
573             ++searchIndex;
574         }
575         return -1;
576     }
577 
578 	//---------------------------------------------------------------------
GetPreviousAvailableItemId(ItemIndex _nNewIndex)579     RoadmapTypes::ItemId ORoadmap::GetPreviousAvailableItemId( ItemIndex _nNewIndex )
580     {
581         RoadmapItem* pItem = NULL;
582         ItemIndex searchIndex = --_nNewIndex;
583         while ( searchIndex > -1 )
584         {
585             pItem = GetByIndex( searchIndex );
586             if ( pItem->IsEnabled() )
587                 return pItem->GetID( );
588 
589             searchIndex--;
590         }
591         return -1;
592     }
593 
594 	//---------------------------------------------------------------------
DeselectOldRoadmapItems()595     void ORoadmap::DeselectOldRoadmapItems()
596     {
597         const HL_Vector& rItems = m_pImpl->getHyperLabels();
598         for (   HL_Vector::const_iterator i = rItems.begin();
599                 i < rItems.end();
600                 ++i
601             )
602         {
603             (*i)->ToggleBackgroundColor( COL_TRANSPARENT );
604         }
605     }
606 
607 	//---------------------------------------------------------------------
SetItemSelectHdl(const Link & _rHdl)608     void ORoadmap::SetItemSelectHdl( const Link& _rHdl )
609     {
610         m_pImpl->setSelectHdl( _rHdl );
611     }
612 
613 	//---------------------------------------------------------------------
GetItemSelectHdl() const614     Link ORoadmap::GetItemSelectHdl( ) const
615     {
616         return m_pImpl->getSelectHdl();
617     }
618 
619 	//---------------------------------------------------------------------
Select()620     void ORoadmap::Select()
621     {
622         GetItemSelectHdl().Call( this );
623         CallEventListeners( VCLEVENT_ROADMAP_ITEMSELECTED );
624     }
625 
626     //---------------------------------------------------------------------
GetFocus()627     void ORoadmap::GetFocus()
628 	{
629         RoadmapItem* pCurHyperLabel = GetByID( GetCurrentRoadmapItemID() );
630         if ( pCurHyperLabel != NULL )
631 		    pCurHyperLabel->GrabFocus();
632 	}
633 
634 	//---------------------------------------------------------------------
SelectRoadmapItemByID(ItemId _nNewID)635     sal_Bool ORoadmap::SelectRoadmapItemByID( ItemId _nNewID )
636     {
637         DeselectOldRoadmapItems();
638         RoadmapItem* pItem = GetByID( _nNewID );
639         if ( pItem != NULL )
640         {
641             if ( pItem->IsEnabled() )
642             {
643 				const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
644                 pItem->ToggleBackgroundColor( rStyleSettings.GetHighlightColor() ); //HighlightColor
645 
646 				pItem->GrabFocus();
647                 m_pImpl->setCurItemID(_nNewID);
648 
649                 Select();
650                 return sal_True;
651             }
652         }
653         return sal_False;
654     }
655 
656 	//---------------------------------------------------------------------
Paint(const Rectangle & _rRect)657 	void ORoadmap::Paint( const Rectangle& _rRect )
658 	{
659 		Control::Paint( _rRect );
660 
661 
662 		// draw the bitmap
663 		if ( !!m_pImpl->getPicture() )
664 		{
665 			Size aBitmapSize = m_pImpl->getPicture().GetSizePixel();
666 			Size aMySize = GetOutputSizePixel();
667 
668 			Point aBitmapPos( aMySize.Width() - aBitmapSize.Width(),  aMySize.Height() - aBitmapSize.Height() );
669 
670 			// draw it
671 			DrawBitmapEx( aBitmapPos, m_pImpl->getPicture() );
672 		}
673 
674         //.................................................................
675 		// draw the headline
676         DrawHeadline();
677 	}
678 
679 	//---------------------------------------------------------------------
DrawHeadline()680     void ORoadmap::DrawHeadline()
681 	{
682 		Point aTextPos = LogicToPixel( Point( ROADMAP_INDENT_X, 8 ), MAP_APPFONT );
683 
684 		Size aOutputSize( GetOutputSizePixel() );
685 
686 		// draw it
687 		DrawText( Rectangle( aTextPos, aOutputSize ), GetText(), TEXT_DRAW_LEFT | TEXT_DRAW_TOP | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK );
688         DrawTextLine( aTextPos, aOutputSize.Width(), STRIKEOUT_NONE, UNDERLINE_SINGLE, UNDERLINE_NONE, sal_False );
689 		const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
690         SetLineColor( rStyleSettings.GetFieldTextColor());
691 		SetTextColor(rStyleSettings.GetFieldTextColor());
692 	}
693 
694 	//---------------------------------------------------------------------
GetByPointer(Window * pWindow)695     RoadmapItem* ORoadmap::GetByPointer(Window* pWindow)
696     {
697         const HL_Vector& rItems = m_pImpl->getHyperLabels();
698         for (   HL_Vector::const_iterator i = rItems.begin();
699                 i < rItems.end();
700                 ++i
701             )
702         {
703 			if ( (*i)->Contains( pWindow ) )
704                 return *i;
705         }
706         return NULL;
707     }
708 
709 	//---------------------------------------------------------------------
PreNotify(NotifyEvent & _rNEvt)710     long ORoadmap::PreNotify( NotifyEvent& _rNEvt )
711     {
712         // capture KeyEvents for taskpane cycling
713         if ( _rNEvt.GetType() == EVENT_KEYINPUT )
714         {
715             Window* pWindow = _rNEvt.GetWindow();
716             RoadmapItem* pItem = GetByPointer( pWindow );
717             if ( pItem != NULL )
718             {
719                 sal_Int16 nKeyCode = _rNEvt.GetKeyEvent()->GetKeyCode().GetCode();
720 		        switch( nKeyCode )
721 		        {
722 			        case KEY_UP:
723                         {   // Note: Performancewise this is not optimal, because we search for an ID in the labels
724                             //       and afterwards we search again for a label with the appropriate ID ->
725                             //       unnecessarily we search twice!!!
726                             ItemId nPrevItemID = GetPreviousAvailableItemId( pItem->GetIndex() );
727                             if ( nPrevItemID != -1 )
728                                 return SelectRoadmapItemByID( nPrevItemID );
729                         }
730                         break;
731 			        case KEY_DOWN:
732                         {
733                             ItemId nNextItemID = GetNextAvailableItemId( pItem->GetIndex() );
734                             if ( nNextItemID != -1 )
735                                 return SelectRoadmapItemByID( nNextItemID );
736                         }
737                         break;
738                     case KEY_SPACE:
739                         return SelectRoadmapItemByID( pItem->GetID() );
740                 }
741             }
742         }
743         return Window::PreNotify( _rNEvt );
744     }
745 
746 	//---------------------------------------------------------------------
IMPL_LINK(ORoadmap,ImplClickHdl,HyperLabel *,_CurHyperLabel)747   	IMPL_LINK(ORoadmap, ImplClickHdl, HyperLabel*, _CurHyperLabel)
748 	{
749        return SelectRoadmapItemByID( _CurHyperLabel->GetID() );
750     }
751 
752 
753 
754     //---------------------------------------------------------------------
DataChanged(const DataChangedEvent & rDCEvt)755 	void ORoadmap::DataChanged( const DataChangedEvent& rDCEvt )
756 	{
757 		if ((( rDCEvt.GetType() == DATACHANGED_SETTINGS	)	||
758 			( rDCEvt.GetType() == DATACHANGED_DISPLAY	))	&&
759 			( rDCEvt.GetFlags() & SETTINGS_STYLE		))
760 		{
761 			const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
762 			SetBackground( Wallpaper( rStyleSettings.GetFieldColor() ) );
763 			Color aTextColor = rStyleSettings.GetFieldTextColor();
764 			Font aFont = GetFont();
765 			aFont.SetColor( aTextColor );
766 			SetFont( aFont );
767 			RoadmapTypes::ItemId curItemID = GetCurrentRoadmapItemID();
768 			RoadmapItem* pLabelItem = GetByID( curItemID );
769             if ( pLabelItem != NULL )
770                 pLabelItem->ToggleBackgroundColor(rStyleSettings.GetHighlightColor());
771 			Invalidate();
772 		}
773 	}
774 
775 
776     //---------------------------------------------------------------------
RoadmapItem(ORoadmap & _rParent,const Size & _rItemPlayground)777     RoadmapItem::RoadmapItem( ORoadmap& _rParent, const Size& _rItemPlayground )
778         :m_aItemPlayground( _rItemPlayground )
779 	{
780 		mpID = new IDLabel( &_rParent, WB_WORDBREAK );
781 		mpID->SetTextColor( mpID->GetSettings().GetStyleSettings().GetFieldTextColor( ) );
782         mpID->Show();
783 		mpDescription = new HyperLabel( &_rParent, WB_NOTABSTOP | WB_WORDBREAK );
784         mpDescription->Show();
785 	}
786 
787     //---------------------------------------------------------------------
Contains(const Window * _pWindow) const788     bool RoadmapItem::Contains( const Window* _pWindow ) const
789     {
790         return ( mpID == _pWindow ) || ( mpDescription == _pWindow );
791     }
792 
793     //---------------------------------------------------------------------
GrabFocus()794     void RoadmapItem::GrabFocus()
795 	{
796         if ( mpDescription )
797             mpDescription->GrabFocus();
798 	}
799 
800     //---------------------------------------------------------------------
SetInteractive(sal_Bool _bInteractive)801 	void RoadmapItem::SetInteractive( sal_Bool _bInteractive )
802 	{
803         if ( mpDescription )
804 		mpDescription->SetInteractive(_bInteractive);
805 	}
806 
807     //---------------------------------------------------------------------
SetID(sal_Int16 _ID)808 	void RoadmapItem::SetID( sal_Int16 _ID )
809 	{
810         if ( mpDescription )
811 		    mpDescription->SetID(_ID);
812 	}
813 
814     //---------------------------------------------------------------------
GetID() const815 	sal_Int16 RoadmapItem::GetID() const
816 	{
817         return mpDescription ? mpDescription->GetID() : sal_Int16(-1);
818 	}
819 
820     //---------------------------------------------------------------------
ImplUpdateIndex(const ItemIndex _nIndex)821     void RoadmapItem::ImplUpdateIndex( const ItemIndex _nIndex )
822     {
823         if ( mpDescription )
824 		    mpDescription->SetIndex( _nIndex );
825 
826         if ( mpID )
827         {
828             ::rtl::OUString aIDText = ::rtl::OUString::valueOf( (sal_Int32)( _nIndex + 1 ) ) +  ::rtl::OUString::createFromAscii( "." );
829  		    mpID->SetText( aIDText );
830         }
831 
832         // update the geometry of both controls
833         ImplUpdatePosSize();
834     }
835 
836     //---------------------------------------------------------------------
SetIndex(ItemIndex _Index)837 	void RoadmapItem::SetIndex( ItemIndex _Index )
838 	{
839         ImplUpdateIndex( _Index );
840 	}
841 
842     //---------------------------------------------------------------------
GetIndex() const843     RoadmapTypes::ItemIndex RoadmapItem::GetIndex() const
844 	{
845         return mpDescription ? mpDescription->GetIndex() : ItemIndex(-1);
846 	}
847 
848     //---------------------------------------------------------------------
SetLabel(const::rtl::OUString & _rText)849 	void RoadmapItem::SetLabel( const ::rtl::OUString& _rText )
850 	{
851         if ( mpDescription )
852 		    mpDescription->SetText(_rText);
853 	}
854 
855     //---------------------------------------------------------------------
GetLabel()856 	::rtl::OUString RoadmapItem::GetLabel( )
857 	{
858         return mpDescription ? mpDescription->GetText() : String();
859 	}
860 
861     //---------------------------------------------------------------------
SetPosition(RoadmapItem * _pOldItem)862 	void RoadmapItem::SetPosition( RoadmapItem* _pOldItem )
863 	{
864 		Point aIDPos;
865 		if ( _pOldItem == NULL )
866 		{
867 			aIDPos = mpID->LogicToPixel( Point( ROADMAP_INDENT_X, ROADMAP_INDENT_Y ), MAP_APPFONT );
868 		}
869 		else
870 		{
871 			Size aOldSize = _pOldItem->GetDescriptionHyperLabel()->GetSizePixel();
872 
873             aIDPos = _pOldItem->mpID->GetPosPixel();
874             aIDPos.Y() += aOldSize.Height();
875             aIDPos.Y() += mpID->GetParent()->LogicToPixel( Size( 0, ROADMAP_ITEM_DISTANCE_Y ) ).Height();
876 		}
877 		mpID->SetPosPixel( aIDPos );
878 
879 		sal_Int32 nDescPos = aIDPos.X() + mpID->GetSizePixel().Width();
880 		mpDescription->SetPosPixel( Point( nDescPos, aIDPos.Y() ) );
881 	}
882 
883     //---------------------------------------------------------------------
SetZOrder(RoadmapItem * pRefRoadmapHyperLabel,sal_uInt16 nFlags)884 	void RoadmapItem::SetZOrder( RoadmapItem* pRefRoadmapHyperLabel, sal_uInt16 nFlags )
885 	{
886 		if (pRefRoadmapHyperLabel == NULL)
887 			mpDescription->SetZOrder( NULL, nFlags); //WINDOW_ZORDER_FIRST );
888 		else
889 			mpDescription->SetZOrder( pRefRoadmapHyperLabel->mpDescription, nFlags); //, WINDOW_ZORDER_BEHIND );
890 	}
891 
892     //---------------------------------------------------------------------
Enable(sal_Bool _bEnable)893 	void RoadmapItem::Enable( sal_Bool _bEnable)
894 	{
895 		mpID->Enable(_bEnable);
896 		mpDescription->Enable(_bEnable);
897 	}
898 
899     //---------------------------------------------------------------------
IsEnabled() const900 	sal_Bool RoadmapItem::IsEnabled() const
901 	{
902 		return mpID->IsEnabled();
903 	}
904 
905     //---------------------------------------------------------------------
ToggleBackgroundColor(const Color & _rGBColor)906 	void RoadmapItem::ToggleBackgroundColor( const Color& _rGBColor )
907 	{
908 		if (_rGBColor == COL_TRANSPARENT)
909 		{
910 			mpID->SetTextColor( mpID->GetSettings().GetStyleSettings().GetFieldTextColor( ) );
911 			mpID->SetControlBackground( COL_TRANSPARENT );
912 		}
913 		else
914 		{
915 			mpID->SetControlBackground( mpID->GetSettings().GetStyleSettings().GetHighlightColor() );
916 			mpID->SetTextColor( mpID->GetSettings().GetStyleSettings().GetHighlightTextColor( ) );
917 		}
918 		mpDescription->ToggleBackgroundColor(_rGBColor);
919 	}
920 
921     //---------------------------------------------------------------------
ImplUpdatePosSize()922     void RoadmapItem::ImplUpdatePosSize()
923     {
924         // calculate widths
925         long nIDWidth = mpID->GetTextWidth( mpID->GetText() );
926 		long nMaxIDWidth = mpID->GetTextWidth( ::rtl::OUString::createFromAscii( "100." ) );
927 		nIDWidth = ::std::min( nIDWidth, nMaxIDWidth );
928 
929         // check how many space the description would need
930         Size aDescriptionSize = mpDescription->CalcMinimumSize( m_aItemPlayground.Width() - nIDWidth );
931 
932         // position and size both controls
933         Size aIDSize( nIDWidth, aDescriptionSize.Height() );
934  		mpID->SetSizePixel( aIDSize );
935 
936         Point aIDPos = mpID->GetPosPixel();
937         mpDescription->SetPosPixel( Point( aIDPos.X() + nIDWidth, aIDPos.Y() ) );
938         mpDescription->SetSizePixel( aDescriptionSize );
939     }
940 
941     //---------------------------------------------------------------------
Update(ItemIndex _RMIndex,const::rtl::OUString & _rText)942 	void RoadmapItem::Update( ItemIndex _RMIndex, const ::rtl::OUString& _rText )
943 	{
944         // update description label
945         mpDescription->SetLabel( _rText );
946 
947         // update the index in both controls, which triggers updating the geometry of both
948         ImplUpdateIndex( _RMIndex );
949 	}
950 
951     //---------------------------------------------------------------------
~RoadmapItem()952 	RoadmapItem::~RoadmapItem( )
953 	{
954         {
955             ::std::auto_ptr<Control> aTemp(mpID);
956 		    mpID = NULL;
957         }
958         {
959             ::std::auto_ptr<Control> aTemp(mpDescription);
960 		    mpDescription = NULL;
961         }
962 	}
963 
964     //---------------------------------------------------------------------
SetClickHdl(const Link & rLink)965 	void RoadmapItem::SetClickHdl( const Link& rLink )
966 	{
967         if ( mpDescription )
968 		    mpDescription->SetClickHdl( rLink);
969 	}
970 
971     //---------------------------------------------------------------------
GetClickHdl() const972 	const Link& RoadmapItem::GetClickHdl( ) const
973 	{
974 		return mpDescription->GetClickHdl();
975 	}
976 
977 	//---------------------------------------------------------------------
IDLabel(Window * _pParent,WinBits _nWinStyle)978     IDLabel::IDLabel( Window* _pParent, WinBits _nWinStyle )
979 		:FixedText( _pParent, _nWinStyle )
980 	{
981 
982 	}
983 
984 	//---------------------------------------------------------------------
~IDLabel()985 	IDLabel::~IDLabel( )
986 	{
987 	}
988 
989 	//---------------------------------------------------------------------
DataChanged(const DataChangedEvent & rDCEvt)990 	void IDLabel::DataChanged( const DataChangedEvent& rDCEvt )
991 	{
992 		const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
993 		FixedText::DataChanged( rDCEvt );
994 		if ((( rDCEvt.GetType() == DATACHANGED_SETTINGS	)	||
995 			( rDCEvt.GetType() == DATACHANGED_DISPLAY	))	&&
996 			( rDCEvt.GetFlags() & SETTINGS_STYLE		))
997 		{
998 			const Color& rGBColor = GetControlBackground();
999 			if (rGBColor == COL_TRANSPARENT)
1000 				SetTextColor( rStyleSettings.GetFieldTextColor( ) );
1001 			else
1002 			{
1003 				SetControlBackground(rStyleSettings.GetHighlightColor());
1004 				SetTextColor( rStyleSettings.GetHighlightTextColor( ) );
1005 			}
1006 			Invalidate();
1007 		}
1008 	}
1009 
1010 
1011 
1012 
1013 //.........................................................................
1014 }	// namespace svt
1015 //.........................................................................
1016