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 "personalization.hxx"
12 #include <comphelper/processfactory.hxx>
13 #include <officecfg/Office/Common.hxx>
14 #include <osl/file.hxx>
15 #include <rtl/bootstrap.hxx>
16 #include <tools/urlobj.hxx>
17 #include <vcl/edit.hxx>
18 #include <vcl/msgbox.hxx>
19 #include <vcl/svapp.hxx>
21 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
22 #include <com/sun/star/system/SystemShellExecute.hpp>
23 #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
24 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
25 #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
26 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
27 #include <com/sun/star/ui/dialogs/FilePicker.hpp>
28 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
29 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
30 #include <com/sun/star/ui/dialogs/XFilterManager.hpp>
32 using namespace com::sun::star
;
34 /** Dialog that will allow the user to choose a Persona to use.
36 So far there is no better possibility than just to paste the URL from
37 https://addons.mozilla.org/firefox/themes ...
39 class SelectPersonaDialog
: public ModalDialog
42 Edit
*m_pEdit
; ///< The input line for the Persona URL
45 SelectPersonaDialog( Window
*pParent
);
47 /// Get the URL from the Edit field.
48 OUString
GetPersonaURL() const;
51 /// Handle the [Visit Firefox Personas] button
52 DECL_LINK( VisitPersonas
, PushButton
* );
55 SelectPersonaDialog::SelectPersonaDialog( Window
*pParent
)
56 : ModalDialog( pParent
, "SelectPersonaDialog", "cui/ui/select_persona_dialog.ui" )
59 get( pButton
, "visit_personas" );
60 pButton
->SetClickHdl( LINK( this, SelectPersonaDialog
, VisitPersonas
) );
62 get( m_pEdit
, "persona_url" );
63 m_pEdit
->SetPlaceholderText( "https://addons.mozilla.org/firefox/themes/" );
66 OUString
SelectPersonaDialog::GetPersonaURL() const
68 OUString
aText( m_pEdit
->GetText() );
70 if ( aText
.startsWith( "https://addons.mozilla.org/" ) )
76 IMPL_LINK( SelectPersonaDialog
, VisitPersonas
, PushButton
*, /*pButton*/ )
78 uno::Reference
< com::sun::star::system::XSystemShellExecute
> xSystemShell( com::sun::star::system::SystemShellExecute::create( ::comphelper::getProcessComponentContext() ) );
80 xSystemShell
->execute( "https://addons.mozilla.org/firefox/themes/", OUString(), com::sun::star::system::SystemShellExecuteFlags::URIS_ONLY
);
85 SvxPersonalizationTabPage::SvxPersonalizationTabPage( Window
*pParent
, const SfxItemSet
&rSet
)
86 : SfxTabPage( pParent
, "PersonalizationTabPage", "cui/ui/personalization_tab.ui", rSet
)
89 get( m_pNoPersona
, "no_persona" );
90 get( m_pDefaultPersona
, "default_persona" );
92 get( m_pOwnPersona
, "own_persona" );
93 m_pOwnPersona
->SetClickHdl( LINK( this, SvxPersonalizationTabPage
, ForceSelect
) );
95 get( m_pSelectPersona
, "select_persona" );
96 m_pSelectPersona
->SetClickHdl( LINK( this, SvxPersonalizationTabPage
, SelectPersona
) );
99 SvxPersonalizationTabPage::~SvxPersonalizationTabPage()
103 SfxTabPage
* SvxPersonalizationTabPage::Create( Window
*pParent
, const SfxItemSet
&rSet
)
105 return new SvxPersonalizationTabPage( pParent
, rSet
);
108 sal_Bool
SvxPersonalizationTabPage::FillItemSet( SfxItemSet
& )
111 OUString
aPersona( "default" );
112 if ( m_pNoPersona
->IsChecked() )
114 else if ( m_pOwnPersona
->IsChecked() )
117 bool bModified
= false;
118 uno::Reference
< uno::XComponentContext
> xContext( comphelper::getProcessComponentContext() );
119 if ( xContext
.is() &&
120 ( aPersona
!= officecfg::Office::Common::Misc::Persona::get( xContext
) ||
121 m_aPersonaSettings
!= officecfg::Office::Common::Misc::PersonaSettings::get( xContext
) ) )
127 boost::shared_ptr
< comphelper::ConfigurationChanges
> batch( comphelper::ConfigurationChanges::create() );
129 officecfg::Office::Common::Misc::Persona::set( aPersona
, batch
);
130 officecfg::Office::Common::Misc::PersonaSettings::set( m_aPersonaSettings
, batch
);
136 // broadcast the change
137 DataChangedEvent
aDataChanged( DATACHANGED_SETTINGS
, NULL
, SETTINGS_STYLE
);
138 Application::NotifyAllWindows( aDataChanged
);
144 void SvxPersonalizationTabPage::Reset( const SfxItemSet
& )
146 uno::Reference
< uno::XComponentContext
> xContext( comphelper::getProcessComponentContext() );
149 OUString
aPersona( "default" );
152 aPersona
= officecfg::Office::Common::Misc::Persona::get( xContext
);
153 m_aPersonaSettings
= officecfg::Office::Common::Misc::PersonaSettings::get( xContext
);
156 if ( aPersona
== "no" )
157 m_pNoPersona
->Check();
158 else if ( aPersona
== "own" )
159 m_pOwnPersona
->Check();
161 m_pDefaultPersona
->Check();
164 IMPL_LINK( SvxPersonalizationTabPage
, SelectPersona
, PushButton
*, /*pButton*/ )
166 SelectPersonaDialog
aDialog( NULL
);
168 while ( aDialog
.Execute() == RET_OK
)
170 OUString
aURL( aDialog
.GetPersonaURL() );
171 if ( !aURL
.isEmpty() )
173 if ( CopyPersonaToGallery( aURL
) )
174 m_pOwnPersona
->Check();
177 // else TODO msgbox that the URL did not match
183 IMPL_LINK( SvxPersonalizationTabPage
, ForceSelect
, RadioButton
*, pButton
)
185 if ( pButton
== m_pOwnPersona
&& m_aPersonaSettings
.isEmpty() )
186 SelectPersona( m_pSelectPersona
);
191 /// Find the value on the Persona page, and convert it to a usable form.
192 static OUString
searchValue( const OString
&rBuffer
, sal_Int32 from
, const OString
&rIdentifier
)
194 sal_Int32 where
= rBuffer
.indexOf( rIdentifier
, from
);
198 where
+= rIdentifier
.getLength();
200 sal_Int32 end
= rBuffer
.indexOf( """, where
);
204 OString
aOString( rBuffer
.copy( where
, end
- where
) );
205 OUString
aString( aOString
.getStr(), aOString
.getLength(), RTL_TEXTENCODING_UTF8
, OSTRING_TO_OUSTRING_CVTFLAGS
);
207 return aString
.replaceAll( "\\/", "/" );
210 /// Parse the Persona web page, and find where to get the bitmaps + the color values.
211 static bool parsePersonaInfo( const OString
&rBuffer
, OUString
*pHeaderURL
, OUString
*pFooterURL
, OUString
*pTextColor
, OUString
*pAccentColor
)
213 // it is the first attribute that contains "persona="
214 sal_Int32 persona
= rBuffer
.indexOf( "data-browsertheme=\"{" );
219 *pHeaderURL
= searchValue( rBuffer
, persona
, ""headerURL":"" );
220 if ( pHeaderURL
->isEmpty() )
223 *pFooterURL
= searchValue( rBuffer
, persona
, ""footerURL":"" );
224 if ( pFooterURL
->isEmpty() )
227 *pTextColor
= searchValue( rBuffer
, persona
, ""textcolor":"" );
228 if ( pTextColor
->isEmpty() )
231 *pAccentColor
= searchValue( rBuffer
, persona
, ""accentcolor":"" );
232 if ( pAccentColor
->isEmpty() )
238 bool SvxPersonalizationTabPage::CopyPersonaToGallery( const OUString
&rURL
)
240 // init the input stream
241 uno::Reference
< ucb::XSimpleFileAccess3
> xFileAccess( ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() ), uno::UNO_QUERY
);
242 if ( !xFileAccess
.is() )
245 uno::Reference
< io::XInputStream
> xStream
;
247 xStream
= xFileAccess
->openFileRead( rURL
);
256 // read the persona specification
257 // NOTE: Parsing for real is an overkill here; and worse - I tried, and
258 // the HTML the site provides is not 100% valid ;-)
259 const sal_Int32 BUF_LEN
= 8000;
260 uno::Sequence
< sal_Int8
> buffer( BUF_LEN
);
261 OStringBuffer
aBuffer( 64000 );
264 while ( ( nRead
= xStream
->readBytes( buffer
, BUF_LEN
) ) == BUF_LEN
)
265 aBuffer
.append( reinterpret_cast< const char* >( buffer
.getConstArray() ), nRead
);
268 aBuffer
.append( reinterpret_cast< const char* >( buffer
.getConstArray() ), nRead
);
270 xStream
->closeInput();
272 // get the important bits of info
273 OUString aHeaderURL
, aFooterURL
, aTextColor
, aAccentColor
;
275 if ( !parsePersonaInfo( aBuffer
.makeStringAndClear(), &aHeaderURL
, &aFooterURL
, &aTextColor
, &aAccentColor
) )
278 // copy the images to the user's gallery
279 OUString gallery
= "${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE( "bootstrap") "::UserInstallation}";
280 rtl::Bootstrap::expandMacros( gallery
);
281 gallery
+= "/user/gallery/personas/";
282 osl::Directory::createPath( gallery
);
284 OUString
aHeaderFile( INetURLObject( aHeaderURL
).getName() );
285 OUString
aFooterFile( INetURLObject( aFooterURL
).getName() );
288 xFileAccess
->copy( aHeaderURL
, gallery
+ aHeaderFile
);
289 xFileAccess
->copy( aFooterURL
, gallery
+ aFooterFile
);
291 catch ( const uno::Exception
& )
296 m_aPersonaSettings
= aHeaderFile
+ ";" + aFooterFile
+ ";" + aTextColor
+ ";" + aAccentColor
;
301 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */