bump product version to 5.0.4.1
[LibreOffice.git] / cui / source / options / personalization.cxx
blobf19cfb4589d92720802a583edc2e35563941c807
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 <config_folders.h>
12 #include "personalization.hxx"
13 #include "personasdochandler.hxx"
15 #include <comphelper/processfactory.hxx>
16 #include <officecfg/Office/Common.hxx>
17 #include <com/sun/star/container/XNameAccess.hpp>
18 #include <com/sun/star/beans/XPropertySet.hpp>
19 #include <osl/file.hxx>
20 #include <rtl/bootstrap.hxx>
21 #include <rtl/strbuf.hxx>
22 #include <tools/urlobj.hxx>
23 #include <vcl/edit.hxx>
24 #include <vcl/msgbox.hxx>
25 #include <vcl/lstbox.hxx>
26 #include <vcl/svapp.hxx>
27 #include <vcl/settings.hxx>
28 #include <vcl/graphicfilter.hxx>
29 #include <dialmgr.hxx>
30 #include "cuires.hrc"
32 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
33 #include <com/sun/star/xml/sax/XParser.hpp>
34 #include <com/sun/star/xml/sax/Parser.hpp>
35 #include "ucbhelper/content.hxx"
37 using namespace com::sun::star;
38 using namespace ::com::sun::star::uno;
39 using namespace ::com::sun::star::ucb;
40 using namespace ::com::sun::star::beans;
42 SelectPersonaDialog::SelectPersonaDialog( vcl::Window *pParent )
43 : ModalDialog( pParent, "SelectPersonaDialog", "cui/ui/select_persona_dialog.ui" )
45 get( m_pSearchButton, "search_personas" );
46 m_pSearchButton->SetClickHdl( LINK( this, SelectPersonaDialog, SearchPersonas ) );
48 get( m_vSearchSuggestions[0], "suggestion1" );
49 m_vSearchSuggestions[0]->SetText( "LibreOffice" );
50 m_vSearchSuggestions[0]->SetClickHdl( LINK( this, SelectPersonaDialog, SearchPersonas ) );
52 get( m_vSearchSuggestions[1], "suggestion2" );
53 m_vSearchSuggestions[1]->SetText( CUI_RES ( RID_SVXSTR_PERSONA_ABSTRACT ) );
54 m_vSearchSuggestions[1]->SetClickHdl( LINK( this, SelectPersonaDialog, SearchPersonas ) );
56 get( m_vSearchSuggestions[2], "suggestion3" );
57 m_vSearchSuggestions[2]->SetText( CUI_RES ( RID_SVXSTR_PERSONA_COLOR ) );
58 m_vSearchSuggestions[2]->SetClickHdl( LINK( this, SelectPersonaDialog, SearchPersonas ) );
60 get( m_vSearchSuggestions[3], "suggestion4" );
61 m_vSearchSuggestions[3]->SetText( CUI_RES( RID_SVXSTR_PERSONA_MUSIC ) );
62 m_vSearchSuggestions[3]->SetClickHdl( LINK( this, SelectPersonaDialog, SearchPersonas ) );
64 get( m_vSearchSuggestions[4], "suggestion5" );
65 m_vSearchSuggestions[4]->SetText( CUI_RES( RID_SVXSTR_PERSONA_NATURE ) );
66 m_vSearchSuggestions[4]->SetClickHdl( LINK( this, SelectPersonaDialog, SearchPersonas ) );
68 get( m_pEdit, "search_term" );
69 m_pEdit->SetPlaceholderText( CUI_RES( RID_SVXSTR_SEARCHTERM ) );
71 get( m_pProgressLabel, "progress_label" );
73 get( m_pOkButton, "ok" );
74 m_pOkButton->SetClickHdl( LINK( this, SelectPersonaDialog, ActionOK ) );
76 get( m_pCancelButton, "cancel" );
77 m_pCancelButton->SetClickHdl( LINK( this, SelectPersonaDialog, ActionCancel ) );
78 get( m_vResultList[0], "result1" );
79 get( m_vResultList[1], "result2" );
80 get( m_vResultList[2], "result3" );
81 get( m_vResultList[3], "result4" );
82 get( m_vResultList[4], "result5" );
83 get( m_vResultList[5], "result6" );
84 get( m_vResultList[6], "result7" );
85 get( m_vResultList[7], "result8" );
86 get( m_vResultList[8], "result9" );
88 for (sal_Int32 nIndex = 0; nIndex < 9; ++nIndex)
90 m_vResultList[nIndex]->SetClickHdl( LINK( this, SelectPersonaDialog, SelectPersona ) );
91 m_vResultList[nIndex]->Disable();
95 SelectPersonaDialog::~SelectPersonaDialog()
97 disposeOnce();
100 void SelectPersonaDialog::dispose()
102 m_pEdit.clear();
103 m_pSearchButton.clear();
104 m_pProgressLabel.clear();
105 for (VclPtr<PushButton> vp : m_vResultList)
106 vp.clear();
107 for (VclPtr<PushButton> vp : m_vSearchSuggestions)
108 vp.clear();
109 m_pOkButton.clear();
110 m_pCancelButton.clear();
111 ModalDialog::dispose();
114 OUString SelectPersonaDialog::GetSelectedPersona() const
116 if( !m_aSelectedPersona.isEmpty( ) )
117 return m_aSelectedPersona;
119 return OUString();
122 IMPL_LINK( SelectPersonaDialog, SearchPersonas, PushButton*, pButton )
124 OUString searchTerm;
125 if( m_rSearchThread.is() )
126 m_rSearchThread->StopExecution();
128 if( pButton == m_pSearchButton )
129 searchTerm = m_pEdit->GetText();
130 else
132 for( sal_Int32 nIndex = 0; nIndex < 5; nIndex++ )
134 if( pButton == m_vSearchSuggestions[nIndex] )
136 searchTerm = m_vSearchSuggestions[nIndex]->GetDisplayText();
137 break;
142 if( searchTerm.isEmpty( ) )
143 return 0;
145 // TODO FIXME!
146 // Before the release, the allizom.org url shoud be changed to:
147 // OUString rSearchURL = "https://services.addons.mozilla.org/en-US/firefox/api/1.5/search/" + searchTerm + "/9/9";
148 // The problem why it cannot be done just now is that the SSL negotiation
149 // with services.addons.mozilla.org fails very early - during an early
150 // propfind, SSL returns X509_V_ERR_CERT_UNTRUSTED to neon, causing the
151 // NE_SSL_UNTRUSTED being set in verify_callback in neon/src/ne_openssl.c
153 // This is not cleared anywhere during the init, and so later, even though
154 // we have found the certificate, this triggers
155 // NeonSession_CertificationNotify callback, that
156 // causes that NE_SSL_UNTRUSTED is igored in cases when the condition
157 // if ( pSession->isDomainMatch(
158 // GetHostnamePart( xEECert.get()->getSubjectName() ) ) )
159 // is true; but that is only when getSubjectName() actually returns a
160 // wildcard, or the exact name.
162 // In the case of services.addons.mozilla.com, the certificate is for
163 // versioncheck.addons.mozilla.com, but it also has
164 // X509v3 Subject Alternative Name:
165 // DNS:services.addons.mozilla.org, DNS:versioncheck-bg.addons.mozilla.org, DNS:pyrepo.addons.mozilla.org, DNS:versioncheck.addons.mozilla.org
166 // So it is all valid; but the early X509_V_ERR_CERT_UNTRUSTED failure
167 // described above just makes this being ignored.
169 // My suspicion is that this never actually worked, and the
170 // if ( pSession->isDomainMatch(
171 // GetHostnamePart( xEECert.get()->getSubjectName() ) ) )
172 // works around the root cause that is there for years, and which makes it
173 // work in most cases. I guess that we initialize something wrongly or
174 // too late; but I have already spent few hours debugging, and
175 // give up for the moment - need to return to this at some stage.
176 OUString rSearchURL = "https://addons.allizom.org/en-US/firefox/api/1.5/search/" + searchTerm + "/9/9";
177 m_rSearchThread = new SearchAndParseThread( this, rSearchURL );
178 m_rSearchThread->launch();
179 return 0;
182 IMPL_LINK( SelectPersonaDialog, ActionOK, PushButton*, /* pButton */ )
184 OUString aSelectedPersona = GetSelectedPersona();
186 if( !aSelectedPersona.isEmpty() )
188 m_rSearchThread = new SearchAndParseThread( this, aSelectedPersona );
189 m_rSearchThread->launch();
192 else
194 if( m_rSearchThread.is() )
195 m_rSearchThread->StopExecution();
196 EndDialog( RET_OK );
198 return 0;
201 IMPL_LINK( SelectPersonaDialog, ActionCancel, PushButton*, /* pButton */ )
203 if( m_rSearchThread.is() )
204 m_rSearchThread->StopExecution();
206 EndDialog( RET_CANCEL );
207 return 0;
210 IMPL_LINK( SelectPersonaDialog, SelectPersona, PushButton*, pButton )
212 if( m_rSearchThread.is() )
213 m_rSearchThread->StopExecution();
215 for( sal_Int32 index = 0; index < 9; index++ )
217 if( pButton == m_vResultList[index] )
219 if( !m_vPersonaSettings[index].isEmpty() )
221 m_aSelectedPersona = m_vPersonaSettings[index];
222 // get the persona name from the setting variable to show in the progress.
223 sal_Int32 nNameIndex = m_aSelectedPersona.indexOf( ';' );
224 OUString aName = m_aSelectedPersona.copy( 0, nNameIndex );
225 OUString aProgress( CUI_RES( RID_SVXSTR_SELECTEDPERSONA ) );
226 aProgress += aName;
227 SetProgress( aProgress );
229 break;
232 return 0;
235 void SelectPersonaDialog::SetAppliedPersonaSetting( OUString& rPersonaSetting )
237 m_aAppliedPersona = rPersonaSetting;
240 OUString SelectPersonaDialog::GetAppliedPersonaSetting() const
242 return m_aAppliedPersona;
245 void SelectPersonaDialog::SetProgress( OUString& rProgress )
247 if(rProgress.isEmpty())
248 m_pProgressLabel->Hide();
249 else
251 SolarMutexGuard aGuard;
252 m_pProgressLabel->Show();
253 m_pProgressLabel->SetText( rProgress );
254 setOptimalLayoutSize();
258 void SelectPersonaDialog::SetImages( Image aImage, sal_Int32 nIndex )
260 m_vResultList[nIndex]->Enable();
261 m_vResultList[nIndex]->SetModeImage( aImage );
264 void SelectPersonaDialog::AddPersonaSetting( OUString& rPersonaSetting )
266 m_vPersonaSettings.push_back( rPersonaSetting );
269 void SelectPersonaDialog::ClearSearchResults()
271 m_vPersonaSettings.clear();
272 m_aSelectedPersona.clear();
273 for( sal_Int32 nIndex = 0; nIndex < 9; nIndex++ )
275 m_vResultList[nIndex]->Disable();
276 m_vResultList[nIndex]->SetModeImage(Image());
280 SvxPersonalizationTabPage::SvxPersonalizationTabPage( vcl::Window *pParent, const SfxItemSet &rSet )
281 : SfxTabPage( pParent, "PersonalizationTabPage", "cui/ui/personalization_tab.ui", &rSet )
283 // persona
284 get( m_pNoPersona, "no_persona" );
285 get( m_pDefaultPersona, "default_persona" );
287 get( m_pOwnPersona, "own_persona" );
288 m_pOwnPersona->SetClickHdl( LINK( this, SvxPersonalizationTabPage, ForceSelect ) );
290 get( m_pSelectPersona, "select_persona" );
291 m_pSelectPersona->SetClickHdl( LINK( this, SvxPersonalizationTabPage, SelectPersona ) );
293 get( m_vDefaultPersonaImages[0], "default1" );
294 m_vDefaultPersonaImages[0]->SetClickHdl( LINK( this, SvxPersonalizationTabPage, DefaultPersona ) );
296 get( m_vDefaultPersonaImages[1], "default2" );
297 m_vDefaultPersonaImages[1]->SetClickHdl( LINK( this, SvxPersonalizationTabPage, DefaultPersona ) );
299 get( m_vDefaultPersonaImages[2], "default3" );
300 m_vDefaultPersonaImages[2]->SetClickHdl( LINK( this, SvxPersonalizationTabPage, DefaultPersona ) );
302 get( m_pPersonaList, "installed_personas" );
303 m_pPersonaList->SetSelectHdl( LINK( this, SvxPersonalizationTabPage, SelectInstalledPersona ) );
305 get( m_pExtensionPersonaPreview, "persona_preview" );
307 get ( m_pExtensionLabel, "extensions_label" );
309 LoadDefaultImages();
310 LoadExtensionThemes();
313 SvxPersonalizationTabPage::~SvxPersonalizationTabPage()
315 disposeOnce();
318 void SvxPersonalizationTabPage::dispose()
320 m_pNoPersona.clear();
321 m_pDefaultPersona.clear();
322 m_pOwnPersona.clear();
323 m_pSelectPersona.clear();
324 for (int i=0; i<3; ++i)
325 m_vDefaultPersonaImages[i].clear();
326 m_pExtensionPersonaPreview.clear();
327 m_pPersonaList.clear();
328 m_pExtensionLabel.clear();
329 SfxTabPage::dispose();
333 VclPtr<SfxTabPage> SvxPersonalizationTabPage::Create( vcl::Window *pParent, const SfxItemSet *rSet )
335 return VclPtr<SvxPersonalizationTabPage>::Create( pParent, *rSet );
338 bool SvxPersonalizationTabPage::FillItemSet( SfxItemSet * )
340 // persona
341 OUString aPersona( "default" );
342 if ( m_pNoPersona->IsChecked() )
343 aPersona = "no";
344 else if ( m_pOwnPersona->IsChecked() )
345 aPersona = "own";
347 bool bModified = false;
348 uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
349 if ( xContext.is() &&
350 ( aPersona != officecfg::Office::Common::Misc::Persona::get( xContext ) ||
351 m_aPersonaSettings != officecfg::Office::Common::Misc::PersonaSettings::get( xContext ) ) )
353 bModified = true;
356 // write
357 std::shared_ptr< comphelper::ConfigurationChanges > batch( comphelper::ConfigurationChanges::create() );
358 if( aPersona == "no" )
359 m_aPersonaSettings.clear();
360 officecfg::Office::Common::Misc::Persona::set( aPersona, batch );
361 officecfg::Office::Common::Misc::PersonaSettings::set( m_aPersonaSettings, batch );
362 batch->commit();
364 if ( bModified )
366 // broadcast the change
367 DataChangedEvent aDataChanged( DataChangedEventType::SETTINGS, NULL, AllSettingsFlags::STYLE );
368 Application::NotifyAllWindows( aDataChanged );
371 return bModified;
374 void SvxPersonalizationTabPage::Reset( const SfxItemSet * )
376 uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
378 // persona
379 OUString aPersona( "default" );
380 if ( xContext.is() )
382 aPersona = officecfg::Office::Common::Misc::Persona::get( xContext );
383 m_aPersonaSettings = officecfg::Office::Common::Misc::PersonaSettings::get( xContext );
386 if ( aPersona == "no" )
387 m_pNoPersona->Check();
388 else if ( aPersona == "own" )
389 m_pOwnPersona->Check();
390 else
391 m_pDefaultPersona->Check();
394 void SvxPersonalizationTabPage::SetPersonaSettings( const OUString& aPersonaSettings )
396 m_aPersonaSettings = aPersonaSettings;
397 m_pOwnPersona->Check();
400 void SvxPersonalizationTabPage::LoadDefaultImages()
402 // Load the pre saved personas
404 OUString gallery( "" );
405 gallery = "$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER;
406 gallery += "/gallery/personas/";
407 rtl::Bootstrap::expandMacros( gallery );
408 OUString aPersonasList = gallery + "personas_list.txt";
409 SvFileStream aStream( aPersonasList, StreamMode::READ );
410 GraphicFilter aFilter;
411 Graphic aGraphic;
412 sal_Int32 nIndex = 0;
414 while( aStream.IsOpen() && !aStream.IsEof() )
416 OString aLine;
417 aStream.ReadLine( aLine );
418 OUString aPersonaSetting( OStringToOUString( aLine, RTL_TEXTENCODING_UTF8 ) );
419 OUString aPreviewFile;
420 sal_Int32 nNewIndex = aPersonaSetting.indexOf( ';', 0 );
421 if( nNewIndex < 0 )
422 break;
423 aPreviewFile = aPersonaSetting.copy( 0, nNewIndex );
424 aPersonaSetting = aPersonaSetting.copy( nNewIndex + 1 );
425 m_vDefaultPersonaSettings.push_back( aPersonaSetting );
427 INetURLObject aURLObj( gallery + aPreviewFile );
428 aFilter.ImportGraphic( aGraphic, aURLObj );
429 Bitmap aBmp = aGraphic.GetBitmap();
430 m_vDefaultPersonaImages[nIndex]->Show();
431 m_vDefaultPersonaImages[nIndex++]->SetModeImage( Image( aBmp ) );
435 void SvxPersonalizationTabPage::LoadExtensionThemes()
437 // See if any extensions are used to install personas. If yes, load them.
439 css::uno::Sequence<OUString> installedPersonas( officecfg::Office::Common::Misc::PersonasList::get()->getElementNames() );
440 sal_Int32 nLength = installedPersonas.getLength();
442 if( nLength == 0 )
443 return;
445 m_pPersonaList->Show();
446 m_pExtensionLabel->Show();
448 for( sal_Int32 nIndex = 0; nIndex < nLength; nIndex++ )
450 Reference< XPropertySet > xPropertySet( officecfg::Office::Common::Misc::PersonasList::get()->getByName( installedPersonas[nIndex] ), UNO_QUERY_THROW );
451 OUString aPersonaName, aPreviewFile, aHeaderFile, aFooterFile, aTextColor, aAccentColor, aPersonaSettings;
452 Any aValue = xPropertySet->getPropertyValue( "Name" );
453 aValue >>= aPersonaName;
454 m_pPersonaList->InsertEntry( aPersonaName );
456 aValue = xPropertySet->getPropertyValue( "Preview" );
457 aValue >>= aPreviewFile;
459 aValue = xPropertySet->getPropertyValue( "Header" );
460 aValue >>= aHeaderFile;
462 aValue = xPropertySet->getPropertyValue( "Footer" );
463 aValue >>= aFooterFile;
465 aValue = xPropertySet->getPropertyValue( "TextColor" );
466 aValue >>= aTextColor;
468 aValue = xPropertySet->getPropertyValue( "AccentColor" );
469 aValue >>= aAccentColor;
471 aPersonaSettings = aPreviewFile + ";" + aHeaderFile + ";" + aFooterFile + ";" + aTextColor + ";" + aAccentColor;
472 rtl::Bootstrap::expandMacros( aPersonaSettings );
473 m_vExtensionPersonaSettings.push_back( aPersonaSettings );
477 IMPL_LINK( SvxPersonalizationTabPage, SelectPersona, PushButton*, /*pButton*/ )
479 ScopedVclPtrInstance< SelectPersonaDialog > aDialog(nullptr);
481 if ( aDialog->Execute() == RET_OK )
483 OUString aPersonaSetting( aDialog->GetAppliedPersonaSetting() );
484 if ( !aPersonaSetting.isEmpty() )
486 SetPersonaSettings( aPersonaSetting );
490 return 0;
493 IMPL_LINK( SvxPersonalizationTabPage, ForceSelect, RadioButton*, pButton )
495 if ( pButton == m_pOwnPersona && m_aPersonaSettings.isEmpty() )
496 SelectPersona( m_pSelectPersona );
498 return 0;
501 IMPL_LINK( SvxPersonalizationTabPage, DefaultPersona, PushButton*, pButton )
503 m_pDefaultPersona->Check();
504 for( sal_Int32 nIndex = 0; nIndex < 3; nIndex++ )
506 if( pButton == m_vDefaultPersonaImages[nIndex] )
507 m_aPersonaSettings = m_vDefaultPersonaSettings[nIndex];
510 return 0;
513 IMPL_LINK( SvxPersonalizationTabPage, SelectInstalledPersona, ListBox*, )
515 m_pOwnPersona->Check();
517 // Get the details of the selected theme.
518 m_pExtensionPersonaPreview->Show();
519 sal_Int32 nSelectedPos = m_pPersonaList->GetSelectEntryPos();
520 OUString aSettings = m_vExtensionPersonaSettings[nSelectedPos];
521 sal_Int32 nIndex = aSettings.indexOf( ';', 0 );
522 OUString aPreviewFile = aSettings.copy( 0, nIndex );
523 m_aPersonaSettings = aSettings.copy( nIndex + 1 );
525 // Show the preview file in the button.
526 GraphicFilter aFilter;
527 Graphic aGraphic;
528 INetURLObject aURLObj( aPreviewFile );
529 aFilter.ImportGraphic( aGraphic, aURLObj );
530 Bitmap aBmp = aGraphic.GetBitmap();
531 m_pExtensionPersonaPreview->SetModeImage( Image( aBmp ) );
533 return 0;
536 /// Find the value on the Persona page, and convert it to a usable form.
537 static OUString searchValue( const OString &rBuffer, sal_Int32 from, const OString &rIdentifier )
539 sal_Int32 where = rBuffer.indexOf( rIdentifier, from );
540 if ( where < 0 )
541 return OUString();
543 where += rIdentifier.getLength();
545 sal_Int32 end = rBuffer.indexOf( "&#34;", where );
546 if ( end < 0 )
547 return OUString();
549 OString aOString( rBuffer.copy( where, end - where ) );
550 OUString aString( aOString.getStr(), aOString.getLength(), RTL_TEXTENCODING_UTF8, OSTRING_TO_OUSTRING_CVTFLAGS );
552 return aString.replaceAll( "\\/", "/" );
555 /// Parse the Persona web page, and find where to get the bitmaps + the color values.
556 static bool parsePersonaInfo( const OString &rBuffer, OUString *pHeaderURL, OUString *pFooterURL,
557 OUString *pTextColor, OUString *pAccentColor, OUString *pPreviewURL,
558 OUString *pName )
560 // it is the first attribute that contains "persona="
561 sal_Int32 persona = rBuffer.indexOf( "data-browsertheme=\"{" );
562 if ( persona < 0 )
563 return false;
565 // now search inside
566 *pHeaderURL = searchValue( rBuffer, persona, "&#34;headerURL&#34;:&#34;" );
567 if ( pHeaderURL->isEmpty() )
568 return false;
570 *pFooterURL = searchValue( rBuffer, persona, "&#34;footerURL&#34;:&#34;" );
571 if ( pFooterURL->isEmpty() )
572 return false;
574 *pTextColor = searchValue( rBuffer, persona, "&#34;textcolor&#34;:&#34;" );
575 if ( pTextColor->isEmpty() )
576 return false;
578 *pAccentColor = searchValue( rBuffer, persona, "&#34;accentcolor&#34;:&#34;" );
579 if ( pAccentColor->isEmpty() )
580 return false;
582 *pPreviewURL = searchValue( rBuffer, persona, "&#34;previewURL&#34;:&#34;" );
583 if ( pPreviewURL->isEmpty() )
584 return false;
586 *pName = searchValue( rBuffer, persona, "&#34;name&#34;:&#34;" );
587 if ( pName->isEmpty() )
588 return false;
590 return true;
593 SearchAndParseThread::SearchAndParseThread( SelectPersonaDialog* pDialog,
594 const OUString& rURL ) :
595 Thread( "cuiPersonasSearchThread" ),
596 m_pPersonaDialog( pDialog ),
597 m_aURL( rURL ),
598 m_bExecute( true )
602 SearchAndParseThread::~SearchAndParseThread()
606 void SearchAndParseThread::execute()
608 if( m_aURL.startsWith( "https://" ) )
610 m_pPersonaDialog->ClearSearchResults();
611 OUString sProgress( CUI_RES( RID_SVXSTR_SEARCHING ) );
612 m_pPersonaDialog->SetProgress( sProgress );
613 Reference<XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
614 Reference< xml::sax::XParser > xParser = xml::sax::Parser::create(xContext);
615 PersonasDocHandler* pHandler = new PersonasDocHandler();
616 Reference< xml::sax::XDocumentHandler > xDocHandler = pHandler;
617 uno::Reference< ucb::XSimpleFileAccess3 > xFileAccess( ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() ), uno::UNO_QUERY );
618 uno::Reference< io::XInputStream > xStream;
619 xParser->setDocumentHandler( xDocHandler );
621 if ( !xFileAccess.is() )
622 return;
624 try {
625 xStream = xFileAccess->openFileRead( m_aURL );
627 catch (...)
629 sProgress = CUI_RES(RID_SVXSTR_SEARCHERROR);
630 sProgress = sProgress.replaceAll("%1", m_aURL);
631 m_pPersonaDialog->SetProgress(sProgress);
632 return;
635 xml::sax::InputSource aParserInput;
636 aParserInput.aInputStream = xStream;
637 xParser->parseStream( aParserInput );
639 if( !pHandler->hasResults() )
641 sProgress = CUI_RES( RID_SVXSTR_NORESULTS );
642 m_pPersonaDialog->SetProgress( sProgress );
643 return;
646 std::vector<OUString> vLearnmoreURLs = pHandler->getLearnmoreURLs();
647 std::vector<OUString>::iterator it;
648 sal_Int32 nIndex = 0;
649 GraphicFilter aFilter;
650 Graphic aGraphic;
652 for( it = vLearnmoreURLs.begin(); it!=vLearnmoreURLs.end(); ++it )
654 OUString sPreviewFile, aPersonaSetting;
655 getPreviewFile( *it, &sPreviewFile, &aPersonaSetting );
656 INetURLObject aURLObj( sPreviewFile );
657 aFilter.ImportGraphic( aGraphic, aURLObj );
658 Bitmap aBmp = aGraphic.GetBitmap();
660 if( !m_bExecute )
661 return;
663 // for VCL to be able to do visual changes in the thread
664 SolarMutexGuard aGuard;
665 m_pPersonaDialog->SetImages( Image( aBmp ), nIndex++ );
666 m_pPersonaDialog->setOptimalLayoutSize();
667 m_pPersonaDialog->AddPersonaSetting( aPersonaSetting );
670 if( !m_bExecute )
671 return;
673 SolarMutexGuard aGuard;
674 sProgress.clear();
675 m_pPersonaDialog->SetProgress( sProgress );
676 m_pPersonaDialog->setOptimalLayoutSize();
679 else
681 OUString sProgress( CUI_RES( RID_SVXSTR_APPLYPERSONA ) );
682 m_pPersonaDialog->SetProgress( sProgress );
684 uno::Reference< ucb::XSimpleFileAccess3 > xFileAccess( ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() ), uno::UNO_QUERY );
685 if ( !xFileAccess.is() )
686 return;
688 OUString aName, aHeaderURL, aFooterURL, aTextColor, aAccentColor;
689 OUString aPersonaSetting;
691 // get the required fields from m_aURL
692 sal_Int32 nOldIndex = 0;
693 sal_Int32 nNewIndex = m_aURL.indexOf( ';', nOldIndex );
694 aName = m_aURL.copy( nOldIndex, ( nNewIndex - nOldIndex ) );
696 nOldIndex = nNewIndex + 1;
697 nNewIndex = m_aURL.indexOf( ';', nOldIndex );
698 aHeaderURL = m_aURL.copy(nOldIndex , ( nNewIndex - nOldIndex ) );
700 nOldIndex = nNewIndex + 1;
701 nNewIndex = m_aURL.indexOf( ';', nOldIndex );
702 aFooterURL = m_aURL.copy( nOldIndex, ( nNewIndex - nOldIndex ) );
704 nOldIndex = nNewIndex + 1;
705 nNewIndex = m_aURL.indexOf( ';', nOldIndex );
706 aTextColor = m_aURL.copy( nOldIndex, ( nNewIndex - nOldIndex ) );
708 nOldIndex = nNewIndex + 1;
709 nNewIndex = m_aURL.getLength();
710 aAccentColor = m_aURL.copy( nOldIndex, ( nNewIndex - nOldIndex ) );
712 // copy the images to the user's gallery
713 OUString gallery = "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE( "bootstrap") "::UserInstallation}";
714 rtl::Bootstrap::expandMacros( gallery );
715 gallery += "/user/gallery/personas/";
716 osl::Directory::createPath( gallery );
718 OUString aHeaderFile( INetURLObject( aHeaderURL ).getName() );
719 OUString aFooterFile( INetURLObject( aFooterURL ).getName() );
721 aHeaderFile = aName + "/" + aHeaderFile;
722 aFooterFile = aName + "/" + aFooterFile;
724 try {
725 xFileAccess->copy( aHeaderURL, gallery + aHeaderFile );
726 xFileAccess->copy( aFooterURL, gallery + aFooterFile );
728 catch ( const uno::Exception & )
730 sProgress = CUI_RES( RID_SVXSTR_SEARCHERROR );
731 sProgress = sProgress.replaceAll("%1", m_aURL);
732 m_pPersonaDialog->SetProgress( sProgress );
733 return;
736 if( !m_bExecute )
737 return;
739 SolarMutexGuard aGuard;
741 aPersonaSetting = aHeaderFile + ";" + aFooterFile + ";" + aTextColor + ";" + aAccentColor;
742 m_pPersonaDialog->SetAppliedPersonaSetting( aPersonaSetting );
743 m_pPersonaDialog->EndDialog( RET_OK );
747 void SearchAndParseThread::getPreviewFile( const OUString& rURL, OUString *pPreviewFile, OUString *pPersonaSetting )
749 uno::Reference< ucb::XSimpleFileAccess3 > xFileAccess( ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() ), uno::UNO_QUERY );
750 if ( !xFileAccess.is() )
751 return;
753 uno::Reference< io::XInputStream > xStream;
754 try {
755 xStream = xFileAccess->openFileRead( rURL );
757 catch (...)
759 OUString sProgress( CUI_RES( RID_SVXSTR_SEARCHERROR ) );
760 sProgress = sProgress.replaceAll("%1", m_aURL);
761 m_pPersonaDialog->SetProgress( sProgress );
762 return;
764 if ( !xStream.is() )
765 return;
767 // read the persona specification
768 // NOTE: Parsing for real is an overkill here; and worse - I tried, and
769 // the HTML the site provides is not 100% valid ;-)
770 const sal_Int32 BUF_LEN = 8000;
771 uno::Sequence< sal_Int8 > buffer( BUF_LEN );
772 OStringBuffer aBuffer( 64000 );
774 sal_Int32 nRead = 0;
775 while ( ( nRead = xStream->readBytes( buffer, BUF_LEN ) ) == BUF_LEN )
776 aBuffer.append( reinterpret_cast< const char* >( buffer.getConstArray() ), nRead );
778 if ( nRead > 0 )
779 aBuffer.append( reinterpret_cast< const char* >( buffer.getConstArray() ), nRead );
781 xStream->closeInput();
783 // get the important bits of info
784 OUString aHeaderURL, aFooterURL, aTextColor, aAccentColor, aPreviewURL, aName;
786 if ( !parsePersonaInfo( aBuffer.makeStringAndClear(), &aHeaderURL, &aFooterURL, &aTextColor, &aAccentColor, &aPreviewURL, &aName ) )
787 return;
789 // copy the images to the user's gallery
790 OUString gallery = "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE( "bootstrap") "::UserInstallation}";
791 rtl::Bootstrap::expandMacros( gallery );
792 gallery += "/user/gallery/personas/";
793 gallery += aName + "/";
794 osl::Directory::createPath( gallery );
796 OUString aPreviewFile( INetURLObject( aPreviewURL ).getName() );
798 try {
799 xFileAccess->copy( aPreviewURL, gallery + aPreviewFile );
801 catch ( const uno::Exception & )
803 return;
805 *pPreviewFile = gallery + aPreviewFile;
806 *pPersonaSetting = aName + ";" + aHeaderURL + ";" + aFooterURL + ";" + aTextColor + ";" + aAccentColor;
809 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */