Currently, entering a search term or clicking on the category buttons on the Firefox Theme selection dialog of Personalization option doesn't work at all. With this url, it returns some results of firefox personas which are applicable to LibreOffice. Change-Id: Ie4da58cd987a1834dee969c09367229d3b69a47a Reviewed-on: https://gerrit.libreoffice.org/27986 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: jan iversen <jani@documentfoundation.org> Tested-by: jan iversen <jani@documentfoundation.org>
865 lines
29 KiB
C++
865 lines
29 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
#include <config_folders.h>
|
|
|
|
#include "personalization.hxx"
|
|
#include "personasdochandler.hxx"
|
|
|
|
#include <comphelper/processfactory.hxx>
|
|
#include <officecfg/Office/Common.hxx>
|
|
#include <com/sun/star/container/XNameAccess.hpp>
|
|
#include <com/sun/star/beans/XPropertySet.hpp>
|
|
#include <osl/file.hxx>
|
|
#include <rtl/bootstrap.hxx>
|
|
#include <rtl/strbuf.hxx>
|
|
#include <tools/urlobj.hxx>
|
|
#include <vcl/edit.hxx>
|
|
#include <vcl/msgbox.hxx>
|
|
#include <vcl/lstbox.hxx>
|
|
#include <vcl/svapp.hxx>
|
|
#include <vcl/settings.hxx>
|
|
#include <vcl/graphicfilter.hxx>
|
|
#include <vcl/mnemonic.hxx>
|
|
#include <dialmgr.hxx>
|
|
#include "cuires.hrc"
|
|
|
|
#include <com/sun/star/task/InteractionHandler.hpp>
|
|
#include <com/sun/star/ucb/SimpleFileAccess.hpp>
|
|
#include <com/sun/star/xml/sax/XParser.hpp>
|
|
#include <com/sun/star/xml/sax/Parser.hpp>
|
|
#include "ucbhelper/content.hxx"
|
|
#include <comphelper/simplefileaccessinteraction.hxx>
|
|
|
|
#define MAX_RESULTS 9
|
|
|
|
using namespace com::sun::star;
|
|
using namespace ::com::sun::star::uno;
|
|
using namespace ::com::sun::star::ucb;
|
|
using namespace ::com::sun::star::beans;
|
|
|
|
SelectPersonaDialog::SelectPersonaDialog( vcl::Window *pParent )
|
|
: ModalDialog( pParent, "SelectPersonaDialog", "cui/ui/select_persona_dialog.ui" )
|
|
{
|
|
get( m_pSearchButton, "search_personas" );
|
|
m_pSearchButton->SetClickHdl( LINK( this, SelectPersonaDialog, SearchPersonas ) );
|
|
|
|
get( m_vSearchSuggestions[0], "suggestion1" );
|
|
m_vSearchSuggestions[0]->SetText( "LibreOffice" );
|
|
m_vSearchSuggestions[0]->SetClickHdl( LINK( this, SelectPersonaDialog, SearchPersonas ) );
|
|
|
|
get( m_vSearchSuggestions[1], "suggestion2" );
|
|
m_vSearchSuggestions[1]->SetText( CUI_RES ( RID_SVXSTR_PERSONA_ABSTRACT ) );
|
|
m_vSearchSuggestions[1]->SetClickHdl( LINK( this, SelectPersonaDialog, SearchPersonas ) );
|
|
|
|
get( m_vSearchSuggestions[2], "suggestion3" );
|
|
m_vSearchSuggestions[2]->SetText( CUI_RES ( RID_SVXSTR_PERSONA_COLOR ) );
|
|
m_vSearchSuggestions[2]->SetClickHdl( LINK( this, SelectPersonaDialog, SearchPersonas ) );
|
|
|
|
get( m_vSearchSuggestions[3], "suggestion4" );
|
|
m_vSearchSuggestions[3]->SetText( CUI_RES( RID_SVXSTR_PERSONA_MUSIC ) );
|
|
m_vSearchSuggestions[3]->SetClickHdl( LINK( this, SelectPersonaDialog, SearchPersonas ) );
|
|
|
|
get( m_vSearchSuggestions[4], "suggestion5" );
|
|
m_vSearchSuggestions[4]->SetText( CUI_RES( RID_SVXSTR_PERSONA_NATURE ) );
|
|
m_vSearchSuggestions[4]->SetClickHdl( LINK( this, SelectPersonaDialog, SearchPersonas ) );
|
|
|
|
get( m_vSearchSuggestions[5], "suggestion6" );
|
|
m_vSearchSuggestions[5]->SetText( CUI_RES( RID_SVXSTR_PERSONA_SOLID ) );
|
|
m_vSearchSuggestions[5]->SetClickHdl( LINK( this, SelectPersonaDialog, SearchPersonas ) );
|
|
|
|
get( m_pEdit, "search_term" );
|
|
|
|
get( m_pProgressLabel, "progress_label" );
|
|
|
|
get( m_pOkButton, "ok" );
|
|
m_pOkButton->SetClickHdl( LINK( this, SelectPersonaDialog, ActionOK ) );
|
|
|
|
get( m_pCancelButton, "cancel" );
|
|
m_pCancelButton->SetClickHdl( LINK( this, SelectPersonaDialog, ActionCancel ) );
|
|
get( m_vResultList[0], "result1" );
|
|
get( m_vResultList[1], "result2" );
|
|
get( m_vResultList[2], "result3" );
|
|
get( m_vResultList[3], "result4" );
|
|
get( m_vResultList[4], "result5" );
|
|
get( m_vResultList[5], "result6" );
|
|
get( m_vResultList[6], "result7" );
|
|
get( m_vResultList[7], "result8" );
|
|
get( m_vResultList[8], "result9" );
|
|
|
|
for (VclPtr<PushButton> & nIndex : m_vResultList)
|
|
{
|
|
nIndex->SetClickHdl( LINK( this, SelectPersonaDialog, SelectPersona ) );
|
|
nIndex->Disable();
|
|
}
|
|
}
|
|
|
|
SelectPersonaDialog::~SelectPersonaDialog()
|
|
{
|
|
disposeOnce();
|
|
}
|
|
|
|
void SelectPersonaDialog::dispose()
|
|
{
|
|
if (m_pSearchThread.is())
|
|
m_pSearchThread->join();
|
|
|
|
m_pEdit.clear();
|
|
m_pSearchButton.clear();
|
|
m_pProgressLabel.clear();
|
|
for (VclPtr<PushButton>& vp : m_vResultList)
|
|
vp.clear();
|
|
for (VclPtr<PushButton>& vp : m_vSearchSuggestions)
|
|
vp.clear();
|
|
m_pOkButton.clear();
|
|
m_pCancelButton.clear();
|
|
ModalDialog::dispose();
|
|
}
|
|
|
|
OUString SelectPersonaDialog::GetSelectedPersona() const
|
|
{
|
|
if( !m_aSelectedPersona.isEmpty( ) )
|
|
return m_aSelectedPersona;
|
|
|
|
return OUString();
|
|
}
|
|
|
|
IMPL_LINK_TYPED( SelectPersonaDialog, SearchPersonas, Button*, pButton, void )
|
|
{
|
|
OUString searchTerm;
|
|
if( m_pSearchThread.is() )
|
|
m_pSearchThread->StopExecution();
|
|
|
|
if( pButton == m_pSearchButton )
|
|
searchTerm = m_pEdit->GetText();
|
|
else
|
|
{
|
|
for( VclPtr<PushButton> & i : m_vSearchSuggestions )
|
|
{
|
|
if( pButton == i )
|
|
{
|
|
// GetDisplayText() is returning a blank string, thus removing mnemonics explicitly.
|
|
searchTerm = MnemonicGenerator::EraseAllMnemonicChars(i->GetText());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( searchTerm.isEmpty( ) )
|
|
return;
|
|
|
|
// 15 results so that invalid and duplicate search results whose names can't be retrieved can be skipped
|
|
OUString rSearchURL = "https://services.addons.mozilla.org/en-US/firefox/api/1.5/search/" + searchTerm + "/9/15";
|
|
|
|
if ( searchTerm.startsWith( "https://addons.mozilla.org/" ) )
|
|
{
|
|
searchTerm = "https://addons.mozilla.org/en-US/" + searchTerm.copy( searchTerm.indexOf( "firefox" ) );
|
|
m_pSearchThread = new SearchAndParseThread( this, searchTerm, true );
|
|
}
|
|
else
|
|
m_pSearchThread = new SearchAndParseThread( this, rSearchURL, false );
|
|
|
|
m_pSearchThread->launch();
|
|
}
|
|
|
|
IMPL_LINK_NOARG_TYPED( SelectPersonaDialog, ActionOK, Button*, void )
|
|
{
|
|
OUString aSelectedPersona = GetSelectedPersona();
|
|
|
|
if( !aSelectedPersona.isEmpty() )
|
|
{
|
|
m_pSearchThread = new SearchAndParseThread( this, aSelectedPersona, false );
|
|
m_pSearchThread->launch();
|
|
}
|
|
|
|
else
|
|
{
|
|
if( m_pSearchThread.is() )
|
|
m_pSearchThread->StopExecution();
|
|
EndDialog( RET_OK );
|
|
}
|
|
}
|
|
|
|
IMPL_LINK_NOARG_TYPED( SelectPersonaDialog, ActionCancel, Button*, void )
|
|
{
|
|
if( m_pSearchThread.is() )
|
|
m_pSearchThread->StopExecution();
|
|
|
|
EndDialog();
|
|
}
|
|
|
|
IMPL_LINK_TYPED( SelectPersonaDialog, SelectPersona, Button*, pButton, void )
|
|
{
|
|
if( m_pSearchThread.is() )
|
|
m_pSearchThread->StopExecution();
|
|
|
|
for( sal_Int32 index = 0; index < 9; index++ )
|
|
{
|
|
if( pButton == m_vResultList[index] )
|
|
{
|
|
if( !m_vPersonaSettings[index].isEmpty() )
|
|
{
|
|
m_aSelectedPersona = m_vPersonaSettings[index];
|
|
// get the persona name from the setting variable to show in the progress.
|
|
sal_Int32 nNameIndex = m_aSelectedPersona.indexOf( ';' );
|
|
OUString aName = m_aSelectedPersona.copy( 0, nNameIndex );
|
|
OUString aProgress( CUI_RES( RID_SVXSTR_SELECTEDPERSONA ) );
|
|
aProgress += aName;
|
|
SetProgress( aProgress );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SelectPersonaDialog::SetAppliedPersonaSetting( OUString& rPersonaSetting )
|
|
{
|
|
m_aAppliedPersona = rPersonaSetting;
|
|
}
|
|
|
|
const OUString& SelectPersonaDialog::GetAppliedPersonaSetting() const
|
|
{
|
|
return m_aAppliedPersona;
|
|
}
|
|
|
|
void SelectPersonaDialog::SetProgress( const OUString& rProgress )
|
|
{
|
|
if(rProgress.isEmpty())
|
|
m_pProgressLabel->Hide();
|
|
else
|
|
{
|
|
SolarMutexGuard aGuard;
|
|
m_pProgressLabel->Show();
|
|
m_pProgressLabel->SetText( rProgress );
|
|
setOptimalLayoutSize();
|
|
}
|
|
}
|
|
|
|
void SelectPersonaDialog::SetImages( const Image& aImage, sal_Int32 nIndex )
|
|
{
|
|
m_vResultList[nIndex]->Enable();
|
|
m_vResultList[nIndex]->SetModeImage( aImage );
|
|
}
|
|
|
|
void SelectPersonaDialog::AddPersonaSetting( OUString& rPersonaSetting )
|
|
{
|
|
m_vPersonaSettings.push_back( rPersonaSetting );
|
|
}
|
|
|
|
void SelectPersonaDialog::ClearSearchResults()
|
|
{
|
|
m_vPersonaSettings.clear();
|
|
m_aSelectedPersona.clear();
|
|
for(VclPtr<PushButton> & nIndex : m_vResultList)
|
|
{
|
|
nIndex->Disable();
|
|
nIndex->SetModeImage(Image());
|
|
}
|
|
}
|
|
|
|
SvxPersonalizationTabPage::SvxPersonalizationTabPage( vcl::Window *pParent, const SfxItemSet &rSet )
|
|
: SfxTabPage( pParent, "PersonalizationTabPage", "cui/ui/personalization_tab.ui", &rSet )
|
|
{
|
|
// persona
|
|
get( m_pNoPersona, "no_persona" );
|
|
get( m_pDefaultPersona, "default_persona" );
|
|
get( m_pAppliedThemeLabel, "applied_theme" );
|
|
|
|
get( m_pOwnPersona, "own_persona" );
|
|
m_pOwnPersona->SetClickHdl( LINK( this, SvxPersonalizationTabPage, ForceSelect ) );
|
|
|
|
get( m_pSelectPersona, "select_persona" );
|
|
m_pSelectPersona->SetClickHdl( LINK( this, SvxPersonalizationTabPage, SelectPersona ) );
|
|
|
|
get( m_vDefaultPersonaImages[0], "default1" );
|
|
m_vDefaultPersonaImages[0]->SetClickHdl( LINK( this, SvxPersonalizationTabPage, DefaultPersona ) );
|
|
|
|
get( m_vDefaultPersonaImages[1], "default2" );
|
|
m_vDefaultPersonaImages[1]->SetClickHdl( LINK( this, SvxPersonalizationTabPage, DefaultPersona ) );
|
|
|
|
get( m_vDefaultPersonaImages[2], "default3" );
|
|
m_vDefaultPersonaImages[2]->SetClickHdl( LINK( this, SvxPersonalizationTabPage, DefaultPersona ) );
|
|
|
|
get( m_pPersonaList, "installed_personas" );
|
|
m_pPersonaList->SetSelectHdl( LINK( this, SvxPersonalizationTabPage, SelectInstalledPersona ) );
|
|
|
|
get( m_pExtensionPersonaPreview, "persona_preview" );
|
|
|
|
get ( m_pExtensionLabel, "extensions_label" );
|
|
|
|
CheckAppliedTheme();
|
|
LoadDefaultImages();
|
|
LoadExtensionThemes();
|
|
}
|
|
|
|
SvxPersonalizationTabPage::~SvxPersonalizationTabPage()
|
|
{
|
|
disposeOnce();
|
|
}
|
|
|
|
void SvxPersonalizationTabPage::dispose()
|
|
{
|
|
m_pNoPersona.clear();
|
|
m_pDefaultPersona.clear();
|
|
m_pOwnPersona.clear();
|
|
m_pSelectPersona.clear();
|
|
for (VclPtr<PushButton> & i : m_vDefaultPersonaImages)
|
|
i.clear();
|
|
m_pExtensionPersonaPreview.clear();
|
|
m_pPersonaList.clear();
|
|
m_pExtensionLabel.clear();
|
|
m_pAppliedThemeLabel.clear();
|
|
SfxTabPage::dispose();
|
|
}
|
|
|
|
|
|
VclPtr<SfxTabPage> SvxPersonalizationTabPage::Create( vcl::Window *pParent, const SfxItemSet *rSet )
|
|
{
|
|
return VclPtr<SvxPersonalizationTabPage>::Create( pParent, *rSet );
|
|
}
|
|
|
|
bool SvxPersonalizationTabPage::FillItemSet( SfxItemSet * )
|
|
{
|
|
// persona
|
|
OUString aPersona( "default" );
|
|
if ( m_pNoPersona->IsChecked() )
|
|
aPersona = "no";
|
|
else if ( m_pOwnPersona->IsChecked() )
|
|
aPersona = "own";
|
|
|
|
bool bModified = false;
|
|
uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
|
|
if ( xContext.is() &&
|
|
( aPersona != officecfg::Office::Common::Misc::Persona::get( xContext ) ||
|
|
m_aPersonaSettings != officecfg::Office::Common::Misc::PersonaSettings::get( xContext ) ) )
|
|
{
|
|
bModified = true;
|
|
}
|
|
|
|
// write
|
|
std::shared_ptr< comphelper::ConfigurationChanges > batch( comphelper::ConfigurationChanges::create() );
|
|
if( aPersona == "no" )
|
|
m_aPersonaSettings.clear();
|
|
officecfg::Office::Common::Misc::Persona::set( aPersona, batch );
|
|
officecfg::Office::Common::Misc::PersonaSettings::set( m_aPersonaSettings, batch );
|
|
batch->commit();
|
|
|
|
if ( bModified )
|
|
{
|
|
// broadcast the change
|
|
DataChangedEvent aDataChanged( DataChangedEventType::SETTINGS, nullptr, AllSettingsFlags::STYLE );
|
|
Application::NotifyAllWindows( aDataChanged );
|
|
}
|
|
|
|
return bModified;
|
|
}
|
|
|
|
void SvxPersonalizationTabPage::Reset( const SfxItemSet * )
|
|
{
|
|
uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
|
|
|
|
// persona
|
|
OUString aPersona( "default" );
|
|
if ( xContext.is() )
|
|
{
|
|
aPersona = officecfg::Office::Common::Misc::Persona::get( xContext );
|
|
m_aPersonaSettings = officecfg::Office::Common::Misc::PersonaSettings::get( xContext );
|
|
}
|
|
|
|
if ( aPersona == "no" )
|
|
m_pNoPersona->Check();
|
|
else if ( aPersona == "own" )
|
|
m_pOwnPersona->Check();
|
|
else
|
|
m_pDefaultPersona->Check();
|
|
}
|
|
|
|
void SvxPersonalizationTabPage::SetPersonaSettings( const OUString& aPersonaSettings )
|
|
{
|
|
m_aPersonaSettings = aPersonaSettings;
|
|
ShowAppliedThemeLabel( m_aPersonaSettings );
|
|
m_pOwnPersona->Check();
|
|
}
|
|
|
|
void SvxPersonalizationTabPage::CheckAppliedTheme()
|
|
{
|
|
uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
|
|
OUString aPersona( "default" ), aPersonaSetting;
|
|
if ( xContext.is())
|
|
{
|
|
aPersona = officecfg::Office::Common::Misc::Persona::get( xContext );
|
|
aPersonaSetting = officecfg::Office::Common::Misc::PersonaSettings::get( xContext );
|
|
}
|
|
if(aPersona == "own")
|
|
ShowAppliedThemeLabel(aPersonaSetting);
|
|
}
|
|
|
|
void SvxPersonalizationTabPage::ShowAppliedThemeLabel(const OUString& aPersonaSetting)
|
|
{
|
|
sal_Int32 nNameIndex = aPersonaSetting.indexOf( '/' );
|
|
OUString aName = "(" + aPersonaSetting.copy( 0, nNameIndex ) +")";
|
|
m_pAppliedThemeLabel->Show();
|
|
m_pAppliedThemeLabel->SetText( aName );
|
|
}
|
|
|
|
void SvxPersonalizationTabPage::LoadDefaultImages()
|
|
{
|
|
// Load the pre saved personas
|
|
|
|
OUString gallery( "" );
|
|
gallery = "$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER;
|
|
gallery += "/gallery/personas/";
|
|
rtl::Bootstrap::expandMacros( gallery );
|
|
OUString aPersonasList = gallery + "personas_list.txt";
|
|
SvFileStream aStream( aPersonasList, StreamMode::READ );
|
|
GraphicFilter aFilter;
|
|
Graphic aGraphic;
|
|
sal_Int32 nIndex = 0;
|
|
|
|
while( aStream.IsOpen() && !aStream.IsEof() )
|
|
{
|
|
OString aLine;
|
|
aStream.ReadLine( aLine );
|
|
OUString aPersonaSetting( OStringToOUString( aLine, RTL_TEXTENCODING_UTF8 ) );
|
|
OUString aPreviewFile;
|
|
sal_Int32 nNewIndex = aPersonaSetting.indexOf( ';' );
|
|
if( nNewIndex < 0 )
|
|
break;
|
|
aPreviewFile = aPersonaSetting.copy( 0, nNewIndex );
|
|
aPersonaSetting = aPersonaSetting.copy( nNewIndex + 1 );
|
|
m_vDefaultPersonaSettings.push_back( aPersonaSetting );
|
|
|
|
INetURLObject aURLObj( gallery + aPreviewFile );
|
|
aFilter.ImportGraphic( aGraphic, aURLObj );
|
|
Bitmap aBmp = aGraphic.GetBitmap();
|
|
m_vDefaultPersonaImages[nIndex]->Show();
|
|
m_vDefaultPersonaImages[nIndex++]->SetModeImage( Image( aBmp ) );
|
|
}
|
|
}
|
|
|
|
void SvxPersonalizationTabPage::LoadExtensionThemes()
|
|
{
|
|
// See if any extensions are used to install personas. If yes, load them.
|
|
|
|
css::uno::Sequence<OUString> installedPersonas( officecfg::Office::Common::Misc::PersonasList::get()->getElementNames() );
|
|
sal_Int32 nLength = installedPersonas.getLength();
|
|
|
|
if( nLength == 0 )
|
|
return;
|
|
|
|
m_pPersonaList->Show();
|
|
m_pExtensionLabel->Show();
|
|
|
|
for( sal_Int32 nIndex = 0; nIndex < nLength; nIndex++ )
|
|
{
|
|
Reference< XPropertySet > xPropertySet( officecfg::Office::Common::Misc::PersonasList::get()->getByName( installedPersonas[nIndex] ), UNO_QUERY_THROW );
|
|
OUString aPersonaName, aPreviewFile, aHeaderFile, aFooterFile, aTextColor, aAccentColor, aPersonaSettings;
|
|
Any aValue = xPropertySet->getPropertyValue( "Name" );
|
|
aValue >>= aPersonaName;
|
|
m_pPersonaList->InsertEntry( aPersonaName );
|
|
|
|
aValue = xPropertySet->getPropertyValue( "Preview" );
|
|
aValue >>= aPreviewFile;
|
|
|
|
aValue = xPropertySet->getPropertyValue( "Header" );
|
|
aValue >>= aHeaderFile;
|
|
|
|
aValue = xPropertySet->getPropertyValue( "Footer" );
|
|
aValue >>= aFooterFile;
|
|
|
|
aValue = xPropertySet->getPropertyValue( "TextColor" );
|
|
aValue >>= aTextColor;
|
|
|
|
aValue = xPropertySet->getPropertyValue( "AccentColor" );
|
|
aValue >>= aAccentColor;
|
|
|
|
aPersonaSettings = aPreviewFile + ";" + aHeaderFile + ";" + aFooterFile + ";" + aTextColor + ";" + aAccentColor;
|
|
rtl::Bootstrap::expandMacros( aPersonaSettings );
|
|
m_vExtensionPersonaSettings.push_back( aPersonaSettings );
|
|
}
|
|
}
|
|
|
|
IMPL_LINK_NOARG_TYPED( SvxPersonalizationTabPage, SelectPersona, Button*, void )
|
|
{
|
|
ScopedVclPtrInstance< SelectPersonaDialog > aDialog(nullptr);
|
|
|
|
if ( aDialog->Execute() == RET_OK )
|
|
{
|
|
OUString aPersonaSetting( aDialog->GetAppliedPersonaSetting() );
|
|
if ( !aPersonaSetting.isEmpty() )
|
|
{
|
|
SetPersonaSettings( aPersonaSetting );
|
|
}
|
|
}
|
|
}
|
|
|
|
IMPL_LINK_TYPED( SvxPersonalizationTabPage, ForceSelect, Button*, pButton, void )
|
|
{
|
|
if ( pButton == m_pOwnPersona && m_aPersonaSettings.isEmpty() )
|
|
SelectPersona( m_pSelectPersona );
|
|
}
|
|
|
|
IMPL_LINK_TYPED( SvxPersonalizationTabPage, DefaultPersona, Button*, pButton, void )
|
|
{
|
|
m_pDefaultPersona->Check();
|
|
for( sal_Int32 nIndex = 0; nIndex < 3; nIndex++ )
|
|
{
|
|
if( pButton == m_vDefaultPersonaImages[nIndex] )
|
|
m_aPersonaSettings = m_vDefaultPersonaSettings[nIndex];
|
|
}
|
|
}
|
|
|
|
IMPL_LINK_NOARG_TYPED( SvxPersonalizationTabPage, SelectInstalledPersona, ListBox&, void)
|
|
{
|
|
m_pOwnPersona->Check();
|
|
|
|
// Get the details of the selected theme.
|
|
m_pExtensionPersonaPreview->Show();
|
|
sal_Int32 nSelectedPos = m_pPersonaList->GetSelectEntryPos();
|
|
OUString aSettings = m_vExtensionPersonaSettings[nSelectedPos];
|
|
sal_Int32 nIndex = aSettings.indexOf( ';' );
|
|
OUString aPreviewFile = aSettings.copy( 0, nIndex );
|
|
m_aPersonaSettings = aSettings.copy( nIndex + 1 );
|
|
|
|
// Show the preview file in the button.
|
|
GraphicFilter aFilter;
|
|
Graphic aGraphic;
|
|
INetURLObject aURLObj( aPreviewFile );
|
|
aFilter.ImportGraphic( aGraphic, aURLObj );
|
|
Bitmap aBmp = aGraphic.GetBitmap();
|
|
m_pExtensionPersonaPreview->SetModeImage( Image( aBmp ) );
|
|
}
|
|
|
|
/// Find the value on the Persona page, and convert it to a usable form.
|
|
static OUString searchValue( const OString &rBuffer, sal_Int32 from, const OString &rIdentifier )
|
|
{
|
|
sal_Int32 where = rBuffer.indexOf( rIdentifier, from );
|
|
if ( where < 0 )
|
|
return OUString();
|
|
|
|
where += rIdentifier.getLength();
|
|
|
|
sal_Int32 end = rBuffer.indexOf( """, where );
|
|
if ( end < 0 )
|
|
return OUString();
|
|
|
|
OString aOString( rBuffer.copy( where, end - where ) );
|
|
OUString aString( aOString.getStr(), aOString.getLength(), RTL_TEXTENCODING_UTF8, OSTRING_TO_OUSTRING_CVTFLAGS );
|
|
|
|
return aString.replaceAll( "\\/", "/" );
|
|
}
|
|
|
|
/// Parse the Persona web page, and find where to get the bitmaps + the color values.
|
|
static bool parsePersonaInfo( const OString &rBuffer, OUString *pHeaderURL, OUString *pFooterURL,
|
|
OUString *pTextColor, OUString *pAccentColor, OUString *pPreviewURL,
|
|
OUString *pName )
|
|
{
|
|
// it is the first attribute that contains "persona="
|
|
sal_Int32 persona = rBuffer.indexOf( "data-browsertheme=\"{" );
|
|
if ( persona < 0 )
|
|
return false;
|
|
|
|
// now search inside
|
|
*pHeaderURL = searchValue( rBuffer, persona, ""headerURL":"" );
|
|
if ( pHeaderURL->isEmpty() )
|
|
return false;
|
|
|
|
*pFooterURL = searchValue( rBuffer, persona, ""footerURL":"" );
|
|
if ( pFooterURL->isEmpty() )
|
|
return false;
|
|
|
|
*pTextColor = searchValue( rBuffer, persona, ""textcolor":"" );
|
|
if ( pTextColor->isEmpty() )
|
|
return false;
|
|
|
|
*pAccentColor = searchValue( rBuffer, persona, ""accentcolor":"" );
|
|
if ( pAccentColor->isEmpty() )
|
|
return false;
|
|
|
|
*pPreviewURL = searchValue( rBuffer, persona, ""previewURL":"" );
|
|
if ( pPreviewURL->isEmpty() )
|
|
return false;
|
|
|
|
*pName = searchValue( rBuffer, persona, ""name":"" );
|
|
if ( pName->isEmpty() )
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
SearchAndParseThread::SearchAndParseThread( SelectPersonaDialog* pDialog,
|
|
const OUString& rURL, bool bDirectURL ) :
|
|
Thread( "cuiPersonasSearchThread" ),
|
|
m_pPersonaDialog( pDialog ),
|
|
m_aURL( rURL ),
|
|
m_bExecute( true ),
|
|
m_bDirectURL( bDirectURL )
|
|
{
|
|
}
|
|
|
|
SearchAndParseThread::~SearchAndParseThread()
|
|
{
|
|
}
|
|
|
|
namespace {
|
|
|
|
bool getPreviewFile( const OUString& rURL, OUString *pPreviewFile, OUString *pPersonaSetting )
|
|
{
|
|
uno::Reference< ucb::XSimpleFileAccess3 > xFileAccess( ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() ), uno::UNO_QUERY );
|
|
if ( !xFileAccess.is() )
|
|
return false;
|
|
|
|
Reference<XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
|
|
uno::Reference< io::XInputStream > xStream;
|
|
try {
|
|
css:: uno::Reference< task::XInteractionHandler > xIH(
|
|
css::task::InteractionHandler::createWithParent( xContext, nullptr ) );
|
|
|
|
xFileAccess->setInteractionHandler( new comphelper::SimpleFileAccessInteraction( xIH ) );
|
|
xStream = xFileAccess->openFileRead( rURL );
|
|
|
|
if( !xStream.is() )
|
|
return false;
|
|
}
|
|
catch (...)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// read the persona specification
|
|
// NOTE: Parsing for real is an overkill here; and worse - I tried, and
|
|
// the HTML the site provides is not 100% valid ;-)
|
|
const sal_Int32 BUF_LEN = 8000;
|
|
uno::Sequence< sal_Int8 > buffer( BUF_LEN );
|
|
OStringBuffer aBuffer( 64000 );
|
|
|
|
sal_Int32 nRead = 0;
|
|
while ( ( nRead = xStream->readBytes( buffer, BUF_LEN ) ) == BUF_LEN )
|
|
aBuffer.append( reinterpret_cast< const char* >( buffer.getConstArray() ), nRead );
|
|
|
|
if ( nRead > 0 )
|
|
aBuffer.append( reinterpret_cast< const char* >( buffer.getConstArray() ), nRead );
|
|
|
|
xStream->closeInput();
|
|
|
|
// get the important bits of info
|
|
OUString aHeaderURL, aFooterURL, aTextColor, aAccentColor, aPreviewURL, aName;
|
|
|
|
if ( !parsePersonaInfo( aBuffer.makeStringAndClear(), &aHeaderURL, &aFooterURL, &aTextColor, &aAccentColor, &aPreviewURL, &aName ) )
|
|
return false;
|
|
|
|
// copy the images to the user's gallery
|
|
OUString gallery = "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE( "bootstrap") "::UserInstallation}";
|
|
rtl::Bootstrap::expandMacros( gallery );
|
|
gallery += "/user/gallery/personas/" + aName + "/";
|
|
osl::Directory::createPath( gallery );
|
|
|
|
OUString aPreviewFile( INetURLObject( aPreviewURL ).getName() );
|
|
|
|
try {
|
|
xFileAccess->copy( aPreviewURL, gallery + aPreviewFile );
|
|
}
|
|
catch ( const uno::Exception & )
|
|
{
|
|
return false;
|
|
}
|
|
*pPreviewFile = gallery + aPreviewFile;
|
|
*pPersonaSetting = aName + ";" + aHeaderURL + ";" + aFooterURL + ";" + aTextColor + ";" + aAccentColor;
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
void SearchAndParseThread::execute()
|
|
{
|
|
if( m_aURL.startsWith( "https://" ) )
|
|
{
|
|
m_pPersonaDialog->ClearSearchResults();
|
|
OUString sProgress( CUI_RES( RID_SVXSTR_SEARCHING ) ), sError;
|
|
m_pPersonaDialog->SetProgress( sProgress );
|
|
|
|
PersonasDocHandler* pHandler = new PersonasDocHandler();
|
|
Reference<XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
|
|
Reference< xml::sax::XParser > xParser = xml::sax::Parser::create(xContext);
|
|
Reference< xml::sax::XDocumentHandler > xDocHandler = pHandler;
|
|
uno::Reference< ucb::XSimpleFileAccess3 > xFileAccess( ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() ), uno::UNO_QUERY );
|
|
uno::Reference< io::XInputStream > xStream;
|
|
xParser->setDocumentHandler( xDocHandler );
|
|
|
|
if( !m_bDirectURL )
|
|
{
|
|
if ( !xFileAccess.is() )
|
|
return;
|
|
|
|
try {
|
|
css:: uno::Reference< task::XInteractionHandler > xIH(
|
|
css::task::InteractionHandler::createWithParent( xContext, nullptr ) );
|
|
|
|
xFileAccess->setInteractionHandler( new comphelper::SimpleFileAccessInteraction( xIH ) );
|
|
|
|
xStream = xFileAccess->openFileRead( m_aURL );
|
|
if( !xStream.is() )
|
|
{
|
|
// in case of a returned CommandFailedException
|
|
// SimpleFileAccess serves it, returning an empty stream
|
|
sError = CUI_RES(RID_SVXSTR_SEARCHERROR);
|
|
sError = sError.replaceAll("%1", m_aURL);
|
|
m_pPersonaDialog->SetProgress( OUString() );
|
|
ScopedVclPtrInstance< ErrorBox > aBox( nullptr, WB_OK, sError);
|
|
aBox->Execute();
|
|
return;
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
// a catch all clause, in case the exception is not
|
|
// served elsewhere
|
|
sError = CUI_RES(RID_SVXSTR_SEARCHERROR);
|
|
sError = sError.replaceAll("%1", m_aURL);
|
|
m_pPersonaDialog->SetProgress( OUString() );
|
|
ScopedVclPtrInstance< ErrorBox > aBox( nullptr, WB_OK, sError );
|
|
aBox->Execute();
|
|
return;
|
|
}
|
|
|
|
xml::sax::InputSource aParserInput;
|
|
aParserInput.aInputStream = xStream;
|
|
xParser->parseStream( aParserInput );
|
|
|
|
if( !pHandler->hasResults() )
|
|
{
|
|
sProgress = CUI_RES( RID_SVXSTR_NORESULTS );
|
|
m_pPersonaDialog->SetProgress( sProgress );
|
|
return;
|
|
}
|
|
}
|
|
|
|
std::vector<OUString> vLearnmoreURLs;
|
|
std::vector<OUString>::iterator it;
|
|
sal_Int32 nIndex = 0;
|
|
GraphicFilter aFilter;
|
|
Graphic aGraphic;
|
|
|
|
if( !m_bDirectURL )
|
|
vLearnmoreURLs = pHandler->getLearnmoreURLs();
|
|
else
|
|
vLearnmoreURLs.push_back( m_aURL );
|
|
|
|
for( it = vLearnmoreURLs.begin(); it!=vLearnmoreURLs.end() && nIndex < MAX_RESULTS; ++it )
|
|
{
|
|
OUString sPreviewFile, aPersonaSetting;
|
|
bool bResult = getPreviewFile( *it, &sPreviewFile, &aPersonaSetting );
|
|
// parsing is buggy at times, as HTML is not proper. Skip it.
|
|
if(aPersonaSetting.isEmpty() || !bResult)
|
|
{
|
|
if( m_bDirectURL )
|
|
{
|
|
sError = CUI_RES(RID_SVXSTR_SEARCHERROR);
|
|
sError = sError.replaceAll("%1", m_aURL);
|
|
m_pPersonaDialog->SetProgress( OUString() );
|
|
ScopedVclPtrInstance< ErrorBox > aBox( nullptr, WB_OK, sError);
|
|
aBox->Execute();
|
|
return;
|
|
}
|
|
continue;
|
|
}
|
|
INetURLObject aURLObj( sPreviewFile );
|
|
aFilter.ImportGraphic( aGraphic, aURLObj );
|
|
Bitmap aBmp = aGraphic.GetBitmap();
|
|
|
|
if( !m_bExecute )
|
|
return;
|
|
|
|
// for VCL to be able to do visual changes in the thread
|
|
SolarMutexGuard aGuard;
|
|
m_pPersonaDialog->SetImages( Image( aBmp ), nIndex++ );
|
|
m_pPersonaDialog->setOptimalLayoutSize();
|
|
m_pPersonaDialog->AddPersonaSetting( aPersonaSetting );
|
|
}
|
|
|
|
if( !m_bExecute )
|
|
return;
|
|
|
|
SolarMutexGuard aGuard;
|
|
sProgress.clear();
|
|
m_pPersonaDialog->SetProgress( sProgress );
|
|
m_pPersonaDialog->setOptimalLayoutSize();
|
|
}
|
|
|
|
else
|
|
{
|
|
OUString sProgress( CUI_RES( RID_SVXSTR_APPLYPERSONA ) ), sError;
|
|
m_pPersonaDialog->SetProgress( sProgress );
|
|
|
|
uno::Reference< ucb::XSimpleFileAccess3 > xFileAccess( ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() ), uno::UNO_QUERY );
|
|
if ( !xFileAccess.is() )
|
|
return;
|
|
|
|
OUString aName, aHeaderURL, aFooterURL, aTextColor, aAccentColor;
|
|
OUString aPersonaSetting;
|
|
|
|
// get the required fields from m_aURL
|
|
sal_Int32 nOldIndex = 0;
|
|
sal_Int32 nNewIndex = m_aURL.indexOf( ';', nOldIndex );
|
|
aName = m_aURL.copy( nOldIndex, ( nNewIndex - nOldIndex ) );
|
|
|
|
nOldIndex = nNewIndex + 1;
|
|
nNewIndex = m_aURL.indexOf( ';', nOldIndex );
|
|
aHeaderURL = m_aURL.copy(nOldIndex , ( nNewIndex - nOldIndex ) );
|
|
|
|
nOldIndex = nNewIndex + 1;
|
|
nNewIndex = m_aURL.indexOf( ';', nOldIndex );
|
|
aFooterURL = m_aURL.copy( nOldIndex, ( nNewIndex - nOldIndex ) );
|
|
|
|
nOldIndex = nNewIndex + 1;
|
|
nNewIndex = m_aURL.indexOf( ';', nOldIndex );
|
|
aTextColor = m_aURL.copy( nOldIndex, ( nNewIndex - nOldIndex ) );
|
|
|
|
nOldIndex = nNewIndex + 1;
|
|
nNewIndex = m_aURL.getLength();
|
|
aAccentColor = m_aURL.copy( nOldIndex, ( nNewIndex - nOldIndex ) );
|
|
|
|
// copy the images to the user's gallery
|
|
OUString gallery = "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE( "bootstrap") "::UserInstallation}";
|
|
rtl::Bootstrap::expandMacros( gallery );
|
|
gallery += "/user/gallery/personas/";
|
|
osl::Directory::createPath( gallery );
|
|
|
|
OUString aHeaderFile( INetURLObject( aHeaderURL ).getName() );
|
|
OUString aFooterFile( INetURLObject( aFooterURL ).getName() );
|
|
|
|
aHeaderFile = aName + "/" + aHeaderFile;
|
|
aFooterFile = aName + "/" + aFooterFile;
|
|
|
|
try {
|
|
xFileAccess->copy( aHeaderURL, gallery + aHeaderFile );
|
|
xFileAccess->copy( aFooterURL, gallery + aFooterFile );
|
|
}
|
|
catch ( const uno::Exception & )
|
|
{
|
|
sError = CUI_RES( RID_SVXSTR_SEARCHERROR );
|
|
sError = sError.replaceAll("%1", m_aURL);
|
|
m_pPersonaDialog->SetProgress( OUString() );
|
|
ScopedVclPtrInstance< ErrorBox > aBox( nullptr, WB_OK, sError);
|
|
aBox->Execute();
|
|
return;
|
|
}
|
|
|
|
if( !m_bExecute )
|
|
return;
|
|
|
|
SolarMutexGuard aGuard;
|
|
|
|
aPersonaSetting = aHeaderFile + ";" + aFooterFile + ";" + aTextColor + ";" + aAccentColor;
|
|
m_pPersonaDialog->SetAppliedPersonaSetting( aPersonaSetting );
|
|
m_pPersonaDialog->EndDialog( RET_OK );
|
|
}
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|