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_chart2.hxx"
30 
31 #include "tp_RangeChooser.hxx"
32 #include "tp_RangeChooser.hrc"
33 #include "Strings.hrc"
34 #include "ResId.hxx"
35 #include "macros.hxx"
36 #include "NoWarningThisInCTOR.hxx"
37 #include "DataSourceHelper.hxx"
38 #include "DiagramHelper.hxx"
39 #include "ChartTypeTemplateProvider.hxx"
40 #include "DialogModel.hxx"
41 #include "RangeSelectionHelper.hxx"
42 #include <com/sun/star/awt/XTopWindow.hpp>
43 #include <com/sun/star/embed/EmbedStates.hpp>
44 #include <com/sun/star/embed/XComponentSupplier.hpp>
45 
46 namespace
47 {
48 void lcl_ShowChooserButton(
49     ::chart::RangeSelectionButton & rChooserButton,
50     Edit & rEditField,
51     sal_Bool bShow )
52 {
53     if( rChooserButton.IsVisible() != bShow )
54     {
55         rChooserButton.Show( bShow );
56         sal_Int32 nWidhtDiff = 10 + 2;
57         if( bShow )
58             nWidhtDiff = -nWidhtDiff;
59         Size aSize = rChooserButton.PixelToLogic( rEditField.GetSizePixel(), MAP_APPFONT );
60         aSize.setWidth( aSize.getWidth() + nWidhtDiff );
61         rEditField.SetSizePixel( rChooserButton.LogicToPixel( aSize, MAP_APPFONT ));
62     }
63 }
64 void lcl_enableRangeChoosing( bool bEnable, Dialog * pDialog )
65 {
66     if( pDialog )
67     {
68         pDialog->Show( bEnable ? sal_False : sal_True );
69         pDialog->SetModalInputMode( bEnable ? sal_False : sal_True );
70     }
71 }
72 void lcl_shiftControlY( Control & rControl, long nYOffset )
73 {
74     Point aPos( rControl.GetPosPixel());
75     aPos.setY( aPos.getY() + nYOffset );
76     rControl.SetPosPixel( aPos );
77 }
78 } // anonymous namespace
79 
80 //.............................................................................
81 namespace chart
82 {
83 //.............................................................................
84 using namespace ::com::sun::star;
85 using namespace ::com::sun::star::chart2;
86 
87 using ::com::sun::star::uno::Reference;
88 using ::com::sun::star::uno::Sequence;
89 
90 
91 RangeChooserTabPage::RangeChooserTabPage( Window* pParent
92         , DialogModel & rDialogModel
93         , ChartTypeTemplateProvider* pTemplateProvider
94         , Dialog * pParentDialog
95         , bool bHideDescription /* = false */ )
96 
97         : OWizardPage( pParent, SchResId(TP_RANGECHOOSER) )
98 
99         , m_aFT_Caption( this, SchResId( FT_CAPTION_FOR_WIZARD ) )
100         , m_aFT_Range( this, SchResId( FT_RANGE ) )
101         , m_aED_Range( this, SchResId( ED_RANGE ) )
102         , m_aIB_Range( this, SchResId( IB_RANGE ) )
103         , m_aRB_Rows( this, SchResId( RB_DATAROWS ) )
104         , m_aRB_Columns( this, SchResId( RB_DATACOLS ) )
105         , m_aCB_FirstRowAsLabel( this, SchResId( CB_FIRST_ROW_ASLABELS ) )
106         , m_aCB_FirstColumnAsLabel( this, SchResId( CB_FIRST_COLUMN_ASLABELS ) )
107         , m_nChangingControlCalls(0)
108         , m_bIsDirty(false)
109         , m_xDataProvider( 0 )
110         , m_aLastValidRangeString()
111         , m_xCurrentChartTypeTemplate(0)
112         , m_pTemplateProvider(pTemplateProvider)
113         , m_rDialogModel( rDialogModel )
114         , m_pParentDialog( pParentDialog )
115         , m_pTabPageNotifiable( dynamic_cast< TabPageNotifiable * >( pParentDialog ))
116 {
117     FreeResource();
118 
119     if( bHideDescription )
120     {
121         // note: the offset should be a negative value for shifting upwards, the
122         // 4 is for the offset difference between a wizard page and a tab-page
123         long nYOffset = - ( m_aFT_Range.GetPosPixel().getY() - m_aFT_Caption.GetPosPixel().getY() + 4 );
124         m_aFT_Caption.Hide();
125 
126         // shift all controls by the offset space saved by hiding the caption
127         lcl_shiftControlY( m_aFT_Range, nYOffset );
128         lcl_shiftControlY( m_aED_Range, nYOffset );
129         lcl_shiftControlY( m_aIB_Range, nYOffset );
130         lcl_shiftControlY( m_aRB_Rows, nYOffset );
131         lcl_shiftControlY( m_aRB_Columns, nYOffset );
132         lcl_shiftControlY( m_aCB_FirstRowAsLabel, nYOffset );
133         lcl_shiftControlY( m_aCB_FirstColumnAsLabel, nYOffset );
134     }
135     else
136     {
137         // make font of caption bold
138         Font aFont( m_aFT_Caption.GetControlFont() );
139         aFont.SetWeight( WEIGHT_BOLD );
140         m_aFT_Caption.SetControlFont( aFont );
141 
142         // no mnemonic
143         m_aFT_Caption.SetStyle( m_aFT_Caption.GetStyle() | WB_NOLABEL );
144     }
145 
146     this->SetText( String(SchResId(STR_PAGE_DATA_RANGE)) );
147     m_aIB_Range.SetQuickHelpText( String(SchResId(STR_TIP_SELECT_RANGE)) );
148 
149     // set defaults as long as DetectArguments does not work
150     m_aRB_Columns.Check();
151     m_aCB_FirstColumnAsLabel.Check();
152     m_aCB_FirstRowAsLabel.Check();
153 
154     // BM: Note, that the range selection is not available, if there is no view.
155     // This happens for charts having their own embedded spreadsheet.  If you
156     // force to get the range selection here, this would mean when entering this
157     // page the calc view would be created in this case.  So, I enable the
158     // button here, and in the worst case nothing happens when it is pressed.
159     // Not nice, but I see no better solution for the moment.
160     m_aIB_Range.SetClickHdl( LINK( this, RangeChooserTabPage, ChooseRangeHdl ));
161     m_aED_Range.SetKeyInputHdl( LINK( this, RangeChooserTabPage, ChooseRangeHdl ));
162 
163     // #i75179# enable setting the background to a different color
164     m_aED_Range.SetStyle( m_aED_Range.GetStyle() | WB_FORCECTRLBACKGROUND );
165 
166     m_aED_Range.SetUpdateDataHdl( LINK( this, RangeChooserTabPage, ControlChangedHdl ));
167     m_aED_Range.SetModifyHdl( LINK( this, RangeChooserTabPage, ControlEditedHdl ));
168     m_aRB_Rows.SetToggleHdl( LINK( this, RangeChooserTabPage, ControlChangedHdl ) );
169     m_aCB_FirstRowAsLabel.SetToggleHdl( LINK( this, RangeChooserTabPage, ControlChangedHdl ) );
170     m_aCB_FirstColumnAsLabel.SetToggleHdl( LINK( this, RangeChooserTabPage, ControlChangedHdl ) );
171 }
172 
173 RangeChooserTabPage::~RangeChooserTabPage()
174 {
175 }
176 
177 void RangeChooserTabPage::ActivatePage()
178 {
179     OWizardPage::ActivatePage();
180     initControlsFromModel();
181 }
182 
183 void RangeChooserTabPage::initControlsFromModel()
184 {
185     m_nChangingControlCalls++;
186 
187     if(m_pTemplateProvider)
188     {
189         m_xCurrentChartTypeTemplate = m_pTemplateProvider->getCurrentTemplate();
190     }
191 
192     bool bUseColumns = ! m_aRB_Rows.IsChecked();
193     bool bFirstCellAsLabel = bUseColumns ? m_aCB_FirstRowAsLabel.IsChecked() : m_aCB_FirstColumnAsLabel.IsChecked();
194     bool bHasCategories = bUseColumns ? m_aCB_FirstColumnAsLabel.IsChecked() : m_aCB_FirstRowAsLabel.IsChecked();
195 
196     bool bIsValid = m_rDialogModel.allArgumentsForRectRangeDetected();
197     if( bIsValid )
198         m_rDialogModel.detectArguments(
199             m_aLastValidRangeString, bUseColumns, bFirstCellAsLabel, bHasCategories );
200     else
201         m_aLastValidRangeString = String::EmptyString();
202 
203     m_aED_Range.SetText( m_aLastValidRangeString );
204 
205     m_aRB_Rows.Check( !bUseColumns );
206     m_aRB_Columns.Check(  bUseColumns );
207 
208     m_aCB_FirstRowAsLabel.Check( m_aRB_Rows.IsChecked()?bHasCategories:bFirstCellAsLabel  );
209     m_aCB_FirstColumnAsLabel.Check( m_aRB_Columns.IsChecked()?bHasCategories:bFirstCellAsLabel  );
210 
211     isValid();
212 
213     m_nChangingControlCalls--;
214 }
215 
216 void RangeChooserTabPage::DeactivatePage()
217 {
218     commitPage();
219     svt::OWizardPage::DeactivatePage();
220 }
221 
222 void RangeChooserTabPage::commitPage()
223 {
224     commitPage(::svt::WizardTypes::eFinish);
225 }
226 
227 sal_Bool RangeChooserTabPage::commitPage( ::svt::WizardTypes::CommitPageReason /*eReason*/ )
228 {
229     //ranges may have been edited in the meanwhile (dirty is true in that case here)
230     if( isValid() )
231     {
232         changeDialogModelAccordingToControls();
233         return sal_True;//return false if this page should not be left
234     }
235     else
236         return sal_False;
237 }
238 
239 void RangeChooserTabPage::changeDialogModelAccordingToControls()
240 {
241     if(m_nChangingControlCalls>0)
242         return;
243 
244     if( !m_xCurrentChartTypeTemplate.is() )
245     {
246         if(m_pTemplateProvider)
247             m_xCurrentChartTypeTemplate.set( m_pTemplateProvider->getCurrentTemplate());
248         if( !m_xCurrentChartTypeTemplate.is())
249         {
250             OSL_ENSURE( false, "Need a template to change data source" );
251             return;
252         }
253     }
254 
255     if( m_bIsDirty )
256     {
257         sal_Bool bFirstCellAsLabel = ( m_aCB_FirstColumnAsLabel.IsChecked() && !m_aRB_Columns.IsChecked() )
258             || ( m_aCB_FirstRowAsLabel.IsChecked()    && !m_aRB_Rows.IsChecked() );
259         sal_Bool bHasCategories = ( m_aCB_FirstColumnAsLabel.IsChecked() && m_aRB_Columns.IsChecked() )
260             || ( m_aCB_FirstRowAsLabel.IsChecked()    && m_aRB_Rows.IsChecked() );
261 
262         Sequence< beans::PropertyValue > aArguments(
263             DataSourceHelper::createArguments(
264                 m_aRB_Columns.IsChecked(), bFirstCellAsLabel, bHasCategories ) );
265 
266         // only if range is valid
267         if( m_aLastValidRangeString.equals( m_aED_Range.GetText()))
268         {
269             m_rDialogModel.setTemplate( m_xCurrentChartTypeTemplate );
270             aArguments.realloc( aArguments.getLength() + 1 );
271             aArguments[aArguments.getLength() - 1] =
272                 beans::PropertyValue( C2U("CellRangeRepresentation"), -1,
273                                       uno::makeAny( m_aLastValidRangeString ),
274                                       beans::PropertyState_DIRECT_VALUE );
275             m_rDialogModel.setData( aArguments );
276             m_bIsDirty = false;
277         }
278 
279         //@todo warn user that the selected range is not valid
280         //@todo better: disable OK-Button if range is invalid
281     }
282 }
283 
284 bool RangeChooserTabPage::isValid()
285 {
286     ::rtl::OUString aRange( m_aED_Range.GetText());
287     sal_Bool bFirstCellAsLabel = ( m_aCB_FirstColumnAsLabel.IsChecked() && !m_aRB_Columns.IsChecked() )
288         || ( m_aCB_FirstRowAsLabel.IsChecked()    && !m_aRB_Rows.IsChecked() );
289     sal_Bool bHasCategories = ( m_aCB_FirstColumnAsLabel.IsChecked() && m_aRB_Columns.IsChecked() )
290         || ( m_aCB_FirstRowAsLabel.IsChecked()    && m_aRB_Rows.IsChecked() );
291     bool bIsValid = ( aRange.getLength() == 0 ) ||
292         m_rDialogModel.getRangeSelectionHelper()->verifyArguments(
293             DataSourceHelper::createArguments(
294                 aRange, Sequence< sal_Int32 >(), m_aRB_Columns.IsChecked(), bFirstCellAsLabel, bHasCategories ));
295 
296     if( bIsValid )
297     {
298         m_aED_Range.SetControlForeground();
299         m_aED_Range.SetControlBackground();
300         if( m_pTabPageNotifiable )
301             m_pTabPageNotifiable->setValidPage( this );
302         m_aLastValidRangeString = aRange;
303     }
304     else
305     {
306         m_aED_Range.SetControlBackground( RANGE_SELECTION_INVALID_RANGE_BACKGROUND_COLOR );
307         m_aED_Range.SetControlForeground( RANGE_SELECTION_INVALID_RANGE_FOREGROUND_COLOR );
308         if( m_pTabPageNotifiable )
309             m_pTabPageNotifiable->setInvalidPage( this );
310     }
311 
312     // enable/disable controls
313     // #i79531# if the range is valid but an action of one of these buttons
314     // would render it invalid, the button should be disabled
315     if( bIsValid )
316     {
317         bool bDataInColumns = m_aRB_Columns.IsChecked();
318         bool bIsSwappedRangeValid = m_rDialogModel.getRangeSelectionHelper()->verifyArguments(
319             DataSourceHelper::createArguments(
320                 aRange, Sequence< sal_Int32 >(), ! bDataInColumns, bHasCategories, bFirstCellAsLabel ));
321         m_aRB_Rows.Enable( bIsSwappedRangeValid );
322         m_aRB_Columns.Enable( bIsSwappedRangeValid );
323 
324         m_aCB_FirstRowAsLabel.Enable(
325             m_rDialogModel.getRangeSelectionHelper()->verifyArguments(
326                 DataSourceHelper::createArguments(
327                     aRange, Sequence< sal_Int32 >(), m_aRB_Columns.IsChecked(),
328                     bDataInColumns ? ! bFirstCellAsLabel : bFirstCellAsLabel,
329                     bDataInColumns ? bHasCategories : ! bHasCategories )));
330         m_aCB_FirstColumnAsLabel.Enable(
331             m_rDialogModel.getRangeSelectionHelper()->verifyArguments(
332                 DataSourceHelper::createArguments(
333                     aRange, Sequence< sal_Int32 >(), m_aRB_Columns.IsChecked(),
334                     bDataInColumns ? bFirstCellAsLabel : ! bFirstCellAsLabel,
335                     bDataInColumns ? ! bHasCategories : bHasCategories )));
336     }
337     else
338     {
339         m_aRB_Rows.Enable( bIsValid );
340         m_aRB_Columns.Enable( bIsValid );
341         m_aCB_FirstRowAsLabel.Enable( bIsValid );
342         m_aCB_FirstColumnAsLabel.Enable( bIsValid );
343 }
344     sal_Bool bShowIB = m_rDialogModel.getRangeSelectionHelper()->hasRangeSelection();
345     lcl_ShowChooserButton( m_aIB_Range, m_aED_Range, bShowIB );
346 
347     return bIsValid;
348 }
349 
350 IMPL_LINK( RangeChooserTabPage, ControlEditedHdl, void*, EMPTYARG )
351 {
352     setDirty();
353     isValid();
354     return 0;
355 }
356 
357 IMPL_LINK( RangeChooserTabPage, ControlChangedHdl, void*, EMPTYARG )
358 {
359     setDirty();
360     if( isValid())
361         changeDialogModelAccordingToControls();
362     return 0;
363 }
364 
365 IMPL_LINK( RangeChooserTabPage, ChooseRangeHdl, void *, EMPTYARG )
366 {
367     rtl::OUString aRange = m_aED_Range.GetText();
368     // using assignment for broken gcc 3.3
369     rtl::OUString aTitle = String( SchResId( STR_PAGE_DATA_RANGE ) );
370 
371     lcl_enableRangeChoosing( true, m_pParentDialog );
372     m_rDialogModel.getRangeSelectionHelper()->chooseRange( aRange, aTitle, *this );
373 
374     return 0;
375 }
376 
377 
378 void RangeChooserTabPage::listeningFinished( const ::rtl::OUString & rNewRange )
379 {
380     //user has selected a new range
381 
382     rtl::OUString aRange( rNewRange );
383 
384     m_rDialogModel.startControllerLockTimer();
385 
386     // stop listening
387     m_rDialogModel.getRangeSelectionHelper()->stopRangeListening();
388 
389     //update dialog state
390     ToTop();
391     GrabFocus();
392     m_aED_Range.SetText( String( aRange ) );
393     m_aED_Range.GrabFocus();
394 
395     setDirty();
396     if( isValid())
397         changeDialogModelAccordingToControls();
398 
399     lcl_enableRangeChoosing( false, m_pParentDialog );
400 }
401 void RangeChooserTabPage::disposingRangeSelection()
402 {
403     m_rDialogModel.getRangeSelectionHelper()->stopRangeListening( false );
404 }
405 
406 void RangeChooserTabPage::setDirty()
407 {
408     if( m_nChangingControlCalls == 0 )
409         m_bIsDirty = true;
410 }
411 
412 //.............................................................................
413 } //namespace chart
414 //.............................................................................
415