1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
10 #include <config_folders.h>
12 #include "personalization.hxx"
14 #include <comphelper/processfactory.hxx>
15 #include <officecfg/Office/Common.hxx>
16 #include <osl/file.hxx>
17 #include <rtl/bootstrap.hxx>
18 #include <tools/urlobj.hxx>
19 #include <vcl/edit.hxx>
20 #include <vcl/msgbox.hxx>
21 #include <vcl/svapp.hxx>
22 #include <vcl/settings.hxx>
24 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
25 #include <com/sun/star/system/SystemShellExecute.hpp>
26 #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
27 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
28 #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
29 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
30 #include <com/sun/star/ui/dialogs/FilePicker.hpp>
31 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
32 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
33 #include <com/sun/star/ui/dialogs/XFilterManager.hpp>
35 using namespace com::sun::star
;
37 /** Dialog that will allow the user to choose a Persona to use.
39 So far there is no better possibility than just to paste the URL from
40 https://addons.mozilla.org/firefox/themes ...
42 class SelectPersonaDialog
: public ModalDialog
45 Edit
*m_pEdit
; ///< The input line for the Persona URL
48 SelectPersonaDialog( Window
*pParent
);
50 /// Get the URL from the Edit field.
51 OUString
GetPersonaURL() const;
54 /// Handle the [Visit Firefox Personas] button
55 DECL_LINK( VisitPersonas
, PushButton
* );
58 SelectPersonaDialog::SelectPersonaDialog( Window
*pParent
)
59 : ModalDialog( pParent
, "SelectPersonaDialog", "cui/ui/select_persona_dialog.ui" )
62 get( pButton
, "visit_personas" );
63 pButton
->SetClickHdl( LINK( this, SelectPersonaDialog
, VisitPersonas
) );
65 get( m_pEdit
, "persona_url" );
66 m_pEdit
->SetPlaceholderText( "https://addons.mozilla.org/firefox/themes/" );
69 OUString
SelectPersonaDialog::GetPersonaURL() const
71 OUString
aText( m_pEdit
->GetText() );
73 if ( aText
.startsWith( "https://addons.mozilla.org/" ) )
79 IMPL_LINK( SelectPersonaDialog
, VisitPersonas
, PushButton
*, /*pButton*/ )
81 uno::Reference
< com::sun::star::system::XSystemShellExecute
> xSystemShell( com::sun::star::system::SystemShellExecute::create( ::comphelper::getProcessComponentContext() ) );
83 xSystemShell
->execute( "https://addons.mozilla.org/firefox/themes/", OUString(), com::sun::star::system::SystemShellExecuteFlags::URIS_ONLY
);
88 SvxPersonalizationTabPage::SvxPersonalizationTabPage( Window
*pParent
, const SfxItemSet
&rSet
)
89 : SfxTabPage( pParent
, "PersonalizationTabPage", "cui/ui/personalization_tab.ui", rSet
)
92 get( m_pNoPersona
, "no_persona" );
93 get( m_pDefaultPersona
, "default_persona" );
95 get( m_pOwnPersona
, "own_persona" );
96 m_pOwnPersona
->SetClickHdl( LINK( this, SvxPersonalizationTabPage
, ForceSelect
) );
98 get( m_pSelectPersona
, "select_persona" );
99 m_pSelectPersona
->SetClickHdl( LINK( this, SvxPersonalizationTabPage
, SelectPersona
) );
102 SvxPersonalizationTabPage::~SvxPersonalizationTabPage()
106 SfxTabPage
* SvxPersonalizationTabPage::Create( Window
*pParent
, const SfxItemSet
&rSet
)
108 return new SvxPersonalizationTabPage( pParent
, rSet
);
111 bool SvxPersonalizationTabPage::FillItemSet( SfxItemSet
& )
114 OUString
aPersona( "default" );
115 if ( m_pNoPersona
->IsChecked() )
117 else if ( m_pOwnPersona
->IsChecked() )
120 bool bModified
= false;
121 uno::Reference
< uno::XComponentContext
> xContext( comphelper::getProcessComponentContext() );
122 if ( xContext
.is() &&
123 ( aPersona
!= officecfg::Office::Common::Misc::Persona::get( xContext
) ||
124 m_aPersonaSettings
!= officecfg::Office::Common::Misc::PersonaSettings::get( xContext
) ) )
130 boost::shared_ptr
< comphelper::ConfigurationChanges
> batch( comphelper::ConfigurationChanges::create() );
132 officecfg::Office::Common::Misc::Persona::set( aPersona
, batch
);
133 officecfg::Office::Common::Misc::PersonaSettings::set( m_aPersonaSettings
, batch
);
139 // broadcast the change
140 DataChangedEvent
aDataChanged( DATACHANGED_SETTINGS
, NULL
, SETTINGS_STYLE
);
141 Application::NotifyAllWindows( aDataChanged
);
147 void SvxPersonalizationTabPage::Reset( const SfxItemSet
& )
149 uno::Reference
< uno::XComponentContext
> xContext( comphelper::getProcessComponentContext() );
152 OUString
aPersona( "default" );
155 aPersona
= officecfg::Office::Common::Misc::Persona::get( xContext
);
156 m_aPersonaSettings
= officecfg::Office::Common::Misc::PersonaSettings::get( xContext
);
159 if ( aPersona
== "no" )
160 m_pNoPersona
->Check();
161 else if ( aPersona
== "own" )
162 m_pOwnPersona
->Check();
164 m_pDefaultPersona
->Check();
167 IMPL_LINK( SvxPersonalizationTabPage
, SelectPersona
, PushButton
*, /*pButton*/ )
169 SelectPersonaDialog
aDialog( NULL
);
171 while ( aDialog
.Execute() == RET_OK
)
173 OUString
aURL( aDialog
.GetPersonaURL() );
174 if ( !aURL
.isEmpty() )
176 if ( CopyPersonaToGallery( aURL
) )
177 m_pOwnPersona
->Check();
180 // else TODO msgbox that the URL did not match
186 IMPL_LINK( SvxPersonalizationTabPage
, ForceSelect
, RadioButton
*, pButton
)
188 if ( pButton
== m_pOwnPersona
&& m_aPersonaSettings
.isEmpty() )
189 SelectPersona( m_pSelectPersona
);
194 /// Find the value on the Persona page, and convert it to a usable form.
195 static OUString
searchValue( const OString
&rBuffer
, sal_Int32 from
, const OString
&rIdentifier
)
197 sal_Int32 where
= rBuffer
.indexOf( rIdentifier
, from
);
201 where
+= rIdentifier
.getLength();
203 sal_Int32 end
= rBuffer
.indexOf( """, where
);
207 OString
aOString( rBuffer
.copy( where
, end
- where
) );
208 OUString
aString( aOString
.getStr(), aOString
.getLength(), RTL_TEXTENCODING_UTF8
, OSTRING_TO_OUSTRING_CVTFLAGS
);
210 return aString
.replaceAll( "\\/", "/" );
213 /// Parse the Persona web page, and find where to get the bitmaps + the color values.
214 static bool parsePersonaInfo( const OString
&rBuffer
, OUString
*pHeaderURL
, OUString
*pFooterURL
, OUString
*pTextColor
, OUString
*pAccentColor
)
216 // it is the first attribute that contains "persona="
217 sal_Int32 persona
= rBuffer
.indexOf( "data-browsertheme=\"{" );
222 *pHeaderURL
= searchValue( rBuffer
, persona
, ""headerURL":"" );
223 if ( pHeaderURL
->isEmpty() )
226 *pFooterURL
= searchValue( rBuffer
, persona
, ""footerURL":"" );
227 if ( pFooterURL
->isEmpty() )
230 *pTextColor
= searchValue( rBuffer
, persona
, ""textcolor":"" );
231 if ( pTextColor
->isEmpty() )
234 *pAccentColor
= searchValue( rBuffer
, persona
, ""accentcolor":"" );
235 if ( pAccentColor
->isEmpty() )
241 bool SvxPersonalizationTabPage::CopyPersonaToGallery( const OUString
&rURL
)
243 // init the input stream
244 uno::Reference
< ucb::XSimpleFileAccess3
> xFileAccess( ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() ), uno::UNO_QUERY
);
245 if ( !xFileAccess
.is() )
248 uno::Reference
< io::XInputStream
> xStream
;
250 xStream
= xFileAccess
->openFileRead( rURL
);
259 // read the persona specification
260 // NOTE: Parsing for real is an overkill here; and worse - I tried, and
261 // the HTML the site provides is not 100% valid ;-)
262 const sal_Int32 BUF_LEN
= 8000;
263 uno::Sequence
< sal_Int8
> buffer( BUF_LEN
);
264 OStringBuffer
aBuffer( 64000 );
267 while ( ( nRead
= xStream
->readBytes( buffer
, BUF_LEN
) ) == BUF_LEN
)
268 aBuffer
.append( reinterpret_cast< const char* >( buffer
.getConstArray() ), nRead
);
271 aBuffer
.append( reinterpret_cast< const char* >( buffer
.getConstArray() ), nRead
);
273 xStream
->closeInput();
275 // get the important bits of info
276 OUString aHeaderURL
, aFooterURL
, aTextColor
, aAccentColor
;
278 if ( !parsePersonaInfo( aBuffer
.makeStringAndClear(), &aHeaderURL
, &aFooterURL
, &aTextColor
, &aAccentColor
) )
281 // copy the images to the user's gallery
282 OUString gallery
= "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE( "bootstrap") "::UserInstallation}";
283 rtl::Bootstrap::expandMacros( gallery
);
284 gallery
+= "/user/gallery/personas/";
285 osl::Directory::createPath( gallery
);
287 OUString
aHeaderFile( INetURLObject( aHeaderURL
).getName() );
288 OUString
aFooterFile( INetURLObject( aFooterURL
).getName() );
291 xFileAccess
->copy( aHeaderURL
, gallery
+ aHeaderFile
);
292 xFileAccess
->copy( aFooterURL
, gallery
+ aFooterFile
);
294 catch ( const uno::Exception
& )
299 m_aPersonaSettings
= aHeaderFile
+ ";" + aFooterFile
+ ";" + aTextColor
+ ";" + aAccentColor
;
304 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */