summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarsten Driesner <cd@openoffice.org>2002-10-11 13:22:14 +0000
committerCarsten Driesner <cd@openoffice.org>2002-10-11 13:22:14 +0000
commit7ac4527627ed772ac0eba86606f3ee5e32dff59d (patch)
tree4f29ba3712a8e11e4d4934437bb04e0018ac2541
parent123f4105c39c701157773ee1ec7a30577b8a60ac (diff)
#102630# New classes for addons menu feature
-rw-r--r--framework/source/classes/addonmenu.cxx417
-rw-r--r--framework/source/classes/addonsoptions.cxx1035
2 files changed, 1452 insertions, 0 deletions
diff --git a/framework/source/classes/addonmenu.cxx b/framework/source/classes/addonmenu.cxx
new file mode 100644
index 000000000000..860a7fd08167
--- /dev/null
+++ b/framework/source/classes/addonmenu.cxx
@@ -0,0 +1,417 @@
+/*************************************************************************
+ *
+ * $RCSfile: addonmenu.cxx,v $
+ *
+ * $Revision: 1.1 $
+ *
+ * last change: $Author: cd $ $Date: 2002-10-11 14:22:14 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+//_________________________________________________________________________________________________________________
+// my own includes
+//_________________________________________________________________________________________________________________
+
+#include <limits.h>
+
+#ifndef __FRAMEWORK_CLASSES_ADDONMENU_HXX_
+#include "classes/addonmenu.hxx"
+#endif
+
+#ifndef __FRAMEWORK_CLASSES_ADDONSOPTIONS_HXX_
+#include "classes/addonsoptions.hxx"
+#endif
+
+#ifndef __FRAMEWORK_GENERAL_H_
+#include <general.h>
+#endif
+
+#ifndef __FRAMEWORK_MACROS_DEBUG_ASSERTION_HXX_
+#include <macros/debug/assertion.hxx>
+#endif
+
+#ifndef __FRAMEWORK_HELPER_IMAGEPRODUCER_HXX_
+#include <helper/imageproducer.hxx>
+#endif
+
+#ifndef __FRAMEWORK_CLASSES_MENUCONFIGURATION_HXX_
+#include <classes/menuconfiguration.hxx>
+#endif
+
+//_________________________________________________________________________________________________________________
+// interface includes
+//_________________________________________________________________________________________________________________
+
+#ifndef _COM_SUN_STAR_UNO_REFERENCE_H_
+#include <com/sun/star/uno/Reference.h>
+#endif
+#ifndef _COM_SUN_STAR_UTIL_URL_HPP_
+#include <com/sun/star/util/URL.hpp>
+#endif
+#ifndef _UNOTOOLS_PROCESSFACTORY_HXX
+#include <comphelper/processfactory.hxx>
+#endif
+#ifndef _COM_SUN_STAR_UTIL_XURLTRANSFORMER_HPP_
+#include <com/sun/star/util/XURLTransformer.hpp>
+#endif
+
+#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#endif
+#ifndef _COM_SUN_STAR_UTIL_DATETIME_HPP_
+#include <com/sun/star/util/DateTime.hpp>
+#endif
+
+//_________________________________________________________________________________________________________________
+// includes of other projects
+//_________________________________________________________________________________________________________________
+
+#include <vcl/config.hxx>
+#include <vcl/svapp.hxx>
+#include <svtools/menuoptions.hxx>
+
+//_________________________________________________________________________________________________________________
+// namespace
+//_________________________________________________________________________________________________________________
+
+using namespace ::rtl;
+using namespace ::comphelper;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::beans;
+
+/*
+extern "C"
+{
+ int bla();
+}
+*/
+namespace framework
+{
+
+static void GetMenuEntry(
+ const Sequence< PropertyValue >& rAddonMenuEntry,
+ ::rtl::OUString& rTitle,
+ ::rtl::OUString& rURL,
+ ::rtl::OUString& rTarget,
+ ::rtl::OUString& rImageId,
+ Sequence< Sequence< PropertyValue > >& rAddonSubMenu );
+
+
+sal_Bool AddonMenu::HasElements()
+{
+ return AddonsOptions().HasAddonsMenu();
+}
+
+class AddonMenu_Impl
+{
+ private:
+ static USHORT m_nMID;
+
+ public:
+ AddonMenu* m_pRoot;
+ BOOL m_bInitialized;
+
+ AddonMenu_Impl( AddonMenu* pRoot );
+ AddonMenu_Impl();
+ ~AddonMenu_Impl();
+
+ static USHORT GetMID();
+};
+
+USHORT AddonMenu_Impl::m_nMID = ADDONMENU_ITEMID_START;
+
+AddonMenu_Impl::AddonMenu_Impl( AddonMenu* pRoot ) :
+ m_pRoot(pRoot),
+ m_bInitialized(FALSE)
+{
+}
+
+AddonMenu_Impl::AddonMenu_Impl() :
+ m_pRoot(0),
+ m_bInitialized(FALSE)
+{
+}
+
+AddonMenu_Impl::~AddonMenu_Impl()
+{
+}
+
+USHORT AddonMenu_Impl::GetMID()
+{
+ m_nMID++;
+ if( !m_nMID )
+ m_nMID = ADDONMENU_ITEMID_START;
+ return m_nMID;
+}
+
+// ------------------------------------------------------------------------
+
+AddonMenu::AddonMenu( Reference< XFrame >& xFrame, AddonMenu* pRoot ) :
+ m_xFrame( xFrame )
+{
+ _pImp = new AddonMenu_Impl( pRoot );
+ Initialize();
+}
+
+AddonMenu::AddonMenu( Reference< XFrame >& xFrame ) :
+ m_xFrame( xFrame )
+{
+ _pImp = new AddonMenu_Impl();
+ Initialize();
+}
+
+AddonMenu::~AddonMenu()
+{
+ delete _pImp;
+
+ for ( int i = 0; i < GetItemCount(); i++ )
+ {
+ if ( GetItemType( i ) != MENUITEM_SEPARATOR )
+ {
+ // delete user attributes created with new!
+ USHORT nId = GetItemId( i );
+ MenuConfiguration::Attributes* pUserAttributes = (MenuConfiguration::Attributes*)GetUserValue( nId );
+ delete pUserAttributes;
+ }
+ }
+}
+
+void AddonMenu::Initialize()
+{
+ if( _pImp->m_bInitialized )
+ return;
+
+ _pImp->m_bInitialized = TRUE;
+
+ AddonsOptions aAddonsOptions;
+
+ const Sequence< Sequence< PropertyValue > >& rAddonMenuEntries = aAddonsOptions.GetAddonsMenu();
+ Sequence< Sequence< PropertyValue > > aAddonSubMenu;
+
+ ::rtl::OUString aTitle;
+ ::rtl::OUString aURL;
+ ::rtl::OUString aTarget;
+ ::rtl::OUString aImageId;
+
+ const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
+ BOOL bIsHiContrastMode = rSettings.GetMenuColor().IsDark();
+ BOOL bShowMenuImages = SvtMenuOptions().IsMenuIconsEnabled();
+
+ UINT32 i, nCount = rAddonMenuEntries.getLength();
+ for ( i = 0; i < nCount; ++i )
+ {
+ GetMenuEntry( rAddonMenuEntries[i], aTitle, aURL, aTarget, aImageId, aAddonSubMenu );
+
+ if ( !aTitle.getLength() && !aURL.getLength() )
+ continue;
+
+ if ( aURL == ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "private:separator" )))
+ InsertSeparator();
+ else
+ {
+ sal_Bool bImageSet = sal_False;
+ USHORT nId = CreateMenuId();
+
+ if ( bShowMenuImages )
+ {
+ if ( aImageId.getLength() > 0 )
+ {
+ Image aImage = GetImageFromURL( m_xFrame, aImageId, FALSE, bIsHiContrastMode );
+ if ( !!aImage )
+ {
+ bImageSet = sal_True;
+ InsertItem( nId, aTitle, aImage );
+ }
+ }
+
+ if ( !bImageSet )
+ {
+ Image aImage = GetImageFromURL( m_xFrame, aURL, FALSE, bIsHiContrastMode );
+ if ( !aImage )
+ aImage = aAddonsOptions.GetImageFromURL( aURL, FALSE, bIsHiContrastMode );
+
+ if ( !aImage )
+ InsertItem( nId, aTitle );
+ else
+ InsertItem( nId, aTitle, aImage );
+ }
+ }
+ else
+ InsertItem( nId, aTitle );
+
+ // Store values from configuration to the New and Wizard menu entries to enable
+ // sfx2 based code to support high contrast mode correctly!
+ MenuConfiguration::Attributes* pUserAttributes = new MenuConfiguration::Attributes;
+ pUserAttributes->aTargetFrame = aTarget;
+ pUserAttributes->aImageId = aImageId;
+ SetUserValue( nId, (ULONG)pUserAttributes );
+
+ SetItemCommand( nId, aURL );
+
+ if ( aAddonSubMenu.getLength() > 0 )
+ SetPopupMenu( nId, BuildSubMenu( aAddonSubMenu ));
+ }
+ }
+}
+
+PopupMenu* AddonMenu::BuildSubMenu( Sequence< Sequence< PropertyValue > > aAddonSubMenuDefinition )
+{
+ Sequence< Sequence< PropertyValue > > aAddonSubMenu;
+ const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
+ BOOL bIsHiContrastMode = rSettings.GetMenuColor().IsDark();
+ BOOL bShowMenuImages = SvtMenuOptions().IsMenuIconsEnabled();
+ UINT32 i, nCount = aAddonSubMenuDefinition.getLength();
+ PopupMenu* pPopupMenu = new PopupMenu;
+ AddonsOptions aAddonsOptions;
+
+ ::rtl::OUString aTitle;
+ ::rtl::OUString aURL;
+ ::rtl::OUString aTarget;
+ ::rtl::OUString aImageId;
+
+ for ( i = 0; i < nCount; ++i )
+ {
+ GetMenuEntry( aAddonSubMenuDefinition[i], aTitle, aURL, aTarget, aImageId, aAddonSubMenu );
+
+ if ( !aTitle.getLength() && !aURL.getLength() )
+ continue;
+
+ if ( aURL == ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "private:separator" )))
+ pPopupMenu->InsertSeparator();
+ else
+ {
+ sal_Bool bImageSet = sal_False;
+ USHORT nId = CreateMenuId();
+
+ if ( bShowMenuImages )
+ {
+ if ( aImageId.getLength() > 0 )
+ {
+ Image aImage = GetImageFromURL( m_xFrame, aImageId, FALSE, bIsHiContrastMode );
+ if ( !!aImage )
+ {
+ bImageSet = sal_True;
+ pPopupMenu->InsertItem( nId, aTitle, aImage );
+ }
+ }
+
+ if ( !bImageSet )
+ {
+ Image aImage = GetImageFromURL( m_xFrame, aURL, FALSE, bIsHiContrastMode );
+ if ( !aImage )
+ aImage = aAddonsOptions.GetImageFromURL( aURL, FALSE, bIsHiContrastMode );
+
+ if ( !aImage )
+ pPopupMenu->InsertItem( nId, aTitle );
+ else
+ pPopupMenu->InsertItem( nId, aTitle, aImage );
+ }
+ }
+ else
+ pPopupMenu->InsertItem( nId, aTitle );
+
+ // Store values from configuration to the New and Wizard menu entries to enable
+ // sfx2 based code to support high contrast mode correctly!
+ MenuConfiguration::Attributes* pUserAttributes = new MenuConfiguration::Attributes;
+ pUserAttributes->aTargetFrame = aTarget;
+ pUserAttributes->aImageId = aImageId;
+ pPopupMenu->SetUserValue( nId, (ULONG)pUserAttributes );
+
+ pPopupMenu->SetItemCommand( nId, aURL );
+
+ if ( aAddonSubMenu.getLength() > 0 )
+ pPopupMenu->SetPopupMenu( nId, BuildSubMenu( aAddonSubMenu ));
+ }
+ }
+
+ return pPopupMenu;
+}
+
+USHORT AddonMenu::CreateMenuId()
+{
+ return AddonMenu_Impl::GetMID();
+}
+
+void GetMenuEntry
+(
+ const Sequence< PropertyValue >& rAddonMenuEntry,
+ ::rtl::OUString& rTitle,
+ ::rtl::OUString& rURL,
+ ::rtl::OUString& rTarget,
+ ::rtl::OUString& rImageId,
+ Sequence< Sequence< PropertyValue > >& rAddonSubMenu
+)
+{
+ // Reset submenu parameter
+ rAddonSubMenu = Sequence< Sequence< PropertyValue > >();
+
+ for ( int i = 0; i < rAddonMenuEntry.getLength(); i++ )
+ {
+ if ( rAddonMenuEntry[i].Name == ADDONSMENUITEM_PROPERTYNAME_URL )
+ rAddonMenuEntry[i].Value >>= rURL;
+ else if ( rAddonMenuEntry[i].Name == ADDONSMENUITEM_PROPERTYNAME_TITLE )
+ rAddonMenuEntry[i].Value >>= rTitle;
+ else if ( rAddonMenuEntry[i].Name == ADDONSMENUITEM_PROPERTYNAME_TARGET )
+ rAddonMenuEntry[i].Value >>= rTarget;
+ else if ( rAddonMenuEntry[i].Name == ADDONSMENUITEM_PROPERTYNAME_IMAGEIDENTIFIER )
+ rAddonMenuEntry[i].Value >>= rImageId;
+ else if ( rAddonMenuEntry[i].Name == ADDONSMENUITEM_PROPERTYNAME_SUBMENU )
+ rAddonMenuEntry[i].Value >>= rAddonSubMenu;
+ }
+}
+
+}
diff --git a/framework/source/classes/addonsoptions.cxx b/framework/source/classes/addonsoptions.cxx
new file mode 100644
index 000000000000..7f29506279d0
--- /dev/null
+++ b/framework/source/classes/addonsoptions.cxx
@@ -0,0 +1,1035 @@
+/*************************************************************************
+ *
+ * $RCSfile: addonsoptions.cxx,v $
+ *
+ * $Revision: 1.1 $
+ *
+ * last change: $Author: cd $ $Date: 2002-10-11 14:22:13 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#pragma hdrstop
+
+//_________________________________________________________________________________________________________________
+// includes
+//_________________________________________________________________________________________________________________
+
+#ifndef __FRAMEWORK_CLASSES_ADDONSOPTIONS_HXX_
+#include <classes/addonsoptions.hxx>
+#endif
+
+#ifndef _UTL_CONFIGMGR_HXX_
+#include <unotools/configmgr.hxx>
+#endif
+
+#ifndef _UTL_CONFIGITEM_HXX_
+#include <unotools/configitem.hxx>
+#endif
+
+#ifndef _TOOLS_DEBUG_HXX
+#include <tools/debug.hxx>
+#endif
+
+#ifndef _STREAM_HXX
+#include <tools/stream.hxx>
+#endif
+
+#ifndef _TOOLS_COLOR_HXX
+#include <tools/color.hxx>
+#endif
+
+#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
+#include <com/sun/star/uno/Any.hxx>
+#endif
+
+#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
+#include <com/sun/star/uno/Sequence.hxx>
+#endif
+
+#ifndef _RTL_USTRBUF_HXX_
+#include <rtl/ustrbuf.hxx>
+#endif
+
+#include <hash_map>
+#include <algorithm>
+
+//_________________________________________________________________________________________________________________
+// namespaces
+//_________________________________________________________________________________________________________________
+
+using namespace ::std ;
+using namespace ::utl ;
+using namespace ::rtl ;
+using namespace ::osl ;
+using namespace ::com::sun::star::uno ;
+using namespace ::com::sun::star::beans ;
+
+//_________________________________________________________________________________________________________________
+// const
+//_________________________________________________________________________________________________________________
+
+#define ROOTNODE_ADDONMENU OUString(RTL_CONSTASCII_USTRINGPARAM("Office.Addons" ))
+#define PATHDELIMITER OUString(RTL_CONSTASCII_USTRINGPARAM("/" ))
+#define SEPARATOR_URL OUString(RTL_CONSTASCII_USTRINGPARAM("private:separator"))
+
+#define PROPERTYNAME_URL ADDONSMENUITEM_PROPERTYNAME_URL
+#define PROPERTYNAME_TITLE ADDONSMENUITEM_PROPERTYNAME_TITLE
+#define PROPERTYNAME_TARGET ADDONSMENUITEM_PROPERTYNAME_TARGET
+#define PROPERTYNAME_IMAGEIDENTIFIER ADDONSMENUITEM_PROPERTYNAME_IMAGEIDENTIFIER
+
+#define PROPERTYNAME_SUBMENU ADDONSMENUITEM_PROPERTYNAME_SUBMENU
+#define PROPERTYNAME_COMPONENTID ADDONSMENUITEM_PROPERTYNAME_COMPONENTID
+
+#define PROPERTYNAME_IMAGESMALL OUString(RTL_CONSTASCII_USTRINGPARAM("ImageSmall" ))
+#define PROPERTYNAME_IMAGEBIG OUString(RTL_CONSTASCII_USTRINGPARAM("ImageBig" ))
+#define PROPERTYNAME_IMAGESMALLHC OUString(RTL_CONSTASCII_USTRINGPARAM("ImageSmallHC" ))
+#define PROPERTYNAME_IMAGEBIGHC OUString(RTL_CONSTASCII_USTRINGPARAM("ImageBigHC" ))
+
+#define IMAGES_NODENAME OUString(RTL_CONSTASCII_USTRINGPARAM("Images" ))
+
+#define PROPERTYCOUNT_ROOT 6 // Used for C++ interface
+#define PROPERTYCOUNT 5
+#define CFG_PROPERTYCOUNT 4
+#define PROPERTYIMAGES_COUNT 4
+
+#define OFFSET_URL 0
+#define OFFSET_TITLE 1
+#define OFFSET_TARGET 2
+#define OFFSET_IMAGEIDENTIFIER 3
+#define OFFSET_SUBMENU 4
+#define OFFSET_COMPONENTID 5
+
+#define OFFSET_IMAGESMALL 0
+#define OFFSET_IMAGEBIG 1
+#define OFFSET_IMAGESMALLHC 2
+#define OFFSET_IMAGEBIGHC 3
+
+#define MENUNODENAME_PREFIX OUString(RTL_CONSTASCII_USTRINGPARAM( "m" ))
+
+//_________________________________________________________________________________________________________________
+// private declarations!
+//_________________________________________________________________________________________________________________
+
+/*-****************************************************************************************************************
+ @descr struct to hold information about one menu entry.
+****************************************************************************************************************-*/
+
+namespace framework
+{
+
+struct AddonMenuEntry;
+typedef vector< AddonMenuEntry > AddonSubMenu;
+
+struct AddonMenuEntry
+{
+ public:
+ AddonMenuEntry() {};
+
+ AddonMenuEntry( const OUString& sNewURL ,
+ const OUString& sNewTitle ,
+ const OUString& sNewImageIdentifier ,
+ const OUString& sNewTarget ,
+ const AddonSubMenu& aNewSubMenu ) :
+ sURL( sNewURL ),
+ sTitle( sNewTitle ),
+ sImageIdentifier( sNewImageIdentifier ),
+ sTarget( sNewTarget ),
+ aSubMenu( aNewSubMenu )
+ {
+ }
+
+ void AppendMenuEntry( const AddonMenuEntry& rEntry )
+ {
+ aSubMenu.push_back( rEntry );
+ }
+
+ public:
+ OUString sName ;
+ OUString sURL ;
+ OUString sTitle ;
+ OUString sTarget ;
+ OUString sImageIdentifier ;
+ AddonSubMenu aSubMenu ;
+};
+
+struct AddonMenuRootEntry
+{
+ public:
+ AddonMenuRootEntry() {};
+
+ AddonMenuRootEntry( const OUString& sNewComponentID ,
+ const OUString& sNewURL ,
+ const OUString& sNewTitle ,
+ const OUString& sNewTarget ,
+ const OUString& sNewImageIdentifier ,
+ const AddonSubMenu& aNewSubMenu ) :
+ sName( sNewComponentID ),
+ sURL( sNewURL ),
+ sTitle( sNewTitle ),
+ sImageIdentifier( sNewImageIdentifier ),
+ sTarget( sNewTarget ),
+ aSubMenu( aNewSubMenu )
+ {
+ }
+
+ public:
+ OUString sName ;
+ OUString sURL ;
+ OUString sTitle ;
+ OUString sTarget ;
+ OUString sImageIdentifier ;
+ AddonSubMenu aSubMenu ;
+};
+
+/*-****************************************************************************************************************
+ @descr support simple menu structures and operations on it
+****************************************************************************************************************-*/
+class SvAddonMenu
+{
+ public:
+ SvAddonMenu() {}
+
+ sal_Int32 Size() const { return aAddonsMenuList.size(); }
+
+ //---------------------------------------------------------------------------------------------------------
+ // append sub menu entry
+ // Assign a unique node name to fulfill to the configuration requirements.
+ sal_Bool AppendMenuEntry( const rtl::OUString& aComponentID, const AddonMenuEntry& rEntry )
+ {
+ for ( sal_uInt32 nIndex = 0; nIndex < aAddonsMenuList.size(); nIndex++ )
+ {
+ AddonMenuRootEntry& rAddonMenuRootEntry = aAddonsMenuList[nIndex];
+ if ( rAddonMenuRootEntry.sName.equals( aComponentID ))
+ {
+ rAddonMenuRootEntry.aSubMenu.push_back( rEntry );
+ return sal_True;
+ }
+ }
+
+ return sal_False;
+ }
+
+ //---------------------------------------------------------------------------------------------------------
+ // append root menu entry
+ void AppendRootMenuEntry( const AddonMenuRootEntry& rEntry )
+ {
+ aAddonsMenuList.push_back( rEntry );
+ }
+
+ //---------------------------------------------------------------------------------------------------------
+ // retrieve a root menu entry from an index
+ const AddonMenuRootEntry* GetRootMenuEntry( sal_uInt32 nIndex ) const
+ {
+ if ( nIndex < aAddonsMenuList.size() )
+ return &(aAddonsMenuList[nIndex]);
+ else
+ return NULL;
+ }
+
+ //---------------------------------------------------------------------------------------------------------
+ // the only way to free memory!
+ void Clear()
+ {
+ aAddonsMenuList.clear();
+ }
+
+ //---------------------------------------------------------------------------------------------------------
+ // convert internal list to external format
+ // for using it on right menus realy
+ // Notice: We build a property list with 4 entries and set it on result list then.
+ // The while-loop starts with pointer on internal member list lSetupEntries, change to
+ // lUserEntries then and stop after that with NULL!
+ // Separator entries will be packed in another way then normal entries! We define
+ // special strings "sEmpty" and "sSeperator" to perform too ...
+ Sequence< Sequence< PropertyValue > > GetList() const;
+
+ //---------------------------------------------------------------------------------------------------------
+ // convert internal submenu to external format
+ // for using it on right menus realy
+ // Notice: We build a property list with 4 entries and set it on result list then.
+ // The while-loop starts with pointer on internal member list lSetupEntries, change to
+ // lUserEntries then and stop after that with NULL!
+ // Separator entries will be packed in another way then normal entries! We define
+ // special strings "sEmpty" and "sSeperator" to perform too ...
+ Sequence< Sequence< PropertyValue > > GetSubMenuList( const AddonSubMenu& rSubMenu ) const;
+
+ private:
+ //---------------------------------------------------------------------------------------------------------
+ // search for an entry named "ux" with x=[0..i] inside our menu
+ // which has set highest number x. So we can add another user entry.
+ sal_Int32 impl_getNextSubMenuEntryNr( const AddonSubMenu& rSubMenu ) const
+ {
+ sal_Int32 nNr = 0;
+ for( vector< AddonMenuEntry >::const_iterator pItem = rSubMenu.begin() ;
+ pItem!=rSubMenu.end() ;
+ ++pItem )
+ {
+ sal_Int32 nCurrNr = pItem->sName.copy( 1 ).toInt32();
+ if ( nCurrNr > nNr )
+ nNr = nCurrNr;
+ }
+ return nNr;
+ }
+
+ private:
+ const OUString sEmpty ;
+ vector< AddonMenuRootEntry > aAddonsMenuList ;
+};
+
+
+Sequence< Sequence< PropertyValue > > SvAddonMenu::GetList() const
+{
+ sal_Int32 nCount = (sal_Int32)aAddonsMenuList.size();
+ sal_Int32 nStep = 0;
+ Sequence< PropertyValue > lRootProperties ( PROPERTYCOUNT_ROOT );
+ Sequence< Sequence< PropertyValue > > lResult ( nCount );
+ const vector< AddonMenuRootEntry >* pList = &aAddonsMenuList;
+
+ // Root menu item properites
+ lRootProperties[OFFSET_URL ].Name = PROPERTYNAME_URL ;
+ lRootProperties[OFFSET_TITLE ].Name = PROPERTYNAME_TITLE ;
+ lRootProperties[OFFSET_IMAGEIDENTIFIER ].Name = PROPERTYNAME_IMAGEIDENTIFIER ;
+ lRootProperties[OFFSET_IMAGEIDENTIFIER ].Name = PROPERTYNAME_TARGET ;
+ lRootProperties[OFFSET_SUBMENU ].Name = PROPERTYNAME_SUBMENU ;
+ lRootProperties[OFFSET_COMPONENTID ].Name = PROPERTYNAME_COMPONENTID ;
+
+ for( vector< AddonMenuRootEntry >::const_iterator pItem =pList->begin();
+ pItem!=pList->end() ;
+ ++pItem )
+ {
+ lRootProperties[OFFSET_URL ].Value <<= pItem->sURL ;
+ lRootProperties[OFFSET_TITLE ].Value <<= pItem->sTitle ;
+ lRootProperties[OFFSET_TARGET ].Value <<= pItem->sTarget ;
+ lRootProperties[OFFSET_IMAGEIDENTIFIER ].Value <<= pItem->sImageIdentifier ;
+
+ sal_Int32 nSubMenuCount = pItem->aSubMenu.size();
+ if ( nSubMenuCount > 0 )
+ lRootProperties[OFFSET_SUBMENU].Value <<= GetSubMenuList( pItem->aSubMenu );
+ else
+ lRootProperties[OFFSET_SUBMENU].Value <<= Sequence< Sequence< PropertyValue > >();
+ lRootProperties[OFFSET_COMPONENTID ].Value <<= pItem->sName ;
+
+ lResult[nStep++] = lRootProperties;
+ }
+
+ return lResult;
+}
+
+
+Sequence< Sequence< PropertyValue > > SvAddonMenu::GetSubMenuList( const AddonSubMenu& rSubMenu ) const
+{
+ const OUString sSeparator( RTL_CONSTASCII_USTRINGPARAM("private:separator") );
+
+ // Sub menu item properites
+ sal_Int32 nStep = 0;
+ Sequence< PropertyValue > lProperties ( PROPERTYCOUNT );
+ Sequence< Sequence< PropertyValue > > lResult ( rSubMenu.size() );
+
+ lProperties[OFFSET_URL ].Name = PROPERTYNAME_URL ;
+ lProperties[OFFSET_TITLE ].Name = PROPERTYNAME_TITLE ;
+ lProperties[OFFSET_TARGET ].Name = PROPERTYNAME_TARGET ;
+ lProperties[OFFSET_IMAGEIDENTIFIER ].Name = PROPERTYNAME_IMAGEIDENTIFIER ;
+ lProperties[OFFSET_SUBMENU ].Name = PROPERTYNAME_SUBMENU ;
+
+ for( vector< AddonMenuEntry >::const_iterator pItem = rSubMenu.begin() ;
+ pItem!=rSubMenu.end() ;
+ ++pItem )
+ {
+ if ( pItem->sURL == sSeparator )
+ {
+ lProperties[OFFSET_URL ].Value <<= sSeparator ;
+ lProperties[OFFSET_TITLE ].Value <<= sEmpty ;
+ lProperties[OFFSET_TARGET ].Value <<= sEmpty ;
+ lProperties[OFFSET_IMAGEIDENTIFIER ].Value <<= sEmpty ;
+ lProperties[OFFSET_SUBMENU ].Value <<= Sequence< Sequence< PropertyValue > >() ;
+ }
+ else
+ {
+ lProperties[OFFSET_URL ].Value <<= pItem->sURL ;
+ lProperties[OFFSET_TITLE ].Value <<= pItem->sTitle ;
+ lProperties[OFFSET_TARGET ].Value <<= sEmpty ;
+ lProperties[OFFSET_IMAGEIDENTIFIER ].Value <<= pItem->sImageIdentifier ;
+
+ sal_Int32 nSubMenuCount = pItem->aSubMenu.size();
+ if ( nSubMenuCount > 0 )
+ lProperties[OFFSET_SUBMENU].Value <<= GetSubMenuList( pItem->aSubMenu );
+ else
+ lProperties[OFFSET_SUBMENU].Value <<= Sequence< Sequence< PropertyValue > >();
+ }
+
+ lResult[nStep++] = lProperties;
+ }
+
+ return lResult;
+}
+
+
+class AddonsOptions_Impl : public ConfigItem
+{
+ //-------------------------------------------------------------------------------------------------------------
+ // public methods
+ //-------------------------------------------------------------------------------------------------------------
+
+ public:
+ //---------------------------------------------------------------------------------------------------------
+ // constructor / destructor
+ //---------------------------------------------------------------------------------------------------------
+
+ AddonsOptions_Impl();
+ ~AddonsOptions_Impl();
+
+ //---------------------------------------------------------------------------------------------------------
+ // overloaded methods of baseclass
+ //---------------------------------------------------------------------------------------------------------
+
+ /*-****************************************************************************************************//**
+ @short called for notify of configmanager
+ @descr These method is called from the ConfigManager before application ends or from the
+ PropertyChangeListener if the sub tree broadcasts changes. You must update your
+ internal values.
+
+ @seealso baseclass ConfigItem
+
+ @param "lPropertyNames" is the list of properties which should be updated.
+ @return -
+
+ @onerror -
+ *//*-*****************************************************************************************************/
+
+ virtual void Notify( const Sequence< OUString >& lPropertyNames );
+
+ /*-****************************************************************************************************//**
+ @short write changes to configuration
+ @descr These method writes the changed values into the sub tree
+ and should always called in our destructor to guarantee consistency of config data.
+
+ @seealso baseclass ConfigItem
+
+ @param -
+ @return -
+
+ @onerror -
+ *//*-*****************************************************************************************************/
+
+ virtual void Commit();
+
+ //---------------------------------------------------------------------------------------------------------
+ // public interface
+ //---------------------------------------------------------------------------------------------------------
+
+ /*-****************************************************************************************************//**
+ @short base implementation of public interface for "SvtDynamicMenuOptions"!
+ @descr These class is used as static member of "SvtDynamicMenuOptions" ...
+ => The code exist only for one time and isn't duplicated for every instance!
+
+ @seealso -
+
+ @param -
+ @return -
+
+ @onerror -
+ *//*-*****************************************************************************************************/
+
+ sal_Bool HasAddonsMenu () const ;
+ const Sequence< Sequence< PropertyValue > >& GetAddonsMenu () const ;
+ Sequence< PropertyValue > GetAddonsComponentMenu( const ::rtl::OUString aComponentID ) const;
+ Image GetImageFromURL( const rtl::OUString& aURL, sal_Bool bBig, sal_Bool bHiContrast ) const;
+
+ //-------------------------------------------------------------------------------------------------------------
+ // private methods
+ //-------------------------------------------------------------------------------------------------------------
+
+ private:
+
+ /*-****************************************************************************************************//**
+ @short return list of key names of our configuration management which represent oue module tree
+ @descr These methods return the current list of key names! We need it to get needed values from our
+ configuration management!
+
+ @seealso -
+
+ @param "nCount" , returns count of menu entries for "new"
+ @return A list of configuration key names is returned.
+
+ @onerror -
+ *//*-*****************************************************************************************************/
+
+ sal_Bool ReadRootMenuEntry( const OUString& aRootMenuNodeName, AddonMenuRootEntry& rRootMenuEntry );
+ sal_Bool ReadSubMenuEntries( const Sequence< OUString >& aSubMenuNodeNames, AddonSubMenu& rSubMenuContainer );
+ sal_Bool ReadSubMenuEntry( const OUString& aMenuEntryNodeName, AddonSubMenu& rSubMenuContainer );
+ Sequence< OUString > GetPropertyNames( const OUString& aPropertyRootNode ) const;
+ Sequence< OUString > GetImagesPropertyNames( const OUString& aPropertyRootNode ) const;
+ sal_Bool CreateImageFromSequence( Image& rImage, sal_Bool bBig, Sequence< sal_Int8 >& rBitmapDataSeq ) const;
+
+ //-------------------------------------------------------------------------------------------------------------
+ // private member
+ //-------------------------------------------------------------------------------------------------------------
+
+ private:
+ struct OUStringHashCode
+ {
+ size_t operator()( const ::rtl::OUString& sString ) const
+ {
+ return sString.hashCode();
+ }
+ };
+
+ struct ImageEntry
+ {
+ Image aImageSmall;
+ Image aImageBig;
+ Image aImageSmallHC;
+ Image aImageBigHC;
+ };
+
+ ImageEntry* ReadOptionalImageData( const OUString& aMenuNodeName );
+ void AddImageEntryToImageManager( const OUString& aURL, ImageEntry* pImageEntry );
+
+ typedef std::hash_map< OUString, ImageEntry, OUStringHashCode, ::std::equal_to< OUString > > ImageManager;
+
+ OUString m_aPropNames[PROPERTYCOUNT_ROOT];
+ OUString m_aPropImagesNames[PROPERTYIMAGES_COUNT];
+ OUString m_aEmpty;
+ OUString m_aPathDelimiter;
+ OUString m_aSeparator;
+ SvAddonMenu m_aAddonMenu;
+ Sequence< Sequence< PropertyValue > > m_aCachedMenuProperties;
+ ImageManager m_aImageManager;
+};
+
+//_________________________________________________________________________________________________________________
+// definitions
+//_________________________________________________________________________________________________________________
+
+//*****************************************************************************************************************
+// constructor
+//*****************************************************************************************************************
+AddonsOptions_Impl::AddonsOptions_Impl()
+ // Init baseclasses first
+ : ConfigItem( ROOTNODE_ADDONMENU ),
+ m_aPathDelimiter( PATHDELIMITER ),
+ m_aSeparator( SEPARATOR_URL )
+{
+ // initialize array with fixed property names
+ m_aPropNames[ OFFSET_URL ] = PROPERTYNAME_URL;
+ m_aPropNames[ OFFSET_TITLE ] = PROPERTYNAME_TITLE;
+ m_aPropNames[ OFFSET_TARGET ] = PROPERTYNAME_TARGET;
+ m_aPropNames[ OFFSET_IMAGEIDENTIFIER ] = PROPERTYNAME_IMAGEIDENTIFIER;
+ m_aPropNames[ OFFSET_SUBMENU ] = PROPERTYNAME_SUBMENU; // Submenu set!
+ m_aPropNames[ OFFSET_COMPONENTID ] = PROPERTYNAME_COMPONENTID; // External property
+
+ // initialize array with fixed images property names
+ m_aPropImagesNames[ OFFSET_IMAGESMALL ] = PROPERTYNAME_IMAGESMALL;
+ m_aPropImagesNames[ OFFSET_IMAGEBIG ] = PROPERTYNAME_IMAGEBIG;
+ m_aPropImagesNames[ OFFSET_IMAGESMALLHC ] = PROPERTYNAME_IMAGESMALLHC;
+ m_aPropImagesNames[ OFFSET_IMAGEBIGHC ] = PROPERTYNAME_IMAGEBIGHC;
+
+ // Get names and values of all accessable menu entries and fill internal structures.
+ // See impl_GetPropertyNames() for further informations.
+ OUString aAddonMenuNodeName( RTL_CONSTASCII_USTRINGPARAM( "AddonUI/AddonMenu" ));
+ Sequence< OUString > aAddonRootMenuNodeSeq = GetNodeNames( aAddonMenuNodeName );
+ OUString aAddonMenuTreeNode( aAddonMenuNodeName + m_aPathDelimiter );
+
+ sal_uInt32 nCount = aAddonRootMenuNodeSeq.getLength();
+ for ( sal_uInt32 n = 0; n < nCount; n++ )
+ {
+ AddonMenuRootEntry aItem;
+ OUString aRootMenuNode( aAddonMenuTreeNode + aAddonRootMenuNodeSeq[n] );
+ if ( ReadRootMenuEntry( aRootMenuNode, aItem ) )
+ m_aAddonMenu.AppendRootMenuEntry( aItem );
+ }
+
+ // Save values to the external representation structure to save memory and time.
+ // Currently this is possible as there is no way to register components during Office runtime!
+ m_aCachedMenuProperties = m_aAddonMenu.GetList();
+
+/*TODO: Not used in the moment! see Notify() ...
+ // Enable notification mechanism of ouer baseclass.
+ // We need it to get information about changes outside these class on ouer used configuration keys!
+ EnableNotification( lNames );
+*/
+}
+
+//*****************************************************************************************************************
+// destructor
+//*****************************************************************************************************************
+AddonsOptions_Impl::~AddonsOptions_Impl()
+{
+ // We must save our current values .. if user forget it!
+ if( IsModified() == sal_True )
+ {
+ Commit();
+ }
+}
+
+//*****************************************************************************************************************
+// public method
+//*****************************************************************************************************************
+void AddonsOptions_Impl::Notify( const Sequence< OUString >& lPropertyNames )
+{
+ DBG_ASSERT( sal_False, "AddonsOptions_Impl::Notify()\nNot implemented yet! I don't know how I can handle a dynamical list of unknown properties ...\n" );
+}
+
+//*****************************************************************************************************************
+// public method
+//*****************************************************************************************************************
+void AddonsOptions_Impl::Commit()
+{
+ DBG_ERROR( "AddonsOptions_Impl::Commit()\nNot implemented yet!\n" );
+}
+
+//*****************************************************************************************************************
+// public method
+//*****************************************************************************************************************
+sal_Bool AddonsOptions_Impl::HasAddonsMenu() const
+{
+ return ( m_aAddonMenu.Size() > 0 );
+}
+
+//*****************************************************************************************************************
+// public method
+//*****************************************************************************************************************
+const Sequence< Sequence< PropertyValue > >& AddonsOptions_Impl::GetAddonsMenu() const
+{
+ return m_aCachedMenuProperties;
+}
+
+//*****************************************************************************************************************
+// public method
+//*****************************************************************************************************************
+Sequence< PropertyValue > AddonsOptions_Impl::GetAddonsComponentMenu( const ::rtl::OUString aComponentID ) const
+{
+ Sequence< PropertyValue > lResult( PROPERTYCOUNT_ROOT );
+
+ for ( sal_uInt32 nIndex = 0; nIndex < (sal_uInt32)m_aAddonMenu.Size(); nIndex++ )
+ {
+ const AddonMenuRootEntry* pRootMenuEntry = m_aAddonMenu.GetRootMenuEntry( nIndex );
+ if ( pRootMenuEntry && pRootMenuEntry->sName.equals( aComponentID ))
+ {
+ lResult[ OFFSET_URL ].Name = m_aPropNames[ OFFSET_URL ];
+ lResult[ OFFSET_URL ].Value <<= pRootMenuEntry->sURL;
+ lResult[ OFFSET_TITLE ].Name = m_aPropNames[ OFFSET_TITLE ];
+ lResult[ OFFSET_TITLE ].Value <<= pRootMenuEntry->sTitle;
+ lResult[ OFFSET_TARGET ].Name = m_aPropNames[ OFFSET_TARGET ];
+ lResult[ OFFSET_TARGET ].Value <<= pRootMenuEntry->sTarget;
+ lResult[ OFFSET_IMAGEIDENTIFIER ].Name = m_aPropNames[ OFFSET_TITLE ];
+ lResult[ OFFSET_IMAGEIDENTIFIER ].Value <<= pRootMenuEntry->sImageIdentifier;
+ lResult[ OFFSET_COMPONENTID ].Name = m_aPropNames[ OFFSET_COMPONENTID ];
+ lResult[ OFFSET_COMPONENTID ].Value <<= pRootMenuEntry->sName;
+ lResult[ OFFSET_SUBMENU ].Name = m_aPropNames[ OFFSET_SUBMENU ];
+
+ if ( pRootMenuEntry->aSubMenu.size() > 0 )
+ lResult[ OFFSET_SUBMENU ].Value <<= m_aAddonMenu.GetSubMenuList( pRootMenuEntry->aSubMenu );
+ else
+ lResult[ OFFSET_SUBMENU ].Value <<= Sequence< Sequence< PropertyValue > >();
+
+ return lResult;
+ }
+ }
+
+ return lResult;
+}
+
+//*****************************************************************************************************************
+// public method
+//*****************************************************************************************************************
+
+Image AddonsOptions_Impl::GetImageFromURL( const rtl::OUString& aURL, sal_Bool bBig, sal_Bool bHiContrast ) const
+{
+ Image aImage;
+
+ ImageManager::const_iterator pIter = m_aImageManager.find( aURL );
+ if ( pIter != m_aImageManager.end() )
+ {
+ if ( !bHiContrast )
+ aImage = ( bBig ? pIter->second.aImageBig : pIter->second.aImageSmall );
+ else
+ aImage = ( bBig ? pIter->second.aImageBigHC : pIter->second.aImageSmallHC );
+ }
+
+ return aImage;
+}
+
+
+//*****************************************************************************************************************
+// private method
+//*****************************************************************************************************************
+sal_Bool AddonsOptions_Impl::ReadRootMenuEntry( const OUString& aRootMenuNodeName, AddonMenuRootEntry& rRootMenuEntry )
+{
+ sal_Bool bResult = sal_False;
+ OUString aAddonRootMenuTreeNode( aRootMenuNodeName + m_aPathDelimiter );
+ Sequence< Any > aRootMenuNodePropValues;
+
+ aRootMenuNodePropValues = GetProperties( GetPropertyNames( aAddonRootMenuTreeNode ) );
+ if ( aRootMenuNodePropValues[ OFFSET_TITLE ] >>= rRootMenuEntry.sTitle )
+ {
+ OUString aRootSubMenuName( aAddonRootMenuTreeNode + m_aPropNames[ OFFSET_SUBMENU ] );
+ Sequence< OUString > aRootSubMenuNodeNames = GetNodeNames( aRootSubMenuName );
+ if ( aRootSubMenuNodeNames.getLength() > 0 )
+ {
+ // A popup menu only needs a title, ignore other properties and continue to read sub menu nodes
+ OUString aSubMenuRootNodeName( aRootSubMenuName + m_aPathDelimiter );
+ for ( sal_uInt32 n = 0; n < (sal_uInt32)aRootSubMenuNodeNames.getLength(); n++ )
+ aRootSubMenuNodeNames[n] = OUString( aSubMenuRootNodeName + aRootSubMenuNodeNames[n] );
+ ReadSubMenuEntries( aRootSubMenuNodeNames, rRootMenuEntry.aSubMenu );
+ rRootMenuEntry.sName = aRootMenuNodeName.copy( aRootMenuNodeName.lastIndexOf( '/' ));
+ bResult = sal_True;
+ }
+ else
+ {
+ // A simple menu item => read the other properties;
+ if ( aRootMenuNodePropValues[ OFFSET_URL ] >>= rRootMenuEntry.sURL ) // Menu item must have a command URL
+ {
+ aRootMenuNodePropValues[ OFFSET_TARGET ] >>= rRootMenuEntry.sTarget;
+ aRootMenuNodePropValues[ OFFSET_IMAGEIDENTIFIER ] >>= rRootMenuEntry.sImageIdentifier;
+
+ // Set the name/component id of the root menu
+ rRootMenuEntry.sName = aRootMenuNodeName.copy( aRootMenuNodeName.lastIndexOf( '/' ));
+
+ // Store bitmap data defined for this menu item into the internal image manager
+ ImageEntry* pImageEntry = ReadOptionalImageData( aRootMenuNodeName );
+ if ( pImageEntry )
+ AddImageEntryToImageManager( rRootMenuEntry.sURL, pImageEntry );
+
+ bResult = sal_True;
+ }
+ }
+ }
+
+ return bResult;
+}
+
+//*****************************************************************************************************************
+// private method
+//*****************************************************************************************************************
+sal_Bool AddonsOptions_Impl::ReadSubMenuEntries( const Sequence< OUString >& aSubMenuNodeNames, AddonSubMenu& rSubMenuContainer )
+{
+ sal_uInt32 nCount = aSubMenuNodeNames.getLength();
+
+ for ( sal_uInt32 n = 0; n < nCount; n++ )
+ ReadSubMenuEntry( aSubMenuNodeNames[n], rSubMenuContainer );
+
+ return sal_True;
+}
+
+//*****************************************************************************************************************
+// private method
+//*****************************************************************************************************************
+sal_Bool AddonsOptions_Impl::ReadSubMenuEntry( const OUString& aMenuEntryNodeName, AddonSubMenu& rSubMenuContainer )
+{
+ sal_Bool bResult = sal_False;
+ OUString aAddonMenuTreeNode( aMenuEntryNodeName + m_aPathDelimiter );
+ Sequence< Any > aMenuNodePropValues;
+ AddonMenuEntry aMenuEntry;
+
+ aMenuNodePropValues = GetProperties( GetPropertyNames( aAddonMenuTreeNode ) );
+ if ( aMenuNodePropValues[ OFFSET_TITLE ] >>= aMenuEntry.sTitle )
+ {
+ OUString aSubMenuNodeName( aAddonMenuTreeNode + m_aPropNames[ OFFSET_SUBMENU ] );
+ Sequence< OUString > aSubMenuNodeNames = GetNodeNames( aSubMenuNodeName );
+ if ( aSubMenuNodeNames.getLength() > 0 )
+ {
+ // A popup menu only needs a title, ignore other properties and continue to read sub menu nodes
+ OUString aSubMenuRootNodeName( aSubMenuNodeName + m_aPathDelimiter );
+ for ( sal_uInt32 n = 0; n < (sal_uInt32)aSubMenuNodeNames.getLength(); n++ )
+ aSubMenuNodeNames[n] = OUString( aSubMenuRootNodeName + aSubMenuNodeNames[n] );
+ ReadSubMenuEntries( aSubMenuNodeNames, aMenuEntry.aSubMenu );
+ rSubMenuContainer.push_back( aMenuEntry );
+ }
+ else
+ {
+ // A simple menu item => read the other properties;
+ if ( aMenuNodePropValues[ OFFSET_URL ] >>= aMenuEntry.sURL ) // Menu item must have a command URL
+ {
+ if ( aMenuEntry.sURL.equals( m_aSeparator ))
+ rSubMenuContainer.push_back( aMenuEntry ); // Separator
+ else
+ {
+ aMenuNodePropValues[ OFFSET_TARGET ] >>= aMenuEntry.sTarget;
+ aMenuNodePropValues[ OFFSET_IMAGEIDENTIFIER ] >>= aMenuEntry.sImageIdentifier;
+ rSubMenuContainer.push_back( aMenuEntry );
+
+ // Store bitmap data defined for this menu item into the internal image manager
+ ImageEntry* pImageEntry = ReadOptionalImageData( aMenuEntryNodeName );
+ if ( pImageEntry )
+ AddImageEntryToImageManager( aMenuEntry.sURL, pImageEntry );
+ }
+
+ bResult = sal_True;
+ }
+ }
+ }
+ else if ( aMenuNodePropValues[ OFFSET_URL ] >>= aMenuEntry.sURL )
+ {
+ aMenuEntry.sURL = m_aSeparator;
+ rSubMenuContainer.push_back( aMenuEntry );
+ bResult = sal_True;
+ }
+
+ return bResult;
+}
+
+//*****************************************************************************************************************
+// private method
+//*****************************************************************************************************************
+AddonsOptions_Impl::ImageEntry* AddonsOptions_Impl::ReadOptionalImageData( const OUString& aMenuNodeName )
+{
+ OUStringBuffer aBuffer( aMenuNodeName );
+ aBuffer.append( m_aPathDelimiter );
+ aBuffer.append( IMAGES_NODENAME );
+ aBuffer.append( m_aPathDelimiter );
+
+ OUString aImageNodeName = aBuffer.makeStringAndClear();
+ Sequence< OUString > aImageDataNodeNames = GetImagesPropertyNames( aImageNodeName );
+ Sequence< Any > aPropertyData;
+ Sequence< sal_Int8 > aImageDataSeq;
+
+ Image aImage;
+ ImageEntry* pEntry = NULL;
+
+ aPropertyData = GetProperties( aImageDataNodeNames );
+ for ( int i = 0; i < PROPERTYIMAGES_COUNT; i++ )
+ {
+ if (( aPropertyData[i] >>= aImageDataSeq ) &&
+ ( CreateImageFromSequence( aImage, (( i == OFFSET_IMAGEBIG ) || ( i == OFFSET_IMAGEBIGHC )), aImageDataSeq )) )
+ {
+ if ( !pEntry )
+ pEntry = new ImageEntry;
+
+ if ( i == OFFSET_IMAGESMALL )
+ pEntry->aImageSmall = aImage;
+ else if ( i == OFFSET_IMAGEBIG )
+ pEntry->aImageBig = aImage;
+ else if ( i == OFFSET_IMAGESMALLHC )
+ pEntry->aImageSmallHC = aImage;
+ else
+ pEntry->aImageBigHC = aImage;
+ }
+ }
+
+ return pEntry;
+}
+
+//*****************************************************************************************************************
+// private method
+//*****************************************************************************************************************
+sal_Bool AddonsOptions_Impl::CreateImageFromSequence( Image& rImage, sal_Bool bBig, Sequence< sal_Int8 >& rBitmapDataSeq ) const
+{
+ sal_Bool bResult = sal_False;
+ Color aTransparentColor( COL_LIGHTMAGENTA );
+ Size aSize = bBig ? Size( 26, 26 ) : Size( 16, 16 ); // Sizes used for menu/toolbox images
+
+ if ( rBitmapDataSeq.getLength() > 0 )
+ {
+ SvMemoryStream aMemStream( rBitmapDataSeq.getArray(), rBitmapDataSeq.getLength(), STREAM_STD_READ );
+ Bitmap aBitmap;
+ aBitmap.Read( aMemStream );
+
+ // Scale bitmap to fit the correct size for the menu/toolbar. Use best quality
+ if ( aBitmap.GetSizePixel() != aSize )
+ aBitmap.Scale( aSize, BMP_SCALE_INTERPOLATE );
+
+ rImage = Image( aBitmap, aTransparentColor );
+ bResult = sal_True;
+ }
+
+ return bResult;
+}
+
+//*****************************************************************************************************************
+// private method
+//*****************************************************************************************************************
+void AddonsOptions_Impl::AddImageEntryToImageManager( const OUString& aURL, ImageEntry* pImageEntry )
+{
+ // Attention: ImageEntry pointer belongs now to the implementation!
+ m_aImageManager.insert( ImageManager::value_type( aURL, *pImageEntry ));
+ delete pImageEntry;
+}
+
+//*****************************************************************************************************************
+// private method
+//*****************************************************************************************************************
+Sequence< OUString > AddonsOptions_Impl::GetPropertyNames( const OUString& aPropertyRootNode ) const
+{
+ Sequence< OUString > lResult( CFG_PROPERTYCOUNT );
+
+ // Create property names dependent from the root node name
+ lResult[0] = OUString( aPropertyRootNode + m_aPropNames[ OFFSET_URL ] );
+ lResult[1] = OUString( aPropertyRootNode + m_aPropNames[ OFFSET_TITLE ] );
+ lResult[2] = OUString( aPropertyRootNode + m_aPropNames[ OFFSET_TARGET ] );
+ lResult[3] = OUString( aPropertyRootNode + m_aPropNames[ OFFSET_IMAGEIDENTIFIER ] );
+
+ return lResult;
+}
+
+//*****************************************************************************************************************
+// private method
+//*****************************************************************************************************************
+Sequence< OUString > AddonsOptions_Impl::GetImagesPropertyNames( const OUString& aPropertyRootNode ) const
+{
+ Sequence< OUString > lResult( PROPERTYIMAGES_COUNT );
+
+ // Create property names dependent from the root node name
+ lResult[0] = OUString( aPropertyRootNode + m_aPropImagesNames[ OFFSET_IMAGESMALL ] );
+ lResult[1] = OUString( aPropertyRootNode + m_aPropImagesNames[ OFFSET_IMAGEBIG ] );
+ lResult[2] = OUString( aPropertyRootNode + m_aPropImagesNames[ OFFSET_IMAGESMALLHC ] );
+ lResult[3] = OUString( aPropertyRootNode + m_aPropImagesNames[ OFFSET_IMAGEBIGHC ] );
+
+ return lResult;
+}
+
+//*****************************************************************************************************************
+// initialize static member
+// DON'T DO IT IN YOUR HEADER!
+// see definition for further informations
+//*****************************************************************************************************************
+AddonsOptions_Impl* AddonsOptions::m_pDataContainer = NULL ;
+sal_Int32 AddonsOptions::m_nRefCount = 0 ;
+
+//*****************************************************************************************************************
+// constructor
+//*****************************************************************************************************************
+AddonsOptions::AddonsOptions()
+{
+ // Global access, must be guarded (multithreading!).
+ MutexGuard aGuard( GetOwnStaticMutex() );
+ // Increase ouer refcount ...
+ ++m_nRefCount;
+ // ... and initialize ouer data container only if it not already exist!
+ if( m_pDataContainer == NULL )
+ {
+ m_pDataContainer = new AddonsOptions_Impl;
+ }
+}
+
+//*****************************************************************************************************************
+// destructor
+//*****************************************************************************************************************
+AddonsOptions::~AddonsOptions()
+{
+ // Global access, must be guarded (multithreading!)
+ MutexGuard aGuard( GetOwnStaticMutex() );
+ // Decrease ouer refcount.
+ --m_nRefCount;
+ // If last instance was deleted ...
+ // we must destroy ouer static data container!
+ if( m_nRefCount <= 0 )
+ {
+ delete m_pDataContainer;
+ m_pDataContainer = NULL;
+ }
+}
+
+//*****************************************************************************************************************
+// public method
+//*****************************************************************************************************************
+sal_Bool AddonsOptions::HasAddonsMenu () const
+{
+ MutexGuard aGuard( GetOwnStaticMutex() );
+ return m_pDataContainer->HasAddonsMenu();
+}
+
+//*****************************************************************************************************************
+// public method
+//*****************************************************************************************************************
+const Sequence< Sequence< PropertyValue > >& AddonsOptions::GetAddonsMenu() const
+{
+ MutexGuard aGuard( GetOwnStaticMutex() );
+ return m_pDataContainer->GetAddonsMenu();
+}
+
+//*****************************************************************************************************************
+// public method
+//*****************************************************************************************************************
+Sequence< PropertyValue > AddonsOptions::GetAddonsComponentMenu( const ::rtl::OUString aComponentID ) const
+{
+ MutexGuard aGuard( GetOwnStaticMutex() );
+ return m_pDataContainer->GetAddonsComponentMenu( aComponentID );
+}
+
+//*****************************************************************************************************************
+// public method
+//*****************************************************************************************************************
+Image AddonsOptions::GetImageFromURL( const rtl::OUString& aURL, sal_Bool bBig, sal_Bool bHiContrast ) const
+{
+ MutexGuard aGuard( GetOwnStaticMutex() );
+ return m_pDataContainer->GetImageFromURL( aURL, bBig, bHiContrast );
+}
+
+//*****************************************************************************************************************
+// private method
+//*****************************************************************************************************************
+Mutex& AddonsOptions::GetOwnStaticMutex()
+{
+ // Initialize static mutex only for one time!
+ static Mutex* pMutex = NULL;
+ // If these method first called (Mutex not already exist!) ...
+ if( pMutex == NULL )
+ {
+ // ... we must create a new one. Protect follow code with the global mutex -
+ // It must be - we create a static variable!
+ MutexGuard aGuard( Mutex::getGlobalMutex() );
+ // We must check our pointer again - because it can be that another instance of ouer class will be fastr then these!
+ if( pMutex == NULL )
+ {
+ // Create the new mutex and set it for return on static variable.
+ static Mutex aMutex;
+ pMutex = &aMutex;
+ }
+ }
+ // Return new created or already existing mutex object.
+ return *pMutex;
+}
+
+} \ No newline at end of file