1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <SvxConfigPageHelper.hxx>
21 
22 #include <com/sun/star/frame/ModuleManager.hpp>
23 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
24 #include <com/sun/star/ui/ImageType.hpp>
25 #include <com/sun/star/ui/ItemType.hpp>
26 
27 #include <comphelper/random.hxx>
28 #include <comphelper/processfactory.hxx>
29 #include <svtools/imgdef.hxx>
30 #include <svtools/miscopt.hxx>
31 
32 static sal_Int16 theImageType =
33     css::ui::ImageType::COLOR_NORMAL |
34     css::ui::ImageType::SIZE_DEFAULT;
35 
RemoveEntry(SvxEntries * pEntries,SvxConfigEntry const * pChildEntry)36 void SvxConfigPageHelper::RemoveEntry( SvxEntries* pEntries, SvxConfigEntry const * pChildEntry )
37 {
38     SvxEntries::iterator iter = pEntries->begin();
39 
40     while ( iter != pEntries->end() )
41     {
42         if ( pChildEntry == *iter )
43         {
44             pEntries->erase( iter );
45             break;
46         }
47         ++iter;
48     }
49 }
50 
replaceSaveInName(const OUString & rMessage,const OUString & rSaveInName)51 OUString SvxConfigPageHelper::replaceSaveInName( const OUString& rMessage, const OUString& rSaveInName )
52 {
53     const OUString placeholder("%SAVE IN SELECTION%" );
54 
55     OUString name = rMessage.replaceFirst(placeholder, rSaveInName);
56 
57     return name;
58 }
59 
stripHotKey(const OUString & str)60 OUString SvxConfigPageHelper::stripHotKey( const OUString& str )
61 {
62     return str.replaceFirst("~", "");
63 }
64 
replaceSixteen(const OUString & str,sal_Int32 nReplacement)65 OUString SvxConfigPageHelper::replaceSixteen( const OUString& str, sal_Int32 nReplacement )
66 {
67     return str.replaceAll( OUString::number( 16 ), OUString::number( nReplacement ));
68 }
69 
GetImageType()70 sal_Int16 SvxConfigPageHelper::GetImageType()
71 {
72     return theImageType;
73 }
74 
InitImageType()75 void SvxConfigPageHelper::InitImageType()
76 {
77     theImageType =
78         css::ui::ImageType::COLOR_NORMAL |
79         css::ui::ImageType::SIZE_DEFAULT;
80 
81     if (SvtMiscOptions().GetCurrentSymbolsSize() == SFX_SYMBOLS_SIZE_LARGE)
82     {
83         theImageType |= css::ui::ImageType::SIZE_LARGE;
84     }
85     else if (SvtMiscOptions().GetCurrentSymbolsSize() == SFX_SYMBOLS_SIZE_32)
86     {
87         theImageType |= css::ui::ImageType::SIZE_32;
88     }
89 }
90 
GetGraphic(const css::uno::Reference<css::ui::XImageManager> & xImageManager,const OUString & rCommandURL)91 css::uno::Reference< css::graphic::XGraphic > SvxConfigPageHelper::GetGraphic(
92     const css::uno::Reference< css::ui::XImageManager >& xImageManager,
93     const OUString& rCommandURL )
94 {
95     css::uno::Reference< css::graphic::XGraphic > result;
96 
97     if ( xImageManager.is() )
98     {
99         // TODO handle large graphics
100         css::uno::Sequence< css::uno::Reference< css::graphic::XGraphic > > aGraphicSeq;
101 
102         css::uno::Sequence<OUString> aImageCmdSeq { rCommandURL };
103 
104         try
105         {
106             aGraphicSeq =
107                 xImageManager->getImages( GetImageType(), aImageCmdSeq );
108 
109             if ( aGraphicSeq.hasElements() )
110             {
111                 result =  aGraphicSeq[0];
112             }
113         }
114         catch ( css::uno::Exception& )
115         {
116             // will return empty XGraphic
117         }
118     }
119 
120     return result;
121 }
122 
123 OUString
generateCustomName(const OUString & prefix,SvxEntries * entries,sal_Int32 suffix)124 SvxConfigPageHelper::generateCustomName(
125     const OUString& prefix,
126     SvxEntries* entries,
127     sal_Int32 suffix /*= 1*/ )
128 {
129     OUString name;
130     sal_Int32 pos = 0;
131 
132     // find and replace the %n placeholder in the prefix string
133     name = prefix.replaceFirst( "%n", OUString::number( suffix ), &pos );
134 
135     if ( pos == -1 )
136     {
137         // no placeholder found so just append the suffix
138         name += OUString::number( suffix );
139     }
140 
141     if (!entries)
142         return name;
143 
144     // now check if there is an already existing entry with this name
145     bool bFoundEntry = false;
146     for (auto const& entry : *entries)
147     {
148         if ( name.equals(entry->GetName()) )
149         {
150             bFoundEntry = true;
151             break;
152         }
153     }
154 
155     if (bFoundEntry)
156     {
157         // name already exists so try the next number up
158         return generateCustomName( prefix, entries, ++suffix );
159     }
160 
161     return name;
162 }
163 
generateCustomMenuURL(SvxEntries * entries,sal_Int32 suffix)164 OUString SvxConfigPageHelper::generateCustomMenuURL(
165     SvxEntries* entries,
166     sal_Int32 suffix /*= 1*/ )
167 {
168     OUString url = "vnd.openoffice.org:CustomMenu" + OUString::number( suffix );
169     if (!entries)
170         return url;
171 
172     // now check is there is an already existing entry with this url
173     bool bFoundEntry = false;
174     for (auto const& entry : *entries)
175     {
176         if ( url.equals(entry->GetCommand()) )
177         {
178             bFoundEntry = true;
179             break;
180         }
181     }
182 
183     if (bFoundEntry)
184     {
185         // url already exists so try the next number up
186         return generateCustomMenuURL( entries, ++suffix );
187     }
188 
189     return url;
190 }
191 
generateRandomValue()192 sal_uInt32 SvxConfigPageHelper::generateRandomValue()
193 {
194     return comphelper::rng::uniform_uint_distribution(0, std::numeric_limits<unsigned int>::max());
195 }
196 
generateCustomURL(SvxEntries * entries)197 OUString SvxConfigPageHelper::generateCustomURL( SvxEntries* entries )
198 {
199     OUString url = OUStringLiteral(ITEM_TOOLBAR_URL) + CUSTOM_TOOLBAR_STR +
200     // use a random number to minimize possible clash with existing custom toolbars
201         OUString::number( generateRandomValue(), 16 );
202 
203     // now check is there is an already existing entry with this url
204     bool bFoundEntry = false;
205     for (auto const& entry : *entries)
206     {
207         if ( url.equals(entry->GetCommand()) )
208         {
209             bFoundEntry = true;
210             break;
211         }
212     }
213 
214     if (bFoundEntry)
215     {
216         // url already exists so try the next number up
217         return generateCustomURL( entries );
218     }
219 
220     return url;
221 }
222 
GetModuleName(const OUString & aModuleId)223 OUString SvxConfigPageHelper::GetModuleName( const OUString& aModuleId )
224 {
225     if ( aModuleId == "com.sun.star.text.TextDocument" ||
226          aModuleId == "com.sun.star.text.GlobalDocument" )
227         return "Writer";
228     else if ( aModuleId == "com.sun.star.text.WebDocument" )
229         return "Writer/Web";
230     else if ( aModuleId == "com.sun.star.drawing.DrawingDocument" )
231         return "Draw";
232     else if ( aModuleId == "com.sun.star.presentation.PresentationDocument" )
233         return "Impress";
234     else if ( aModuleId == "com.sun.star.sheet.SpreadsheetDocument" )
235         return "Calc";
236     else if ( aModuleId == "com.sun.star.script.BasicIDE" )
237         return "Basic";
238     else if ( aModuleId == "com.sun.star.formula.FormulaProperties" )
239         return "Math";
240     else if ( aModuleId == "com.sun.star.sdb.RelationDesign" )
241         return "Relation Design";
242     else if ( aModuleId == "com.sun.star.sdb.QueryDesign" )
243         return "Query Design";
244     else if ( aModuleId == "com.sun.star.sdb.TableDesign" )
245         return "Table Design";
246     else if ( aModuleId == "com.sun.star.sdb.DataSourceBrowser" )
247         return "Data Source Browser";
248     else if ( aModuleId == "com.sun.star.sdb.DatabaseDocument" )
249         return "Database";
250 
251     return OUString();
252 }
253 
GetUIModuleName(const OUString & aModuleId,const css::uno::Reference<css::frame::XModuleManager2> & rModuleManager)254 OUString SvxConfigPageHelper::GetUIModuleName(
255     const OUString& aModuleId,
256     const css::uno::Reference< css::frame::XModuleManager2 >& rModuleManager )
257 {
258     assert(rModuleManager.is());
259 
260     OUString aModuleUIName;
261 
262     try
263     {
264         css::uno::Any a = rModuleManager->getByName( aModuleId );
265         css::uno::Sequence< css::beans::PropertyValue > aSeq;
266 
267         if ( a >>= aSeq )
268         {
269             for ( sal_Int32 i = 0; i < aSeq.getLength(); ++i )
270             {
271                 if ( aSeq[i].Name == "ooSetupFactoryUIName" )
272                 {
273                     aSeq[i].Value >>= aModuleUIName;
274                     break;
275                 }
276             }
277         }
278     }
279     catch ( css::uno::RuntimeException& )
280     {
281         throw;
282     }
283     catch ( css::uno::Exception& )
284     {
285     }
286 
287     if ( aModuleUIName.isEmpty() )
288         aModuleUIName = GetModuleName( aModuleId );
289 
290     return aModuleUIName;
291 }
292 
GetMenuItemData(const css::uno::Reference<css::container::XIndexAccess> & rItemContainer,sal_Int32 nIndex,OUString & rCommandURL,OUString & rLabel,sal_uInt16 & rType,sal_Int32 & rStyle,css::uno::Reference<css::container::XIndexAccess> & rSubMenu)293 bool SvxConfigPageHelper::GetMenuItemData(
294     const css::uno::Reference< css::container::XIndexAccess >& rItemContainer,
295     sal_Int32 nIndex,
296     OUString& rCommandURL,
297     OUString& rLabel,
298     sal_uInt16& rType,
299     sal_Int32& rStyle,
300     css::uno::Reference< css::container::XIndexAccess >& rSubMenu )
301 {
302     try
303     {
304         css::uno::Sequence< css::beans::PropertyValue > aProp;
305         if ( rItemContainer->getByIndex( nIndex ) >>= aProp )
306         {
307             for ( sal_Int32 i = 0; i < aProp.getLength(); ++i )
308             {
309                 if ( aProp[i].Name == ITEM_DESCRIPTOR_COMMANDURL )
310                 {
311                     aProp[i].Value >>= rCommandURL;
312                 }
313                 else if ( aProp[i].Name == ITEM_DESCRIPTOR_CONTAINER )
314                 {
315                     aProp[i].Value >>= rSubMenu;
316                 }
317                 else if ( aProp[i].Name == ITEM_DESCRIPTOR_STYLE )
318                 {
319                     aProp[i].Value >>= rStyle;
320                 }
321                 else if ( aProp[i].Name == ITEM_DESCRIPTOR_LABEL )
322                 {
323                     aProp[i].Value >>= rLabel;
324                 }
325                 else if ( aProp[i].Name == ITEM_DESCRIPTOR_TYPE )
326                 {
327                     aProp[i].Value >>= rType;
328                 }
329             }
330 
331             return true;
332         }
333     }
334     catch ( css::lang::IndexOutOfBoundsException& )
335     {
336     }
337 
338     return false;
339 }
340 
GetToolbarItemData(const css::uno::Reference<css::container::XIndexAccess> & rItemContainer,sal_Int32 nIndex,OUString & rCommandURL,OUString & rLabel,sal_uInt16 & rType,bool & rIsVisible,sal_Int32 & rStyle)341 bool SvxConfigPageHelper::GetToolbarItemData(
342     const css::uno::Reference< css::container::XIndexAccess >& rItemContainer,
343     sal_Int32 nIndex,
344     OUString& rCommandURL,
345     OUString& rLabel,
346     sal_uInt16& rType,
347     bool& rIsVisible,
348     sal_Int32& rStyle )
349 {
350     try
351     {
352         css::uno::Sequence< css::beans::PropertyValue > aProp;
353         if ( rItemContainer->getByIndex( nIndex ) >>= aProp )
354         {
355             for ( sal_Int32 i = 0; i < aProp.getLength(); ++i )
356             {
357                 if ( aProp[i].Name == ITEM_DESCRIPTOR_COMMANDURL )
358                 {
359                     aProp[i].Value >>= rCommandURL;
360                 }
361                 else if ( aProp[i].Name == ITEM_DESCRIPTOR_STYLE )
362                 {
363                     aProp[i].Value >>= rStyle;
364                 }
365                 else if ( aProp[i].Name == ITEM_DESCRIPTOR_LABEL )
366                 {
367                     aProp[i].Value >>= rLabel;
368                 }
369                 else if ( aProp[i].Name == ITEM_DESCRIPTOR_TYPE )
370                 {
371                     aProp[i].Value >>= rType;
372                 }
373                 else if ( aProp[i].Name == ITEM_DESCRIPTOR_ISVISIBLE )
374                 {
375                     aProp[i].Value >>= rIsVisible;
376                 }
377             }
378 
379             return true;
380         }
381     }
382     catch ( css::lang::IndexOutOfBoundsException& )
383     {
384     }
385 
386     return false;
387 }
388 
ConvertSvxConfigEntry(const SvxConfigEntry * pEntry)389 css::uno::Sequence< css::beans::PropertyValue > SvxConfigPageHelper::ConvertSvxConfigEntry(
390         const SvxConfigEntry* pEntry )
391 {
392     css::uno::Sequence< css::beans::PropertyValue > aPropSeq( 4 );
393 
394     aPropSeq[0].Name = ITEM_DESCRIPTOR_COMMANDURL;
395     aPropSeq[0].Value <<= pEntry->GetCommand();
396 
397     aPropSeq[1].Name = ITEM_DESCRIPTOR_TYPE;
398     aPropSeq[1].Value <<= css::ui::ItemType::DEFAULT;
399 
400     // If the name has not been changed, then the label can be stored
401     // as an empty string.
402     // It will be initialised again later using the command to label map.
403     aPropSeq[2].Name = ITEM_DESCRIPTOR_LABEL;
404     if ( !pEntry->HasChangedName() && !pEntry->GetCommand().isEmpty() )
405     {
406         aPropSeq[2].Value <<= OUString();
407     }
408     else
409     {
410         aPropSeq[2].Value <<= pEntry->GetName();
411     }
412 
413     aPropSeq[3].Name = ITEM_DESCRIPTOR_STYLE;
414     aPropSeq[3].Value <<= static_cast<sal_Int16>(pEntry->GetStyle());
415 
416     return aPropSeq;
417 }
418 
ConvertToolbarEntry(const SvxConfigEntry * pEntry)419 css::uno::Sequence< css::beans::PropertyValue > SvxConfigPageHelper::ConvertToolbarEntry(
420     const SvxConfigEntry* pEntry )
421 {
422     css::uno::Sequence< css::beans::PropertyValue > aPropSeq( 5 );
423 
424     aPropSeq[0].Name = ITEM_DESCRIPTOR_COMMANDURL;
425     aPropSeq[0].Value <<= pEntry->GetCommand();
426 
427     aPropSeq[1].Name = ITEM_DESCRIPTOR_TYPE;
428     aPropSeq[1].Value <<= css::ui::ItemType::DEFAULT;
429 
430     // If the name has not been changed, then the label can be stored
431     // as an empty string.
432     // It will be initialised again later using the command to label map.
433     aPropSeq[2].Name = ITEM_DESCRIPTOR_LABEL;
434     if ( !pEntry->HasChangedName() && !pEntry->GetCommand().isEmpty() )
435     {
436         aPropSeq[2].Value <<= OUString();
437     }
438     else
439     {
440         aPropSeq[2].Value <<= pEntry->GetName();
441     }
442 
443     aPropSeq[3].Name = ITEM_DESCRIPTOR_ISVISIBLE;
444     aPropSeq[3].Value <<= pEntry->IsVisible();
445 
446     aPropSeq[4].Name = ITEM_DESCRIPTOR_STYLE;
447     aPropSeq[4].Value <<= static_cast<sal_Int16>(pEntry->GetStyle());
448 
449     return aPropSeq;
450 }
451 
EntrySort(SvxConfigEntry const * a,SvxConfigEntry const * b)452 bool SvxConfigPageHelper::EntrySort( SvxConfigEntry const * a, SvxConfigEntry const * b )
453 {
454     return a->GetName().compareTo( b->GetName() ) < 0;
455 }
456 
SvxConfigEntryModified(SvxConfigEntry const * pEntry)457 bool SvxConfigPageHelper::SvxConfigEntryModified( SvxConfigEntry const * pEntry )
458 {
459     SvxEntries* pEntries = pEntry->GetEntries();
460     if ( !pEntries )
461         return false;
462 
463     for ( const auto& entry : *pEntries )
464     {
465         if ( entry->IsModified() || SvxConfigEntryModified( entry ) )
466             return true;
467     }
468     return false;
469 }
470 
471 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
472