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