Line data Source code
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 :
10 : #include "personalization.hxx"
11 :
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 :
20 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
21 : #include <com/sun/star/system/SystemShellExecute.hpp>
22 : #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
23 : #include <com/sun/star/ucb/SimpleFileAccess.hpp>
24 : #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
25 : #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
26 : #include <com/sun/star/ui/dialogs/XFilePicker.hpp>
27 : #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
28 : #include <com/sun/star/ui/dialogs/XFilterManager.hpp>
29 :
30 : using namespace com::sun::star;
31 :
32 : /** Dialog that will allow the user to choose a Persona to use.
33 :
34 : So far there is no better possibility than just to paste the URL from
35 : http://www.getpersona.com ...
36 : */
37 0 : class SelectPersonaDialog : public ModalDialog
38 : {
39 : private:
40 : Edit *m_pEdit; ///< The input line for the Persona URL
41 :
42 : public:
43 : SelectPersonaDialog( Window *pParent );
44 :
45 : /// Get the URL from the Edit field.
46 : OUString GetPersonaURL() const;
47 :
48 : private:
49 : /// Handle the [Visit Firefox Personas] button
50 : DECL_LINK( VisitPersonas, PushButton* );
51 : };
52 :
53 0 : SelectPersonaDialog::SelectPersonaDialog( Window *pParent )
54 0 : : ModalDialog( pParent, "SelectPersonaDialog", "cui/ui/select_persona_dialog.ui" )
55 : {
56 : PushButton *pButton;
57 0 : get( pButton, "visit_personas" );
58 0 : pButton->SetClickHdl( LINK( this, SelectPersonaDialog, VisitPersonas ) );
59 :
60 0 : get( m_pEdit, "persona_url" );
61 0 : m_pEdit->SetPlaceholderText( "http://www.getpersonas.com/persona/" );
62 0 : }
63 :
64 0 : OUString SelectPersonaDialog::GetPersonaURL() const
65 : {
66 0 : OUString aText( m_pEdit->GetText() );
67 :
68 0 : if ( !aText.startsWith( "http://www.getpersonas.com/" ) &&
69 0 : !aText.startsWith( "https://www.getpersonas.com/" ) )
70 : {
71 0 : return OUString();
72 : }
73 :
74 0 : return aText;
75 : }
76 :
77 0 : IMPL_LINK( SelectPersonaDialog, VisitPersonas, PushButton*, /*pButton*/ )
78 : {
79 0 : uno::Reference< com::sun::star::system::XSystemShellExecute > xSystemShell( com::sun::star::system::SystemShellExecute::create( ::comphelper::getProcessComponentContext() ) );
80 :
81 0 : xSystemShell->execute( "http://www.getpersonas.com", OUString(), com::sun::star::system::SystemShellExecuteFlags::URIS_ONLY );
82 :
83 0 : return 0;
84 : }
85 :
86 0 : SvxPersonalizationTabPage::SvxPersonalizationTabPage( Window *pParent, const SfxItemSet &rSet )
87 : : SfxTabPage( pParent, "PersonalizationTabPage", "cui/ui/personalization_tab.ui", rSet ),
88 0 : m_aBackgroundURL()
89 : {
90 : // background image
91 0 : get( m_pNoBackground, "no_background" );
92 0 : get( m_pDefaultBackground, "default_background" );
93 :
94 0 : get( m_pOwnBackground, "own_background" );
95 0 : m_pOwnBackground->SetClickHdl( LINK( this, SvxPersonalizationTabPage, ForceSelect ) );
96 :
97 0 : get( m_pSelectBackground, "select_background" );
98 0 : m_pSelectBackground->SetClickHdl( LINK( this, SvxPersonalizationTabPage, SelectBackground ) );
99 :
100 : // persona
101 0 : get( m_pNoPersona, "no_persona" );
102 0 : get( m_pDefaultPersona, "default_persona" );
103 :
104 0 : get( m_pOwnPersona, "own_persona" );
105 0 : m_pOwnPersona->SetClickHdl( LINK( this, SvxPersonalizationTabPage, ForceSelect ) );
106 :
107 0 : get( m_pSelectPersona, "select_persona" );
108 0 : m_pSelectPersona->SetClickHdl( LINK( this, SvxPersonalizationTabPage, SelectPersona ) );
109 :
110 : #ifndef __WIN32__
111 : // so far available for Windows only
112 : Window *pWindow;
113 0 : get( pWindow, "personas_label" );
114 0 : pWindow->Hide();
115 :
116 0 : m_pNoPersona->Hide();
117 0 : m_pDefaultPersona->Hide();
118 0 : m_pOwnPersona->Hide();
119 0 : m_pSelectPersona->Hide();
120 : #endif
121 0 : }
122 :
123 0 : SvxPersonalizationTabPage::~SvxPersonalizationTabPage()
124 : {
125 0 : }
126 :
127 0 : SfxTabPage* SvxPersonalizationTabPage::Create( Window *pParent, const SfxItemSet &rSet )
128 : {
129 0 : return new SvxPersonalizationTabPage( pParent, rSet );
130 : }
131 :
132 0 : sal_Bool SvxPersonalizationTabPage::FillItemSet( SfxItemSet & )
133 : {
134 : // background image
135 0 : OUString aBackground( "default" );
136 0 : if ( m_pNoBackground->IsChecked() )
137 0 : aBackground = "no";
138 0 : else if ( m_pOwnBackground->IsChecked() )
139 0 : aBackground = "own";
140 :
141 : // persona
142 0 : OUString aPersona( "default" );
143 0 : if ( m_pNoPersona->IsChecked() )
144 0 : aPersona = "no";
145 0 : else if ( m_pOwnPersona->IsChecked() )
146 0 : aPersona = "own";
147 :
148 0 : bool bModified = false;
149 0 : uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
150 0 : if ( xContext.is() &&
151 0 : ( aBackground != officecfg::Office::Common::Misc::BackgroundImage::get( xContext ) ||
152 0 : m_aBackgroundURL != officecfg::Office::Common::Misc::BackgroundImageURL::get( xContext ) ||
153 0 : aPersona != officecfg::Office::Common::Misc::Persona::get( xContext ) ||
154 0 : m_aPersonaSettings != officecfg::Office::Common::Misc::PersonaSettings::get( xContext ) ) )
155 : {
156 0 : bModified = true;
157 : }
158 :
159 : // write
160 0 : boost::shared_ptr< comphelper::ConfigurationChanges > batch( comphelper::ConfigurationChanges::create() );
161 :
162 0 : officecfg::Office::Common::Misc::BackgroundImage::set( aBackground, batch );
163 0 : officecfg::Office::Common::Misc::BackgroundImageURL::set( m_aBackgroundURL, batch );
164 0 : officecfg::Office::Common::Misc::Persona::set( aPersona, batch );
165 0 : officecfg::Office::Common::Misc::PersonaSettings::set( m_aPersonaSettings, batch );
166 :
167 0 : batch->commit();
168 :
169 0 : return bModified;
170 : }
171 :
172 0 : void SvxPersonalizationTabPage::Reset( const SfxItemSet & )
173 : {
174 0 : uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
175 :
176 : // background image
177 0 : OUString aBackground( "default" );
178 0 : if ( xContext.is() )
179 : {
180 0 : aBackground = officecfg::Office::Common::Misc::BackgroundImage::get( xContext );
181 0 : m_aBackgroundURL = officecfg::Office::Common::Misc::BackgroundImageURL::get( xContext );
182 : }
183 :
184 0 : if ( aBackground == "no" )
185 0 : m_pNoBackground->Check();
186 0 : else if ( aBackground == "own" )
187 0 : m_pOwnBackground->Check();
188 : else
189 0 : m_pDefaultBackground->Check();
190 :
191 : // persona
192 0 : OUString aPersona( "default" );
193 0 : if ( xContext.is() )
194 : {
195 0 : aPersona = officecfg::Office::Common::Misc::Persona::get( xContext );
196 0 : m_aPersonaSettings = officecfg::Office::Common::Misc::PersonaSettings::get( xContext );
197 : }
198 :
199 0 : if ( aPersona == "no" )
200 0 : m_pNoPersona->Check();
201 0 : else if ( aPersona == "own" )
202 0 : m_pOwnPersona->Check();
203 : else
204 0 : m_pDefaultPersona->Check();
205 0 : }
206 :
207 0 : IMPL_LINK( SvxPersonalizationTabPage, SelectBackground, PushButton*, /*pButton*/ )
208 : {
209 0 : uno::Reference< lang::XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() );
210 0 : if ( !xFactory.is() )
211 0 : return 0;
212 :
213 0 : uno::Reference< ui::dialogs::XFilePicker > xFilePicker( xFactory->createInstance( "com.sun.star.ui.dialogs.FilePicker" ), uno::UNO_QUERY );
214 0 : if ( !xFilePicker.is() )
215 0 : return 0;
216 :
217 0 : xFilePicker->setMultiSelectionMode( false );
218 :
219 0 : uno::Reference< ui::dialogs::XFilePickerControlAccess > xController( xFilePicker, uno::UNO_QUERY );
220 0 : if ( xController.is() )
221 0 : xController->setValue( ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PREVIEW, 0, uno::makeAny( sal_True ) );
222 :
223 0 : uno::Reference< ui::dialogs::XFilterManager > xFilterMgr( xFilePicker, uno::UNO_QUERY );
224 0 : if ( xFilterMgr.is() )
225 0 : xFilterMgr->appendFilter( "Background images (*.jpg;*.png)", "*.jpg;*.png" ); // TODO localize
226 :
227 0 : while ( xFilePicker->execute() == ui::dialogs::ExecutableDialogResults::OK )
228 : {
229 0 : OUString aFile( xFilePicker->getFiles()[0] );
230 :
231 0 : if ( aFile.startsWith( "file:///" ) && ( aFile.endsWith( ".png" ) || aFile.endsWith( ".jpg" ) ) )
232 : {
233 0 : m_aBackgroundURL = aFile;
234 0 : m_pOwnBackground->Check();
235 : break;
236 : }
237 :
238 : // TODO display what is wrong (not a file:// or not .png / .jpg)
239 0 : }
240 :
241 0 : return 0;
242 : }
243 :
244 0 : IMPL_LINK( SvxPersonalizationTabPage, SelectPersona, PushButton*, /*pButton*/ )
245 : {
246 0 : SelectPersonaDialog aDialog( NULL );
247 :
248 0 : while ( aDialog.Execute() == RET_OK )
249 : {
250 0 : OUString aURL( aDialog.GetPersonaURL() );
251 0 : if ( aURL != "" )
252 : {
253 0 : if ( CopyPersonaToGallery( aURL ) )
254 0 : m_pOwnPersona->Check();
255 : break;
256 : }
257 : // else TODO msgbox that the URL did not match
258 0 : }
259 :
260 0 : return 0;
261 : }
262 :
263 0 : IMPL_LINK( SvxPersonalizationTabPage, ForceSelect, RadioButton*, pButton )
264 : {
265 0 : if ( pButton == m_pOwnBackground && m_aBackgroundURL.isEmpty() )
266 0 : SelectBackground( m_pSelectBackground );
267 0 : else if ( pButton == m_pOwnPersona && m_aPersonaSettings.isEmpty() )
268 0 : SelectPersona( m_pSelectPersona );
269 :
270 0 : return 0;
271 : }
272 :
273 : /// Find the value on the Persona page, and convert it to a usable form.
274 0 : static OUString searchValue( const OString &rBuffer, sal_Int32 from, const OString &rIdentifier )
275 : {
276 0 : sal_Int32 where = rBuffer.indexOf( rIdentifier, from );
277 0 : if ( where < 0 )
278 0 : return OUString();
279 :
280 0 : where += rIdentifier.getLength();
281 :
282 0 : sal_Int32 end = rBuffer.indexOf( """, where );
283 0 : if ( end < 0 )
284 0 : return OUString();
285 :
286 0 : OString aOString( rBuffer.copy( where, end - where ) );
287 0 : OUString aString( aOString.getStr(), aOString.getLength(), RTL_TEXTENCODING_UTF8, OSTRING_TO_OUSTRING_CVTFLAGS );
288 :
289 0 : return aString.replaceAll( "\\/", "/" );
290 : }
291 :
292 : /// Parse the Persona web page, and find where to get the bitmaps + the color values.
293 0 : static bool parsePersonaInfo( const OString &rBuffer, OUString *pHeaderURL, OUString *pFooterURL, OUString *pTextColor, OUString *pAccentColor )
294 : {
295 : // it is the first attribute that contains "persona="
296 0 : sal_Int32 persona = rBuffer.indexOf( "persona=\"{" );
297 0 : if ( persona < 0 )
298 0 : return false;
299 :
300 : // now search inside
301 0 : *pHeaderURL = searchValue( rBuffer, persona, ""headerURL":"" );
302 0 : if ( pHeaderURL->isEmpty() )
303 0 : return false;
304 :
305 0 : *pFooterURL = searchValue( rBuffer, persona, ""footerURL":"" );
306 0 : if ( pFooterURL->isEmpty() )
307 0 : return false;
308 :
309 0 : *pTextColor = searchValue( rBuffer, persona, ""textcolor":"" );
310 0 : if ( pTextColor->isEmpty() )
311 0 : return false;
312 :
313 0 : *pAccentColor = searchValue( rBuffer, persona, ""accentcolor":"" );
314 0 : if ( pAccentColor->isEmpty() )
315 0 : return false;
316 :
317 0 : return true;
318 : }
319 :
320 0 : bool SvxPersonalizationTabPage::CopyPersonaToGallery( const OUString &rURL )
321 : {
322 : // init the input stream
323 0 : uno::Reference< ucb::XSimpleFileAccess3 > xFileAccess( ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() ), uno::UNO_QUERY );
324 0 : if ( !xFileAccess.is() )
325 0 : return false;
326 :
327 0 : uno::Reference< io::XInputStream > xStream( xFileAccess->openFileRead( rURL ), uno::UNO_QUERY );
328 0 : if ( !xStream.is() )
329 0 : return false;
330 :
331 : // read the persona specification
332 : // NOTE: Parsing for real is an overkill here; and worse - I tried, and
333 : // the HTML the site provides is not 100% valid ;-)
334 0 : const sal_Int32 BUF_LEN = 8000;
335 0 : uno::Sequence< sal_Int8 > buffer( BUF_LEN );
336 0 : OStringBuffer aBuffer( 64000 );
337 :
338 0 : sal_Int32 nRead = 0;
339 0 : while ( ( nRead = xStream->readBytes( buffer, BUF_LEN ) ) == BUF_LEN )
340 0 : aBuffer.append( reinterpret_cast< const char* >( buffer.getConstArray() ), nRead );
341 :
342 0 : if ( nRead > 0 )
343 0 : aBuffer.append( reinterpret_cast< const char* >( buffer.getConstArray() ), nRead );
344 :
345 0 : xStream->closeInput();
346 :
347 : // get the important bits of info
348 0 : OUString aHeaderURL, aFooterURL, aTextColor, aAccentColor;
349 :
350 0 : if ( !parsePersonaInfo( aBuffer.makeStringAndClear(), &aHeaderURL, &aFooterURL, &aTextColor, &aAccentColor ) )
351 0 : return false;
352 :
353 : // copy the images to the user's gallery
354 0 : OUString gallery = "${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE( "bootstrap") "::UserInstallation}";
355 0 : rtl::Bootstrap::expandMacros( gallery );
356 0 : gallery += "/user/gallery/personas/";
357 0 : osl::Directory::createPath( gallery );
358 :
359 0 : OUString aHeaderFile( INetURLObject( aHeaderURL ).getName() );
360 0 : OUString aFooterFile( INetURLObject( aFooterURL ).getName() );
361 :
362 : try {
363 0 : xFileAccess->copy( aHeaderURL, gallery + aHeaderFile );
364 0 : xFileAccess->copy( aFooterURL, gallery + aFooterFile );
365 : }
366 0 : catch ( const uno::Exception & )
367 : {
368 0 : return false;
369 : }
370 :
371 0 : m_aPersonaSettings = aHeaderFile + ";" + aFooterFile + ";" + aTextColor + ";" + aAccentColor;
372 :
373 0 : return true;
374 3 : }
375 :
376 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|