bump product version to 4.1.6.2
[LibreOffice.git] / cui / source / options / personalization.cxx
blob453fc30e131adfd615e5c2174e2dfa01be02cb9f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
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
41 private:
42 Edit *m_pEdit; ///< The input line for the Persona URL
44 public:
45 SelectPersonaDialog( Window *pParent );
47 /// Get the URL from the Edit field.
48 OUString GetPersonaURL() const;
50 private:
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" )
58 PushButton *pButton;
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/" ) )
71 return aText;
73 return OUString();
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 );
82 return 0;
85 SvxPersonalizationTabPage::SvxPersonalizationTabPage( Window *pParent, const SfxItemSet &rSet )
86 : SfxTabPage( pParent, "PersonalizationTabPage", "cui/ui/personalization_tab.ui", rSet )
88 // persona
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 & )
110 // persona
111 OUString aPersona( "default" );
112 if ( m_pNoPersona->IsChecked() )
113 aPersona = "no";
114 else if ( m_pOwnPersona->IsChecked() )
115 aPersona = "own";
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 ) ) )
123 bModified = true;
126 // write
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 );
132 batch->commit();
134 if ( bModified )
136 // broadcast the change
137 DataChangedEvent aDataChanged( DATACHANGED_SETTINGS, NULL, SETTINGS_STYLE );
138 Application::NotifyAllWindows( aDataChanged );
141 return bModified;
144 void SvxPersonalizationTabPage::Reset( const SfxItemSet & )
146 uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
148 // persona
149 OUString aPersona( "default" );
150 if ( xContext.is() )
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();
160 else
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();
175 break;
177 // else TODO msgbox that the URL did not match
180 return 0;
183 IMPL_LINK( SvxPersonalizationTabPage, ForceSelect, RadioButton*, pButton )
185 if ( pButton == m_pOwnPersona && m_aPersonaSettings.isEmpty() )
186 SelectPersona( m_pSelectPersona );
188 return 0;
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 );
195 if ( where < 0 )
196 return OUString();
198 where += rIdentifier.getLength();
200 sal_Int32 end = rBuffer.indexOf( "&#34;", where );
201 if ( end < 0 )
202 return OUString();
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=\"{" );
215 if ( persona < 0 )
216 return false;
218 // now search inside
219 *pHeaderURL = searchValue( rBuffer, persona, "&#34;headerURL&#34;:&#34;" );
220 if ( pHeaderURL->isEmpty() )
221 return false;
223 *pFooterURL = searchValue( rBuffer, persona, "&#34;footerURL&#34;:&#34;" );
224 if ( pFooterURL->isEmpty() )
225 return false;
227 *pTextColor = searchValue( rBuffer, persona, "&#34;textcolor&#34;:&#34;" );
228 if ( pTextColor->isEmpty() )
229 return false;
231 *pAccentColor = searchValue( rBuffer, persona, "&#34;accentcolor&#34;:&#34;" );
232 if ( pAccentColor->isEmpty() )
233 return false;
235 return true;
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() )
243 return false;
245 uno::Reference< io::XInputStream > xStream;
246 try {
247 xStream = xFileAccess->openFileRead( rURL );
249 catch (...)
251 return false;
253 if ( !xStream.is() )
254 return false;
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 );
263 sal_Int32 nRead = 0;
264 while ( ( nRead = xStream->readBytes( buffer, BUF_LEN ) ) == BUF_LEN )
265 aBuffer.append( reinterpret_cast< const char* >( buffer.getConstArray() ), nRead );
267 if ( nRead > 0 )
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 ) )
276 return false;
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() );
287 try {
288 xFileAccess->copy( aHeaderURL, gallery + aHeaderFile );
289 xFileAccess->copy( aFooterURL, gallery + aFooterFile );
291 catch ( const uno::Exception & )
293 return false;
296 m_aPersonaSettings = aHeaderFile + ";" + aFooterFile + ";" + aTextColor + ";" + aAccentColor;
298 return true;
301 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */