diff options
Diffstat (limited to 'desktop/source/deployment')
137 files changed, 34016 insertions, 0 deletions
diff --git a/desktop/source/deployment/dp_log.cxx b/desktop/source/deployment/dp_log.cxx new file mode 100644 index 000000000000..0fc8b08a15b7 --- /dev/null +++ b/desktop/source/deployment/dp_log.cxx @@ -0,0 +1,213 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_misc.h" +#include "rtl/strbuf.hxx" +#include "osl/time.h" +#include "osl/thread.h" +#include "cppuhelper/compbase1.hxx" +#include "comphelper/anytostring.hxx" +#include "comphelper/servicedecl.hxx" +#include "comphelper/unwrapargs.hxx" +#include "com/sun/star/deployment/DeploymentException.hpp" +#include "com/sun/star/ucb/XProgressHandler.hpp" +#include "com/sun/star/ucb/XSimpleFileAccess.hpp" +#include "com/sun/star/io/XSeekable.hpp" +#include <stdio.h> + + +using namespace ::rtl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace dp_log { + +typedef ::cppu::WeakComponentImplHelper1<ucb::XProgressHandler> t_log_helper; + +//============================================================================== +class ProgressLogImpl : public ::dp_misc::MutexHolder, public t_log_helper +{ + Reference<io::XOutputStream> m_xLogFile; + sal_Int32 m_log_level; + void log_write( OString const & text ); + +protected: + virtual void SAL_CALL disposing(); + virtual ~ProgressLogImpl(); + +public: + ProgressLogImpl( Sequence<Any> const & args, + Reference<XComponentContext> const & xContext ); + + // XProgressHandler + virtual void SAL_CALL push( Any const & Status ) throw (RuntimeException); + virtual void SAL_CALL update( Any const & Status ) throw (RuntimeException); + virtual void SAL_CALL pop() throw (RuntimeException); +}; + +//______________________________________________________________________________ +ProgressLogImpl::~ProgressLogImpl() +{ +} + +//______________________________________________________________________________ +void ProgressLogImpl::disposing() +{ + try { + if (m_xLogFile.is()) { + m_xLogFile->closeOutput(); + m_xLogFile.clear(); + } + } + catch (Exception & exc) { + (void) exc; + OSL_ENSURE( 0, OUStringToOString( + exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); + } +} + +//______________________________________________________________________________ +ProgressLogImpl::ProgressLogImpl( + Sequence<Any> const & args, + Reference<XComponentContext> const & xContext ) + : t_log_helper( getMutex() ), + m_log_level( 0 ) +{ + OUString log_file; + boost::optional< Reference<task::XInteractionHandler> > interactionHandler; + comphelper::unwrapArgs( args, log_file, interactionHandler ); + + Reference<ucb::XSimpleFileAccess> xSimpleFileAccess( + xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.ucb.SimpleFileAccess"), + xContext ), UNO_QUERY_THROW ); + // optional ia handler: + if (interactionHandler) + xSimpleFileAccess->setInteractionHandler( *interactionHandler ); + + m_xLogFile.set( + xSimpleFileAccess->openFileWrite( log_file ), UNO_QUERY_THROW ); + Reference<io::XSeekable> xSeekable( m_xLogFile, UNO_QUERY_THROW ); + xSeekable->seek( xSeekable->getLength() ); + + // write log stamp + OStringBuffer buf; + buf.append( + RTL_CONSTASCII_STRINGPARAM("###### Progress log entry ") ); + TimeValue m_start_time, tLocal; + oslDateTime date_time; + if (osl_getSystemTime( &m_start_time ) && + osl_getLocalTimeFromSystemTime( &m_start_time, &tLocal ) && + osl_getDateTimeFromTimeValue( &tLocal, &date_time )) + { + char ar[ 128 ]; + snprintf( + ar, sizeof (ar), + "%04d-%02d-%02d %02d:%02d:%02d ", + date_time.Year, date_time.Month, date_time.Day, + date_time.Hours, date_time.Minutes, date_time.Seconds ); + buf.append( ar ); + } + buf.append( RTL_CONSTASCII_STRINGPARAM("######\n") ); + log_write( buf.makeStringAndClear() ); +} + +//______________________________________________________________________________ +void ProgressLogImpl::log_write( OString const & text ) +{ + try { + if (m_xLogFile.is()) { + m_xLogFile->writeBytes( + Sequence< sal_Int8 >( + reinterpret_cast< sal_Int8 const * >(text.getStr()), + text.getLength() ) ); + } + } + catch (io::IOException & exc) { + (void) exc; + OSL_ENSURE( 0, OUStringToOString( + exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); + } +} + +// XProgressHandler +//______________________________________________________________________________ +void ProgressLogImpl::push( Any const & Status ) + throw (RuntimeException) +{ + update( Status ); + OSL_ASSERT( m_log_level >= 0 ); + ++m_log_level; +} + +//______________________________________________________________________________ +void ProgressLogImpl::update( Any const & Status ) + throw (RuntimeException) +{ + if (! Status.hasValue()) + return; + + OUStringBuffer buf; + OSL_ASSERT( m_log_level >= 0 ); + for ( sal_Int32 n = 0; n < m_log_level; ++n ) + buf.append( static_cast<sal_Unicode>(' ') ); + + OUString msg; + if (Status >>= msg) { + buf.append( msg ); + } + else { + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("ERROR: ") ); + buf.append( ::comphelper::anyToString(Status) ); + } + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\n") ); + log_write( OUStringToOString( + buf.makeStringAndClear(), osl_getThreadTextEncoding() ) ); +} + +//______________________________________________________________________________ +void ProgressLogImpl::pop() throw (RuntimeException) +{ + OSL_ASSERT( m_log_level > 0 ); + --m_log_level; +} + +namespace sdecl = comphelper::service_decl; +sdecl::class_<ProgressLogImpl, sdecl::with_args<true> > servicePLI; +extern sdecl::ServiceDecl const serviceDecl( + servicePLI, + // a private one: + "com.sun.star.comp.deployment.ProgressLog", + "com.sun.star.comp.deployment.ProgressLog" ); + +} // namespace dp_log + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/dp_persmap.cxx b/desktop/source/deployment/dp_persmap.cxx new file mode 100644 index 000000000000..2716ed23fc0a --- /dev/null +++ b/desktop/source/deployment/dp_persmap.cxx @@ -0,0 +1,255 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_misc.h" +#include "dp_ucb.h" +#include "dp_persmap.h" +#include "rtl/strbuf.hxx" +#include "rtl/ustrbuf.hxx" +#include "osl/file.hxx" +#include "osl/thread.h" + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::rtl; +using ::osl::File; + +namespace dp_misc +{ + +//______________________________________________________________________________ +void PersistentMap::throw_rtexc( int err, char const * pmsg ) const +{ + OUStringBuffer buf; + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[") ); + buf.append( m_sysPath ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("] Berkeley Db error (") ); + buf.append( static_cast<sal_Int32>(err) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("): ") ); + if (pmsg == 0) + pmsg = DbEnv::strerror(err); + const OString msg(pmsg); + buf.append( OUString( msg.getStr(), msg.getLength(), + osl_getThreadTextEncoding() ) ); + const OUString msg_(buf.makeStringAndClear()); + OSL_ENSURE( 0, rtl::OUStringToOString( + msg_, RTL_TEXTENCODING_UTF8 ).getStr() ); + throw RuntimeException( msg_, Reference<XInterface>() ); +} + +//______________________________________________________________________________ +PersistentMap::~PersistentMap() +{ + try { + m_db.close(0); + } + catch (DbException & exc) { + (void) exc; // avoid warnings + OSL_ENSURE( 0, DbEnv::strerror( exc.get_errno() ) ); + } +} + +//______________________________________________________________________________ +PersistentMap::PersistentMap( OUString const & url_, bool readOnly ) + : m_db( 0, 0 ) +{ + try { + OUString url( expandUnoRcUrl(url_) ); + if ( File::getSystemPathFromFileURL( url, m_sysPath ) != File::E_None ) + { + OSL_ASSERT( false ); + } + OString cstr_sysPath( + OUStringToOString( m_sysPath, RTL_TEXTENCODING_UTF8 ) ); + char const * pcstr_sysPath = cstr_sysPath.getStr(); + + u_int32_t flags = DB_CREATE; + if (readOnly) { + flags = DB_RDONLY; + if (! create_ucb_content( + 0, url, + Reference<com::sun::star::ucb::XCommandEnvironment>(), + false /* no throw */ )) { + // ignore non-existent file in read-only mode: simulate empty db + pcstr_sysPath = 0; + flags = DB_CREATE; + } + } + + int err = m_db.open( + // xxx todo: DB_THREAD, DB_DBT_MALLOC currently not used + 0, pcstr_sysPath, 0, DB_HASH, flags/* | DB_THREAD*/, 0664 /* fs mode */ ); + if (err != 0) + throw_rtexc(err); + } + catch (DbException & exc) { + throw_rtexc( exc.get_errno(), exc.what() ); + } +} + +//______________________________________________________________________________ +PersistentMap::PersistentMap() + : m_db( 0, 0 ) +{ + try { + // xxx todo: DB_THREAD, DB_DBT_MALLOC currently not used + int err = m_db.open( 0, 0, 0, DB_HASH, DB_CREATE/* | DB_THREAD*/, 0 ); + if (err != 0) + throw_rtexc(err); + } + catch (DbException & exc) { + throw_rtexc( exc.get_errno(), exc.what() ); + } +} + +//______________________________________________________________________________ +bool PersistentMap::has( OString const & key ) const +{ + return get( 0, key ); +} + +//______________________________________________________________________________ +bool PersistentMap::get( OString * value, OString const & key ) const +{ + try { + Dbt dbKey( const_cast< sal_Char * >(key.getStr()), key.getLength() ); + Dbt dbData; + int err = m_db.get( 0, &dbKey, &dbData, 0 ); + if (err == DB_NOTFOUND) + return false; + if (err == 0) { + if (value != 0) { + *value = OString( + static_cast< sal_Char const * >(dbData.get_data()), + dbData.get_size() ); + } + return true; + } + throw_rtexc(err); + } + catch (DbException & exc) { + throw_rtexc( exc.get_errno(), exc.what() ); + } + return false; // avoiding warning +} + +//______________________________________________________________________________ +void PersistentMap::put( OString const & key, OString const & value ) +{ + try { + Dbt dbKey( const_cast< sal_Char * >(key.getStr()), key.getLength() ); + Dbt dbData( const_cast< sal_Char * >( + value.getStr()), value.getLength() ); + int err = m_db.put( 0, &dbKey, &dbData, 0 ); + if (err == 0) { +#if OSL_DEBUG_LEVEL > 0 + OString v; + OSL_ASSERT( get( &v, key ) ); + OSL_ASSERT( v.equals( value ) ); +#endif + err = m_db.sync(0); + } + if (err != 0) + throw_rtexc(err); + } + catch (DbException & exc) { + throw_rtexc( exc.get_errno(), exc.what() ); + } +} + +//______________________________________________________________________________ +bool PersistentMap::erase( OString const & key, bool flush_immediately ) +{ + try { + Dbt dbKey( const_cast< sal_Char * >(key.getStr()), key.getLength() ); + int err = m_db.del( &dbKey, 0 ); + if (err == 0) { + if (flush_immediately) { + err = m_db.sync(0); + if (err != 0) + throw_rtexc(err); + } + return true; + } + if (err == DB_NOTFOUND) + return false; + throw_rtexc(err); + } + catch (DbException & exc) { + throw_rtexc( exc.get_errno(), exc.what() ); + } + return false; // avoiding warning +} + +//______________________________________________________________________________ +t_string2string_map PersistentMap::getEntries() const +{ + try { + Dbc * pcurs = 0; + int err = m_db.cursor( 0, &pcurs, 0 ); + if (err != 0) + throw_rtexc(err); + + t_string2string_map ret; + for (;;) { + Dbt dbKey, dbData; + err = pcurs->get( &dbKey, &dbData, DB_NEXT ); + if (err == DB_NOTFOUND) + break; + if (err != 0) + throw_rtexc(err); + + ::std::pair<t_string2string_map::iterator, bool > insertion( + ret.insert( t_string2string_map::value_type( + t_string2string_map::value_type( + OString( static_cast< sal_Char const * >( + dbKey.get_data()), + dbKey.get_size() ), + OString( static_cast< sal_Char const * >( + dbData.get_data()), + dbData.get_size() ) ) ) ) ); + OSL_ASSERT( insertion.second ); + } + err = pcurs->close(); + if (err != 0) + throw_rtexc(err); + return ret; + } + catch (DbException & exc) { + throw_rtexc( exc.get_errno(), exc.what() ); + } + return t_string2string_map(); // avoiding warning +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/dp_services.cxx b/desktop/source/deployment/dp_services.cxx new file mode 100644 index 000000000000..b9b7959ccaba --- /dev/null +++ b/desktop/source/deployment/dp_services.cxx @@ -0,0 +1,138 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#define COMPHELPER_SERVICEDECL_COMPONENT_HELPER_MAX_ARGS 12 +#include "comphelper/servicedecl.hxx" + +using namespace com::sun::star; +namespace sdecl = comphelper::service_decl; + +namespace dp_registry { +namespace backend { + +namespace configuration { +extern sdecl::ServiceDecl const serviceDecl; +} + +namespace component { +extern sdecl::ServiceDecl const serviceDecl; +} + +namespace script { +extern sdecl::ServiceDecl const serviceDecl; +} + +namespace sfwk { +extern sdecl::ServiceDecl const serviceDecl; +} + +namespace help { +extern sdecl::ServiceDecl const serviceDecl; +} + +namespace executable { +extern sdecl::ServiceDecl const serviceDecl; +} + +} // namespace backend +} // namespace dp_registry + +namespace dp_manager { +namespace factory { +extern sdecl::ServiceDecl const serviceDecl; +bool singleton_entries( uno::Reference<registry::XRegistryKey> const& ); +} +extern sdecl::ServiceDecl const serviceDecl; +bool singleton_entries( uno::Reference<registry::XRegistryKey> const& ); +} + +namespace dp_log { +extern sdecl::ServiceDecl const serviceDecl; +} + +namespace dp_info { +extern sdecl::ServiceDecl const serviceDecl; +bool singleton_entries( uno::Reference<registry::XRegistryKey> const& ); +} + +extern "C" { + +struct uno_Environment; + +void SAL_CALL component_getImplementationEnvironment( + const sal_Char ** ppEnvTypeName, uno_Environment ** ) +{ + *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; +} + +sal_Bool SAL_CALL component_writeInfo( + lang::XMultiServiceFactory * pServiceManager, + registry::XRegistryKey * pRegistryKey ) +{ + return component_writeInfoHelper( + pServiceManager, pRegistryKey, + dp_registry::backend::configuration::serviceDecl, + dp_registry::backend::component::serviceDecl, + dp_registry::backend::help::serviceDecl, + dp_registry::backend::script::serviceDecl, + dp_registry::backend::sfwk::serviceDecl, + dp_registry::backend::executable::serviceDecl, + dp_manager::factory::serviceDecl, + dp_log::serviceDecl, + dp_info::serviceDecl, + dp_manager::serviceDecl) && + dp_manager::factory::singleton_entries( pRegistryKey ) && + dp_info::singleton_entries( pRegistryKey ) && + dp_manager::singleton_entries( pRegistryKey); +} + +void * SAL_CALL component_getFactory( + sal_Char const * pImplName, + lang::XMultiServiceFactory * pServiceManager, + registry::XRegistryKey * pRegistryKey ) +{ + return component_getFactoryHelper( + pImplName, pServiceManager, pRegistryKey, + dp_registry::backend::configuration::serviceDecl, + dp_registry::backend::component::serviceDecl, + dp_registry::backend::help::serviceDecl, + dp_registry::backend::script::serviceDecl, + dp_registry::backend::sfwk::serviceDecl, + dp_registry::backend::executable::serviceDecl, + dp_manager::factory::serviceDecl, + dp_log::serviceDecl, + dp_info::serviceDecl, + dp_manager::serviceDecl); +} + +} // extern "C" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/dp_xml.cxx b/desktop/source/deployment/dp_xml.cxx new file mode 100644 index 000000000000..b46d9835548c --- /dev/null +++ b/desktop/source/deployment/dp_xml.cxx @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_misc.h" +#include "dp_xml.h" +#include "rtl/ustrbuf.hxx" +#include "ucbhelper/content.hxx" +#include "com/sun/star/xml/sax/XParser.hpp" + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using ::rtl::OUString; + +namespace dp_misc +{ + +//============================================================================== +void xml_parse( + Reference<xml::sax::XDocumentHandler> const & xDocHandler, + ::ucbhelper::Content & ucb_content, + Reference<XComponentContext> const & xContext ) +{ + // raise sax parser: + Reference<xml::sax::XParser> xParser( + xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.xml.sax.Parser"), xContext ), UNO_QUERY_THROW ); + + // error handler, entity resolver omitted + xParser->setDocumentHandler( xDocHandler ); + xml::sax::InputSource source; + source.aInputStream = ucb_content.openStream(); + source.sSystemId = ucb_content.getURL(); + xParser->parseStream( source ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/descedit.cxx b/desktop/source/deployment/gui/descedit.cxx new file mode 100644 index 000000000000..8887b40a3946 --- /dev/null +++ b/desktop/source/deployment/gui/descedit.cxx @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include <vcl/scrbar.hxx> +#include <svtools/txtattr.hxx> +#include <svtools/xtextedt.hxx> + +#include "descedit.hxx" + +#include "dp_gui.hrc" + +using dp_gui::DescriptionEdit; + +// DescriptionEdit ------------------------------------------------------- + +DescriptionEdit::DescriptionEdit( Window* pParent, const ResId& rResId ) : + + ExtMultiLineEdit( pParent, rResId ), + + m_bIsVerticalScrollBarHidden( true ) + +{ + Init(); +} + +// ----------------------------------------------------------------------- + +void DescriptionEdit::Init() +{ + Clear(); + // no tabstop + SetStyle( ( GetStyle() & ~WB_TABSTOP ) | WB_NOTABSTOP ); + // read-only + SetReadOnly(); + // no cursor + EnableCursor( FALSE ); +} + +// ----------------------------------------------------------------------- + +void DescriptionEdit::UpdateScrollBar() +{ + if ( m_bIsVerticalScrollBarHidden ) + { + ScrollBar* pVScrBar = GetVScrollBar(); + if ( pVScrBar && pVScrBar->GetVisibleSize() < pVScrBar->GetRangeMax() ) + { + pVScrBar->Show(); + m_bIsVerticalScrollBarHidden = false; + } + } +} + +// ----------------------------------------------------------------------- + +void DescriptionEdit::Clear() +{ + SetText( String() ); + + m_bIsVerticalScrollBarHidden = true; + ScrollBar* pVScrBar = GetVScrollBar(); + if ( pVScrBar ) + pVScrBar->Hide(); +} + +// ----------------------------------------------------------------------- + +void DescriptionEdit::SetDescription( const String& rDescription ) +{ + SetText( rDescription ); + UpdateScrollBar(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/descedit.hxx b/desktop/source/deployment/gui/descedit.hxx new file mode 100644 index 000000000000..ed8b8f9c333f --- /dev/null +++ b/desktop/source/deployment/gui/descedit.hxx @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_GUI_DP_GUI_DESCEDIT_HXX +#define INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_GUI_DP_GUI_DESCEDIT_HXX + +#include "svtools/svmedit2.hxx" + +/// @HTML + +namespace dp_gui +{ + + class DescriptionEdit : public ExtMultiLineEdit + { + private: + bool m_bIsVerticalScrollBarHidden; + + void Init(); + void UpdateScrollBar(); + + public: + DescriptionEdit( Window* pParent, const ResId& rResId ); + inline ~DescriptionEdit() {} + + void Clear(); + void SetDescription( const String& rDescription ); + }; + +} // namespace dp_gui + +#endif // INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_GUI_DP_GUI_DESCEDIT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/dp_gui.h b/desktop/source/deployment/gui/dp_gui.h new file mode 100644 index 000000000000..1c57aa5b800e --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui.h @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_GUI_H +#define INCLUDED_DP_GUI_H + +#include "dp_gui_updatedata.hxx" +#include "dp_misc.h" +#include "dp_gui.hrc" +#include "rtl/ref.hxx" +#include "rtl/instance.hxx" +#include "osl/thread.hxx" +#include "cppuhelper/implbase2.hxx" +#include "vcl/svapp.hxx" +#include "vcl/dialog.hxx" +#include "vcl/button.hxx" +#include "vcl/fixed.hxx" +#include "salhelper/simplereferenceobject.hxx" +#include "svtools/svtabbx.hxx" +#include "svtools/headbar.hxx" +#include "com/sun/star/ucb/XContentEventListener.hpp" +#include "osl/mutex.hxx" +#include <list> +#include <memory> +#include <queue> + +namespace com { namespace sun { namespace star { + namespace container { + class XNameAccess; + } + namespace frame { + class XDesktop; + } + namespace awt { + class XWindow; + } + namespace uno { + class XComponentContext; + } + namespace deployment { + class XPackageManagerFactory; + } +} } } + +namespace svt { + class FixedHyperlink; +} + +namespace dp_gui { + +enum PackageState { REGISTERED, NOT_REGISTERED, AMBIGUOUS, NOT_AVAILABLE }; + +//============================================================================== + +class SelectedPackage: public salhelper::SimpleReferenceObject { +public: + SelectedPackage() {} + SelectedPackage( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage> &xPackage) + : m_xPackage( xPackage ) + {} + + virtual ~SelectedPackage(); + ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage> getPackage() const { return m_xPackage; } + +private: + SelectedPackage(SelectedPackage &); // not defined + void operator =(SelectedPackage &); // not defined + + ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage> m_xPackage; +}; + +} // namespace dp_gui + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/dp_gui.hrc b/desktop/source/deployment/gui/dp_gui.hrc new file mode 100755 index 000000000000..d0ae3c468d9b --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui.hrc @@ -0,0 +1,174 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_GUI_HRC +#define INCLUDED_DP_GUI_HRC + +#include "deployment.hrc" +#include "helpid.hrc" + +// Package Manager Dialog: +#define RID_DLG_EXTENSION_MANAGER RID_DEPLOYMENT_GUI_START +#define RID_DLG_UPDATE_REQUIRED (RID_DEPLOYMENT_GUI_START + 11) + +#define RID_EM_BTN_CLOSE 10 +#define RID_EM_BTN_HELP 11 +#define RID_EM_BTN_ADD 12 +#define RID_EM_BTN_CHECK_UPDATES 13 +#define RID_EM_BTN_OPTIONS 14 +#define RID_EM_BTN_CANCEL 15 +#define RID_EM_FT_GET_EXTENSIONS 20 +#define RID_EM_FT_PROGRESS 21 +#define RID_EM_FT_MSG 22 + +// local RIDs: +#define PB_LICENSE_DOWN 50 +#define ML_LICENSE 51 +#define BTN_LICENSE_DECLINE 53 +#define FT_LICENSE_HEADER 54 +#define FT_LICENSE_BODY_1 55 +#define FT_LICENSE_BODY_1_TXT 56 +#define FT_LICENSE_BODY_2 57 +#define FT_LICENSE_BODY_2_TXT 58 +#define FL_LICENSE 69 +#define FI_LICENSE_ARROW1 60 +#define FI_LICENSE_ARROW2 61 +#define BTN_LICENSE_ACCEPT 63 + +// local RIDs for "Download and Install" dialog + +#define RID_DLG_UPDATE_INSTALL_ABORT 2 +#define RID_DLG_UPDATE_INSTALL_OK 3 +#define RID_DLG_UPDATE_INSTALL_DOWNLOADING 4 +#define RID_DLG_UPDATE_INSTALL_INSTALLING 5 +#define RID_DLG_UPDATE_INSTALL_FINISHED 6 +#define RID_DLG_UPDATE_INSTALL_LINE 7 +#define RID_DLG_UPDATE_INSTALL_HELP 8 +#define RID_DLG_UPDATE_INSTALL_STATUSBAR 9 +#define RID_DLG_UPDATE_INSTALL_EXTENSION_NAME 10 +#define RID_DLG_UPDATE_INSTALL_RESULTS 11 +#define RID_DLG_UPDATE_INSTALL_INFO 12 +#define RID_DLG_UPDATE_INSTALL_NO_ERRORS 13 +#define RID_DLG_UPDATE_INSTALL_THIS_ERROR_OCCURRED 14 +#define RID_DLG_UPDATE_INSTALL_ERROR_DOWNLOAD 15 +#define RID_DLG_UPDATE_INSTALL_ERROR_INSTALLATION 16 +#define RID_DLG_UPDATE_INSTALL_ERROR_LIC_DECLINED 17 +#define RID_DLG_UPDATE_INSTALL_EXTENSION_NOINSTALL 18 + +#define RID_DLG_DEPENDENCIES (RID_DEPLOYMENT_GUI_START + 1) +#define RID_DLG_DEPENDENCIES_TEXT 1 +#define RID_DLG_DEPENDENCIES_LIST 2 +#define RID_DLG_DEPENDENCIES_OK 3 + +#define RID_QUERYBOX_INSTALL_FOR_ALL (RID_DEPLOYMENT_GUI_START + 2) +#define RID_WARNINGBOX_VERSION_LESS (RID_DEPLOYMENT_GUI_START + 3) +#define RID_STR_WARNINGBOX_VERSION_LESS_DIFFERENT_NAMES (RID_DEPLOYMENT_GUI_START + 4) +#define RID_WARNINGBOX_VERSION_EQUAL (RID_DEPLOYMENT_GUI_START + 5) +#define RID_STR_WARNINGBOX_VERSION_EQUAL_DIFFERENT_NAMES (RID_DEPLOYMENT_GUI_START + 6) +#define RID_WARNINGBOX_VERSION_GREATER (RID_DEPLOYMENT_GUI_START + 7) +#define RID_STR_WARNINGBOX_VERSION_GREATER_DIFFERENT_NAMES (RID_DEPLOYMENT_GUI_START + 8) +#define RID_WARNINGBOX_INSTALL_EXTENSION (RID_DEPLOYMENT_GUI_START + 9) + +#define RID_DLG_UPDATE (RID_DEPLOYMENT_GUI_START + 10) + +#define RID_DLG_UPDATE_CHECKING 1 +#define RID_DLG_UPDATE_THROBBER 2 +#define RID_DLG_UPDATE_UPDATE 3 +#define RID_DLG_UPDATE_UPDATES 4 +#define RID_DLG_UPDATE_ALL 5 +#define RID_DLG_UPDATE_DESCRIPTION 6 +#define RID_DLG_UPDATE_DESCRIPTIONS 7 +#define RID_DLG_UPDATE_LINE 8 +#define RID_DLG_UPDATE_HELP 9 +#define RID_DLG_UPDATE_OK 10 +#define RID_DLG_UPDATE_CANCEL 11 +#define RID_DLG_UPDATE_NORMALALERT 12 +#define RID_DLG_UPDATE_ERROR 14 +#define RID_DLG_UPDATE_NONE 15 +#define RID_DLG_UPDATE_NOINSTALLABLE 16 +#define RID_DLG_UPDATE_FAILURE 17 +#define RID_DLG_UPDATE_UNKNOWNERROR 18 +#define RID_DLG_UPDATE_NODESCRIPTION 19 +#define RID_DLG_UPDATE_NOINSTALL 20 +#define RID_DLG_UPDATE_NODEPENDENCY 21 +#define RID_DLG_UPDATE_NODEPENDENCY_CUR_VER 22 +#define RID_DLG_UPDATE_NOPERMISSION 23 +#define RID_DLG_UPDATE_NOPERMISSION_VISTA 24 +#define RID_DLG_UPDATE_BROWSERBASED 25 +#define RID_DLG_UPDATE_PUBLISHER_LABEL 26 +#define RID_DLG_UPDATE_PUBLISHER_LINK 27 +#define RID_DLG_UPDATE_RELEASENOTES_LABEL 28 +#define RID_DLG_UPDATE_RELEASENOTES_LINK 29 +#define RID_DLG_UPDATE_NOUPDATE 30 +#define RID_DLG_UPDATE_VERSION 31 + + +#define RID_DLG_UPDATEINSTALL (RID_DEPLOYMENT_GUI_START + 20) +#define RID_INFOBOX_UPDATE_SHARED_EXTENSION (RID_DEPLOYMENT_GUI_START + 21) + +#define RID_IMG_WARNING (RID_DEPLOYMENT_GUI_START+56) +#define RID_IMG_LOCKED (RID_DEPLOYMENT_GUI_START+58) +#define RID_IMG_EXTENSION (RID_DEPLOYMENT_GUI_START+60) +#define RID_IMG_SHARED (RID_DEPLOYMENT_GUI_START+62) + +#define RID_STR_ADD_PACKAGES (RID_DEPLOYMENT_GUI_START+70) + +#define RID_CTX_ITEM_REMOVE (RID_DEPLOYMENT_GUI_START+80) +#define RID_CTX_ITEM_ENABLE (RID_DEPLOYMENT_GUI_START+81) +#define RID_CTX_ITEM_DISABLE (RID_DEPLOYMENT_GUI_START+82) +#define RID_CTX_ITEM_CHECK_UPDATE (RID_DEPLOYMENT_GUI_START+83) +#define RID_CTX_ITEM_OPTIONS (RID_DEPLOYMENT_GUI_START+84) + +#define RID_STR_ADDING_PACKAGES (RID_DEPLOYMENT_GUI_START+85) +#define RID_STR_REMOVING_PACKAGES (RID_DEPLOYMENT_GUI_START+86) +#define RID_STR_ENABLING_PACKAGES (RID_DEPLOYMENT_GUI_START+87) +#define RID_STR_DISABLING_PACKAGES (RID_DEPLOYMENT_GUI_START+88) +#define RID_STR_ACCEPT_LICENSE (RID_DEPLOYMENT_GUI_START+89) + +#define RID_STR_INSTALL_FOR_ALL (RID_DEPLOYMENT_GUI_START+90) +#define RID_STR_INSTALL_FOR_ME (RID_DEPLOYMENT_GUI_START+91) +#define RID_STR_ERROR_UNKNOWN_STATUS (RID_DEPLOYMENT_GUI_START+92) +#define RID_STR_CLOSE_BTN (RID_DEPLOYMENT_GUI_START+93) +#define RID_STR_EXIT_BTN (RID_DEPLOYMENT_GUI_START+94) +#define RID_STR_NO_ADMIN_PRIVILEGE (RID_DEPLOYMENT_GUI_START+95) +#define RID_STR_ERROR_MISSING_DEPENDENCIES (RID_DEPLOYMENT_GUI_START+96) +#define RID_STR_ERROR_MISSING_LICENSE (RID_DEPLOYMENT_GUI_START+97) + +#define WARNINGBOX_CONCURRENTINSTANCE (RID_DEPLOYMENT_GUI_START+100) + +#define RID_STR_UNSUPPORTED_PLATFORM (RID_DEPLOYMENT_GUI_START+101) +#define RID_WARNINGBOX_UPDATE_SHARED_EXTENSION (RID_DEPLOYMENT_GUI_START+102) +#define RID_WARNINGBOX_REMOVE_EXTENSION (RID_DEPLOYMENT_GUI_START+103) +#define RID_WARNINGBOX_REMOVE_SHARED_EXTENSION (RID_DEPLOYMENT_GUI_START+104) +#define RID_WARNINGBOX_ENABLE_SHARED_EXTENSION (RID_DEPLOYMENT_GUI_START+105) +#define RID_WARNINGBOX_DISABLE_SHARED_EXTENSION (RID_DEPLOYMENT_GUI_START+106) + +#define RID_DLG_LICENSE RID_DEPLOYMENT_LICENSE_START + + + +#endif diff --git a/desktop/source/deployment/gui/dp_gui_autoscrolledit.cxx b/desktop/source/deployment/gui/dp_gui_autoscrolledit.cxx new file mode 100644 index 000000000000..9bde835bf140 --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_autoscrolledit.cxx @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + + +#include "svtools/svmedit2.hxx" +#include "svl/lstner.hxx" +#include "svtools/xtextedt.hxx" +#include "vcl/scrbar.hxx" + +#include "dp_gui_autoscrolledit.hxx" + + +namespace dp_gui { + + +AutoScrollEdit::AutoScrollEdit( Window* pParent, const ResId& rResId ) + : ExtMultiLineEdit( pParent, rResId ) +{ + ScrollBar* pScroll = GetVScrollBar(); + if (pScroll) + pScroll->Hide(); +// SetLeftMargin( 0 ); + StartListening( *GetTextEngine() ); +} + +AutoScrollEdit::~AutoScrollEdit() +{ + EndListeningAll(); +} + +void AutoScrollEdit::Notify( SfxBroadcaster&, const SfxHint& rHint ) +{ + if ( rHint.IsA( TYPE(TextHint) ) ) + { + ULONG nId = ((const TextHint&)rHint).GetId(); + if ( nId == TEXT_HINT_VIEWSCROLLED ) + { + ScrollBar* pScroll = GetVScrollBar(); + if ( pScroll ) + pScroll->Show(); + } + } +} + + +} // namespace dp_gui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/dp_gui_autoscrolledit.hxx b/desktop/source/deployment/gui/dp_gui_autoscrolledit.hxx new file mode 100644 index 000000000000..c49477358c1b --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_autoscrolledit.hxx @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_GUI_DP_GUI_AUTOSCROLLEDIT_HXX +#define INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_GUI_DP_GUI_AUTOSCROLLEDIT_HXX + +#include "svtools/svmedit2.hxx" +#include "svl/lstner.hxx" + +namespace dp_gui { + +/** This control shows automatically the vertical scroll bar if text is inserted, + that does not fit into the text area. In the resource one uses MultiLineEdit + and needs to set VScroll = TRUE +*/ +class AutoScrollEdit : public ExtMultiLineEdit, public SfxListener +{ +public: + AutoScrollEdit( Window* pParent, const ResId& rResId ); + ~AutoScrollEdit(); + + using ExtMultiLineEdit::Notify; + virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ); +}; + +} // namespace dp_gui + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/dp_gui_backend.src b/desktop/source/deployment/gui/dp_gui_backend.src new file mode 100644 index 000000000000..e5adb84ba596 --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_backend.src @@ -0,0 +1,86 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "dp_gui.hrc" + +// package bundle: +Image RID_IMG_DEF_PACKAGE_BUNDLE +{ + ImageBitmap = Bitmap { File = "sx03256.bmp"; }; + MASKCOLOR +}; + +// script, dialog: +Image RID_IMG_SCRIPTLIB +{ + ImageBitmap = Bitmap { File = "im30820.bmp"; }; + MASKCOLOR +}; + +Image RID_IMG_DIALOGLIB +{ + ImageBitmap = Bitmap { File = "dialogfolder_16.bmp"; }; + MASKCOLOR +}; + +// configuration: +Image RID_IMG_CONF_XML +{ + ImageBitmap = Bitmap { File = "xml_16.bmp"; }; + MASKCOLOR +}; + +// component, typelib: +Image RID_IMG_COMPONENT +{ + ImageBitmap = Bitmap { File = "component_16.bmp"; }; + MASKCOLOR +}; + +Image RID_IMG_JAVA_COMPONENT +{ + ImageBitmap = Bitmap { File = "javacomponent_16.bmp"; }; + MASKCOLOR +}; + +Image RID_IMG_TYPELIB +{ + ImageBitmap = Bitmap { File = "library_16.bmp"; }; + MASKCOLOR +}; + +Image RID_IMG_JAVA_TYPELIB +{ + ImageBitmap = Bitmap { File = "javalibrary_16.bmp"; }; + MASKCOLOR +}; + +Image RID_IMG_HELP +{ + ImageBitmap = Bitmap { File = "commandimagelist/sc_helperdialog.bmp"; }; + MASKCOLOR +}; diff --git a/desktop/source/deployment/gui/dp_gui_dependencydialog.cxx b/desktop/source/deployment/gui/dp_gui_dependencydialog.cxx new file mode 100644 index 000000000000..7019db610b85 --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_dependencydialog.cxx @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "sal/config.h" + +#include <algorithm> +#include <vector> + +#include "rtl/ustring.hxx" +#include "tools/gen.hxx" +#include "tools/resid.hxx" +#include "tools/resmgr.hxx" +#include "tools/solar.h" +#include "tools/string.hxx" +#include "vcl/dialog.hxx" + +#include "dp_gui.hrc" +#include "dp_gui_dependencydialog.hxx" +#include "dp_gui_shared.hxx" + +class Window; + +using dp_gui::DependencyDialog; + +DependencyDialog::DependencyDialog( + Window * parent, std::vector< rtl::OUString > const & dependencies): + ModalDialog(parent, DpGuiResId(RID_DLG_DEPENDENCIES) ), + m_text(this, DpGuiResId(RID_DLG_DEPENDENCIES_TEXT)), + m_list(this, DpGuiResId(RID_DLG_DEPENDENCIES_LIST)), + m_ok(this, DpGuiResId(RID_DLG_DEPENDENCIES_OK)), + m_listDelta( + GetOutputSizePixel().Width() - m_list.GetSizePixel().Width(), + GetOutputSizePixel().Height() - m_list.GetSizePixel().Height()) +{ + FreeResource(); + SetMinOutputSizePixel(GetOutputSizePixel()); + m_list.SetReadOnly(); + for (std::vector< rtl::OUString >::const_iterator i(dependencies.begin()); + i != dependencies.end(); ++i) + { + m_list.InsertEntry(*i); + } +} + +DependencyDialog::~DependencyDialog() {} + +void DependencyDialog::Resize() { + long n = m_ok.GetPosPixel().Y() - + (m_list.GetPosPixel().Y() + m_list.GetSizePixel().Height()); + m_list.SetSizePixel( + Size( + GetOutputSizePixel().Width() - m_listDelta.Width(), + GetOutputSizePixel().Height() - m_listDelta.Height())); + m_ok.SetPosPixel( + Point( + (m_list.GetPosPixel().X() + + (m_list.GetSizePixel().Width() - m_ok.GetSizePixel().Width()) / 2), + m_list.GetPosPixel().Y() + m_list.GetSizePixel().Height() + n)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/dp_gui_dependencydialog.hxx b/desktop/source/deployment/gui/dp_gui_dependencydialog.hxx new file mode 100644 index 000000000000..48ef45fd15c0 --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_dependencydialog.hxx @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_GUI_DP_GUI_DEPENDENCYDIALOG_HXX +#define INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_GUI_DP_GUI_DEPENDENCYDIALOG_HXX + +#include "sal/config.h" + +#include <vector> +#include "tools/gen.hxx" +#include "vcl/button.hxx" +#include "vcl/dialog.hxx" +#include "vcl/fixed.hxx" +#include "vcl/lstbox.hxx" + +class Window; +namespace rtl { class OUString; } + +namespace dp_gui { + +class DependencyDialog: public ModalDialog { +public: + DependencyDialog( + Window * parent, std::vector< rtl::OUString > const & dependencies); + + ~DependencyDialog(); + +private: + DependencyDialog(DependencyDialog &); // not defined + void operator =(DependencyDialog &); // not defined + + virtual void Resize(); + + FixedText m_text; + ListBox m_list; + OKButton m_ok; + Size m_listDelta; +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/dp_gui_dependencydialog.src b/desktop/source/deployment/gui/dp_gui_dependencydialog.src new file mode 100644 index 000000000000..fa7465678326 --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_dependencydialog.src @@ -0,0 +1,70 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "svtools/controldims.hrc" + +#include "dp_gui.hrc" + +#define LOCAL_WIDTH (50 * RSC_BS_CHARWIDTH) +#define LOCAL_TEXT_HEIGHT (2 * RSC_CD_FIXEDTEXT_HEIGHT) +#define LOCAL_LIST_HEIGHT (6 * RSC_BS_CHARHEIGHT) + +ModalDialog RID_DLG_DEPENDENCIES { + Size = MAP_APPFONT( + (RSC_SP_DLG_INNERBORDER_LEFT + LOCAL_WIDTH + + RSC_SP_DLG_INNERBORDER_RIGHT), + (RSC_SP_DLG_INNERBORDER_TOP + LOCAL_TEXT_HEIGHT + RSC_SP_CTRL_DESC_Y + + LOCAL_LIST_HEIGHT + RSC_SP_CTRL_Y + RSC_CD_PUSHBUTTON_HEIGHT + + RSC_SP_DLG_INNERBORDER_BOTTOM)); + Text[en-US] = "System dependencies check"; + Sizeable = TRUE; + Moveable = TRUE; + Closeable = TRUE; + FixedText RID_DLG_DEPENDENCIES_TEXT { + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT, RSC_SP_DLG_INNERBORDER_TOP); + Size = MAP_APPFONT(LOCAL_WIDTH, LOCAL_TEXT_HEIGHT); + Text[en-US] = "The extension cannot be installed as the following\nsystem dependencies are not fulfilled:"; + NoLabel = TRUE; + }; + ListBox RID_DLG_DEPENDENCIES_LIST { + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT, + (RSC_SP_DLG_INNERBORDER_TOP + LOCAL_TEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y)); + Size = MAP_APPFONT(LOCAL_WIDTH, LOCAL_LIST_HEIGHT); + }; + OKButton RID_DLG_DEPENDENCIES_OK { + Pos = MAP_APPFONT( + (RSC_SP_DLG_INNERBORDER_LEFT + + (LOCAL_WIDTH - RSC_CD_PUSHBUTTON_WIDTH) / 2), + (RSC_SP_DLG_INNERBORDER_TOP + LOCAL_TEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + LOCAL_LIST_HEIGHT + RSC_SP_CTRL_Y)); + Size = MAP_APPFONT(RSC_CD_PUSHBUTTON_WIDTH, RSC_CD_PUSHBUTTON_HEIGHT); + DefButton = TRUE; + }; +}; diff --git a/desktop/source/deployment/gui/dp_gui_dialog.src b/desktop/source/deployment/gui/dp_gui_dialog.src new file mode 100755 index 000000000000..2ea6fefff877 --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_dialog.src @@ -0,0 +1,350 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#include "svtools/controldims.hrc" +#include "dp_gui.hrc" + +String RID_STR_ADD_PACKAGES +{ + Text [ en-US ] = "Add Extension(s)"; +}; + +String RID_CTX_ITEM_REMOVE +{ + Text [ en-US ] = "~Remove"; +}; + +String RID_CTX_ITEM_ENABLE +{ + Text [ en-US ] = "~Enable"; +}; + +String RID_CTX_ITEM_DISABLE +{ + Text [ en-US ] = "~Disable"; +}; + +String RID_CTX_ITEM_CHECK_UPDATE +{ + Text [ en-US ] = "~Update..."; +}; + +String RID_CTX_ITEM_OPTIONS +{ + Text [ en-US ] = "~Options..."; +}; + + +String RID_STR_ADDING_PACKAGES +{ + Text [ en-US ] = "Adding %EXTENSION_NAME"; +}; + +String RID_STR_REMOVING_PACKAGES +{ + Text [ en-US ] = "Removing %EXTENSION_NAME"; +}; + +String RID_STR_ENABLING_PACKAGES +{ + Text [ en-US ] = "Enabling %EXTENSION_NAME"; +}; + +String RID_STR_DISABLING_PACKAGES +{ + Text [ en-US ] = "Disabling %EXTENSION_NAME"; +}; + +String RID_STR_ACCEPT_LICENSE +{ + Text [ en-US ] = "Accept license for %EXTENSION_NAME"; +}; + +String RID_STR_INSTALL_FOR_ALL +{ + Text [ en-US ] = "~For all users"; +}; + +String RID_STR_INSTALL_FOR_ME +{ + Text [ en-US ] = "~Only for me"; +}; + +String RID_STR_ERROR_UNKNOWN_STATUS +{ + Text [ en-US ] = "Error: The status of this extension is unknown"; +}; + +String RID_STR_CLOSE_BTN +{ + Text [ en-US ] = "Close"; +}; + +String RID_STR_EXIT_BTN +{ + Text [ en-US ] = "Quit"; +}; + +String RID_STR_NO_ADMIN_PRIVILEGE +{ + Text [ en-US ] = "%PRODUCTNAME has been updated to a new version. " + "Some shared %PRODUCTNAME extensions are not compatible with this version and need to be updated before %PRODUCTNAME can be started.\n\n" + "Updating of shared extension requires administrator privileges. Contact your system administrator to update the following shared extensions:"; +}; + +String RID_STR_ERROR_MISSING_DEPENDENCIES +{ + Text [ en-US ] = "The extension cannot be enabled as the following system dependencies are not fulfilled:"; +}; + +String RID_STR_ERROR_MISSING_LICENSE +{ + Text [ en-US ] = "This extension is disabled because you haven't accepted the license yet.\n"; +}; + +// Dialog layout +// --------------------------------------------------- +// row 1 | multi line edit +// --------------------------------------------------- +// row 2 | fixed text +// --------------------------------------------------- +// row 3 | img | fixed text | fixed text | button +// ---------------------------------------------------- +// row 4 | img | fixed text | fixed text +// --------------------------------------------------- +// row 5 |fixed line +// --------------------------------------------------- +// row 6 | | |button | button +// --------------------------------------------------- +// | col 1 | col 2 | col3 | col4 | col5 + +//To change the overall size of the multi line edit change +//ROW1_HEIGHT and COL3_WIDTH + +#define ROW1_Y RSC_SP_DLG_INNERBORDER_TOP +#define ROW1_HEIGHT 16*RSC_CD_FIXEDTEXT_HEIGHT +#define ROW2_Y ROW1_Y+ROW1_HEIGHT+RSC_SP_CTRL_GROUP_Y +#define ROW2_HEIGHT 3*RSC_CD_FIXEDTEXT_HEIGHT +#define ROW3_Y ROW2_Y+ROW2_HEIGHT+RSC_SP_CTRL_GROUP_Y +#define ROW3_HEIGHT 3*RSC_CD_FIXEDTEXT_HEIGHT +#define ROW4_Y ROW3_Y+ROW3_HEIGHT+RSC_SP_CTRL_GROUP_Y +#define ROW4_HEIGHT 3*RSC_CD_FIXEDTEXT_HEIGHT +#define ROW5_Y ROW4_Y+ROW4_HEIGHT+RSC_SP_CTRL_GROUP_Y +#define ROW5_HEIGHT RSC_CD_FIXEDTEXT_HEIGHT +#define ROW6_Y ROW5_Y+ROW5_HEIGHT+RSC_SP_CTRL_GROUP_Y +#define ROW6_HEIGHT RSC_CD_PUSHBUTTON_HEIGHT + +#define LIC_DLG_HEIGHT ROW6_Y+ROW6_HEIGHT+RSC_SP_DLG_INNERBORDER_BOTTOM + +#define COL1_X RSC_SP_DLG_INNERBORDER_LEFT +#define IMG_ARROW_WIDTH 16 +#define COL1_WIDTH IMG_ARROW_WIDTH +#define COL2_X COL1_X+COL1_WIDTH +#define COL2_WIDTH 10 +#define COL3_X COL2_X+COL2_WIDTH+RSC_SP_CTRL_GROUP_X +#define COL3_WIDTH 150 +#define COL4_X COL3_X+COL3_WIDTH +#define COL4_WIDTH RSC_CD_PUSHBUTTON_WIDTH+RSC_SP_CTRL_GROUP_X +#define COL5_X COL4_X+COL4_WIDTH + +#define LIC_DLG_WIDTH COL5_X+RSC_CD_PUSHBUTTON_WIDTH+RSC_SP_DLG_INNERBORDER_RIGHT +#define BODYWIDTH LIC_DLG_WIDTH-RSC_SP_DLG_INNERBORDER_LEFT-RSC_SP_DLG_INNERBORDER_RIGHT + +ModalDialog RID_DLG_LICENSE +{ + Text [ en-US ] = "Extension Software License Agreement"; + + Size = MAP_APPFONT(LIC_DLG_WIDTH, LIC_DLG_HEIGHT); + OutputSize = TRUE; + SVLook = TRUE; + Moveable = TRUE; + Closeable = TRUE; + Sizeable = FALSE; + + MultiLineEdit ML_LICENSE + { + Pos = MAP_APPFONT(COL1_X, ROW1_Y); + Size = MAP_APPFONT(BODYWIDTH, ROW1_HEIGHT); + Border = TRUE; + VScroll = TRUE; + ReadOnly = TRUE; + }; + + FixedText FT_LICENSE_HEADER + { + Pos = MAP_APPFONT(COL1_X, ROW2_Y); + Size = MAP_APPFONT(COL1_WIDTH+COL2_WIDTH+COL3_WIDTH+COL4_WIDTH, ROW2_HEIGHT); + WordBreak = TRUE; + NoLabel = TRUE; + Text [ en-US ] = "Please follow these steps to proceed with the installation of the extension:"; + }; + + FixedText FT_LICENSE_BODY_1 + { + Pos = MAP_APPFONT(COL2_X, ROW3_Y); + Size = MAP_APPFONT( COL2_WIDTH, ROW3_HEIGHT ); + NoLabel = TRUE; + Text [ en-US ] = "1."; + }; + + //spans col3 + col4 + FixedText FT_LICENSE_BODY_1_TXT + { + Pos = MAP_APPFONT(COL3_X, ROW3_Y); + Size = MAP_APPFONT(COL3_WIDTH+COL4_WIDTH, ROW3_HEIGHT); + WordBreak = TRUE; + NoLabel = TRUE; + Text [ en-US ] = "Read the complete License Agreement. Use the scroll bar or the \'Scroll Down\' button in this dialog to view the entire license text."; + }; + + FixedText FT_LICENSE_BODY_2 + { + Pos = MAP_APPFONT(COL2_X, ROW4_Y); + Size = MAP_APPFONT(COL2_WIDTH, ROW4_HEIGHT); + NoLabel = TRUE; + Text [ en-US ] = "2."; + }; + + FixedText FT_LICENSE_BODY_2_TXT + { + Pos = MAP_APPFONT(COL3_X, ROW4_Y); + Size = MAP_APPFONT(COL3_WIDTH+COL4_WIDTH, ROW4_HEIGHT); + WordBreak = TRUE; + NoLabel = TRUE; + Text [ en-US ] = "Accept the License Agreement for the extension by pressing the \'Accept\' button."; + + }; + + PushButton PB_LICENSE_DOWN + { + TabStop = TRUE ; + Pos = MAP_APPFONT(COL5_X , ROW3_Y) ; + Size = MAP_APPFONT(RSC_CD_PUSHBUTTON_WIDTH, RSC_CD_PUSHBUTTON_HEIGHT) ; + Text [ en-US ] = "~Scroll Down"; + + }; + + FixedLine FL_LICENSE + { + Pos = MAP_APPFONT ( 0, ROW5_Y) ; + Size = MAP_APPFONT ( LIC_DLG_WIDTH, ROW5_HEIGHT ) ; + }; + + FixedImage FI_LICENSE_ARROW1 + { + Pos = MAP_APPFONT (COL1_X, ROW3_Y) ; + Size = (16, 16); + Fixed = Image + { + ImageBitmap = Bitmap { File = "sc06300.png"; }; + MASKCOLOR + }; + }; + + FixedImage FI_LICENSE_ARROW2 + { + Pos = MAP_APPFONT (COL1_X, ROW4_Y) ; + Size = (16,16); + Fixed = Image + { + ImageBitmap = Bitmap { File = "sc06300.png"; }; + MASKCOLOR + }; + }; + + OKButton BTN_LICENSE_ACCEPT + { + Pos = MAP_APPFONT(COL4_X, ROW6_Y); + Size = MAP_APPFONT(RSC_CD_PUSHBUTTON_WIDTH, RSC_CD_PUSHBUTTON_HEIGHT ); + + TabStop = TRUE; + DefButton = TRUE; + Text [ en-US ] = "Accept"; + }; + + CancelButton BTN_LICENSE_DECLINE + { + Pos = MAP_APPFONT(COL5_X, ROW6_Y); + Size = MAP_APPFONT( RSC_CD_PUSHBUTTON_WIDTH, RSC_CD_PUSHBUTTON_HEIGHT ); + Text [ en-US ] = "Decline" ; + TabStop = TRUE; + }; + +}; + + + +WarningBox RID_WARNINGBOX_INSTALL_EXTENSION { + Buttons = WB_OK_CANCEL; + DefButton = WB_DEF_OK; + Message[en-US] = "You are about to install the extension \'%NAME\'.\n" + "Click \'OK\' to proceed with the installation.\n" + "Click \'Cancel\' to stop the installation."; +}; + +WarningBox RID_WARNINGBOX_REMOVE_EXTENSION { + Buttons = WB_OK_CANCEL; + DefButton = WB_DEF_CANCEL; + Message[en-US] = "You are about to remove the extension \'%NAME\'.\n" + "Click \'OK\' to remove the extension.\n" + "Click \'Cancel\' to stop removing the extension."; +}; + +WARNINGBOX RID_WARNINGBOX_REMOVE_SHARED_EXTENSION +{ + Buttons = WB_OK_CANCEL; + DefButton = WB_DEF_CANCEL; + Message[en-US] = "Make sure that no further users are working with the same " + "%PRODUCTNAME, when changing shared extensions in a multi user environment.\n" + "Click \'OK\' to remove the extension.\n" + "Click \'Cancel\' to stop removing the extension."; +}; + +WARNINGBOX RID_WARNINGBOX_ENABLE_SHARED_EXTENSION +{ + Buttons = WB_OK_CANCEL; + DefButton = WB_DEF_CANCEL; + Message[en-US] = "Make sure that no further users are working with the same " + "%PRODUCTNAME, when changing shared extensions in a multi user environment.\n" + "Click \'OK\' to enable the extension.\n" + "Click \'Cancel\' to stop enabling the extension."; +}; + +WARNINGBOX RID_WARNINGBOX_DISABLE_SHARED_EXTENSION +{ + Buttons = WB_OK_CANCEL; + DefButton = WB_DEF_CANCEL; + Message[en-US] = "Make sure that no further users are working with the same " + "%PRODUCTNAME, when changing shared extensions in a multi user environment.\n" + "Click \'OK\' to disable the extension.\n" + "Click \'Cancel\' to stop disabling the extension."; +}; + + +String RID_STR_UNSUPPORTED_PLATFORM +{ + Text [ en-US ] = "The extension \'%Name\' does not work on this computer."; +}; diff --git a/desktop/source/deployment/gui/dp_gui_dialog2.cxx b/desktop/source/deployment/gui/dp_gui_dialog2.cxx new file mode 100644 index 000000000000..3790f273c305 --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_dialog2.cxx @@ -0,0 +1,1785 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_gui.hrc" +#include "svtools/controldims.hrc" +#include "svtools/svtools.hrc" + +#include "dp_gui.h" +#include "dp_gui_dialog2.hxx" +#include "dp_gui_extlistbox.hxx" +#include "dp_gui_shared.hxx" +#include "dp_gui_theextmgr.hxx" +#include "dp_gui_extensioncmdqueue.hxx" +#include "dp_misc.h" +#include "dp_update.hxx" +#include "dp_identifier.hxx" + +#include "vcl/ctrl.hxx" +#include "vcl/menu.hxx" +#include "vcl/msgbox.hxx" +#include "vcl/scrbar.hxx" +#include "vcl/svapp.hxx" + +#include "osl/mutex.hxx" + +#include "svtools/extensionlistbox.hxx" + +#include "sfx2/sfxdlg.hxx" + +#include "comphelper/anytostring.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "cppuhelper/bootstrap.hxx" + +#include "comphelper/processfactory.hxx" +#include "ucbhelper/content.hxx" +#include "unotools/collatorwrapper.hxx" + +#include "com/sun/star/beans/StringPair.hpp" + +#include "com/sun/star/i18n/CollatorOptions.hpp" + +#include "com/sun/star/system/SystemShellExecuteFlags.hpp" +#include "com/sun/star/system/XSystemShellExecute.hpp" + +#include "com/sun/star/ui/dialogs/ExecutableDialogResults.hpp" +#include "com/sun/star/ui/dialogs/TemplateDescription.hpp" +#include "com/sun/star/ui/dialogs/XFilePicker.hpp" +#include "com/sun/star/ui/dialogs/XFilterManager.hpp" + +#include "com/sun/star/uno/Any.hxx" +#include "com/sun/star/uno/XComponentContext.hpp" + +#include <map> +#include <vector> +#include <boost/shared_ptr.hpp> + +#define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) + +using namespace ::com::sun::star; +using namespace ::com::sun::star::system; + +using ::rtl::OUString; + + +namespace dp_gui { + +#define TOP_OFFSET 5 +#define LINE_SIZE 4 +#define PROGRESS_WIDTH 60 +#define PROGRESS_HEIGHT 14 + +//------------------------------------------------------------------------------ +struct StrAllFiles : public rtl::StaticWithInit< const OUString, StrAllFiles > +{ + const OUString operator () () { + const SolarMutexGuard guard; + ::std::auto_ptr< ResMgr > const resmgr( ResMgr::CreateResMgr( "fps_office" ) ); + OSL_ASSERT( resmgr.get() != 0 ); + String ret( ResId( STR_FILTERNAME_ALL, *resmgr.get() ) ); + return ret; + } +}; + +//------------------------------------------------------------------------------ +// ExtBoxWithBtns_Impl +//------------------------------------------------------------------------------ + +enum MENU_COMMAND +{ + CMD_NONE = 0, + CMD_REMOVE = 1, + CMD_ENABLE, + CMD_DISABLE, + CMD_UPDATE +}; + +class ExtBoxWithBtns_Impl : public ExtensionBox_Impl +{ + Size m_aOutputSize; + bool m_bInterfaceLocked; + + PushButton *m_pOptionsBtn; + PushButton *m_pEnableBtn; + PushButton *m_pRemoveBtn; + + ExtMgrDialog *m_pParent; + + void SetButtonPos( const Rectangle& rRect ); + void SetButtonStatus( const TEntry_Impl pEntry ); + bool HandleTabKey( bool bReverse ); + MENU_COMMAND ShowPopupMenu( const Point &rPos, const long nPos ); + + //----------------- + DECL_DLLPRIVATE_LINK( ScrollHdl, ScrollBar * ); + + DECL_DLLPRIVATE_LINK( HandleOptionsBtn, void * ); + DECL_DLLPRIVATE_LINK( HandleEnableBtn, void * ); + DECL_DLLPRIVATE_LINK( HandleRemoveBtn, void * ); + DECL_DLLPRIVATE_LINK( HandleHyperlink, svt::FixedHyperlink * ); + +public: + ExtBoxWithBtns_Impl( ExtMgrDialog* pParent, TheExtensionManager *pManager ); + ~ExtBoxWithBtns_Impl(); + + virtual void MouseButtonDown( const MouseEvent& rMEvt ); + virtual long Notify( NotifyEvent& rNEvt ); + + const Size GetMinOutputSizePixel() const; + + virtual void RecalcAll(); + virtual void selectEntry( const long nPos ); + //----------------- + void enableButtons( bool bEnable ); +}; + +//------------------------------------------------------------------------------ +ExtBoxWithBtns_Impl::ExtBoxWithBtns_Impl( ExtMgrDialog* pParent, TheExtensionManager *pManager ) : + ExtensionBox_Impl( pParent, pManager ), + m_bInterfaceLocked( false ), + m_pOptionsBtn( NULL ), + m_pEnableBtn( NULL ), + m_pRemoveBtn( NULL ), + m_pParent( pParent ) +{ + m_pOptionsBtn = new PushButton( this, WB_TABSTOP ); + m_pEnableBtn = new PushButton( this, WB_TABSTOP ); + m_pRemoveBtn = new PushButton( this, WB_TABSTOP ); + + SetHelpId( HID_EXTENSION_MANAGER_LISTBOX ); + m_pOptionsBtn->SetHelpId( HID_EXTENSION_MANAGER_LISTBOX_OPTIONS ); + m_pEnableBtn->SetHelpId( HID_EXTENSION_MANAGER_LISTBOX_DISABLE ); + m_pRemoveBtn->SetHelpId( HID_EXTENSION_MANAGER_LISTBOX_REMOVE ); + + m_pOptionsBtn->SetClickHdl( LINK( this, ExtBoxWithBtns_Impl, HandleOptionsBtn ) ); + m_pEnableBtn->SetClickHdl( LINK( this, ExtBoxWithBtns_Impl, HandleEnableBtn ) ); + m_pRemoveBtn->SetClickHdl( LINK( this, ExtBoxWithBtns_Impl, HandleRemoveBtn ) ); + + m_pOptionsBtn->SetText( DialogHelper::getResourceString( RID_CTX_ITEM_OPTIONS ) ); + m_pEnableBtn->SetText( DialogHelper::getResourceString( RID_CTX_ITEM_DISABLE ) ); + m_pRemoveBtn->SetText( DialogHelper::getResourceString( RID_CTX_ITEM_REMOVE ) ); + + Size aSize = LogicToPixel( Size( RSC_CD_PUSHBUTTON_WIDTH, RSC_CD_PUSHBUTTON_HEIGHT ), + MapMode( MAP_APPFONT ) ); + m_pOptionsBtn->SetSizePixel( aSize ); + m_pEnableBtn->SetSizePixel( aSize ); + m_pRemoveBtn->SetSizePixel( aSize ); + + SetExtraSize( aSize.Height() + 2 * TOP_OFFSET ); + + SetScrollHdl( LINK( this, ExtBoxWithBtns_Impl, ScrollHdl ) ); +} + +//------------------------------------------------------------------------------ +ExtBoxWithBtns_Impl::~ExtBoxWithBtns_Impl() +{ + delete m_pOptionsBtn; + delete m_pEnableBtn; + delete m_pRemoveBtn; +} + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +const Size ExtBoxWithBtns_Impl::GetMinOutputSizePixel() const +{ + Size aMinSize( ExtensionBox_Impl::GetMinOutputSizePixel() ); + long nHeight = aMinSize.Height(); + nHeight += m_pOptionsBtn->GetSizePixel().Height(); + nHeight += 2 * TOP_OFFSET; + long nWidth = m_pOptionsBtn->GetSizePixel().Width(); + nWidth *= 3; + nWidth += 5*TOP_OFFSET + 20; + + return Size( nWidth, nHeight ); +} + +// ----------------------------------------------------------------------- +void ExtBoxWithBtns_Impl::RecalcAll() +{ + ExtensionBox_Impl::RecalcAll(); + + const sal_Int32 nActive = getSelIndex(); + + if ( nActive != EXTENSION_LISTBOX_ENTRY_NOTFOUND ) + { + SetButtonPos( GetEntryRect( nActive ) ); + SetButtonStatus( GetEntryData( nActive) ); + } + else + { + m_pOptionsBtn->Hide(); + m_pEnableBtn->Hide(); + m_pRemoveBtn->Hide(); + } +} + + +//------------------------------------------------------------------------------ +//This function may be called with nPos < 0 +void ExtBoxWithBtns_Impl::selectEntry( const long nPos ) +{ + if ( HasActive() && ( nPos == getSelIndex() ) ) + return; + + ExtensionBox_Impl::selectEntry( nPos ); +} + +// ----------------------------------------------------------------------- +void ExtBoxWithBtns_Impl::SetButtonPos( const Rectangle& rRect ) +{ + Size aBtnSize( m_pOptionsBtn->GetSizePixel() ); + Point aBtnPos( rRect.Left() + ICON_OFFSET, + rRect.Bottom() - TOP_OFFSET - aBtnSize.Height() ); + + m_pOptionsBtn->SetPosPixel( aBtnPos ); + aBtnPos.X() = rRect.Right() - TOP_OFFSET - aBtnSize.Width(); + m_pRemoveBtn->SetPosPixel( aBtnPos ); + aBtnPos.X() -= ( TOP_OFFSET + aBtnSize.Width() ); + m_pEnableBtn->SetPosPixel( aBtnPos ); +} + +// ----------------------------------------------------------------------- +void ExtBoxWithBtns_Impl::SetButtonStatus( const TEntry_Impl pEntry ) +{ + bool bShowOptionBtn = true; + + pEntry->m_bHasButtons = false; + if ( ( pEntry->m_eState == REGISTERED ) || ( pEntry->m_eState == NOT_AVAILABLE ) ) + { + m_pEnableBtn->SetText( DialogHelper::getResourceString( RID_CTX_ITEM_DISABLE ) ); + m_pEnableBtn->SetHelpId( HID_EXTENSION_MANAGER_LISTBOX_DISABLE ); + } + else + { + m_pEnableBtn->SetText( DialogHelper::getResourceString( RID_CTX_ITEM_ENABLE ) ); + m_pEnableBtn->SetHelpId( HID_EXTENSION_MANAGER_LISTBOX_ENABLE ); + bShowOptionBtn = false; + } + + if ( ( !pEntry->m_bUser || ( pEntry->m_eState == NOT_AVAILABLE ) || pEntry->m_bMissingDeps ) + && !pEntry->m_bMissingLic ) + m_pEnableBtn->Hide(); + else + { + m_pEnableBtn->Enable( !pEntry->m_bLocked ); + m_pEnableBtn->Show(); + pEntry->m_bHasButtons = true; + } + + if ( pEntry->m_bHasOptions && bShowOptionBtn ) + { + m_pOptionsBtn->Enable( pEntry->m_bHasOptions ); + m_pOptionsBtn->Show(); + pEntry->m_bHasButtons = true; + } + else + m_pOptionsBtn->Hide(); + + if ( pEntry->m_bUser || pEntry->m_bShared ) + { + m_pRemoveBtn->Enable( !pEntry->m_bLocked ); + m_pRemoveBtn->Show(); + pEntry->m_bHasButtons = true; + } + else + m_pRemoveBtn->Hide(); +} + +// ----------------------------------------------------------------------- +bool ExtBoxWithBtns_Impl::HandleTabKey( bool bReverse ) +{ + sal_Int32 nIndex = getSelIndex(); + + if ( nIndex == EXTENSION_LISTBOX_ENTRY_NOTFOUND ) + return false; + + PushButton *pNext = NULL; + + if ( m_pOptionsBtn->HasFocus() ) { + if ( !bReverse && !GetEntryData( nIndex )->m_bLocked ) + pNext = m_pEnableBtn; + } + else if ( m_pEnableBtn->HasFocus() ) { + if ( !bReverse ) + pNext = m_pRemoveBtn; + else if ( GetEntryData( nIndex )->m_bHasOptions ) + pNext = m_pOptionsBtn; + } + else if ( m_pRemoveBtn->HasFocus() ) { + if ( bReverse ) + pNext = m_pEnableBtn; + } + else { + if ( !bReverse ) { + if ( GetEntryData( nIndex )->m_bHasOptions ) + pNext = m_pOptionsBtn; + else if ( ! GetEntryData( nIndex )->m_bLocked ) + pNext = m_pEnableBtn; + } else { + if ( ! GetEntryData( nIndex )->m_bLocked ) + pNext = m_pRemoveBtn; + else if ( GetEntryData( nIndex )->m_bHasOptions ) + pNext = m_pOptionsBtn; + } + } + + if ( pNext ) + { + pNext->GrabFocus(); + return true; + } + else + return false; +} + +// ----------------------------------------------------------------------- +MENU_COMMAND ExtBoxWithBtns_Impl::ShowPopupMenu( const Point & rPos, const long nPos ) +{ + if ( ( nPos >= 0 ) && ( nPos < (long) getItemCount() ) ) + { + if ( ! GetEntryData( nPos )->m_bLocked ) + { + PopupMenu aPopup; + + aPopup.InsertItem( CMD_UPDATE, DialogHelper::getResourceString( RID_CTX_ITEM_CHECK_UPDATE ) ); + + if ( GetEntryData( nPos )->m_bUser ) + { + if ( GetEntryData( nPos )->m_eState == REGISTERED ) + aPopup.InsertItem( CMD_DISABLE, DialogHelper::getResourceString( RID_CTX_ITEM_DISABLE ) ); + else if ( GetEntryData( nPos )->m_eState != NOT_AVAILABLE ) + aPopup.InsertItem( CMD_ENABLE, DialogHelper::getResourceString( RID_CTX_ITEM_ENABLE ) ); + } + + aPopup.InsertItem( CMD_REMOVE, DialogHelper::getResourceString( RID_CTX_ITEM_REMOVE ) ); + + return (MENU_COMMAND) aPopup.Execute( this, rPos ); + } + } + return CMD_NONE; +} + +//------------------------------------------------------------------------------ +void ExtBoxWithBtns_Impl::MouseButtonDown( const MouseEvent& rMEvt ) +{ + if ( m_bInterfaceLocked ) + return; + + const Point aMousePos( rMEvt.GetPosPixel() ); + const long nPos = PointToPos( aMousePos ); + + if ( rMEvt.IsRight() ) + { + switch( ShowPopupMenu( aMousePos, nPos ) ) + { + case CMD_NONE: break; + case CMD_ENABLE: m_pParent->enablePackage( GetEntryData( nPos )->m_xPackage, true ); + break; + case CMD_DISABLE: m_pParent->enablePackage( GetEntryData( nPos )->m_xPackage, false ); + break; + case CMD_UPDATE: m_pParent->updatePackage( GetEntryData( nPos )->m_xPackage ); + break; + case CMD_REMOVE: m_pParent->removePackage( GetEntryData( nPos )->m_xPackage ); + break; + } + } + else if ( rMEvt.IsLeft() ) + { + const SolarMutexGuard aGuard; + if ( rMEvt.IsMod1() && HasActive() ) + selectEntry( EXTENSION_LISTBOX_ENTRY_NOTFOUND ); // Selecting an not existing entry will deselect the current one + else + selectEntry( nPos ); + } +} + +//------------------------------------------------------------------------------ +long ExtBoxWithBtns_Impl::Notify( NotifyEvent& rNEvt ) +{ + bool bHandled = false; + + if ( rNEvt.GetType() == EVENT_KEYINPUT ) + { + const KeyEvent* pKEvt = rNEvt.GetKeyEvent(); + KeyCode aKeyCode = pKEvt->GetKeyCode(); + USHORT nKeyCode = aKeyCode.GetCode(); + + if ( nKeyCode == KEY_TAB ) + bHandled = HandleTabKey( aKeyCode.IsShift() ); + } + + if ( !bHandled ) + return ExtensionBox_Impl::Notify( rNEvt ); + else + return true; +} + +//------------------------------------------------------------------------------ +void ExtBoxWithBtns_Impl::enableButtons( bool bEnable ) +{ + m_bInterfaceLocked = ! bEnable; + + if ( bEnable ) + { + sal_Int32 nIndex = getSelIndex(); + if ( nIndex != EXTENSION_LISTBOX_ENTRY_NOTFOUND ) + SetButtonStatus( GetEntryData( nIndex ) ); + } + else + { + m_pOptionsBtn->Enable( false ); + m_pRemoveBtn->Enable( false ); + m_pEnableBtn->Enable( false ); + } +} + +// ----------------------------------------------------------------------- +IMPL_LINK( ExtBoxWithBtns_Impl, ScrollHdl, ScrollBar*, pScrBar ) +{ + long nDelta = pScrBar->GetDelta(); + + Point aNewOptPt( m_pOptionsBtn->GetPosPixel() - Point( 0, nDelta ) ); + Point aNewRemPt( m_pRemoveBtn->GetPosPixel() - Point( 0, nDelta ) ); + Point aNewEnPt( m_pEnableBtn->GetPosPixel() - Point( 0, nDelta ) ); + + DoScroll( nDelta ); + + m_pOptionsBtn->SetPosPixel( aNewOptPt ); + m_pRemoveBtn->SetPosPixel( aNewRemPt ); + m_pEnableBtn->SetPosPixel( aNewEnPt ); + + return 1; +} + +// ----------------------------------------------------------------------- +IMPL_LINK( ExtBoxWithBtns_Impl, HandleOptionsBtn, void*, EMPTYARG ) +{ + const sal_Int32 nActive = getSelIndex(); + + if ( nActive != EXTENSION_LISTBOX_ENTRY_NOTFOUND ) + { + SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create(); + + if ( pFact ) + { + OUString sExtensionId = GetEntryData( nActive )->m_xPackage->getIdentifier().Value; + VclAbstractDialog* pDlg = pFact->CreateOptionsDialog( this, sExtensionId, rtl::OUString() ); + + pDlg->Execute(); + + delete pDlg; + } + } + + return 1; +} + +// ----------------------------------------------------------------------- +IMPL_LINK( ExtBoxWithBtns_Impl, HandleEnableBtn, void*, EMPTYARG ) +{ + const sal_Int32 nActive = getSelIndex(); + + if ( nActive != EXTENSION_LISTBOX_ENTRY_NOTFOUND ) + { + TEntry_Impl pEntry = GetEntryData( nActive ); + + if ( pEntry->m_bMissingLic ) + m_pParent->acceptLicense( pEntry->m_xPackage ); + else + { + const bool bEnable( pEntry->m_eState != REGISTERED ); + m_pParent->enablePackage( pEntry->m_xPackage, bEnable ); + } + } + + return 1; +} + +// ----------------------------------------------------------------------- +IMPL_LINK( ExtBoxWithBtns_Impl, HandleRemoveBtn, void*, EMPTYARG ) +{ + const sal_Int32 nActive = getSelIndex(); + + if ( nActive != EXTENSION_LISTBOX_ENTRY_NOTFOUND ) + { + TEntry_Impl pEntry = GetEntryData( nActive ); + m_pParent->removePackage( pEntry->m_xPackage ); + } + + return 1; +} + +//------------------------------------------------------------------------------ +// DialogHelper +//------------------------------------------------------------------------------ +DialogHelper::DialogHelper( const uno::Reference< uno::XComponentContext > &xContext, + Dialog *pWindow ) : + m_pVCLWindow( pWindow ), + m_nEventID( 0 ), + m_bIsBusy( false ) +{ + m_xContext = xContext; +} + +//------------------------------------------------------------------------------ +DialogHelper::~DialogHelper() +{ + if ( m_nEventID ) + Application::RemoveUserEvent( m_nEventID ); +} + +//------------------------------------------------------------------------------ +ResId DialogHelper::getResId( USHORT nId ) +{ + const SolarMutexGuard guard; + return ResId( nId, *DeploymentGuiResMgr::get() ); +} + +//------------------------------------------------------------------------------ +String DialogHelper::getResourceString( USHORT id ) +{ + // init with non-acquired solar mutex: + BrandName::get(); + const SolarMutexGuard guard; + String ret( ResId( id, *DeploymentGuiResMgr::get() ) ); + if (ret.SearchAscii( "%PRODUCTNAME" ) != STRING_NOTFOUND) { + ret.SearchAndReplaceAllAscii( "%PRODUCTNAME", BrandName::get() ); + } + return ret; +} + +//------------------------------------------------------------------------------ +bool DialogHelper::IsSharedPkgMgr( const uno::Reference< deployment::XPackage > &xPackage ) +{ + if ( xPackage->getRepositoryName().equals( OUSTR("shared") ) ) + return true; + else + return false; +} + +//------------------------------------------------------------------------------ +bool DialogHelper::continueOnSharedExtension( const uno::Reference< deployment::XPackage > &xPackage, + Window *pParent, + const USHORT nResID, + bool &bHadWarning ) +{ + if ( !bHadWarning && IsSharedPkgMgr( xPackage ) ) + { + const SolarMutexGuard guard; + WarningBox aInfoBox( pParent, getResId( nResID ) ); + String aMsgText = aInfoBox.GetMessText(); + aMsgText.SearchAndReplaceAllAscii( "%PRODUCTNAME", BrandName::get() ); + aInfoBox.SetMessText( aMsgText ); + + bHadWarning = true; + + if ( RET_OK == aInfoBox.Execute() ) + return true; + else + return false; + } + else + return true; +} + +//------------------------------------------------------------------------------ +void DialogHelper::openWebBrowser( const OUString & sURL, const OUString &sTitle ) const +{ + if ( ! sURL.getLength() ) // Nothing to do, when the URL is empty + return; + + try + { + uno::Reference< XSystemShellExecute > xSystemShellExecute( + m_xContext->getServiceManager()->createInstanceWithContext( OUSTR( "com.sun.star.system.SystemShellExecute" ), m_xContext), uno::UNO_QUERY_THROW); + //throws css::lang::IllegalArgumentException, css::system::SystemShellExecuteException + xSystemShellExecute->execute( sURL, OUString(), SystemShellExecuteFlags::DEFAULTS ); + } + catch ( uno::Exception& ) + { + uno::Any exc( ::cppu::getCaughtException() ); + OUString msg( ::comphelper::anyToString( exc ) ); + const SolarMutexGuard guard; + ErrorBox aErrorBox( NULL, WB_OK, msg ); + aErrorBox.SetText( sTitle ); + aErrorBox.Execute(); + } +} + +//------------------------------------------------------------------------------ +bool DialogHelper::installExtensionWarn( const OUString &rExtensionName ) const +{ + const SolarMutexGuard guard; + WarningBox aInfo( m_pVCLWindow, getResId( RID_WARNINGBOX_INSTALL_EXTENSION ) ); + + String sText( aInfo.GetMessText() ); + sText.SearchAndReplaceAllAscii( "%NAME", rExtensionName ); + aInfo.SetMessText( sText ); + + return ( RET_OK == aInfo.Execute() ); +} + +//------------------------------------------------------------------------------ +bool DialogHelper::installForAllUsers( bool &bInstallForAll ) const +{ + const SolarMutexGuard guard; + QueryBox aQuery( m_pVCLWindow, getResId( RID_QUERYBOX_INSTALL_FOR_ALL ) ); + + String sMsgText = aQuery.GetMessText(); + sMsgText.SearchAndReplaceAllAscii( "%PRODUCTNAME", BrandName::get() ); + aQuery.SetMessText( sMsgText ); + + USHORT nYesBtnID = aQuery.GetButtonId( 0 ); + USHORT nNoBtnID = aQuery.GetButtonId( 1 ); + + if ( nYesBtnID != BUTTONDIALOG_BUTTON_NOTFOUND ) + aQuery.SetButtonText( nYesBtnID, getResourceString( RID_STR_INSTALL_FOR_ME ) ); + if ( nNoBtnID != BUTTONDIALOG_BUTTON_NOTFOUND ) + aQuery.SetButtonText( nNoBtnID, getResourceString( RID_STR_INSTALL_FOR_ALL ) ); + + short nRet = aQuery.Execute(); + + if ( nRet == RET_CANCEL ) + return false; + + bInstallForAll = ( nRet == RET_NO ); + return true; +} + +//------------------------------------------------------------------------------ +void DialogHelper::PostUserEvent( const Link& rLink, void* pCaller ) +{ + if ( m_nEventID ) + Application::RemoveUserEvent( m_nEventID ); + + m_nEventID = Application::PostUserEvent( rLink, pCaller ); +} + +//------------------------------------------------------------------------------ +// ExtMgrDialog +//------------------------------------------------------------------------------ +ExtMgrDialog::ExtMgrDialog( Window *pParent, TheExtensionManager *pManager ) : + ModelessDialog( pParent, getResId( RID_DLG_EXTENSION_MANAGER ) ), + DialogHelper( pManager->getContext(), (Dialog*) this ), + m_aAddBtn( this, getResId( RID_EM_BTN_ADD ) ), + m_aUpdateBtn( this, getResId( RID_EM_BTN_CHECK_UPDATES ) ), + m_aCloseBtn( this, getResId( RID_EM_BTN_CLOSE ) ), + m_aHelpBtn( this, getResId( RID_EM_BTN_HELP ) ), + m_aDivider( this ), + m_aGetExtensions( this, getResId( RID_EM_FT_GET_EXTENSIONS ) ), + m_aProgressText( this, getResId( RID_EM_FT_PROGRESS ) ), + m_aProgressBar( this, WB_BORDER + WB_3DLOOK ), + m_aCancelBtn( this, getResId( RID_EM_BTN_CANCEL ) ), + m_sAddPackages( getResourceString( RID_STR_ADD_PACKAGES ) ), + m_bHasProgress( false ), + m_bProgressChanged( false ), + m_bStartProgress( false ), + m_bStopProgress( false ), + m_bUpdateWarning( false ), + m_bEnableWarning( false ), + m_bDisableWarning( false ), + m_bDeleteWarning( false ), + m_nProgress( 0 ), + m_pManager( pManager ) +{ + // free local resources (RID < 256): + FreeResource(); + + m_pExtensionBox = new ExtBoxWithBtns_Impl( this, pManager ); + m_pExtensionBox->SetHyperlinkHdl( LINK( this, ExtMgrDialog, HandleHyperlink ) ); + + m_aAddBtn.SetClickHdl( LINK( this, ExtMgrDialog, HandleAddBtn ) ); + m_aUpdateBtn.SetClickHdl( LINK( this, ExtMgrDialog, HandleUpdateBtn ) ); + m_aGetExtensions.SetClickHdl( LINK( this, ExtMgrDialog, HandleHyperlink ) ); + m_aCancelBtn.SetClickHdl( LINK( this, ExtMgrDialog, HandleCancelBtn ) ); + + // resize update button + Size aBtnSize = m_aUpdateBtn.GetSizePixel(); + String sTitle = m_aUpdateBtn.GetText(); + long nWidth = m_aUpdateBtn.GetCtrlTextWidth( sTitle ); + nWidth += 2 * m_aUpdateBtn.GetTextHeight(); + if ( nWidth > aBtnSize.Width() ) + m_aUpdateBtn.SetSizePixel( Size( nWidth, aBtnSize.Height() ) ); + + // minimum size: + SetMinOutputSizePixel( + Size( // width: + (3 * m_aHelpBtn.GetSizePixel().Width()) + + m_aUpdateBtn.GetSizePixel().Width() + + (5 * RSC_SP_DLG_INNERBORDER_LEFT ), + // height: + (1 * m_aHelpBtn.GetSizePixel().Height()) + + (1 * m_aGetExtensions.GetSizePixel().Height()) + + (1 * m_pExtensionBox->GetMinOutputSizePixel().Height()) + + (3 * RSC_SP_DLG_INNERBORDER_LEFT) ) ); + + m_aDivider.Show(); + m_aProgressBar.Hide(); + + m_aUpdateBtn.Enable( false ); + + m_aTimeoutTimer.SetTimeout( 500 ); // mSec + m_aTimeoutTimer.SetTimeoutHdl( LINK( this, ExtMgrDialog, TimeOutHdl ) ); +} + +//------------------------------------------------------------------------------ +ExtMgrDialog::~ExtMgrDialog() +{ + m_aTimeoutTimer.Stop(); + delete m_pExtensionBox; +} + +//------------------------------------------------------------------------------ +void ExtMgrDialog::setGetExtensionsURL( const ::rtl::OUString &rURL ) +{ + m_aGetExtensions.SetURL( rURL ); +} + +//------------------------------------------------------------------------------ +long ExtMgrDialog::addPackageToList( const uno::Reference< deployment::XPackage > &xPackage, + bool bLicenseMissing ) +{ + const SolarMutexGuard aGuard; + m_aUpdateBtn.Enable( true ); + return m_pExtensionBox->addEntry( xPackage, bLicenseMissing ); +} + +//------------------------------------------------------------------------------ +void ExtMgrDialog::prepareChecking() +{ + m_pExtensionBox->prepareChecking(); +} + +//------------------------------------------------------------------------------ +void ExtMgrDialog::checkEntries() +{ + const SolarMutexGuard guard; + m_pExtensionBox->checkEntries(); +} + +//------------------------------------------------------------------------------ +bool ExtMgrDialog::removeExtensionWarn( const OUString &rExtensionName ) const +{ + const SolarMutexGuard guard; + WarningBox aInfo( const_cast< ExtMgrDialog* >(this), getResId( RID_WARNINGBOX_REMOVE_EXTENSION ) ); + + String sText( aInfo.GetMessText() ); + sText.SearchAndReplaceAllAscii( "%NAME", rExtensionName ); + aInfo.SetMessText( sText ); + + return ( RET_OK == aInfo.Execute() ); +} + +//------------------------------------------------------------------------------ +bool ExtMgrDialog::enablePackage( const uno::Reference< deployment::XPackage > &xPackage, + bool bEnable ) +{ + if ( !xPackage.is() ) + return false; + + if ( bEnable ) + { + if ( ! continueOnSharedExtension( xPackage, this, RID_WARNINGBOX_ENABLE_SHARED_EXTENSION, m_bEnableWarning ) ) + return false; + } + else + { + if ( ! continueOnSharedExtension( xPackage, this, RID_WARNINGBOX_DISABLE_SHARED_EXTENSION, m_bDisableWarning ) ) + return false; + } + + m_pManager->getCmdQueue()->enableExtension( xPackage, bEnable ); + + return true; +} + +//------------------------------------------------------------------------------ +bool ExtMgrDialog::removePackage( const uno::Reference< deployment::XPackage > &xPackage ) +{ + if ( !xPackage.is() ) + return false; + + if ( !IsSharedPkgMgr( xPackage ) || m_bDeleteWarning ) + { + if ( ! removeExtensionWarn( xPackage->getDisplayName() ) ) + return false; + } + + if ( ! continueOnSharedExtension( xPackage, this, RID_WARNINGBOX_REMOVE_SHARED_EXTENSION, m_bDeleteWarning ) ) + return false; + + m_pManager->getCmdQueue()->removeExtension( xPackage ); + + return true; +} + +//------------------------------------------------------------------------------ +bool ExtMgrDialog::updatePackage( const uno::Reference< deployment::XPackage > &xPackage ) +{ + if ( !xPackage.is() ) + return false; + + // get the extension with highest version + uno::Sequence<uno::Reference<deployment::XPackage> > seqExtensions = + m_pManager->getExtensionManager()->getExtensionsWithSameIdentifier( + dp_misc::getIdentifier(xPackage), xPackage->getName(), uno::Reference<ucb::XCommandEnvironment>()); + uno::Reference<deployment::XPackage> extension = + dp_misc::getExtensionWithHighestVersion(seqExtensions); + OSL_ASSERT(extension.is()); + std::vector< css::uno::Reference< css::deployment::XPackage > > vEntries; + vEntries.push_back(extension); + + m_pManager->getCmdQueue()->checkForUpdates( vEntries ); + + return true; +} + +//------------------------------------------------------------------------------ +bool ExtMgrDialog::acceptLicense( const uno::Reference< deployment::XPackage > &xPackage ) +{ + if ( !xPackage.is() ) + return false; + + m_pManager->getCmdQueue()->acceptLicense( xPackage ); + + return true; +} + +//------------------------------------------------------------------------------ +uno::Sequence< OUString > ExtMgrDialog::raiseAddPicker() +{ + const uno::Any mode( static_cast< sal_Int16 >( ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE ) ); + const uno::Reference< uno::XComponentContext > xContext( m_pManager->getContext() ); + const uno::Reference< ui::dialogs::XFilePicker > xFilePicker( + xContext->getServiceManager()->createInstanceWithArgumentsAndContext( + OUSTR("com.sun.star.ui.dialogs.FilePicker"), + uno::Sequence< uno::Any >( &mode, 1 ), xContext ), uno::UNO_QUERY_THROW ); + xFilePicker->setTitle( m_sAddPackages ); + + if ( m_sLastFolderURL.Len() ) + xFilePicker->setDisplayDirectory( m_sLastFolderURL ); + + // collect and set filter list: + typedef ::std::map< OUString, OUString > t_string2string; + t_string2string title2filter; + OUString sDefaultFilter( StrAllFiles::get() ); + + const uno::Sequence< uno::Reference< deployment::XPackageTypeInfo > > packageTypes( + m_pManager->getExtensionManager()->getSupportedPackageTypes() ); + + for ( sal_Int32 pos = 0; pos < packageTypes.getLength(); ++pos ) + { + uno::Reference< deployment::XPackageTypeInfo > const & xPackageType = packageTypes[ pos ]; + const OUString filter( xPackageType->getFileFilter() ); + if (filter.getLength() > 0) + { + const OUString title( xPackageType->getShortDescription() ); + const ::std::pair< t_string2string::iterator, bool > insertion( + title2filter.insert( t_string2string::value_type( title, filter ) ) ); + if ( ! insertion.second ) + { // already existing, append extensions: + ::rtl::OUStringBuffer buf; + buf.append( insertion.first->second ); + buf.append( static_cast<sal_Unicode>(';') ); + buf.append( filter ); + insertion.first->second = buf.makeStringAndClear(); + } + if ( xPackageType->getMediaType() == OUSTR( "application/vnd.sun.star.package-bundle" ) ) + sDefaultFilter = title; + } + } + + const uno::Reference< ui::dialogs::XFilterManager > xFilterManager( xFilePicker, uno::UNO_QUERY_THROW ); + // All files at top: + xFilterManager->appendFilter( StrAllFiles::get(), OUSTR("*.*") ); + // then supported ones: + t_string2string::const_iterator iPos( title2filter.begin() ); + const t_string2string::const_iterator iEnd( title2filter.end() ); + for ( ; iPos != iEnd; ++iPos ) { + try { + xFilterManager->appendFilter( iPos->first, iPos->second ); + } + catch (lang::IllegalArgumentException & exc) { + OSL_ENSURE( 0, ::rtl::OUStringToOString( + exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); + (void) exc; + } + } + xFilterManager->setCurrentFilter( sDefaultFilter ); + + if ( xFilePicker->execute() != ui::dialogs::ExecutableDialogResults::OK ) + return uno::Sequence<OUString>(); // cancelled + + m_sLastFolderURL = xFilePicker->getDisplayDirectory(); + uno::Sequence< OUString > files( xFilePicker->getFiles() ); + OSL_ASSERT( files.getLength() > 0 ); + return files; +} + +//------------------------------------------------------------------------------ +IMPL_LINK( ExtMgrDialog, HandleCancelBtn, void*, EMPTYARG ) +{ + // m_dialog->m_cmdEnv->m_aborted = true; + if ( m_xAbortChannel.is() ) + { + try + { + m_xAbortChannel->sendAbort(); + } + catch ( uno::RuntimeException & ) + { + OSL_ENSURE( 0, "### unexpected RuntimeException!" ); + } + } + return 1; +} + +// ------------------------------------------------------------------------------ +IMPL_LINK( ExtMgrDialog, startProgress, void*, _bLockInterface ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + bool bLockInterface = (bool) _bLockInterface; + + if ( m_bStartProgress && !m_bHasProgress ) + m_aTimeoutTimer.Start(); + + if ( m_bStopProgress ) + { + if ( m_aProgressBar.IsVisible() ) + m_aProgressBar.SetValue( 100 ); + m_xAbortChannel.clear(); + + OSL_TRACE( " startProgress handler: stop\n" ); + } + else + { + OSL_TRACE( " startProgress handler: start\n" ); + } + + m_aCancelBtn.Enable( bLockInterface ); + m_aAddBtn.Enable( !bLockInterface ); + m_aUpdateBtn.Enable( !bLockInterface && m_pExtensionBox->getItemCount() ); + m_pExtensionBox->enableButtons( !bLockInterface ); + + clearEventID(); + + return 0; +} + +// ------------------------------------------------------------------------------ +void ExtMgrDialog::showProgress( bool _bStart ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + bool bStart = _bStart; + + if ( bStart ) + { + m_nProgress = 0; + m_bStartProgress = true; + OSL_TRACE( "showProgress start\n" ); + } + else + { + m_nProgress = 100; + m_bStopProgress = true; + OSL_TRACE( "showProgress stop!\n" ); + } + + DialogHelper::PostUserEvent( LINK( this, ExtMgrDialog, startProgress ), (void*) bStart ); +} + +// ----------------------------------------------------------------------- +void ExtMgrDialog::updateProgress( const long nProgress ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + m_nProgress = nProgress; +} + +// ----------------------------------------------------------------------- +void ExtMgrDialog::updateProgress( const OUString &rText, + const uno::Reference< task::XAbortChannel > &xAbortChannel) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + m_xAbortChannel = xAbortChannel; + m_sProgressText = rText; + m_bProgressChanged = true; +} + +//------------------------------------------------------------------------------ +void ExtMgrDialog::updatePackageInfo( const uno::Reference< deployment::XPackage > &xPackage ) +{ + const SolarMutexGuard aGuard; + m_pExtensionBox->updateEntry( xPackage ); +} + +// ----------------------------------------------------------------------- +IMPL_LINK( ExtMgrDialog, HandleAddBtn, void*, EMPTYARG ) +{ + setBusy( true ); + + uno::Sequence< OUString > aFileList = raiseAddPicker(); + + if ( aFileList.getLength() ) + { + m_pManager->installPackage( aFileList[0] ); + } + + setBusy( false ); + return 1; +} + +// ----------------------------------------------------------------------- +IMPL_LINK( ExtMgrDialog, HandleUpdateBtn, void*, EMPTYARG ) +{ + m_pManager->checkUpdates( false, true ); + + return 1; +} + +// ----------------------------------------------------------------------- +IMPL_LINK( ExtMgrDialog, HandleHyperlink, svt::FixedHyperlink*, pHyperlink ) +{ + openWebBrowser( pHyperlink->GetURL(), GetText() ); + + return 1; +} + +// ----------------------------------------------------------------------- +IMPL_LINK( ExtMgrDialog, TimeOutHdl, Timer*, EMPTYARG ) +{ + if ( m_bStopProgress ) + { + m_bHasProgress = false; + m_bStopProgress = false; + m_aProgressText.Hide(); + m_aProgressBar.Hide(); + m_aCancelBtn.Hide(); + } + else + { + if ( m_bProgressChanged ) + { + m_bProgressChanged = false; + m_aProgressText.SetText( m_sProgressText ); + } + + if ( m_bStartProgress ) + { + m_bStartProgress = false; + m_bHasProgress = true; + m_aProgressBar.Show(); + m_aProgressText.Show(); + m_aCancelBtn.Enable(); + m_aCancelBtn.Show(); + } + + if ( m_aProgressBar.IsVisible() ) + m_aProgressBar.SetValue( (USHORT) m_nProgress ); + + m_aTimeoutTimer.Start(); + } + + return 1; +} + +//------------------------------------------------------------------------------ +// VCL::Window / Dialog +void ExtMgrDialog::Resize() +{ + Size aTotalSize( GetOutputSizePixel() ); + Size aBtnSize( m_aHelpBtn.GetSizePixel() ); + Size aUpdBtnSize( m_aUpdateBtn.GetSizePixel() ); + + Point aPos( RSC_SP_DLG_INNERBORDER_LEFT, + aTotalSize.Height() - RSC_SP_DLG_INNERBORDER_BOTTOM - aBtnSize.Height() ); + + m_aHelpBtn.SetPosPixel( aPos ); + + aPos.X() = aTotalSize.Width() - RSC_SP_DLG_INNERBORDER_RIGHT - aBtnSize.Width(); + m_aCloseBtn.SetPosPixel( aPos ); + + aPos.X() -= ( RSC_SP_CTRL_X + aUpdBtnSize.Width() ); + m_aUpdateBtn.SetPosPixel( aPos ); + + aPos.X() -= ( RSC_SP_CTRL_GROUP_Y + aBtnSize.Width() ); + m_aAddBtn.SetPosPixel( aPos ); + + Size aDivSize( aTotalSize.Width(), LINE_SIZE ); + aPos = Point( 0, aPos.Y() - LINE_SIZE - RSC_SP_DLG_INNERBORDER_BOTTOM ); + m_aDivider.SetPosSizePixel( aPos, aDivSize ); + + Size aFTSize( m_aGetExtensions.CalcMinimumSize() ); + aPos = Point( RSC_SP_DLG_INNERBORDER_LEFT, aPos.Y() - RSC_CD_FIXEDTEXT_HEIGHT - 2*RSC_SP_DLG_INNERBORDER_BOTTOM ); + + m_aGetExtensions.SetPosSizePixel( aPos, aFTSize ); + + aPos.X() = aTotalSize.Width() - RSC_SP_DLG_INNERBORDER_RIGHT - aBtnSize.Width(); + m_aCancelBtn.SetPosPixel( Point( aPos.X(), aPos.Y() - ((aBtnSize.Height()-aFTSize.Height())/2) ) ); + + // Calc progress height + long nProgressHeight = aFTSize.Height(); + + if( IsNativeControlSupported( CTRL_PROGRESS, PART_ENTIRE_CONTROL ) ) + { + ImplControlValue aValue; + Rectangle aControlRegion( Point( 0, 0 ), m_aProgressBar.GetSizePixel() ); + Rectangle aNativeControlRegion, aNativeContentRegion; + if( GetNativeControlRegion( CTRL_PROGRESS, PART_ENTIRE_CONTROL, aControlRegion, + CTRL_STATE_ENABLED, aValue, rtl::OUString(), + aNativeControlRegion, aNativeContentRegion ) != FALSE ) + { + nProgressHeight = aNativeControlRegion.GetHeight(); + } + } + + if ( nProgressHeight < PROGRESS_HEIGHT ) + nProgressHeight = PROGRESS_HEIGHT; + + aPos.X() -= ( RSC_SP_CTRL_GROUP_Y + PROGRESS_WIDTH ); + m_aProgressBar.SetPosSizePixel( Point( aPos.X(), aPos.Y() - ((nProgressHeight-aFTSize.Height())/2) ), + Size( PROGRESS_WIDTH, nProgressHeight ) ); + + Rectangle aRect1( m_aGetExtensions.GetPosPixel(), m_aGetExtensions.GetSizePixel() ); + Rectangle aRect2( m_aProgressBar.GetPosPixel(), m_aProgressBar.GetSizePixel() ); + + aFTSize.Width() = ( aRect2.Left() - aRect1.Right() ) - 2*RSC_SP_DLG_INNERBORDER_LEFT; + aPos.X() = aRect1.Right() + RSC_SP_DLG_INNERBORDER_LEFT; + m_aProgressText.SetPosSizePixel( aPos, aFTSize ); + + Size aSize( aTotalSize.Width() - RSC_SP_DLG_INNERBORDER_LEFT - RSC_SP_DLG_INNERBORDER_RIGHT, + aTotalSize.Height() - 2*aBtnSize.Height() - LINE_SIZE - + RSC_SP_DLG_INNERBORDER_TOP - 3*RSC_SP_DLG_INNERBORDER_BOTTOM ); + + m_pExtensionBox->SetSizePixel( aSize ); +} +//------------------------------------------------------------------------------ +// VCL::Window / Dialog + +long ExtMgrDialog::Notify( NotifyEvent& rNEvt ) +{ + bool bHandled = false; + + if ( rNEvt.GetType() == EVENT_KEYINPUT ) + { + const KeyEvent* pKEvt = rNEvt.GetKeyEvent(); + KeyCode aKeyCode = pKEvt->GetKeyCode(); + USHORT nKeyCode = aKeyCode.GetCode(); + + if ( nKeyCode == KEY_TAB ) + { + if ( aKeyCode.IsShift() ) { + if ( m_aAddBtn.HasFocus() ) { + m_pExtensionBox->GrabFocus(); + bHandled = true; + } + } else { + if ( m_aGetExtensions.HasFocus() ) { + m_pExtensionBox->GrabFocus(); + bHandled = true; + } + } + } + if ( aKeyCode.GetGroup() == KEYGROUP_CURSOR ) + bHandled = m_pExtensionBox->Notify( rNEvt ); + } +// VCLEVENT_WINDOW_CLOSE + if ( !bHandled ) + return ModelessDialog::Notify( rNEvt ); + else + return true; +} + +//------------------------------------------------------------------------------ +BOOL ExtMgrDialog::Close() +{ + bool bRet = m_pManager->queryTermination(); + if ( bRet ) + { + bRet = ModelessDialog::Close(); + m_pManager->terminateDialog(); + } + return bRet; +} + +//------------------------------------------------------------------------------ +// UpdateRequiredDialog +//------------------------------------------------------------------------------ +UpdateRequiredDialog::UpdateRequiredDialog( Window *pParent, TheExtensionManager *pManager ) : + ModalDialog( pParent, getResId( RID_DLG_UPDATE_REQUIRED ) ), + DialogHelper( pManager->getContext(), (Dialog*) this ), + m_aUpdateNeeded( this, getResId( RID_EM_FT_MSG ) ), + m_aUpdateBtn( this, getResId( RID_EM_BTN_CHECK_UPDATES ) ), + m_aCloseBtn( this, getResId( RID_EM_BTN_CLOSE ) ), + m_aHelpBtn( this, getResId( RID_EM_BTN_HELP ) ), + m_aCancelBtn( this, getResId( RID_EM_BTN_CANCEL ) ), + m_aDivider( this ), + m_aProgressText( this, getResId( RID_EM_FT_PROGRESS ) ), + m_aProgressBar( this, WB_BORDER + WB_3DLOOK ), + m_sAddPackages( getResourceString( RID_STR_ADD_PACKAGES ) ), + m_sCloseText( getResourceString( RID_STR_CLOSE_BTN ) ), + m_bHasProgress( false ), + m_bProgressChanged( false ), + m_bStartProgress( false ), + m_bStopProgress( false ), + m_bUpdateWarning( false ), + m_bDisableWarning( false ), + m_bHasLockedEntries( false ), + m_nProgress( 0 ), + m_pManager( pManager ) +{ + // free local resources (RID < 256): + FreeResource(); + + m_pExtensionBox = new ExtensionBox_Impl( this, pManager ); + m_pExtensionBox->SetHyperlinkHdl( LINK( this, UpdateRequiredDialog, HandleHyperlink ) ); + + m_aUpdateBtn.SetClickHdl( LINK( this, UpdateRequiredDialog, HandleUpdateBtn ) ); + m_aCloseBtn.SetClickHdl( LINK( this, UpdateRequiredDialog, HandleCloseBtn ) ); + m_aCancelBtn.SetClickHdl( LINK( this, UpdateRequiredDialog, HandleCancelBtn ) ); + + String aText = m_aUpdateNeeded.GetText(); + aText.SearchAndReplaceAllAscii( "%PRODUCTNAME", BrandName::get() ); + m_aUpdateNeeded.SetText( aText ); + + // resize update button + Size aBtnSize = m_aUpdateBtn.GetSizePixel(); + String sTitle = m_aUpdateBtn.GetText(); + long nWidth = m_aUpdateBtn.GetCtrlTextWidth( sTitle ); + nWidth += 2 * m_aUpdateBtn.GetTextHeight(); + if ( nWidth > aBtnSize.Width() ) + m_aUpdateBtn.SetSizePixel( Size( nWidth, aBtnSize.Height() ) ); + + // resize update button + aBtnSize = m_aCloseBtn.GetSizePixel(); + sTitle = m_aCloseBtn.GetText(); + nWidth = m_aCloseBtn.GetCtrlTextWidth( sTitle ); + nWidth += 2 * m_aCloseBtn.GetTextHeight(); + if ( nWidth > aBtnSize.Width() ) + m_aCloseBtn.SetSizePixel( Size( nWidth, aBtnSize.Height() ) ); + + // minimum size: + SetMinOutputSizePixel( + Size( // width: + (5 * m_aHelpBtn.GetSizePixel().Width()) + + (5 * RSC_SP_DLG_INNERBORDER_LEFT ), + // height: + (1 * m_aHelpBtn.GetSizePixel().Height()) + + (1 * m_aUpdateNeeded.GetSizePixel().Height()) + + (1 * m_pExtensionBox->GetMinOutputSizePixel().Height()) + + (3 * RSC_SP_DLG_INNERBORDER_LEFT) ) ); + + m_aDivider.Show(); + m_aProgressBar.Hide(); + m_aUpdateBtn.Enable( false ); + m_aCloseBtn.GrabFocus(); + + m_aTimeoutTimer.SetTimeout( 50 ); // mSec + m_aTimeoutTimer.SetTimeoutHdl( LINK( this, UpdateRequiredDialog, TimeOutHdl ) ); +} + +//------------------------------------------------------------------------------ +UpdateRequiredDialog::~UpdateRequiredDialog() +{ + m_aTimeoutTimer.Stop(); + + delete m_pExtensionBox; +} + +//------------------------------------------------------------------------------ +long UpdateRequiredDialog::addPackageToList( const uno::Reference< deployment::XPackage > &xPackage, + bool bLicenseMissing ) +{ + // We will only add entries to the list with unsatisfied dependencies + if ( !bLicenseMissing && !checkDependencies( xPackage ) ) + { + m_bHasLockedEntries |= m_pManager->isReadOnly( xPackage ); + const SolarMutexGuard aGuard; + m_aUpdateBtn.Enable( true ); + return m_pExtensionBox->addEntry( xPackage ); + } + return 0; +} + +//------------------------------------------------------------------------------ +void UpdateRequiredDialog::prepareChecking() +{ + m_pExtensionBox->prepareChecking(); +} + +//------------------------------------------------------------------------------ +void UpdateRequiredDialog::checkEntries() +{ + const SolarMutexGuard guard; + m_pExtensionBox->checkEntries(); + + if ( ! hasActiveEntries() ) + { + m_aCloseBtn.SetText( m_sCloseText ); + m_aCloseBtn.GrabFocus(); + } +} + +//------------------------------------------------------------------------------ +bool UpdateRequiredDialog::enablePackage( const uno::Reference< deployment::XPackage > &xPackage, + bool bEnable ) +{ + m_pManager->getCmdQueue()->enableExtension( xPackage, bEnable ); + + return true; +} + +//------------------------------------------------------------------------------ +IMPL_LINK( UpdateRequiredDialog, HandleCancelBtn, void*, EMPTYARG ) +{ + // m_dialog->m_cmdEnv->m_aborted = true; + if ( m_xAbortChannel.is() ) + { + try + { + m_xAbortChannel->sendAbort(); + } + catch ( uno::RuntimeException & ) + { + OSL_ENSURE( 0, "### unexpected RuntimeException!" ); + } + } + return 1; +} + +// ------------------------------------------------------------------------------ +IMPL_LINK( UpdateRequiredDialog, startProgress, void*, _bLockInterface ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + bool bLockInterface = (bool) _bLockInterface; + + if ( m_bStartProgress && !m_bHasProgress ) + m_aTimeoutTimer.Start(); + + if ( m_bStopProgress ) + { + if ( m_aProgressBar.IsVisible() ) + m_aProgressBar.SetValue( 100 ); + m_xAbortChannel.clear(); + OSL_TRACE( " startProgress handler: stop\n" ); + } + else + { + OSL_TRACE( " startProgress handler: start\n" ); + } + + m_aCancelBtn.Enable( bLockInterface ); + m_aUpdateBtn.Enable( false ); + clearEventID(); + + return 0; +} + +// ------------------------------------------------------------------------------ +void UpdateRequiredDialog::showProgress( bool _bStart ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + bool bStart = _bStart; + + if ( bStart ) + { + m_nProgress = 0; + m_bStartProgress = true; + OSL_TRACE( "showProgress start\n" ); + } + else + { + m_nProgress = 100; + m_bStopProgress = true; + OSL_TRACE( "showProgress stop!\n" ); + } + + DialogHelper::PostUserEvent( LINK( this, UpdateRequiredDialog, startProgress ), (void*) bStart ); +} + +// ----------------------------------------------------------------------- +void UpdateRequiredDialog::updateProgress( const long nProgress ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + m_nProgress = nProgress; +} + +// ----------------------------------------------------------------------- +void UpdateRequiredDialog::updateProgress( const OUString &rText, + const uno::Reference< task::XAbortChannel > &xAbortChannel) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + m_xAbortChannel = xAbortChannel; + m_sProgressText = rText; + m_bProgressChanged = true; +} + +//------------------------------------------------------------------------------ +void UpdateRequiredDialog::updatePackageInfo( const uno::Reference< deployment::XPackage > &xPackage ) +{ + // We will remove all updated packages with satisfied dependencies, but + // we will show all disabled entries so the user sees the result + // of the 'disable all' button + const SolarMutexGuard aGuard; + if ( isEnabled( xPackage ) && checkDependencies( xPackage ) ) + m_pExtensionBox->removeEntry( xPackage ); + else + m_pExtensionBox->updateEntry( xPackage ); + + if ( ! hasActiveEntries() ) + { + m_aCloseBtn.SetText( m_sCloseText ); + m_aCloseBtn.GrabFocus(); + } +} + +// ----------------------------------------------------------------------- +IMPL_LINK( UpdateRequiredDialog, HandleUpdateBtn, void*, EMPTYARG ) +{ + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + + std::vector< uno::Reference< deployment::XPackage > > vUpdateEntries; + sal_Int32 nCount = m_pExtensionBox->GetEntryCount(); + + for ( sal_Int32 i = 0; i < nCount; ++i ) + { + TEntry_Impl pEntry = m_pExtensionBox->GetEntryData( i ); + vUpdateEntries.push_back( pEntry->m_xPackage ); + } + + aGuard.clear(); + + m_pManager->getCmdQueue()->checkForUpdates( vUpdateEntries ); + + return 1; +} + +// ----------------------------------------------------------------------- +IMPL_LINK( UpdateRequiredDialog, HandleCloseBtn, void*, EMPTYARG ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !isBusy() ) + { + if ( m_bHasLockedEntries ) + EndDialog( -1 ); + else if ( hasActiveEntries() ) + disableAllEntries(); + else + EndDialog( 0 ); + } + + return 1; +} + +// ----------------------------------------------------------------------- +IMPL_LINK( UpdateRequiredDialog, HandleHyperlink, svt::FixedHyperlink*, pHyperlink ) +{ + openWebBrowser( pHyperlink->GetURL(), GetText() ); + + return 1; +} + +// ----------------------------------------------------------------------- +IMPL_LINK( UpdateRequiredDialog, TimeOutHdl, Timer*, EMPTYARG ) +{ + if ( m_bStopProgress ) + { + m_bHasProgress = false; + m_bStopProgress = false; + m_aProgressText.Hide(); + m_aProgressBar.Hide(); + m_aCancelBtn.Hide(); + } + else + { + if ( m_bProgressChanged ) + { + m_bProgressChanged = false; + m_aProgressText.SetText( m_sProgressText ); + } + + if ( m_bStartProgress ) + { + m_bStartProgress = false; + m_bHasProgress = true; + m_aProgressBar.Show(); + m_aProgressText.Show(); + m_aCancelBtn.Enable(); + m_aCancelBtn.Show(); + } + + if ( m_aProgressBar.IsVisible() ) + m_aProgressBar.SetValue( (USHORT) m_nProgress ); + + m_aTimeoutTimer.Start(); + } + + return 1; +} + +//------------------------------------------------------------------------------ +// VCL::Window / Dialog +void UpdateRequiredDialog::Resize() +{ + Size aTotalSize( GetOutputSizePixel() ); + Size aBtnSize( m_aHelpBtn.GetSizePixel() ); + + Point aPos( RSC_SP_DLG_INNERBORDER_LEFT, + aTotalSize.Height() - RSC_SP_DLG_INNERBORDER_BOTTOM - aBtnSize.Height() ); + + m_aHelpBtn.SetPosPixel( aPos ); + + aPos.X() = aTotalSize.Width() - RSC_SP_DLG_INNERBORDER_RIGHT - m_aCloseBtn.GetSizePixel().Width(); + m_aCloseBtn.SetPosPixel( aPos ); + + aPos.X() -= ( RSC_SP_CTRL_X + m_aUpdateBtn.GetSizePixel().Width() ); + m_aUpdateBtn.SetPosPixel( aPos ); + + Size aDivSize( aTotalSize.Width(), LINE_SIZE ); + aPos = Point( 0, aPos.Y() - LINE_SIZE - RSC_SP_DLG_INNERBORDER_BOTTOM ); + m_aDivider.SetPosSizePixel( aPos, aDivSize ); + + // Calc fixed text size + aPos = Point( RSC_SP_DLG_INNERBORDER_LEFT, RSC_SP_DLG_INNERBORDER_TOP ); + Size aFTSize = m_aUpdateNeeded.CalcMinimumSize( aTotalSize.Width() - RSC_SP_DLG_INNERBORDER_RIGHT - RSC_SP_DLG_INNERBORDER_LEFT ); + m_aUpdateNeeded.SetPosSizePixel( aPos, aFTSize ); + + // Calc list box size + Size aSize( aTotalSize.Width() - RSC_SP_DLG_INNERBORDER_LEFT - RSC_SP_DLG_INNERBORDER_RIGHT, + aTotalSize.Height() - 2*aBtnSize.Height() - LINE_SIZE - + 2*RSC_SP_DLG_INNERBORDER_TOP - 3*RSC_SP_DLG_INNERBORDER_BOTTOM - aFTSize.Height() ); + aPos.Y() += aFTSize.Height()+RSC_SP_DLG_INNERBORDER_TOP; + + m_pExtensionBox->SetPosSizePixel( aPos, aSize ); + + aPos.X() = aTotalSize.Width() - RSC_SP_DLG_INNERBORDER_RIGHT - aBtnSize.Width(); + aPos.Y() += aSize.Height()+RSC_SP_DLG_INNERBORDER_TOP; + m_aCancelBtn.SetPosPixel( aPos ); + + // Calc progress height + aFTSize = m_aProgressText.GetSizePixel(); + long nProgressHeight = aFTSize.Height(); + + if( IsNativeControlSupported( CTRL_PROGRESS, PART_ENTIRE_CONTROL ) ) + { + ImplControlValue aValue; + Rectangle aControlRegion( Point( 0, 0 ), m_aProgressBar.GetSizePixel() ); + Rectangle aNativeControlRegion, aNativeContentRegion; + if( GetNativeControlRegion( CTRL_PROGRESS, PART_ENTIRE_CONTROL, aControlRegion, + CTRL_STATE_ENABLED, aValue, rtl::OUString(), + aNativeControlRegion, aNativeContentRegion ) != FALSE ) + { + nProgressHeight = aNativeControlRegion.GetHeight(); + } + } + + if ( nProgressHeight < PROGRESS_HEIGHT ) + nProgressHeight = PROGRESS_HEIGHT; + + aPos.X() -= ( RSC_SP_CTRL_GROUP_Y + PROGRESS_WIDTH ); + m_aProgressBar.SetPosSizePixel( Point( aPos.X(), aPos.Y() + ((aBtnSize.Height()-nProgressHeight)/2) ), + Size( PROGRESS_WIDTH, nProgressHeight ) ); + + aFTSize.Width() = aPos.X() - 2*RSC_SP_DLG_INNERBORDER_LEFT; + aPos.X() = RSC_SP_DLG_INNERBORDER_LEFT; + aPos.Y() += ( aBtnSize.Height() - aFTSize.Height() - 1 ) / 2; + m_aProgressText.SetPosSizePixel( aPos, aFTSize ); +} + +//------------------------------------------------------------------------------ +// VCL::Dialog +short UpdateRequiredDialog::Execute() +{ + if ( m_bHasLockedEntries ) + { + // Set other text, disable update btn, remove not shared entries from list; + m_aUpdateNeeded.SetText( DialogHelper::getResourceString( RID_STR_NO_ADMIN_PRIVILEGE ) ); + m_aCloseBtn.SetText( DialogHelper::getResourceString( RID_STR_EXIT_BTN ) ); + m_aUpdateBtn.Enable( false ); + m_pExtensionBox->RemoveUnlocked(); + Resize(); + } + + return Dialog::Execute(); +} + +//------------------------------------------------------------------------------ +// VCL::Dialog +BOOL UpdateRequiredDialog::Close() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !isBusy() ) + { + if ( m_bHasLockedEntries ) + EndDialog( -1 ); + else if ( hasActiveEntries() ) + disableAllEntries(); + else + EndDialog( 0 ); + } + + return false; +} + +//------------------------------------------------------------------------------ +// Check dependencies of all packages +//------------------------------------------------------------------------------ +bool UpdateRequiredDialog::isEnabled( const uno::Reference< deployment::XPackage > &xPackage ) const +{ + bool bRegistered = false; + try { + beans::Optional< beans::Ambiguous< sal_Bool > > option( xPackage->isRegistered( uno::Reference< task::XAbortChannel >(), + uno::Reference< ucb::XCommandEnvironment >() ) ); + if ( option.IsPresent ) + { + ::beans::Ambiguous< sal_Bool > const & reg = option.Value; + if ( reg.IsAmbiguous ) + bRegistered = false; + else + bRegistered = reg.Value ? true : false; + } + else + bRegistered = false; + } + catch ( uno::RuntimeException & ) { throw; } + catch ( uno::Exception & exc) { + (void) exc; + OSL_ENSURE( 0, ::rtl::OUStringToOString( exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); + bRegistered = false; + } + + return bRegistered; +} + +//------------------------------------------------------------------------------ +bool UpdateRequiredDialog::checkDependencies( const uno::Reference< deployment::XPackage > &xPackage ) const +{ + if ( isEnabled( xPackage ) ) + { + bool bDependenciesValid = false; + try { + bDependenciesValid = xPackage->checkDependencies( uno::Reference< ucb::XCommandEnvironment >() ); + } + catch ( deployment::DeploymentException & ) {} + if ( ! bDependenciesValid ) + { + return false; + } + } + return true; +} + +//------------------------------------------------------------------------------ +bool UpdateRequiredDialog::hasActiveEntries() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + bool bRet = false; + long nCount = m_pExtensionBox->GetEntryCount(); + for ( long nIndex = 0; nIndex < nCount; nIndex++ ) + { + TEntry_Impl pEntry = m_pExtensionBox->GetEntryData( nIndex ); + + if ( !checkDependencies( pEntry->m_xPackage ) ) + { + bRet = true; + break; + } + } + + return bRet; +} + +//------------------------------------------------------------------------------ +void UpdateRequiredDialog::disableAllEntries() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + setBusy( true ); + + long nCount = m_pExtensionBox->GetEntryCount(); + for ( long nIndex = 0; nIndex < nCount; nIndex++ ) + { + TEntry_Impl pEntry = m_pExtensionBox->GetEntryData( nIndex ); + enablePackage( pEntry->m_xPackage, false ); + } + + setBusy( false ); + + if ( ! hasActiveEntries() ) + m_aCloseBtn.SetText( m_sCloseText ); +} + +//================================================================================= +// UpdateRequiredDialogService +//================================================================================= +UpdateRequiredDialogService::UpdateRequiredDialogService( uno::Sequence< uno::Any > const&, + uno::Reference< uno::XComponentContext > const& xComponentContext ) + : m_xComponentContext( xComponentContext ) +{ +} + +//------------------------------------------------------------------------------ +// XExecutableDialog +//------------------------------------------------------------------------------ +void UpdateRequiredDialogService::setTitle( OUString const & ) throw ( uno::RuntimeException ) +{ +} + +//------------------------------------------------------------------------------ +sal_Int16 UpdateRequiredDialogService::execute() throw ( uno::RuntimeException ) +{ + ::rtl::Reference< ::dp_gui::TheExtensionManager > xManager( TheExtensionManager::get( + m_xComponentContext, + uno::Reference< awt::XWindow >(), + OUString() ) ); + xManager->createDialog( true ); + sal_Int16 nRet = xManager->execute(); + + return nRet; +} + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +SelectedPackage::~SelectedPackage() {} + +} //namespace dp_gui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/dp_gui_dialog2.hxx b/desktop/source/deployment/gui/dp_gui_dialog2.hxx new file mode 100644 index 000000000000..795360732837 --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_dialog2.hxx @@ -0,0 +1,269 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_DP_GUI_DIALOG2_HXX +#define INCLUDED_DP_GUI_DIALOG2_HXX + +#include "vcl/dialog.hxx" +#include "vcl/button.hxx" +#include "vcl/fixed.hxx" +#include "vcl/timer.hxx" + +#include "svtools/fixedhyper.hxx" +#include "svtools/prgsbar.hxx" + +#include "osl/conditn.hxx" +#include "osl/mutex.hxx" + +#include "rtl/ref.hxx" +#include "rtl/ustring.hxx" + +#include "cppuhelper/implbase1.hxx" + +#include "com/sun/star/awt/XWindow.hpp" +#include "com/sun/star/deployment/XPackage.hpp" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/ui/dialogs/XExecutableDialog.hpp" +#include "com/sun/star/util/XModifyListener.hpp" + +namespace dp_gui { + +//============================================================================== +class ExtBoxWithBtns_Impl; +class ExtensionBox_Impl; +class TheExtensionManager; + +//============================================================================== +class DialogHelper +{ + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > m_xContext; + Dialog* m_pVCLWindow; + ULONG m_nEventID; + bool m_bIsBusy; + +public: + DialogHelper( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > &, + Dialog *pWindow ); + virtual ~DialogHelper(); + + void openWebBrowser( const ::rtl::OUString & sURL, const ::rtl::OUString & sTitle ) const; + Dialog* getWindow() const { return m_pVCLWindow; }; + void PostUserEvent( const Link& rLink, void* pCaller ); + void clearEventID() { m_nEventID = 0; } + + virtual void showProgress( bool bStart ) = 0; + virtual void updateProgress( const ::rtl::OUString &rText, + const ::com::sun::star::uno::Reference< ::com::sun::star::task::XAbortChannel > &xAbortChannel) = 0; + virtual void updateProgress( const long nProgress ) = 0; + + virtual void updatePackageInfo( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage ) = 0; + virtual long addPackageToList( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage, + bool bLicenseMissing = false ) = 0; + + virtual void prepareChecking() = 0; + virtual void checkEntries() = 0; + + static ResId getResId( USHORT nId ); + static String getResourceString( USHORT id ); + static bool IsSharedPkgMgr( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &); + static bool continueOnSharedExtension( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &, + Window *pParent, + const USHORT nResID, + bool &bHadWarning ); + + void setBusy( const bool bBusy ) { m_bIsBusy = bBusy; } + bool isBusy() const { return m_bIsBusy; } + bool installExtensionWarn( const ::rtl::OUString &rExtensionURL ) const; + bool installForAllUsers( bool &bInstallForAll ) const; +}; + +//============================================================================== +class ExtMgrDialog : public ModelessDialog, + public DialogHelper +{ + ExtBoxWithBtns_Impl *m_pExtensionBox; + PushButton m_aAddBtn; + PushButton m_aUpdateBtn; + OKButton m_aCloseBtn; + HelpButton m_aHelpBtn; + FixedLine m_aDivider; + svt::FixedHyperlink m_aGetExtensions; + FixedText m_aProgressText; + ProgressBar m_aProgressBar; + CancelButton m_aCancelBtn; + const String m_sAddPackages; + String m_sProgressText; + String m_sLastFolderURL; + ::osl::Mutex m_aMutex; + bool m_bHasProgress; + bool m_bProgressChanged; + bool m_bStartProgress; + bool m_bStopProgress; + bool m_bUpdateWarning; + bool m_bEnableWarning; + bool m_bDisableWarning; + bool m_bDeleteWarning; + long m_nProgress; + Timer m_aTimeoutTimer; + TheExtensionManager *m_pManager; + + ::com::sun::star::uno::Reference< ::com::sun::star::task::XAbortChannel > m_xAbortChannel; + + bool removeExtensionWarn( const ::rtl::OUString &rExtensionTitle ) const; + + DECL_DLLPRIVATE_LINK( HandleAddBtn, void * ); + DECL_DLLPRIVATE_LINK( HandleUpdateBtn, void * ); + DECL_DLLPRIVATE_LINK( HandleCancelBtn, void * ); + DECL_DLLPRIVATE_LINK( HandleHyperlink, svt::FixedHyperlink * ); + DECL_DLLPRIVATE_LINK( TimeOutHdl, Timer* ); + DECL_DLLPRIVATE_LINK( startProgress, void * ); + +public: + ExtMgrDialog( Window * pParent, TheExtensionManager *pManager ); + virtual ~ExtMgrDialog(); + + virtual void Resize(); + virtual long Notify( NotifyEvent& rNEvt ); + virtual BOOL Close(); + + virtual void showProgress( bool bStart ); + virtual void updateProgress( const ::rtl::OUString &rText, + const ::com::sun::star::uno::Reference< ::com::sun::star::task::XAbortChannel > &xAbortChannel); + virtual void updateProgress( const long nProgress ); + + virtual void updatePackageInfo( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage ); + + void setGetExtensionsURL( const ::rtl::OUString &rURL ); + virtual long addPackageToList( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &, + bool bLicenseMissing = false ); + bool enablePackage(const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage, + bool bEnable ); + bool removePackage(const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage ); + bool updatePackage(const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage ); + bool acceptLicense(const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage ); + + virtual void prepareChecking(); + virtual void checkEntries(); + + ::com::sun::star::uno::Sequence< ::rtl::OUString > raiseAddPicker(); +}; + +//============================================================================== +class UpdateRequiredDialog : public ModalDialog, + public DialogHelper +{ + ExtensionBox_Impl *m_pExtensionBox; + FixedText m_aUpdateNeeded; + PushButton m_aUpdateBtn; + PushButton m_aCloseBtn; + HelpButton m_aHelpBtn; + CancelButton m_aCancelBtn; + FixedLine m_aDivider; + FixedText m_aProgressText; + ProgressBar m_aProgressBar; + const String m_sAddPackages; + const String m_sCloseText; + String m_sProgressText; + ::osl::Mutex m_aMutex; + bool m_bHasProgress; + bool m_bProgressChanged; + bool m_bStartProgress; + bool m_bStopProgress; + bool m_bUpdateWarning; + bool m_bDisableWarning; + bool m_bHasLockedEntries; + long m_nProgress; + Timer m_aTimeoutTimer; + TheExtensionManager *m_pManager; + + ::com::sun::star::uno::Reference< ::com::sun::star::task::XAbortChannel > m_xAbortChannel; + + DECL_DLLPRIVATE_LINK( HandleUpdateBtn, void * ); + DECL_DLLPRIVATE_LINK( HandleCloseBtn, void * ); + DECL_DLLPRIVATE_LINK( HandleCancelBtn, void * ); + DECL_DLLPRIVATE_LINK( TimeOutHdl, Timer* ); + DECL_DLLPRIVATE_LINK( startProgress, void * ); + DECL_DLLPRIVATE_LINK( HandleHyperlink, svt::FixedHyperlink * ); + + bool isEnabled( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage ) const; + bool checkDependencies( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage ) const; + bool hasActiveEntries(); + void disableAllEntries(); + +public: + UpdateRequiredDialog( Window * pParent, TheExtensionManager *pManager ); + virtual ~UpdateRequiredDialog(); + + virtual short Execute(); + virtual void Resize(); + virtual BOOL Close(); +// virtual long Notify( NotifyEvent& rNEvt ); + + virtual void showProgress( bool bStart ); + virtual void updateProgress( const ::rtl::OUString &rText, + const ::com::sun::star::uno::Reference< ::com::sun::star::task::XAbortChannel > &xAbortChannel); + virtual void updateProgress( const long nProgress ); + + virtual void updatePackageInfo( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage ); + + void selectEntry( long nPos ); + virtual long addPackageToList( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &, + bool bLicenseMissing = false ); + bool enablePackage( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage, bool bEnable ); + bool updatePackage( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage ); + + virtual void prepareChecking(); + virtual void checkEntries(); + + ::com::sun::star::uno::Sequence< ::rtl::OUString > raiseAddPicker(); + + bool installForAllUsers( bool &bInstallForAll ) const; + bool installExtensionWarn( const ::rtl::OUString &rExtensionURL ) const; +}; + +//============================================================================== +class UpdateRequiredDialogService : public ::cppu::WeakImplHelper1< ::com::sun::star::ui::dialogs::XExecutableDialog > +{ + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > const m_xComponentContext; + ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindow > m_xParent; + ::rtl::OUString m_sInitialTitle; + +public: + UpdateRequiredDialogService( ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > const & args, + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext> const & xComponentContext ); + + // XExecutableDialog + virtual void SAL_CALL setTitle( rtl::OUString const & title ) throw ( ::com::sun::star::uno::RuntimeException ); + virtual sal_Int16 SAL_CALL execute() throw ( ::com::sun::star::uno::RuntimeException ); +}; + +} // namespace dp_gui + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/dp_gui_dialog2.src b/desktop/source/deployment/gui/dp_gui_dialog2.src new file mode 100644 index 000000000000..5233890d1da8 --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_dialog2.src @@ -0,0 +1,232 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "svtools/controldims.hrc" +#include "dp_gui.hrc" + +ModelessDialog RID_DLG_EXTENSION_MANAGER +{ + HelpId = HID_PACKAGE_MANAGER; + Text [ en-US ] = "Extension Manager"; + + Size = MAP_APPFONT( 300, 200 ); + OutputSize = TRUE; + SVLook = TRUE; + Moveable = TRUE; + Closeable = TRUE; + Sizeable = TRUE; + Hide = TRUE; + + PushButton RID_EM_BTN_ADD + { + TabStop = TRUE; + Text [ en-US ] = "~Add..."; + Size = MAP_APPFONT(RSC_CD_PUSHBUTTON_WIDTH, RSC_CD_PUSHBUTTON_HEIGHT ); + }; + + PushButton RID_EM_BTN_CHECK_UPDATES + { + TabStop = TRUE; + Text [ en-US ] = "Check for ~Updates..."; + Size = MAP_APPFONT(RSC_CD_PUSHBUTTON_WIDTH, RSC_CD_PUSHBUTTON_HEIGHT ); + }; + + FixedText RID_EM_FT_GET_EXTENSIONS + { + NoLabel = TRUE; + TabStop = TRUE; + Text [ en-US ] = "Get more extensions online..."; + Size = MAP_APPFONT(RSC_CD_PUSHBUTTON_WIDTH, RSC_CD_FIXEDTEXT_HEIGHT ); + }; + + FixedText RID_EM_FT_PROGRESS + { + Hide = TRUE; + Right = TRUE; + Text [ en-US ] = "Adding %EXTENSION_NAME"; + Size = MAP_APPFONT(RSC_CD_PUSHBUTTON_WIDTH, RSC_CD_FIXEDTEXT_HEIGHT ); + }; + + CancelButton RID_EM_BTN_CANCEL + { + TabStop = TRUE; + Hide = TRUE; + Size = MAP_APPFONT(RSC_CD_PUSHBUTTON_WIDTH, RSC_CD_PUSHBUTTON_HEIGHT ); + }; + + OKButton RID_EM_BTN_CLOSE + { + TabStop = TRUE; + DefButton = TRUE; + Text [ en-US ] = "Close"; + Size = MAP_APPFONT(RSC_CD_PUSHBUTTON_WIDTH, RSC_CD_PUSHBUTTON_HEIGHT ); + }; + + HelpButton RID_EM_BTN_HELP + { + TabStop = TRUE; + Size = MAP_APPFONT(RSC_CD_PUSHBUTTON_WIDTH, RSC_CD_PUSHBUTTON_HEIGHT ); + }; +}; + +ModalDialog RID_DLG_UPDATE_REQUIRED +{ + HelpId = HID_PACKAGE_MANAGER_UPD_REQ; + Text [ en-US ] = "Extension Update Required"; + + Size = MAP_APPFONT( 300, 200 ); + OutputSize = TRUE; + SVLook = TRUE; + Moveable = TRUE; + Closeable = TRUE; + Sizeable = TRUE; + Hide = TRUE; + + FixedText RID_EM_FT_MSG + { + Text [ en-US ] = "%PRODUCTNAME has been updated to a new version. Some installed %PRODUCTNAME extensions are not compatible with this version and need to be updated before they can be used."; + WordBreak = TRUE; + NoLabel = TRUE; + Size = MAP_APPFONT( 280, 3*RSC_BS_CHARHEIGHT ); + Pos = MAP_APPFONT( 5, 5 ); + }; + + FixedText RID_EM_FT_PROGRESS + { + Hide = TRUE; + Right = TRUE; + Text [ en-US ] = "Adding %EXTENSION_NAME"; + Size = MAP_APPFONT(RSC_CD_PUSHBUTTON_WIDTH, RSC_CD_FIXEDTEXT_HEIGHT ); + }; + + HelpButton RID_EM_BTN_HELP + { + TabStop = TRUE; + Size = MAP_APPFONT(RSC_CD_PUSHBUTTON_WIDTH, RSC_CD_PUSHBUTTON_HEIGHT ); + }; + + PushButton RID_EM_BTN_CHECK_UPDATES + { + TabStop = TRUE; + Text [ en-US ] = "Check for ~Updates..."; + Size = MAP_APPFONT(RSC_CD_PUSHBUTTON_WIDTH, RSC_CD_PUSHBUTTON_HEIGHT ); + }; + + PushButton RID_EM_BTN_CLOSE + { + TabStop = TRUE; + DefButton = TRUE; + Text [ en-US ] = "Disable all"; + Size = MAP_APPFONT(RSC_CD_PUSHBUTTON_WIDTH, RSC_CD_PUSHBUTTON_HEIGHT ); + }; + + CancelButton RID_EM_BTN_CANCEL + { + TabStop = TRUE; + Hide = TRUE; + Size = MAP_APPFONT(RSC_CD_PUSHBUTTON_WIDTH, RSC_CD_PUSHBUTTON_HEIGHT ); + }; + +}; + +Image RID_IMG_WARNING +{ + ImageBitmap = Bitmap { File = "caution_16.png"; }; +}; + +Image RID_IMG_LOCKED +{ + ImageBitmap = Bitmap { File = "lock_16.png"; }; +}; + +Image RID_IMG_SHARED +{ + ImageBitmap = Bitmap { File = "shared_16.png"; }; +}; + +Image RID_IMG_EXTENSION +{ + ImageBitmap = Bitmap { File = "extension_32.png"; }; +}; + +QueryBox RID_QUERYBOX_INSTALL_FOR_ALL +{ + Buttons = WB_YES_NO_CANCEL; + DefButton = WB_DEF_YES; + Message[en-US] = "Make sure that no further users are working with the same %PRODUCTNAME, when installing an extension for all users in a multi user environment.\n\nFor whom do you want to install the extension?\n"; +}; + + +// Dialog layout +// --------------------------------------------------- +// row 1 | multi line edit +// --------------------------------------------------- +// row 2 | fixed text +// --------------------------------------------------- +// row 3 | img | fixed text | fixed text | button +// ---------------------------------------------------- +// row 4 | img | fixed text | fixed text +// --------------------------------------------------- +// row 5 |fixed line +// --------------------------------------------------- +// row 6 | | |button | button +// --------------------------------------------------- +// | col 1 | col 2 | col3 | col4 | col5 + +//To change the overall size of the multi line edit change +//ROW1_HEIGHT and COL3_WIDTH + +#define ROW1_Y RSC_SP_DLG_INNERBORDER_TOP +#define ROW1_HEIGHT 16*RSC_CD_FIXEDTEXT_HEIGHT +#define ROW2_Y ROW1_Y+ROW1_HEIGHT+RSC_SP_CTRL_GROUP_Y +#define ROW2_HEIGHT 2*RSC_CD_FIXEDTEXT_HEIGHT +#define ROW3_Y ROW2_Y+ROW2_HEIGHT+RSC_SP_CTRL_GROUP_Y +#define ROW3_HEIGHT 3*RSC_CD_FIXEDTEXT_HEIGHT +#define ROW4_Y ROW3_Y+ROW3_HEIGHT+RSC_SP_CTRL_GROUP_Y +#define ROW4_HEIGHT 3*RSC_CD_FIXEDTEXT_HEIGHT +#define ROW5_Y ROW4_Y+ROW4_HEIGHT+RSC_SP_CTRL_GROUP_Y +#define ROW5_HEIGHT RSC_CD_FIXEDTEXT_HEIGHT +#define ROW6_Y ROW5_Y+ROW5_HEIGHT+RSC_SP_CTRL_GROUP_Y +#define ROW6_HEIGHT RSC_CD_PUSHBUTTON_HEIGHT + +#define LIC_DLG_HEIGHT ROW6_Y+ROW6_HEIGHT+RSC_SP_DLG_INNERBORDER_BOTTOM + +#define COL1_X RSC_SP_DLG_INNERBORDER_LEFT +#define IMG_ARROW_WIDTH 16 +#define COL1_WIDTH IMG_ARROW_WIDTH +#define COL2_X COL1_X+COL1_WIDTH +#define COL2_WIDTH 10 +#define COL3_X COL2_X+COL2_WIDTH+RSC_SP_CTRL_GROUP_X +#define COL3_WIDTH 150 +#define COL4_X COL3_X+COL3_WIDTH +#define COL4_WIDTH RSC_CD_PUSHBUTTON_WIDTH+RSC_SP_CTRL_GROUP_X +#define COL5_X COL4_X+COL4_WIDTH + +#define LIC_DLG_WIDTH COL5_X+RSC_CD_PUSHBUTTON_WIDTH+RSC_SP_DLG_INNERBORDER_RIGHT +#define BODYWIDTH LIC_DLG_WIDTH-RSC_SP_DLG_INNERBORDER_LEFT-RSC_SP_DLG_INNERBORDER_RIGHT + + diff --git a/desktop/source/deployment/gui/dp_gui_extensioncmdqueue.cxx b/desktop/source/deployment/gui/dp_gui_extensioncmdqueue.cxx new file mode 100644 index 000000000000..a202e592d9c3 --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_extensioncmdqueue.cxx @@ -0,0 +1,1188 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#define _WIN32_WINNT 0x0500 + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + + + + +#include "sal/config.h" + +#include <cstddef> + +#include "com/sun/star/beans/PropertyValue.hpp" +#include "com/sun/star/beans/NamedValue.hpp" + +#include "com/sun/star/deployment/DependencyException.hpp" +#include "com/sun/star/deployment/LicenseException.hpp" +#include "com/sun/star/deployment/VersionException.hpp" +#include "com/sun/star/deployment/InstallException.hpp" +#include "com/sun/star/deployment/PlatformException.hpp" + +#include "com/sun/star/deployment/ui/LicenseDialog.hpp" +#include "com/sun/star/deployment/DeploymentException.hpp" +#include "com/sun/star/deployment/UpdateInformationProvider.hpp" +#include "com/sun/star/deployment/XPackage.hpp" + +#include "com/sun/star/task/XAbortChannel.hpp" +#include "com/sun/star/task/XInteractionAbort.hpp" +#include "com/sun/star/task/XInteractionApprove.hpp" + +#include "com/sun/star/ucb/CommandAbortedException.hpp" +#include "com/sun/star/ucb/CommandFailedException.hpp" +#include "com/sun/star/ucb/XCommandEnvironment.hpp" + +#include "com/sun/star/ui/dialogs/ExecutableDialogResults.hpp" + +#include "com/sun/star/uno/Reference.hxx" +#include "com/sun/star/uno/RuntimeException.hpp" +#include "com/sun/star/uno/Sequence.hxx" +#include "com/sun/star/uno/XInterface.hpp" +#include "com/sun/star/uno/TypeClass.hpp" +#include "osl/diagnose.h" +#include "osl/mutex.hxx" +#include "rtl/ref.hxx" +#include "rtl/ustring.h" +#include "rtl/ustring.hxx" +#include "sal/types.h" +#include "ucbhelper/content.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "cppuhelper/implbase3.hxx" +#include "comphelper/anytostring.hxx" +#include "vcl/msgbox.hxx" +#include "toolkit/helper/vclunohelper.hxx" +#include "comphelper/processfactory.hxx" + +#include "dp_gui.h" +#include "dp_gui_thread.hxx" +#include "dp_gui_extensioncmdqueue.hxx" +#include "dp_gui_dependencydialog.hxx" +#include "dp_gui_dialog2.hxx" +#include "dp_gui_shared.hxx" +#include "dp_gui_theextmgr.hxx" +#include "dp_gui_updatedialog.hxx" +#include "dp_gui_updateinstalldialog.hxx" +#include "dp_dependencies.hxx" +#include "dp_identifier.hxx" +#include "dp_version.hxx" + +#include <queue> +#include <boost/shared_ptr.hpp> + +#if (defined(_MSC_VER) && (_MSC_VER < 1400)) +#define _WIN32_WINNT 0x0400 +#endif + +#ifdef WNT +#include "tools/prewin.h" +#include <objbase.h> +#include "tools/postwin.h" +#endif + + +using namespace ::com::sun::star; +using ::rtl::OUString; + +namespace { + +OUString getVersion( OUString const & sVersion ) +{ + return ( sVersion.getLength() == 0 ) ? OUString( RTL_CONSTASCII_USTRINGPARAM( "0" ) ) : sVersion; +} + +OUString getVersion( const uno::Reference< deployment::XPackage > &rPackage ) +{ + return getVersion( rPackage->getVersion()); +} +} + + +namespace dp_gui { + +//============================================================================== + +class ProgressCmdEnv + : public ::cppu::WeakImplHelper3< ucb::XCommandEnvironment, + task::XInteractionHandler, + ucb::XProgressHandler > +{ + uno::Reference< task::XInteractionHandler> m_xHandler; + uno::Reference< uno::XComponentContext > m_xContext; + uno::Reference< task::XAbortChannel> m_xAbortChannel; + + DialogHelper *m_pDialogHelper; + OUString m_sTitle; + bool m_bAborted; + bool m_bWarnUser; + sal_Int32 m_nCurrentProgress; + + void updateProgress(); + + void update_( uno::Any const & Status ) throw ( uno::RuntimeException ); + +public: + virtual ~ProgressCmdEnv(); + + /** When param bAskWhenInstalling = true, then the user is asked if he + agrees to install this extension. In case this extension is already installed + then the user is also notified and asked if he wants to replace that existing + extension. In first case an interaction request with an InstallException + will be handled and in the second case a VersionException will be handled. + */ + + ProgressCmdEnv( const uno::Reference< uno::XComponentContext > rContext, + DialogHelper *pDialogHelper, + const OUString &rTitle ) + : m_xContext( rContext ), + m_pDialogHelper( pDialogHelper ), + m_sTitle( rTitle ), + m_bAborted( false ), + m_bWarnUser( false ) + {} + + Dialog * activeDialog() { return m_pDialogHelper ? m_pDialogHelper->getWindow() : NULL; } + + void setTitle( const OUString& rNewTitle ) { m_sTitle = rNewTitle; } + void startProgress(); + void stopProgress(); + void progressSection( const OUString &rText, + const uno::Reference< task::XAbortChannel > &xAbortChannel = 0 ); + inline bool isAborted() const { return m_bAborted; } + inline void setWarnUser( bool bNewVal ) { m_bWarnUser = bNewVal; } + + // XCommandEnvironment + virtual uno::Reference< task::XInteractionHandler > SAL_CALL getInteractionHandler() + throw ( uno::RuntimeException ); + virtual uno::Reference< ucb::XProgressHandler > SAL_CALL getProgressHandler() + throw ( uno::RuntimeException ); + + // XInteractionHandler + virtual void SAL_CALL handle( uno::Reference< task::XInteractionRequest > const & xRequest ) + throw ( uno::RuntimeException ); + + // XProgressHandler + virtual void SAL_CALL push( uno::Any const & Status ) + throw ( uno::RuntimeException ); + virtual void SAL_CALL update( uno::Any const & Status ) + throw ( uno::RuntimeException ); + virtual void SAL_CALL pop() throw ( uno::RuntimeException ); +}; + +//------------------------------------------------------------------------------ +struct ExtensionCmd +{ + enum E_CMD_TYPE { ADD, ENABLE, DISABLE, REMOVE, CHECK_FOR_UPDATES, ACCEPT_LICENSE }; + + E_CMD_TYPE m_eCmdType; + bool m_bWarnUser; + OUString m_sExtensionURL; + OUString m_sRepository; + uno::Reference< deployment::XPackage > m_xPackage; + std::vector< uno::Reference< deployment::XPackage > > m_vExtensionList; + + ExtensionCmd( const E_CMD_TYPE eCommand, + const OUString &rExtensionURL, + const OUString &rRepository, + const bool bWarnUser ) + : m_eCmdType( eCommand ), + m_bWarnUser( bWarnUser ), + m_sExtensionURL( rExtensionURL ), + m_sRepository( rRepository ) {}; + ExtensionCmd( const E_CMD_TYPE eCommand, + const uno::Reference< deployment::XPackage > &rPackage ) + : m_eCmdType( eCommand ), + m_bWarnUser( false ), + m_xPackage( rPackage ) {}; + ExtensionCmd( const E_CMD_TYPE eCommand, + const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList ) + : m_eCmdType( eCommand ), + m_bWarnUser( false ), + m_vExtensionList( vExtensionList ) {}; +}; + +typedef ::boost::shared_ptr< ExtensionCmd > TExtensionCmd; + +//------------------------------------------------------------------------------ +class ExtensionCmdQueue::Thread: public dp_gui::Thread +{ +public: + Thread( DialogHelper *pDialogHelper, + TheExtensionManager *pManager, + const uno::Reference< uno::XComponentContext > & rContext ); + + void addExtension( const OUString &rExtensionURL, + const OUString &rRepository, + const bool bWarnUser ); + void removeExtension( const uno::Reference< deployment::XPackage > &rPackage ); + void enableExtension( const uno::Reference< deployment::XPackage > &rPackage, + const bool bEnable ); + void checkForUpdates( const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList ); + void acceptLicense( const uno::Reference< deployment::XPackage > &rPackage ); + void stop(); + bool isBusy(); + + static OUString searchAndReplaceAll( const OUString &rSource, + const OUString &rWhat, + const OUString &rWith ); +private: + Thread( Thread & ); // not defined + void operator =( Thread & ); // not defined + + virtual ~Thread(); + + virtual void execute(); + virtual void SAL_CALL onTerminated(); + + void _insert(const TExtensionCmd& rExtCmd); + + void _addExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, + const OUString &rPackageURL, + const OUString &rRepository, + const bool bWarnUser ); + void _removeExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, + const uno::Reference< deployment::XPackage > &xPackage ); + void _enableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, + const uno::Reference< deployment::XPackage > &xPackage ); + void _disableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, + const uno::Reference< deployment::XPackage > &xPackage ); + void _checkForUpdates( const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList ); + void _acceptLicense( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, + const uno::Reference< deployment::XPackage > &xPackage ); + + enum Input { NONE, START, STOP }; + + uno::Reference< uno::XComponentContext > m_xContext; + std::queue< TExtensionCmd > m_queue; + + DialogHelper *m_pDialogHelper; + TheExtensionManager *m_pManager; + + const OUString m_sEnablingPackages; + const OUString m_sDisablingPackages; + const OUString m_sAddingPackages; + const OUString m_sRemovingPackages; + const OUString m_sDefaultCmd; + const OUString m_sAcceptLicense; + osl::Condition m_wakeup; + osl::Mutex m_mutex; + Input m_eInput; + bool m_bTerminated; + bool m_bStopped; + bool m_bWorking; +}; + +//------------------------------------------------------------------------------ +void ProgressCmdEnv::startProgress() +{ + m_nCurrentProgress = 0; + + if ( m_pDialogHelper ) + m_pDialogHelper->showProgress( true ); +} + +//------------------------------------------------------------------------------ +void ProgressCmdEnv::stopProgress() +{ + if ( m_pDialogHelper ) + m_pDialogHelper->showProgress( false ); +} + +//------------------------------------------------------------------------------ +void ProgressCmdEnv::progressSection( const OUString &rText, + const uno::Reference< task::XAbortChannel > &xAbortChannel ) +{ + m_xAbortChannel = xAbortChannel; + if (! m_bAborted) + { + m_nCurrentProgress = 0; + if ( m_pDialogHelper ) + { + m_pDialogHelper->updateProgress( rText, xAbortChannel ); + m_pDialogHelper->updateProgress( 5 ); + } + } +} + +//------------------------------------------------------------------------------ +void ProgressCmdEnv::updateProgress() +{ + if ( ! m_bAborted ) + { + long nProgress = ((m_nCurrentProgress*5) % 100) + 5; + if ( m_pDialogHelper ) + m_pDialogHelper->updateProgress( nProgress ); + } +} + +//------------------------------------------------------------------------------ +ProgressCmdEnv::~ProgressCmdEnv() +{ + // TODO: stop all threads and wait +} + + +//------------------------------------------------------------------------------ +// XCommandEnvironment +//------------------------------------------------------------------------------ +uno::Reference< task::XInteractionHandler > ProgressCmdEnv::getInteractionHandler() + throw ( uno::RuntimeException ) +{ + return this; +} + +//------------------------------------------------------------------------------ +uno::Reference< ucb::XProgressHandler > ProgressCmdEnv::getProgressHandler() + throw ( uno::RuntimeException ) +{ + return this; +} + +//------------------------------------------------------------------------------ +// XInteractionHandler +//------------------------------------------------------------------------------ +void ProgressCmdEnv::handle( uno::Reference< task::XInteractionRequest > const & xRequest ) + throw ( uno::RuntimeException ) +{ + uno::Any request( xRequest->getRequest() ); + OSL_ASSERT( request.getValueTypeClass() == uno::TypeClass_EXCEPTION ); + dp_misc::TRACE( OUSTR("[dp_gui_cmdenv.cxx] incoming request:\n") + + ::comphelper::anyToString(request) + OUSTR("\n")); + + lang::WrappedTargetException wtExc; + deployment::DependencyException depExc; + deployment::LicenseException licExc; + deployment::VersionException verExc; + deployment::InstallException instExc; + deployment::PlatformException platExc; + + // selections: + bool approve = false; + bool abort = false; + + if (request >>= wtExc) { + // handable deployment error signalled, e.g. + // bundle item registration failed, notify cause only: + uno::Any cause; + deployment::DeploymentException dpExc; + if (wtExc.TargetException >>= dpExc) + cause = dpExc.Cause; + else { + ucb::CommandFailedException cfExc; + if (wtExc.TargetException >>= cfExc) + cause = cfExc.Reason; + else + cause = wtExc.TargetException; + } + update_( cause ); + + // ignore intermediate errors of legacy packages, i.e. + // former pkgchk behaviour: + const uno::Reference< deployment::XPackage > xPackage( wtExc.Context, uno::UNO_QUERY ); + OSL_ASSERT( xPackage.is() ); + if ( xPackage.is() ) + { + const uno::Reference< deployment::XPackageTypeInfo > xPackageType( xPackage->getPackageType() ); + OSL_ASSERT( xPackageType.is() ); + if (xPackageType.is()) + { + approve = ( xPackage->isBundle() && + xPackageType->getMediaType().matchAsciiL( + RTL_CONSTASCII_STRINGPARAM( + "application/" + "vnd.sun.star.legacy-package-bundle") )); + } + } + abort = !approve; + } + else if (request >>= depExc) + { + std::vector< rtl::OUString > deps; + for (sal_Int32 i = 0; i < depExc.UnsatisfiedDependencies.getLength(); + ++i) + { + deps.push_back( + dp_misc::Dependencies::getErrorText( depExc.UnsatisfiedDependencies[i]) ); + } + { + SolarMutexGuard guard; + short n = DependencyDialog( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, deps ).Execute(); + // Distinguish between closing the dialog and programatically + // canceling the dialog (headless VCL): + approve = n == RET_OK + || (n == RET_CANCEL && !Application::IsDialogCancelEnabled()); + } + } + else if (request >>= licExc) + { + uno::Reference< ui::dialogs::XExecutableDialog > xDialog( + deployment::ui::LicenseDialog::create( + m_xContext, VCLUnoHelper::GetInterface( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL ), + licExc.ExtensionName, licExc.Text ) ); + sal_Int16 res = xDialog->execute(); + if ( res == ui::dialogs::ExecutableDialogResults::CANCEL ) + abort = true; + else if ( res == ui::dialogs::ExecutableDialogResults::OK ) + approve = true; + else + { + OSL_ASSERT(0); + } + } + else if (request >>= verExc) + { + sal_uInt32 id; + switch (dp_misc::compareVersions( + verExc.NewVersion, verExc.Deployed->getVersion() )) + { + case dp_misc::LESS: + id = RID_WARNINGBOX_VERSION_LESS; + break; + case dp_misc::EQUAL: + id = RID_WARNINGBOX_VERSION_EQUAL; + break; + default: // dp_misc::GREATER + id = RID_WARNINGBOX_VERSION_GREATER; + break; + } + OSL_ASSERT( verExc.Deployed.is() ); + bool bEqualNames = verExc.NewDisplayName.equals( + verExc.Deployed->getDisplayName()); + { + SolarMutexGuard guard; + WarningBox box( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, ResId(id, *DeploymentGuiResMgr::get())); + String s; + if (bEqualNames) + { + s = box.GetMessText(); + } + else if (id == RID_WARNINGBOX_VERSION_EQUAL) + { + //hypothetical: requires two instances of an extension with the same + //version to have different display names. Probably the developer forgot + //to change the version. + s = String(ResId(RID_STR_WARNINGBOX_VERSION_EQUAL_DIFFERENT_NAMES, *DeploymentGuiResMgr::get())); + } + else if (id == RID_WARNINGBOX_VERSION_LESS) + { + s = String(ResId(RID_STR_WARNINGBOX_VERSION_LESS_DIFFERENT_NAMES, *DeploymentGuiResMgr::get())); + } + else if (id == RID_WARNINGBOX_VERSION_GREATER) + { + s = String(ResId(RID_STR_WARNINGBOX_VERSION_GREATER_DIFFERENT_NAMES, *DeploymentGuiResMgr::get())); + } + s.SearchAndReplaceAllAscii( "$NAME", verExc.NewDisplayName); + s.SearchAndReplaceAllAscii( "$OLDNAME", verExc.Deployed->getDisplayName()); + s.SearchAndReplaceAllAscii( "$NEW", getVersion(verExc.NewVersion) ); + s.SearchAndReplaceAllAscii( "$DEPLOYED", getVersion(verExc.Deployed) ); + box.SetMessText(s); + approve = box.Execute() == RET_OK; + abort = !approve; + } + } + else if (request >>= instExc) + { + if ( ! m_bWarnUser ) + { + approve = true; + } + else + { + if ( m_pDialogHelper ) + { + SolarMutexGuard guard; + + approve = m_pDialogHelper->installExtensionWarn( instExc.displayName ); + } + else + approve = false; + abort = !approve; + } + } + else if (request >>= platExc) + { + SolarMutexGuard guard; + String sMsg( ResId( RID_STR_UNSUPPORTED_PLATFORM, *DeploymentGuiResMgr::get() ) ); + sMsg.SearchAndReplaceAllAscii( "%Name", platExc.package->getDisplayName() ); + ErrorBox box( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, WB_OK, sMsg ); + box.Execute(); + approve = true; + } + + if (approve == false && abort == false) + { + // forward to UUI handler: + if (! m_xHandler.is()) { + // late init: + uno::Sequence< uno::Any > handlerArgs( 1 ); + handlerArgs[ 0 ] <<= beans::PropertyValue( + OUSTR("Context"), -1, uno::Any( m_sTitle ), + beans::PropertyState_DIRECT_VALUE ); + m_xHandler.set( m_xContext->getServiceManager() + ->createInstanceWithArgumentsAndContext( + OUSTR("com.sun.star.uui.InteractionHandler"), + handlerArgs, m_xContext ), uno::UNO_QUERY_THROW ); + } + m_xHandler->handle( xRequest ); + } + else + { + // select: + uno::Sequence< uno::Reference< task::XInteractionContinuation > > conts( + xRequest->getContinuations() ); + uno::Reference< task::XInteractionContinuation > const * pConts = conts.getConstArray(); + sal_Int32 len = conts.getLength(); + for ( sal_Int32 pos = 0; pos < len; ++pos ) + { + if (approve) { + uno::Reference< task::XInteractionApprove > xInteractionApprove( pConts[ pos ], uno::UNO_QUERY ); + if (xInteractionApprove.is()) { + xInteractionApprove->select(); + // don't query again for ongoing continuations: + approve = false; + } + } + else if (abort) { + uno::Reference< task::XInteractionAbort > xInteractionAbort( pConts[ pos ], uno::UNO_QUERY ); + if (xInteractionAbort.is()) { + xInteractionAbort->select(); + // don't query again for ongoing continuations: + abort = false; + } + } + } + } +} + +//------------------------------------------------------------------------------ +// XProgressHandler +//------------------------------------------------------------------------------ +void ProgressCmdEnv::push( uno::Any const & rStatus ) + throw( uno::RuntimeException ) +{ + update_( rStatus ); +} + +//------------------------------------------------------------------------------ +void ProgressCmdEnv::update_( uno::Any const & rStatus ) + throw( uno::RuntimeException ) +{ + OUString text; + if ( rStatus.hasValue() && !( rStatus >>= text) ) + { + if ( rStatus.getValueTypeClass() == uno::TypeClass_EXCEPTION ) + text = static_cast< uno::Exception const *>( rStatus.getValue() )->Message; + if ( text.getLength() == 0 ) + text = ::comphelper::anyToString( rStatus ); // fallback + + const SolarMutexGuard aGuard; + const ::std::auto_ptr< ErrorBox > aBox( new ErrorBox( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, WB_OK, text ) ); + aBox->Execute(); + } + ++m_nCurrentProgress; + updateProgress(); +} + +//------------------------------------------------------------------------------ +void ProgressCmdEnv::update( uno::Any const & rStatus ) + throw( uno::RuntimeException ) +{ + update_( rStatus ); +} + +//------------------------------------------------------------------------------ +void ProgressCmdEnv::pop() + throw( uno::RuntimeException ) +{ + update_( uno::Any() ); // no message +} + +//------------------------------------------------------------------------------ +ExtensionCmdQueue::Thread::Thread( DialogHelper *pDialogHelper, + TheExtensionManager *pManager, + const uno::Reference< uno::XComponentContext > & rContext ) : + m_xContext( rContext ), + m_pDialogHelper( pDialogHelper ), + m_pManager( pManager ), + m_sEnablingPackages( DialogHelper::getResourceString( RID_STR_ENABLING_PACKAGES ) ), + m_sDisablingPackages( DialogHelper::getResourceString( RID_STR_DISABLING_PACKAGES ) ), + m_sAddingPackages( DialogHelper::getResourceString( RID_STR_ADDING_PACKAGES ) ), + m_sRemovingPackages( DialogHelper::getResourceString( RID_STR_REMOVING_PACKAGES ) ), + m_sDefaultCmd( DialogHelper::getResourceString( RID_STR_ADD_PACKAGES ) ), + m_sAcceptLicense( DialogHelper::getResourceString( RID_STR_ACCEPT_LICENSE ) ), + m_eInput( NONE ), + m_bTerminated( false ), + m_bStopped( false ), + m_bWorking( false ) +{ + OSL_ASSERT( pDialogHelper ); +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::addExtension( const ::rtl::OUString &rExtensionURL, + const ::rtl::OUString &rRepository, + const bool bWarnUser ) +{ + if ( rExtensionURL.getLength() ) + { + TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::ADD, rExtensionURL, rRepository, bWarnUser ) ); + _insert( pEntry ); + } +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::removeExtension( const uno::Reference< deployment::XPackage > &rPackage ) +{ + if ( rPackage.is() ) + { + TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::REMOVE, rPackage ) ); + _insert( pEntry ); + } +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::acceptLicense( const uno::Reference< deployment::XPackage > &rPackage ) +{ + if ( rPackage.is() ) + { + TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::ACCEPT_LICENSE, rPackage ) ); + _insert( pEntry ); + } +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::enableExtension( const uno::Reference< deployment::XPackage > &rPackage, + const bool bEnable ) +{ + if ( rPackage.is() ) + { + TExtensionCmd pEntry( new ExtensionCmd( bEnable ? ExtensionCmd::ENABLE : + ExtensionCmd::DISABLE, + rPackage ) ); + _insert( pEntry ); + } +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::checkForUpdates( + const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList ) +{ + TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::CHECK_FOR_UPDATES, vExtensionList ) ); + _insert( pEntry ); +} + +//------------------------------------------------------------------------------ +//Stopping this thread will not abort the installation of extensions. +void ExtensionCmdQueue::Thread::stop() +{ + osl::MutexGuard aGuard( m_mutex ); + m_bStopped = true; + m_eInput = STOP; + m_wakeup.set(); +} + +//------------------------------------------------------------------------------ +bool ExtensionCmdQueue::Thread::isBusy() +{ + osl::MutexGuard aGuard( m_mutex ); + return m_bWorking; +} + +//------------------------------------------------------------------------------ +ExtensionCmdQueue::Thread::~Thread() {} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::execute() +{ +#ifdef WNT + //Needed for use of the service "com.sun.star.system.SystemShellExecute" in + //DialogHelper::openWebBrowser + CoUninitialize(); + HRESULT r = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); +#endif + for (;;) + { + if ( m_wakeup.wait() != osl::Condition::result_ok ) + { + dp_misc::TRACE( "dp_gui::ExtensionCmdQueue::Thread::run: ignored " + "osl::Condition::wait failure\n" ); + } + m_wakeup.reset(); + + int nSize; + Input eInput; + { + osl::MutexGuard aGuard( m_mutex ); + eInput = m_eInput; + m_eInput = NONE; + nSize = m_queue.size(); + m_bWorking = false; + } + + // If this thread has been woken up by anything else except start, stop + // then input is NONE and we wait again. + // We only install the extension which are currently in the queue. + // The progressbar will be set to show the progress of the current number + // of extensions. If we allowed to add extensions now then the progressbar may + // have reached the end while we still install newly added extensions. + if ( ( eInput == NONE ) || ( nSize == 0 ) ) + continue; + if ( eInput == STOP ) + break; + + ::rtl::Reference< ProgressCmdEnv > currentCmdEnv( new ProgressCmdEnv( m_xContext, m_pDialogHelper, m_sDefaultCmd ) ); + + // Do not lock the following part with addExtension. addExtension may be called in the main thread. + // If the message box "Do you want to install the extension (or similar)" is shown and then + // addExtension is called, which then blocks the main thread, then we deadlock. + bool bStartProgress = true; + + while ( !currentCmdEnv->isAborted() && --nSize >= 0 ) + { + { + osl::MutexGuard aGuard( m_mutex ); + m_bWorking = true; + } + + try + { + TExtensionCmd pEntry; + { + ::osl::MutexGuard queueGuard( m_mutex ); + pEntry = m_queue.front(); + m_queue.pop(); + } + + if ( bStartProgress && ( pEntry->m_eCmdType != ExtensionCmd::CHECK_FOR_UPDATES ) ) + { + currentCmdEnv->startProgress(); + bStartProgress = false; + } + + switch ( pEntry->m_eCmdType ) { + case ExtensionCmd::ADD : + _addExtension( currentCmdEnv, pEntry->m_sExtensionURL, pEntry->m_sRepository, pEntry->m_bWarnUser ); + break; + case ExtensionCmd::REMOVE : + _removeExtension( currentCmdEnv, pEntry->m_xPackage ); + break; + case ExtensionCmd::ENABLE : + _enableExtension( currentCmdEnv, pEntry->m_xPackage ); + break; + case ExtensionCmd::DISABLE : + _disableExtension( currentCmdEnv, pEntry->m_xPackage ); + break; + case ExtensionCmd::CHECK_FOR_UPDATES : + _checkForUpdates( pEntry->m_vExtensionList ); + break; + case ExtensionCmd::ACCEPT_LICENSE : + _acceptLicense( currentCmdEnv, pEntry->m_xPackage ); + break; + } + } + //catch ( deployment::DeploymentException &) + //{ + //} + //catch ( lang::IllegalArgumentException &) + //{ + //} + catch ( ucb::CommandAbortedException & ) + { + //This exception is thrown when the user clicks cancel on the progressbar. + //Then we cancel the installation of all extensions and remove them from + //the queue. + { + ::osl::MutexGuard queueGuard2(m_mutex); + while ( --nSize >= 0 ) + m_queue.pop(); + } + break; + } + catch ( ucb::CommandFailedException & ) + { + //This exception is thrown when a user clicked cancel in the messagebox which was + //startet by the interaction handler. For example the user will be asked if he/she + //really wants to install the extension. + //These interaction are run for exectly one extension at a time. Therefore we continue + //with installing the remaining extensions. + continue; + } + catch ( uno::Exception & ) + { + //Todo display the user an error + //see also DialogImpl::SyncPushButton::Click() + uno::Any exc( ::cppu::getCaughtException() ); + OUString msg; + deployment::DeploymentException dpExc; + if ((exc >>= dpExc) && + dpExc.Cause.getValueTypeClass() == uno::TypeClass_EXCEPTION) + { + // notify error cause only: + msg = reinterpret_cast< uno::Exception const * >( dpExc.Cause.getValue() )->Message; + } + if (msg.getLength() == 0) // fallback for debugging purposes + msg = ::comphelper::anyToString(exc); + + const SolarMutexGuard guard; + ::std::auto_ptr<ErrorBox> box( + new ErrorBox( currentCmdEnv->activeDialog(), WB_OK, msg ) ); + if ( m_pDialogHelper ) + box->SetText( m_pDialogHelper->getWindow()->GetText() ); + box->Execute(); + //Continue with installation of the remaining extensions + } + { + osl::MutexGuard aGuard( m_mutex ); + m_bWorking = false; + } + } + + { + // when leaving the while loop with break, we should set working to false, too + osl::MutexGuard aGuard( m_mutex ); + m_bWorking = false; + } + + if ( !bStartProgress ) + currentCmdEnv->stopProgress(); + } + //end for + //enable all buttons +// m_pDialog->m_bAddingExtensions = false; +// m_pDialog->updateButtonStates(); +#ifdef WNT + CoUninitialize(); +#endif +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::_addExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, + const OUString &rPackageURL, + const OUString &rRepository, + const bool bWarnUser ) +{ + //check if we have a string in anyTitle. For example "unopkg gui \" caused anyTitle to be void + //and anyTitle.get<OUString> throws as RuntimeException. + uno::Any anyTitle; + try + { + anyTitle = ::ucbhelper::Content( rPackageURL, rCmdEnv.get() ).getPropertyValue( OUSTR("Title") ); + } + catch ( uno::Exception & ) + { + return; + } + + OUString sName; + if ( ! (anyTitle >>= sName) ) + { + OSL_ENSURE(0, "Could not get file name for extension."); + return; + } + + rCmdEnv->setWarnUser( bWarnUser ); + uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager(); + uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() ); + OUString sTitle = searchAndReplaceAll( m_sAddingPackages, OUSTR("%EXTENSION_NAME"), sName ); + rCmdEnv->progressSection( sTitle, xAbortChannel ); + + try + { + xExtMgr->addExtension(rPackageURL, uno::Sequence<beans::NamedValue>(), + rRepository, xAbortChannel, rCmdEnv.get() ); + } + catch ( ucb::CommandFailedException & ) + { + // When the extension is already installed we'll get a dialog asking if we want to overwrite. If we then press + // cancel this exception is thrown. + } + catch ( ucb::CommandAbortedException & ) + { + // User clicked the cancel button + // TODO: handle cancel + } + rCmdEnv->setWarnUser( false ); +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::_removeExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, + const uno::Reference< deployment::XPackage > &xPackage ) +{ + uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager(); + uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() ); + OUString sTitle = searchAndReplaceAll( m_sRemovingPackages, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() ); + rCmdEnv->progressSection( sTitle, xAbortChannel ); + + OUString id( dp_misc::getIdentifier( xPackage ) ); + try + { + xExtMgr->removeExtension( id, xPackage->getName(), xPackage->getRepositoryName(), xAbortChannel, rCmdEnv.get() ); + } + catch ( deployment::DeploymentException & ) + {} + catch ( ucb::CommandFailedException & ) + {} + catch ( ucb::CommandAbortedException & ) + {} + + // Check, if there are still updates to be notified via menu bar icon + uno::Sequence< uno::Sequence< rtl::OUString > > aItemList; + UpdateDialog::createNotifyJob( false, aItemList ); +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::_checkForUpdates( + const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList ) +{ + UpdateDialog* pUpdateDialog; + std::vector< UpdateData > vData; + + const SolarMutexGuard guard; + + pUpdateDialog = new UpdateDialog( m_xContext, m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, vExtensionList, &vData ); + + pUpdateDialog->notifyMenubar( true, false ); // prepare the checking, if there updates to be notified via menu bar icon + + if ( ( pUpdateDialog->Execute() == RET_OK ) && !vData.empty() ) + { + // If there is at least one directly downloadable extension then we + // open the install dialog. + ::std::vector< UpdateData > dataDownload; + int countWebsiteDownload = 0; + typedef std::vector< dp_gui::UpdateData >::const_iterator cit; + + for ( cit i = vData.begin(); i < vData.end(); ++i ) + { + if ( i->sWebsiteURL.getLength() > 0 ) + countWebsiteDownload ++; + else + dataDownload.push_back( *i ); + } + + short nDialogResult = RET_OK; + if ( !dataDownload.empty() ) + { + nDialogResult = UpdateInstallDialog( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, dataDownload, m_xContext ).Execute(); + pUpdateDialog->notifyMenubar( false, true ); // Check, if there are still pending updates to be notified via menu bar icon + } + else + pUpdateDialog->notifyMenubar( false, false ); // Check, if there are pending updates to be notified via menu bar icon + + //Now start the webbrowser and navigate to the websites where we get the updates + if ( RET_OK == nDialogResult ) + { + for ( cit i = vData.begin(); i < vData.end(); ++i ) + { + if ( m_pDialogHelper && ( i->sWebsiteURL.getLength() > 0 ) ) + m_pDialogHelper->openWebBrowser( i->sWebsiteURL, m_pDialogHelper->getWindow()->GetText() ); + } + } + } + else + pUpdateDialog->notifyMenubar( false, false ); // check if there updates to be notified via menu bar icon + + delete pUpdateDialog; +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::_enableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, + const uno::Reference< deployment::XPackage > &xPackage ) +{ + if ( !xPackage.is() ) + return; + + uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager(); + uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() ); + OUString sTitle = searchAndReplaceAll( m_sEnablingPackages, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() ); + rCmdEnv->progressSection( sTitle, xAbortChannel ); + + try + { + xExtMgr->enableExtension( xPackage, xAbortChannel, rCmdEnv.get() ); + if ( m_pDialogHelper ) + m_pDialogHelper->updatePackageInfo( xPackage ); + } + catch ( ::ucb::CommandAbortedException & ) + {} +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::_disableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, + const uno::Reference< deployment::XPackage > &xPackage ) +{ + if ( !xPackage.is() ) + return; + + uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager(); + uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() ); + OUString sTitle = searchAndReplaceAll( m_sDisablingPackages, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() ); + rCmdEnv->progressSection( sTitle, xAbortChannel ); + + try + { + xExtMgr->disableExtension( xPackage, xAbortChannel, rCmdEnv.get() ); + if ( m_pDialogHelper ) + m_pDialogHelper->updatePackageInfo( xPackage ); + } + catch ( ::ucb::CommandAbortedException & ) + {} +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::_acceptLicense( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, + const uno::Reference< deployment::XPackage > &xPackage ) +{ + if ( !xPackage.is() ) + return; + + uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager(); + uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() ); + OUString sTitle = searchAndReplaceAll( m_sAcceptLicense, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() ); + rCmdEnv->progressSection( sTitle, xAbortChannel ); + + try + { + xExtMgr->checkPrerequisitesAndEnable( xPackage, xAbortChannel, rCmdEnv.get() ); + if ( m_pDialogHelper ) + m_pDialogHelper->updatePackageInfo( xPackage ); + } + catch ( ::ucb::CommandAbortedException & ) + {} +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::onTerminated() +{ + ::osl::MutexGuard g(m_mutex); + m_bTerminated = true; +} + +void ExtensionCmdQueue::Thread::_insert(const TExtensionCmd& rExtCmd) +{ + ::osl::MutexGuard aGuard( m_mutex ); + + // If someone called stop then we do not process the command -> game over! + if ( m_bStopped ) + return; + + m_queue.push( rExtCmd ); + m_eInput = START; + m_wakeup.set(); +} + +//------------------------------------------------------------------------------ +OUString ExtensionCmdQueue::Thread::searchAndReplaceAll( const OUString &rSource, + const OUString &rWhat, + const OUString &rWith ) +{ + OUString aRet( rSource ); + sal_Int32 nLen = rWhat.getLength(); + + if ( !nLen ) + return aRet; + + sal_Int32 nIndex = rSource.indexOf( rWhat ); + while ( nIndex != -1 ) + { + aRet = aRet.replaceAt( nIndex, nLen, rWith ); + nIndex = aRet.indexOf( rWhat, nIndex + rWith.getLength() ); + } + return aRet; +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +ExtensionCmdQueue::ExtensionCmdQueue( DialogHelper * pDialogHelper, + TheExtensionManager *pManager, + const uno::Reference< uno::XComponentContext > &rContext ) + : m_thread( new Thread( pDialogHelper, pManager, rContext ) ) +{ + m_thread->launch(); +} + +ExtensionCmdQueue::~ExtensionCmdQueue() { + stop(); +} + +void ExtensionCmdQueue::addExtension( const ::rtl::OUString & extensionURL, + const ::rtl::OUString & repository, + const bool bWarnUser ) +{ + m_thread->addExtension( extensionURL, repository, bWarnUser ); +} + +void ExtensionCmdQueue::removeExtension( const uno::Reference< deployment::XPackage > &rPackage ) +{ + m_thread->removeExtension( rPackage ); +} + +void ExtensionCmdQueue::enableExtension( const uno::Reference< deployment::XPackage > &rPackage, + const bool bEnable ) +{ + m_thread->enableExtension( rPackage, bEnable ); +} + +void ExtensionCmdQueue::checkForUpdates( const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList ) +{ + m_thread->checkForUpdates( vExtensionList ); +} + +void ExtensionCmdQueue::acceptLicense( const uno::Reference< deployment::XPackage > &rPackage ) +{ + m_thread->acceptLicense( rPackage ); +} + +void ExtensionCmdQueue::syncRepositories( const uno::Reference< uno::XComponentContext > &xContext ) +{ + dp_misc::syncRepositories( new ProgressCmdEnv( xContext, NULL, OUSTR("Extension Manager") ) ); +} + +void ExtensionCmdQueue::stop() +{ + m_thread->stop(); +} + +bool ExtensionCmdQueue::isBusy() +{ + return m_thread->isBusy(); +} + +void handleInteractionRequest( const uno::Reference< uno::XComponentContext > & xContext, + const uno::Reference< task::XInteractionRequest > & xRequest ) +{ + ::rtl::Reference< ProgressCmdEnv > xCmdEnv( new ProgressCmdEnv( xContext, NULL, OUSTR("Extension Manager") ) ); + xCmdEnv->handle( xRequest ); +} + +} //namespace dp_gui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/dp_gui_extensioncmdqueue.hxx b/desktop/source/deployment/gui/dp_gui_extensioncmdqueue.hxx new file mode 100644 index 000000000000..f8fd1f1b2e05 --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_extensioncmdqueue.hxx @@ -0,0 +1,114 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_DP_GUI_EXTENSIONCMDQUEUE_HXX +#define INCLUDED_DP_GUI_EXTENSIONCMDQUEUE_HXX + +#include "sal/config.h" + +#include "com/sun/star/uno/Reference.hxx" +#include "rtl/ref.hxx" + +#include <vector> + +#include "dp_gui_updatedata.hxx" + +/// @HTML + +namespace com { namespace sun { namespace star { + namespace task { class XInteractionRequest; } + namespace uno { class XComponentContext; } +} } } + +namespace dp_gui { + +class DialogHelper; +class TheExtensionManager; + +/** + Manages installing of extensions in the GUI mode. Requests for installing + Extensions can be asynchronous. For example, the Extension Manager is running + in an office process and someone uses the system integration to install an Extension. + That is, the user double clicks an extension symbol in a file browser, which then + causes an invocation of "unopkg gui ext". When at that time the Extension Manager + already performs a task, triggered by the user (for example, add, update, disable, + enable) then adding of the extension will be postponed until the user has finished + the task. + + This class also ensures that the extensions are not installed in the main thread. + Doing so would cause a deadlock because of the progress bar which needs to be constantly + updated. +*/ +class ExtensionCmdQueue { + +public: + /** + Create an instance. + */ + ExtensionCmdQueue( DialogHelper * pDialogHelper, + TheExtensionManager *pManager, + const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > & rContext); + + ~ExtensionCmdQueue(); + + /** + */ + void addExtension( const ::rtl::OUString &rExtensionURL, + const ::rtl::OUString &rRepository, + const bool bWarnUser ); + void removeExtension( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &rPackage ); + void enableExtension( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &rPackage, + const bool bEnable ); + void checkForUpdates(const std::vector< ::com::sun::star::uno::Reference< + ::com::sun::star::deployment::XPackage > > &vList ); + void acceptLicense( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &rPackage ); + static void syncRepositories( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > & xContext ); + /** + This call does not block. It signals the internal thread + that it should install the remaining extensions and then terminate. + */ + void stop(); + + bool isBusy(); +private: + ExtensionCmdQueue(ExtensionCmdQueue &); // not defined + void operator =(ExtensionCmdQueue &); // not defined + + class Thread; + + rtl::Reference< Thread > m_thread; +}; + +void handleInteractionRequest( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > & xContext, + const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionRequest > & xRequest ); + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/dp_gui_extlistbox.cxx b/desktop/source/deployment/gui/dp_gui_extlistbox.cxx new file mode 100644 index 000000000000..134593a7e5eb --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_extlistbox.cxx @@ -0,0 +1,1214 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "svtools/controldims.hrc" + +#include "dp_gui.h" +#include "dp_gui_extlistbox.hxx" +#include "dp_gui_theextmgr.hxx" +#include "dp_gui_dialog2.hxx" +#include "dp_dependencies.hxx" + +#include "comphelper/processfactory.hxx" +#include "com/sun/star/i18n/CollatorOptions.hpp" +#include "com/sun/star/deployment/DependencyException.hpp" +#include "com/sun/star/deployment/DeploymentException.hpp" + + +#define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) + +#define USER_PACKAGE_MANAGER OUSTR("user") +#define SHARED_PACKAGE_MANAGER OUSTR("shared") +#define BUNDLED_PACKAGE_MANAGER OUSTR("bundled") + +using namespace ::com::sun::star; + +namespace dp_gui { + +//------------------------------------------------------------------------------ +// struct Entry_Impl +//------------------------------------------------------------------------------ +Entry_Impl::Entry_Impl( const uno::Reference< deployment::XPackage > &xPackage, + const PackageState eState, const bool bReadOnly ) : + m_bActive( false ), + m_bLocked( bReadOnly ), + m_bHasOptions( false ), + m_bUser( false ), + m_bShared( false ), + m_bNew( false ), + m_bChecked( false ), + m_bMissingDeps( false ), + m_bHasButtons( false ), + m_bMissingLic( false ), + m_eState( eState ), + m_pPublisher( NULL ), + m_xPackage( xPackage ) +{ + try + { + m_sTitle = xPackage->getDisplayName(); + m_sVersion = xPackage->getVersion(); + m_sDescription = xPackage->getDescription(); + + beans::StringPair aInfo( m_xPackage->getPublisherInfo() ); + m_sPublisher = aInfo.First; + m_sPublisherURL = aInfo.Second; + + // get the icons for the package if there are any + uno::Reference< graphic::XGraphic > xGraphic = xPackage->getIcon( false ); + if ( xGraphic.is() ) + m_aIcon = Image( xGraphic ); + + xGraphic = xPackage->getIcon( true ); + if ( xGraphic.is() ) + m_aIconHC = Image( xGraphic ); + else + m_aIconHC = m_aIcon; + + if ( eState == AMBIGUOUS ) + m_sErrorText = DialogHelper::getResourceString( RID_STR_ERROR_UNKNOWN_STATUS ); + else if ( eState == NOT_REGISTERED ) + checkDependencies(); + } + catch (deployment::ExtensionRemovedException &) {} + catch (uno::RuntimeException &) {} +} + +//------------------------------------------------------------------------------ +Entry_Impl::~Entry_Impl() +{} + +//------------------------------------------------------------------------------ +StringCompare Entry_Impl::CompareTo( const CollatorWrapper *pCollator, const TEntry_Impl pEntry ) const +{ + StringCompare eCompare = (StringCompare) pCollator->compareString( m_sTitle, pEntry->m_sTitle ); + if ( eCompare == COMPARE_EQUAL ) + { + eCompare = m_sVersion.CompareTo( pEntry->m_sVersion ); + if ( eCompare == COMPARE_EQUAL ) + { + sal_Int32 nCompare = m_xPackage->getRepositoryName().compareTo( pEntry->m_xPackage->getRepositoryName() ); + if ( nCompare < 0 ) + eCompare = COMPARE_LESS; + else if ( nCompare > 0 ) + eCompare = COMPARE_GREATER; + } + } + return eCompare; +} + +//------------------------------------------------------------------------------ +void Entry_Impl::checkDependencies() +{ + try { + m_xPackage->checkDependencies( uno::Reference< ucb::XCommandEnvironment >() ); + } + catch ( deployment::DeploymentException &e ) + { + deployment::DependencyException depExc; + if ( e.Cause >>= depExc ) + { + rtl::OUString aMissingDep( DialogHelper::getResourceString( RID_STR_ERROR_MISSING_DEPENDENCIES ) ); + for ( sal_Int32 i = 0; i < depExc.UnsatisfiedDependencies.getLength(); ++i ) + { + aMissingDep += OUSTR("\n"); + aMissingDep += dp_misc::Dependencies::getErrorText( depExc.UnsatisfiedDependencies[i]); + } + aMissingDep += OUSTR("\n"); + m_sErrorText = aMissingDep; + m_bMissingDeps = true; + } + } +} +//------------------------------------------------------------------------------ +// ExtensionRemovedListener +//------------------------------------------------------------------------------ +void ExtensionRemovedListener::disposing( lang::EventObject const & rEvt ) + throw ( uno::RuntimeException ) +{ + uno::Reference< deployment::XPackage > xPackage( rEvt.Source, uno::UNO_QUERY ); + + if ( xPackage.is() ) + { + m_pParent->removeEntry( xPackage ); + } +} + +//------------------------------------------------------------------------------ +ExtensionRemovedListener::~ExtensionRemovedListener() +{ +} + +//------------------------------------------------------------------------------ +// ExtensionBox_Impl +//------------------------------------------------------------------------------ +ExtensionBox_Impl::ExtensionBox_Impl( Dialog* pParent, TheExtensionManager *pManager ) : + IExtensionListBox( pParent, WB_BORDER | WB_TABSTOP | WB_CHILDDLGCTRL ), + m_bHasScrollBar( false ), + m_bHasActive( false ), + m_bNeedsRecalc( true ), + m_bHasNew( false ), + m_bInCheckMode( false ), + m_bAdjustActive( false ), + m_bInDelete( false ), + m_nActive( 0 ), + m_nTopIndex( 0 ), + m_nActiveHeight( 0 ), + m_nExtraHeight( 2 ), + m_aSharedImage( DialogHelper::getResId( RID_IMG_SHARED ) ), + m_aLockedImage( DialogHelper::getResId( RID_IMG_LOCKED ) ), + m_aWarningImage( DialogHelper::getResId( RID_IMG_WARNING ) ), + m_aDefaultImage( DialogHelper::getResId( RID_IMG_EXTENSION ) ), + m_pScrollBar( NULL ), + m_pManager( pManager ) +{ + SetHelpId( HID_EXTENSION_MANAGER_LISTBOX ); + + m_pScrollBar = new ScrollBar( this, WB_VERT ); + m_pScrollBar->SetScrollHdl( LINK( this, ExtensionBox_Impl, ScrollHdl ) ); + m_pScrollBar->EnableDrag(); + + SetPaintTransparent( true ); + SetPosPixel( Point( RSC_SP_DLG_INNERBORDER_LEFT, RSC_SP_DLG_INNERBORDER_TOP ) ); + long nIconHeight = 2*TOP_OFFSET + SMALL_ICON_SIZE; + long nTitleHeight = 2*TOP_OFFSET + GetTextHeight(); + if ( nIconHeight < nTitleHeight ) + m_nStdHeight = nTitleHeight; + else + m_nStdHeight = nIconHeight; + m_nStdHeight += GetTextHeight() + TOP_OFFSET; + + nIconHeight = ICON_HEIGHT + 2*TOP_OFFSET + 1; + if ( m_nStdHeight < nIconHeight ) + m_nStdHeight = nIconHeight; + + m_nActiveHeight = m_nStdHeight; + + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + if( IsControlBackground() ) + SetBackground( GetControlBackground() ); + else + SetBackground( rStyleSettings.GetFieldColor() ); + + m_xRemoveListener = new ExtensionRemovedListener( this ); + + m_pLocale = new lang::Locale( Application::GetSettings().GetLocale() ); + m_pCollator = new CollatorWrapper( ::comphelper::getProcessServiceFactory() ); + m_pCollator->loadDefaultCollator( *m_pLocale, i18n::CollatorOptions::CollatorOptions_IGNORE_CASE ); + + Show(); +} + +//------------------------------------------------------------------------------ +ExtensionBox_Impl::~ExtensionBox_Impl() +{ + if ( ! m_bInDelete ) + DeleteRemoved(); + + m_bInDelete = true; + + typedef std::vector< TEntry_Impl >::iterator ITER; + + for ( ITER iIndex = m_vEntries.begin(); iIndex < m_vEntries.end(); ++iIndex ) + { + if ( (*iIndex)->m_pPublisher ) + { + delete (*iIndex)->m_pPublisher; + (*iIndex)->m_pPublisher = NULL; + } + (*iIndex)->m_xPackage->removeEventListener( uno::Reference< lang::XEventListener > ( m_xRemoveListener, uno::UNO_QUERY ) ); + } + + m_vEntries.clear(); + + delete m_pScrollBar; + + m_xRemoveListener.clear(); + + delete m_pLocale; + delete m_pCollator; +} + +//------------------------------------------------------------------------------ +sal_Int32 ExtensionBox_Impl::getItemCount() const +{ + return static_cast< sal_Int32 >( m_vEntries.size() ); +} + +//------------------------------------------------------------------------------ +sal_Int32 ExtensionBox_Impl::getSelIndex() const +{ + if ( m_bHasActive ) + { + OSL_ASSERT( m_nActive >= -1); + return static_cast< sal_Int32 >( m_nActive ); + } + else + return static_cast< sal_Int32 >( EXTENSION_LISTBOX_ENTRY_NOTFOUND ); +} + +//------------------------------------------------------------------------------ +void ExtensionBox_Impl::checkIndex( sal_Int32 nIndex ) const +{ + if ( nIndex < 0 ) + throw lang::IllegalArgumentException( OUSTR("The list index starts with 0"),0, 0 ); + if ( static_cast< sal_uInt32 >( nIndex ) >= m_vEntries.size()) + throw lang::IllegalArgumentException( OUSTR("There is no element at the provided position." + "The position exceeds the number of available list entries"),0, 0 ); +} + +//------------------------------------------------------------------------------ +rtl::OUString ExtensionBox_Impl::getItemName( sal_Int32 nIndex ) const +{ + const ::osl::MutexGuard aGuard( m_entriesMutex ); + checkIndex( nIndex ); + return m_vEntries[ nIndex ]->m_sTitle; +} + +//------------------------------------------------------------------------------ +rtl::OUString ExtensionBox_Impl::getItemVersion( sal_Int32 nIndex ) const +{ + const ::osl::MutexGuard aGuard( m_entriesMutex ); + checkIndex( nIndex ); + return m_vEntries[ nIndex ]->m_sVersion; +} + +//------------------------------------------------------------------------------ +rtl::OUString ExtensionBox_Impl::getItemDescription( sal_Int32 nIndex ) const +{ + const ::osl::MutexGuard aGuard( m_entriesMutex ); + checkIndex( nIndex ); + return m_vEntries[ nIndex ]->m_sDescription; +} + +//------------------------------------------------------------------------------ +rtl::OUString ExtensionBox_Impl::getItemPublisher( sal_Int32 nIndex ) const +{ + const ::osl::MutexGuard aGuard( m_entriesMutex ); + checkIndex( nIndex ); + return m_vEntries[ nIndex ]->m_sPublisher; +} + +//------------------------------------------------------------------------------ +rtl::OUString ExtensionBox_Impl::getItemPublisherLink( sal_Int32 nIndex ) const +{ + const ::osl::MutexGuard aGuard( m_entriesMutex ); + checkIndex( nIndex ); + return m_vEntries[ nIndex ]->m_sPublisherURL; +} + +//------------------------------------------------------------------------------ +void ExtensionBox_Impl::select( sal_Int32 nIndex ) +{ + const ::osl::MutexGuard aGuard( m_entriesMutex ); + checkIndex( nIndex ); + selectEntry( nIndex ); +} + +//------------------------------------------------------------------------------ +void ExtensionBox_Impl::select( const rtl::OUString & sName ) +{ + const ::osl::MutexGuard aGuard( m_entriesMutex ); + typedef ::std::vector< TEntry_Impl >::const_iterator It; + + for ( It iIter = m_vEntries.begin(); iIter < m_vEntries.end(); iIter++ ) + { + if ( sName.equals( (*iIter)->m_sTitle ) ) + { + long nPos = iIter - m_vEntries.begin(); + selectEntry( nPos ); + break; + } + } +} + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +// Title + description +void ExtensionBox_Impl::CalcActiveHeight( const long nPos ) +{ + const ::osl::MutexGuard aGuard( m_entriesMutex ); + + // get title height + long aTextHeight; + long nIconHeight = 2*TOP_OFFSET + SMALL_ICON_SIZE; + long nTitleHeight = 2*TOP_OFFSET + GetTextHeight(); + if ( nIconHeight < nTitleHeight ) + aTextHeight = nTitleHeight; + else + aTextHeight = nIconHeight; + + // calc description height + Size aSize = GetOutputSizePixel(); + if ( m_bHasScrollBar ) + aSize.Width() -= m_pScrollBar->GetSizePixel().Width(); + + aSize.Width() -= ICON_OFFSET; + aSize.Height() = 10000; + + rtl::OUString aText( m_vEntries[ nPos ]->m_sErrorText ); + if ( aText.getLength() ) + aText += OUSTR("\n"); + aText += m_vEntries[ nPos ]->m_sDescription; + + Rectangle aRect = GetTextRect( Rectangle( Point(), aSize ), aText, + TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK ); + aTextHeight += aRect.GetHeight(); + + if ( aTextHeight < m_nStdHeight ) + aTextHeight = m_nStdHeight; + + if ( m_vEntries[ nPos ]->m_bHasButtons ) + m_nActiveHeight = aTextHeight + m_nExtraHeight; + else + m_nActiveHeight = aTextHeight + 2; +} + +//------------------------------------------------------------------------------ +const Size ExtensionBox_Impl::GetMinOutputSizePixel() const +{ + return Size( 200, 80 ); +} + +//------------------------------------------------------------------------------ +Rectangle ExtensionBox_Impl::GetEntryRect( const long nPos ) const +{ + const ::osl::MutexGuard aGuard( m_entriesMutex ); + + Size aSize( GetOutputSizePixel() ); + + if ( m_bHasScrollBar ) + aSize.Width() -= m_pScrollBar->GetSizePixel().Width(); + + if ( m_vEntries[ nPos ]->m_bActive ) + aSize.Height() = m_nActiveHeight; + else + aSize.Height() = m_nStdHeight; + + Point aPos( 0, -m_nTopIndex + nPos * m_nStdHeight ); + if ( m_bHasActive && ( nPos < m_nActive ) ) + aPos.Y() += m_nActiveHeight - m_nStdHeight; + + return Rectangle( aPos, aSize ); +} + +//------------------------------------------------------------------------------ +void ExtensionBox_Impl::DeleteRemoved() +{ + const ::osl::MutexGuard aGuard( m_entriesMutex ); + + m_bInDelete = true; + + if ( ! m_vRemovedEntries.empty() ) + { + typedef std::vector< TEntry_Impl >::iterator ITER; + + for ( ITER iIndex = m_vRemovedEntries.begin(); iIndex < m_vRemovedEntries.end(); ++iIndex ) + { + if ( (*iIndex)->m_pPublisher ) + { + delete (*iIndex)->m_pPublisher; + (*iIndex)->m_pPublisher = NULL; + } + } + + m_vRemovedEntries.clear(); + } + + m_bInDelete = false; +} + +//------------------------------------------------------------------------------ +//This function may be called with nPos < 0 +void ExtensionBox_Impl::selectEntry( const long nPos ) +{ + //ToDo whe should not use the guard at such a big scope here. + //Currently it is used to gard m_vEntries and m_nActive. m_nActive will be + //modified in this function. + //It would be probably best to always use a copy of m_vEntries + //and some other state variables from ExtensionBox_Impl for + //the whole painting operation. See issue i86993 + ::osl::ClearableMutexGuard guard(m_entriesMutex); + + if ( m_bInCheckMode ) + return; + + if ( m_bHasActive ) + { + if ( nPos == m_nActive ) + return; + + m_bHasActive = false; + m_vEntries[ m_nActive ]->m_bActive = false; + } + + if ( ( nPos >= 0 ) && ( nPos < (long) m_vEntries.size() ) ) + { + m_bHasActive = true; + m_nActive = nPos; + m_vEntries[ nPos ]->m_bActive = true; + + if ( IsReallyVisible() ) + { + m_bAdjustActive = true; + } + } + + if ( IsReallyVisible() ) + { + m_bNeedsRecalc = true; + Invalidate(); + } + + guard.clear(); +} + +// ----------------------------------------------------------------------- +void ExtensionBox_Impl::DrawRow( const Rectangle& rRect, const TEntry_Impl pEntry ) +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + if ( pEntry->m_bActive ) + SetTextColor( rStyleSettings.GetHighlightTextColor() ); + else if ( ( pEntry->m_eState != REGISTERED ) && ( pEntry->m_eState != NOT_AVAILABLE ) ) + SetTextColor( rStyleSettings.GetDisableColor() ); + else if ( IsControlForeground() ) + SetTextColor( GetControlForeground() ); + else + SetTextColor( rStyleSettings.GetFieldTextColor() ); + + if ( pEntry->m_bActive ) + { + SetLineColor(); + SetFillColor( rStyleSettings.GetHighlightColor() ); + DrawRect( rRect ); + } + else + { + if( IsControlBackground() ) + SetBackground( GetControlBackground() ); + else + SetBackground( rStyleSettings.GetFieldColor() ); + + SetTextFillColor(); + Erase( rRect ); + } + + // Draw extension icon + Point aPos( rRect.TopLeft() ); + aPos += Point( TOP_OFFSET, TOP_OFFSET ); + Image aImage; + if ( ! pEntry->m_aIcon ) + aImage = m_aDefaultImage; + else + aImage = pEntry->m_aIcon; + Size aImageSize = aImage.GetSizePixel(); + if ( ( aImageSize.Width() <= ICON_WIDTH ) && ( aImageSize.Height() <= ICON_HEIGHT ) ) + DrawImage( Point( aPos.X()+((ICON_WIDTH-aImageSize.Width())/2), aPos.Y()+((ICON_HEIGHT-aImageSize.Height())/2) ), aImage ); + else + DrawImage( aPos, Size( ICON_WIDTH, ICON_HEIGHT ), aImage ); + + // Setup fonts + Font aStdFont( GetFont() ); + Font aBoldFont( aStdFont ); + aBoldFont.SetWeight( WEIGHT_BOLD ); + SetFont( aBoldFont ); + long aTextHeight = GetTextHeight(); + + // Init publisher link here + if ( !pEntry->m_pPublisher && pEntry->m_sPublisher.Len() ) + { + pEntry->m_pPublisher = new svt::FixedHyperlink( this ); + pEntry->m_pPublisher->SetBackground(); + pEntry->m_pPublisher->SetPaintTransparent( true ); + pEntry->m_pPublisher->SetURL( pEntry->m_sPublisherURL ); + pEntry->m_pPublisher->SetDescription( pEntry->m_sPublisher ); + Size aSize = FixedText::CalcMinimumTextSize( pEntry->m_pPublisher ); + pEntry->m_pPublisher->SetSizePixel( aSize ); + + if ( m_aClickHdl.IsSet() ) + pEntry->m_pPublisher->SetClickHdl( m_aClickHdl ); + } + + // Get max title width + long nMaxTitleWidth = rRect.GetWidth() - ICON_OFFSET; + nMaxTitleWidth -= ( 2 * SMALL_ICON_SIZE ) + ( 4 * SPACE_BETWEEN ); + if ( pEntry->m_pPublisher ) + { + nMaxTitleWidth -= pEntry->m_pPublisher->GetSizePixel().Width() + (2*SPACE_BETWEEN); + } + + long aVersionWidth = GetTextWidth( pEntry->m_sVersion ); + long aTitleWidth = GetTextWidth( pEntry->m_sTitle ) + (aTextHeight / 3); + + aPos = rRect.TopLeft() + Point( ICON_OFFSET, TOP_OFFSET ); + + if ( aTitleWidth > nMaxTitleWidth - aVersionWidth ) + { + aTitleWidth = nMaxTitleWidth - aVersionWidth - (aTextHeight / 3); + String aShortTitle = GetEllipsisString( pEntry->m_sTitle, aTitleWidth ); + DrawText( aPos, aShortTitle ); + aTitleWidth += (aTextHeight / 3); + } + else + DrawText( aPos, pEntry->m_sTitle ); + + SetFont( aStdFont ); + DrawText( Point( aPos.X() + aTitleWidth, aPos.Y() ), pEntry->m_sVersion ); + + long nIconHeight = TOP_OFFSET + SMALL_ICON_SIZE; + long nTitleHeight = TOP_OFFSET + GetTextHeight(); + if ( nIconHeight < nTitleHeight ) + aTextHeight = nTitleHeight; + else + aTextHeight = nIconHeight; + + // draw description + String sDescription; + if ( pEntry->m_sErrorText.Len() ) + { + if ( pEntry->m_bActive ) + sDescription = pEntry->m_sErrorText + OUSTR("\n") + pEntry->m_sDescription; + else + sDescription = pEntry->m_sErrorText; + } + else + sDescription = pEntry->m_sDescription; + + aPos.Y() += aTextHeight; + if ( pEntry->m_bActive ) + { + long nExtraHeight = 0; + + if ( pEntry->m_bHasButtons ) + nExtraHeight = m_nExtraHeight; + + DrawText( Rectangle( aPos.X(), aPos.Y(), rRect.Right(), rRect.Bottom() - nExtraHeight ), + sDescription, TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK ); + } + else + { + const long nWidth = GetTextWidth( sDescription ); + if ( nWidth > rRect.GetWidth() - aPos.X() ) + sDescription = GetEllipsisString( sDescription, rRect.GetWidth() - aPos.X() ); + DrawText( aPos, sDescription ); + } + + // Draw publisher link + if ( pEntry->m_pPublisher ) + { + pEntry->m_pPublisher->Show(); + aPos = rRect.TopLeft() + Point( ICON_OFFSET + nMaxTitleWidth + (2*SPACE_BETWEEN), TOP_OFFSET ); + pEntry->m_pPublisher->SetPosPixel( aPos ); + } + + // Draw status icons + if ( !pEntry->m_bUser ) + { + aPos = rRect.TopRight() + Point( -(RIGHT_ICON_OFFSET + SMALL_ICON_SIZE), TOP_OFFSET ); + if ( pEntry->m_bLocked ) + DrawImage( aPos, Size( SMALL_ICON_SIZE, SMALL_ICON_SIZE ), m_aLockedImage ); + else + DrawImage( aPos, Size( SMALL_ICON_SIZE, SMALL_ICON_SIZE ), m_aSharedImage ); + } + if ( ( pEntry->m_eState == AMBIGUOUS ) || pEntry->m_bMissingDeps || pEntry->m_bMissingLic ) + { + aPos = rRect.TopRight() + Point( -(RIGHT_ICON_OFFSET + SPACE_BETWEEN + 2*SMALL_ICON_SIZE), TOP_OFFSET ); + DrawImage( aPos, Size( SMALL_ICON_SIZE, SMALL_ICON_SIZE ), m_aWarningImage ); + } + + SetLineColor( Color( COL_LIGHTGRAY ) ); + DrawLine( rRect.BottomLeft(), rRect.BottomRight() ); +} + +// ----------------------------------------------------------------------- +void ExtensionBox_Impl::RecalcAll() +{ + if ( m_bHasActive ) + CalcActiveHeight( m_nActive ); + + SetupScrollBar(); + + if ( m_bHasActive ) + { + Rectangle aEntryRect = GetEntryRect( m_nActive ); + + if ( m_bAdjustActive ) + { + m_bAdjustActive = false; + + // If the top of the selected entry isn't visible, make it visible + if ( aEntryRect.Top() < 0 ) + { + m_nTopIndex += aEntryRect.Top(); + aEntryRect.Move( 0, -aEntryRect.Top() ); + } + + // If the bottom of the selected entry isn't visible, make it visible even if now the top + // isn't visible any longer ( the buttons are more important ) + Size aOutputSize = GetOutputSizePixel(); + if ( aEntryRect.Bottom() > aOutputSize.Height() ) + { + m_nTopIndex += ( aEntryRect.Bottom() - aOutputSize.Height() ); + aEntryRect.Move( 0, -( aEntryRect.Bottom() - aOutputSize.Height() ) ); + } + + // If there is unused space below the last entry but all entries don't fit into the box, + // move the content down to use the whole space + const long nTotalHeight = GetTotalHeight(); + if ( m_bHasScrollBar && ( aOutputSize.Height() + m_nTopIndex > nTotalHeight ) ) + { + long nOffset = m_nTopIndex; + m_nTopIndex = nTotalHeight - aOutputSize.Height(); + nOffset -= m_nTopIndex; + aEntryRect.Move( 0, nOffset ); + } + + if ( m_bHasScrollBar ) + m_pScrollBar->SetThumbPos( m_nTopIndex ); + } + } + + m_bNeedsRecalc = false; +} + +// ----------------------------------------------------------------------- +bool ExtensionBox_Impl::HandleTabKey( bool ) +{ + return false; +} + +// ----------------------------------------------------------------------- +bool ExtensionBox_Impl::HandleCursorKey( USHORT nKeyCode ) +{ + if ( m_vEntries.empty() ) + return true; + + long nSelect = 0; + + if ( m_bHasActive ) + { + long nPageSize = GetOutputSizePixel().Height() / m_nStdHeight; + if ( nPageSize < 2 ) + nPageSize = 2; + + if ( ( nKeyCode == KEY_DOWN ) || ( nKeyCode == KEY_RIGHT ) ) + nSelect = m_nActive + 1; + else if ( ( nKeyCode == KEY_UP ) || ( nKeyCode == KEY_LEFT ) ) + nSelect = m_nActive - 1; + else if ( nKeyCode == KEY_HOME ) + nSelect = 0; + else if ( nKeyCode == KEY_END ) + nSelect = m_vEntries.size() - 1; + else if ( nKeyCode == KEY_PAGEUP ) + nSelect = m_nActive - nPageSize + 1; + else if ( nKeyCode == KEY_PAGEDOWN ) + nSelect = m_nActive + nPageSize - 1; + } + else // when there is no selected entry, we will select the first or the last. + { + if ( ( nKeyCode == KEY_DOWN ) || ( nKeyCode == KEY_PAGEDOWN ) || ( nKeyCode == KEY_HOME ) ) + nSelect = 0; + else if ( ( nKeyCode == KEY_UP ) || ( nKeyCode == KEY_PAGEUP ) || ( nKeyCode == KEY_END ) ) + nSelect = m_vEntries.size() - 1; + } + + if ( nSelect < 0 ) + nSelect = 0; + if ( nSelect >= (long) m_vEntries.size() ) + nSelect = m_vEntries.size() - 1; + + selectEntry( nSelect ); + + return true; +} + +// ----------------------------------------------------------------------- +void ExtensionBox_Impl::Paint( const Rectangle &/*rPaintRect*/ ) +{ + if ( !m_bInDelete ) + DeleteRemoved(); + + if ( m_bNeedsRecalc ) + RecalcAll(); + + Point aStart( 0, -m_nTopIndex ); + Size aSize( GetOutputSizePixel() ); + + if ( m_bHasScrollBar ) + aSize.Width() -= m_pScrollBar->GetSizePixel().Width(); + + const ::osl::MutexGuard aGuard( m_entriesMutex ); + + typedef std::vector< TEntry_Impl >::iterator ITER; + for ( ITER iIndex = m_vEntries.begin(); iIndex < m_vEntries.end(); ++iIndex ) + { + aSize.Height() = (*iIndex)->m_bActive ? m_nActiveHeight : m_nStdHeight; + Rectangle aEntryRect( aStart, aSize ); + DrawRow( aEntryRect, *iIndex ); + aStart.Y() += aSize.Height(); + } +} + +// ----------------------------------------------------------------------- +long ExtensionBox_Impl::GetTotalHeight() const +{ + long nHeight = m_vEntries.size() * m_nStdHeight; + + if ( m_bHasActive ) + { + nHeight += m_nActiveHeight - m_nStdHeight; + } + + return nHeight; +} + +// ----------------------------------------------------------------------- +void ExtensionBox_Impl::SetupScrollBar() +{ + const Size aSize = GetOutputSizePixel(); + const long nScrBarSize = GetSettings().GetStyleSettings().GetScrollBarSize(); + const long nTotalHeight = GetTotalHeight(); + const bool bNeedsScrollBar = ( nTotalHeight > aSize.Height() ); + + if ( bNeedsScrollBar ) + { + if ( m_nTopIndex + aSize.Height() > nTotalHeight ) + m_nTopIndex = nTotalHeight - aSize.Height(); + + m_pScrollBar->SetPosSizePixel( Point( aSize.Width() - nScrBarSize, 0 ), + Size( nScrBarSize, aSize.Height() ) ); + m_pScrollBar->SetRangeMax( nTotalHeight ); + m_pScrollBar->SetVisibleSize( aSize.Height() ); + m_pScrollBar->SetPageSize( ( aSize.Height() * 4 ) / 5 ); + m_pScrollBar->SetLineSize( m_nStdHeight ); + m_pScrollBar->SetThumbPos( m_nTopIndex ); + + if ( !m_bHasScrollBar ) + m_pScrollBar->Show(); + } + else if ( m_bHasScrollBar ) + { + m_pScrollBar->Hide(); + m_nTopIndex = 0; + } + + m_bHasScrollBar = bNeedsScrollBar; +} + +// ----------------------------------------------------------------------- +void ExtensionBox_Impl::Resize() +{ + RecalcAll(); +} + +//------------------------------------------------------------------------------ +long ExtensionBox_Impl::PointToPos( const Point& rPos ) +{ + long nPos = ( rPos.Y() + m_nTopIndex ) / m_nStdHeight; + + if ( m_bHasActive && ( nPos > m_nActive ) ) + { + if ( rPos.Y() + m_nTopIndex <= m_nActive*m_nStdHeight + m_nActiveHeight ) + nPos = m_nActive; + else + nPos = ( rPos.Y() + m_nTopIndex - (m_nActiveHeight - m_nStdHeight) ) / m_nStdHeight; + } + + return nPos; +} + +//------------------------------------------------------------------------------ +void ExtensionBox_Impl::MouseButtonDown( const MouseEvent& rMEvt ) +{ + long nPos = PointToPos( rMEvt.GetPosPixel() ); + + if ( rMEvt.IsLeft() ) + { + if ( rMEvt.IsMod1() && m_bHasActive ) + selectEntry( m_vEntries.size() ); // Selecting an not existing entry will deselect the current one + else + selectEntry( nPos ); + } +} + +//------------------------------------------------------------------------------ +long ExtensionBox_Impl::Notify( NotifyEvent& rNEvt ) +{ + if ( !m_bInDelete ) + DeleteRemoved(); + + bool bHandled = false; + + if ( rNEvt.GetType() == EVENT_KEYINPUT ) + { + const KeyEvent* pKEvt = rNEvt.GetKeyEvent(); + KeyCode aKeyCode = pKEvt->GetKeyCode(); + USHORT nKeyCode = aKeyCode.GetCode(); + + if ( nKeyCode == KEY_TAB ) + bHandled = HandleTabKey( aKeyCode.IsShift() ); + else if ( aKeyCode.GetGroup() == KEYGROUP_CURSOR ) + bHandled = HandleCursorKey( nKeyCode ); + } + + if ( rNEvt.GetType() == EVENT_COMMAND ) + { + if ( m_bHasScrollBar && + ( rNEvt.GetCommandEvent()->GetCommand() == COMMAND_WHEEL ) ) + { + const CommandWheelData* pData = rNEvt.GetCommandEvent()->GetWheelData(); + if ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) + { + long nThumbPos = m_pScrollBar->GetThumbPos(); + if ( pData->GetDelta() < 0 ) + m_pScrollBar->DoScroll( nThumbPos + m_nStdHeight ); + else + m_pScrollBar->DoScroll( nThumbPos - m_nStdHeight ); + bHandled = true; + } + } + } + + if ( !bHandled ) + return Control::Notify( rNEvt ); + else + return true; +} + +//------------------------------------------------------------------------------ +bool ExtensionBox_Impl::FindEntryPos( const TEntry_Impl pEntry, const long nStart, + const long nEnd, long &nPos ) +{ + nPos = nStart; + if ( nStart > nEnd ) + return false; + + StringCompare eCompare; + + if ( nStart == nEnd ) + { + eCompare = pEntry->CompareTo( m_pCollator, m_vEntries[ nStart ] ); + if ( eCompare == COMPARE_LESS ) + return false; + else if ( eCompare == COMPARE_EQUAL ) + { + //Workaround. See i86963. + if (pEntry->m_xPackage != m_vEntries[nStart]->m_xPackage) + return false; + + if ( m_bInCheckMode ) + m_vEntries[ nStart ]->m_bChecked = true; + return true; + } + else + { + nPos = nStart + 1; + return false; + } + } + + const long nMid = nStart + ( ( nEnd - nStart ) / 2 ); + eCompare = pEntry->CompareTo( m_pCollator, m_vEntries[ nMid ] ); + + if ( eCompare == COMPARE_LESS ) + return FindEntryPos( pEntry, nStart, nMid-1, nPos ); + else if ( eCompare == COMPARE_GREATER ) + return FindEntryPos( pEntry, nMid+1, nEnd, nPos ); + else + { + //Workaround.See i86963. + if (pEntry->m_xPackage != m_vEntries[nMid]->m_xPackage) + return false; + + if ( m_bInCheckMode ) + m_vEntries[ nMid ]->m_bChecked = true; + nPos = nMid; + return true; + } +} + +//------------------------------------------------------------------------------ +long ExtensionBox_Impl::addEntry( const uno::Reference< deployment::XPackage > &xPackage, + bool bLicenseMissing ) +{ + long nPos = 0; + PackageState eState = m_pManager->getPackageState( xPackage ); + bool bLocked = m_pManager->isReadOnly( xPackage ); + + TEntry_Impl pEntry( new Entry_Impl( xPackage, eState, bLocked ) ); + + // Don't add empty entries + if ( ! pEntry->m_sTitle.Len() ) + return 0; + + xPackage->addEventListener( uno::Reference< lang::XEventListener > ( m_xRemoveListener, uno::UNO_QUERY ) ); + + ::osl::ClearableMutexGuard guard(m_entriesMutex); + if ( m_vEntries.empty() ) + { + m_vEntries.push_back( pEntry ); + } + else + { + if ( !FindEntryPos( pEntry, 0, m_vEntries.size()-1, nPos ) ) + { + m_vEntries.insert( m_vEntries.begin()+nPos, pEntry ); + } + else if ( !m_bInCheckMode ) + { + OSL_ENSURE( 0, "ExtensionBox_Impl::addEntry(): Will not add duplicate entries" ); + } + } + + pEntry->m_bHasOptions = m_pManager->supportsOptions( xPackage ); + pEntry->m_bUser = xPackage->getRepositoryName().equals( USER_PACKAGE_MANAGER ); + pEntry->m_bShared = xPackage->getRepositoryName().equals( SHARED_PACKAGE_MANAGER ); + pEntry->m_bNew = m_bInCheckMode; + pEntry->m_bMissingLic = bLicenseMissing; + + if ( bLicenseMissing ) + pEntry->m_sErrorText = DialogHelper::getResourceString( RID_STR_ERROR_MISSING_LICENSE ); + + //access to m_nActive must be guarded + if ( !m_bInCheckMode && m_bHasActive && ( m_nActive >= nPos ) ) + m_nActive += 1; + + guard.clear(); + + if ( IsReallyVisible() ) + Invalidate(); + + m_bNeedsRecalc = true; + + return nPos; +} + +//------------------------------------------------------------------------------ +void ExtensionBox_Impl::updateEntry( const uno::Reference< deployment::XPackage > &xPackage ) +{ + typedef std::vector< TEntry_Impl >::iterator ITER; + for ( ITER iIndex = m_vEntries.begin(); iIndex < m_vEntries.end(); ++iIndex ) + { + if ( (*iIndex)->m_xPackage == xPackage ) + { + PackageState eState = m_pManager->getPackageState( xPackage ); + (*iIndex)->m_bHasOptions = m_pManager->supportsOptions( xPackage ); + (*iIndex)->m_eState = eState; + (*iIndex)->m_sTitle = xPackage->getDisplayName(); + (*iIndex)->m_sVersion = xPackage->getVersion(); + (*iIndex)->m_sDescription = xPackage->getDescription(); + + if ( eState == REGISTERED ) + (*iIndex)->m_bMissingLic = false; + + if ( eState == AMBIGUOUS ) + (*iIndex)->m_sErrorText = DialogHelper::getResourceString( RID_STR_ERROR_UNKNOWN_STATUS ); + else if ( ! (*iIndex)->m_bMissingLic ) + (*iIndex)->m_sErrorText = String(); + + if ( IsReallyVisible() ) + Invalidate(); + break; + } + } +} + +//------------------------------------------------------------------------------ +void ExtensionBox_Impl::removeEntry( const uno::Reference< deployment::XPackage > &xPackage ) +{ + if ( ! m_bInDelete ) + { + ::osl::ClearableMutexGuard aGuard( m_entriesMutex ); + + typedef std::vector< TEntry_Impl >::iterator ITER; + + for ( ITER iIndex = m_vEntries.begin(); iIndex < m_vEntries.end(); ++iIndex ) + { + if ( (*iIndex)->m_xPackage == xPackage ) + { + long nPos = iIndex - m_vEntries.begin(); + + // Entries mustn't removed here, because they contain a hyperlink control + // which can only be deleted when the thread has the solar mutex. Therefor + // the entry will be moved into the m_vRemovedEntries list which will be + // cleared on the next paint event + m_vRemovedEntries.push_back( *iIndex ); + m_vEntries.erase( iIndex ); + + m_bNeedsRecalc = true; + + if ( IsReallyVisible() ) + Invalidate(); + + if ( m_bHasActive ) + { + if ( nPos < m_nActive ) + m_nActive -= 1; + else if ( ( nPos == m_nActive ) && + ( nPos == (long) m_vEntries.size() ) ) + m_nActive -= 1; + + m_bHasActive = false; + //clear before calling out of this method + aGuard.clear(); + selectEntry( m_nActive ); + } + break; + } + } + } +} + +//------------------------------------------------------------------------------ +void ExtensionBox_Impl::RemoveUnlocked() +{ + bool bAllRemoved = false; + + while ( ! bAllRemoved ) + { + bAllRemoved = true; + + ::osl::ClearableMutexGuard aGuard( m_entriesMutex ); + + typedef std::vector< TEntry_Impl >::iterator ITER; + + for ( ITER iIndex = m_vEntries.begin(); iIndex < m_vEntries.end(); ++iIndex ) + { + if ( !(*iIndex)->m_bLocked ) + { + bAllRemoved = false; + uno::Reference< deployment::XPackage> xPackage = (*iIndex)->m_xPackage; + aGuard.clear(); + removeEntry( xPackage ); + break; + } + } + } +} + +//------------------------------------------------------------------------------ +void ExtensionBox_Impl::prepareChecking() +{ + m_bInCheckMode = true; + typedef std::vector< TEntry_Impl >::iterator ITER; + for ( ITER iIndex = m_vEntries.begin(); iIndex < m_vEntries.end(); ++iIndex ) + { + (*iIndex)->m_bChecked = false; + (*iIndex)->m_bNew = false; + } +} + +//------------------------------------------------------------------------------ +void ExtensionBox_Impl::checkEntries() +{ + long nNewPos = -1; + long nPos = 0; + bool bNeedsUpdate = false; + + ::osl::ClearableMutexGuard guard(m_entriesMutex); + typedef std::vector< TEntry_Impl >::iterator ITER; + ITER iIndex = m_vEntries.begin(); + while ( iIndex < m_vEntries.end() ) + { + if ( (*iIndex)->m_bChecked == false ) + { + (*iIndex)->m_bChecked = true; + bNeedsUpdate = true; + nPos = iIndex-m_vEntries.begin(); + if ( (*iIndex)->m_bNew ) + { // add entry to list and correct active pos + if ( nNewPos == - 1) + nNewPos = nPos; + if ( nPos <= m_nActive ) + m_nActive += 1; + ++iIndex; + } + else + { // remove entry from list + if ( nPos < m_nActive ) + m_nActive -= 1; + else if ( ( nPos == m_nActive ) && ( nPos == (long) m_vEntries.size() - 1 ) ) + m_nActive -= 1; + m_vRemovedEntries.push_back( *iIndex ); + m_vEntries.erase( iIndex ); + iIndex = m_vEntries.begin() + nPos; + } + } + else + ++iIndex; + } + guard.clear(); + + m_bInCheckMode = false; + + if ( nNewPos != - 1) + selectEntry( nNewPos ); + + if ( bNeedsUpdate ) + { + m_bNeedsRecalc = true; + if ( IsReallyVisible() ) + Invalidate(); + } +} + +//------------------------------------------------------------------------------ +void ExtensionBox_Impl::SetScrollHdl( const Link& rLink ) +{ + if ( m_pScrollBar ) + m_pScrollBar->SetScrollHdl( rLink ); +} + +// ----------------------------------------------------------------------- +void ExtensionBox_Impl::DoScroll( long nDelta ) +{ + m_nTopIndex += nDelta; + Point aNewSBPt( m_pScrollBar->GetPosPixel() ); + + Rectangle aScrRect( Point(), GetOutputSizePixel() ); + aScrRect.Right() -= m_pScrollBar->GetSizePixel().Width(); + Scroll( 0, -nDelta, aScrRect ); + + m_pScrollBar->SetPosPixel( aNewSBPt ); +} + +// ----------------------------------------------------------------------- +IMPL_LINK( ExtensionBox_Impl, ScrollHdl, ScrollBar*, pScrBar ) +{ + DoScroll( pScrBar->GetDelta() ); + + return 1; +} + +} //namespace dp_gui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/dp_gui_extlistbox.hxx b/desktop/source/deployment/gui/dp_gui_extlistbox.hxx new file mode 100644 index 000000000000..7cdaa7483e7f --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_extlistbox.hxx @@ -0,0 +1,268 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "rtl/ustring.hxx" +#include "vcl/scrbar.hxx" +#include "vcl/fixed.hxx" +#include "vcl/dialog.hxx" + +#include "svtools/extensionlistbox.hxx" +#include "svtools/fixedhyper.hxx" +#include "cppuhelper/implbase1.hxx" +#include "unotools/collatorwrapper.hxx" + +#include "com/sun/star/lang/Locale.hpp" +#include "com/sun/star/lang/XEventListener.hpp" +#include "com/sun/star/deployment/XPackage.hpp" + +#include <boost/shared_ptr.hpp> + +namespace dp_gui { + +#define SMALL_ICON_SIZE 16 +#define TOP_OFFSET 5 +#define ICON_HEIGHT 42 +#define ICON_WIDTH 47 +#define ICON_OFFSET 72 +#define RIGHT_ICON_OFFSET 5 +#define SPACE_BETWEEN 3 + +class TheExtensionManager; + +typedef ::boost::shared_ptr< svt::FixedHyperlink > TFixedHyperlink; + +//------------------------------------------------------------------------------ +// struct Entry_Impl +//------------------------------------------------------------------------------ +struct Entry_Impl; + +typedef ::boost::shared_ptr< Entry_Impl > TEntry_Impl; + +struct Entry_Impl +{ + bool m_bActive :1; + bool m_bLocked :1; + bool m_bHasOptions :1; + bool m_bUser :1; + bool m_bShared :1; + bool m_bNew :1; + bool m_bChecked :1; + bool m_bMissingDeps :1; + bool m_bHasButtons :1; + bool m_bMissingLic :1; + PackageState m_eState; + String m_sTitle; + String m_sVersion; + String m_sDescription; + String m_sPublisher; + String m_sPublisherURL; + String m_sErrorText; + Image m_aIcon; + Image m_aIconHC; + svt::FixedHyperlink *m_pPublisher; + + ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage> m_xPackage; + + Entry_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage, + const PackageState eState, const bool bReadOnly ); + ~Entry_Impl(); + + StringCompare CompareTo( const CollatorWrapper *pCollator, const TEntry_Impl pEntry ) const; + void checkDependencies(); +}; + +//------------------------------------------------------------------------------ +// class ExtensionBox_Impl +//------------------------------------------------------------------------------ + +class ExtensionBox_Impl; + +//------------------------------------------------------------------------------ +class ExtensionRemovedListener : public ::cppu::WeakImplHelper1< ::com::sun::star::lang::XEventListener > +{ + ExtensionBox_Impl *m_pParent; + +public: + + ExtensionRemovedListener( ExtensionBox_Impl *pParent ) { m_pParent = pParent; } + ~ExtensionRemovedListener(); + + //=================================================================================== + // XEventListener + virtual void SAL_CALL disposing( ::com::sun::star::lang::EventObject const & evt ) + throw (::com::sun::star::uno::RuntimeException); +}; + +//------------------------------------------------------------------------------ +class ExtensionBox_Impl : public ::svt::IExtensionListBox +{ + bool m_bHasScrollBar; + bool m_bHasActive; + bool m_bNeedsRecalc; + bool m_bHasNew; + bool m_bInCheckMode; + bool m_bAdjustActive; + bool m_bInDelete; + //Must be guarded together with m_vEntries to ensure a valid index at all times. + //Use m_entriesMutex as guard. + long m_nActive; + long m_nTopIndex; + long m_nStdHeight; + long m_nActiveHeight; + long m_nExtraHeight; + Size m_aOutputSize; + Image m_aSharedImage; + Image m_aLockedImage; + Image m_aWarningImage; + Image m_aDefaultImage; + Link m_aClickHdl; + + ScrollBar *m_pScrollBar; + + com::sun::star::uno::Reference< ExtensionRemovedListener > m_xRemoveListener; + + TheExtensionManager *m_pManager; + //This mutex is used for synchronizing access to m_vEntries. + //Currently it is used to synchronize adding, removing entries and + //functions like getItemName, getItemDescription, etc. to prevent + //that m_vEntries is accessed at an invalid index. + //ToDo: There are many more places where m_vEntries is read and which may + //fail. For example the Paint method is probable called from the main thread + //while new entries are added / removed in a separate thread. + mutable ::osl::Mutex m_entriesMutex; + std::vector< TEntry_Impl > m_vEntries; + std::vector< TEntry_Impl > m_vRemovedEntries; + + ::com::sun::star::lang::Locale *m_pLocale; + CollatorWrapper *m_pCollator; + + void CalcActiveHeight( const long nPos ); + long GetTotalHeight() const; + void SetupScrollBar(); + void DrawRow( const Rectangle& rRect, const TEntry_Impl pEntry ); + bool HandleTabKey( bool bReverse ); + bool HandleCursorKey( USHORT nKeyCode ); + bool FindEntryPos( const TEntry_Impl pEntry, long nStart, long nEnd, long &nFound ); + void DeleteRemoved(); + + //----------------- + DECL_DLLPRIVATE_LINK( ScrollHdl, ScrollBar * ); + + //Index starts with 1. + //Throws an com::sun::star::lang::IllegalArgumentException, when the index is invalid. + void checkIndex(sal_Int32 pos) const; + + +public: + ExtensionBox_Impl( Dialog* pParent, TheExtensionManager *pManager ); + ~ExtensionBox_Impl(); + + virtual void MouseButtonDown( const MouseEvent& rMEvt ); + virtual void Paint( const Rectangle &rPaintRect ); + virtual void Resize(); + virtual long Notify( NotifyEvent& rNEvt ); + + const Size GetMinOutputSizePixel() const; + void SetExtraSize( long nSize ) { m_nExtraHeight = nSize; } + TEntry_Impl GetEntryData( long nPos ) { return m_vEntries[ nPos ]; } + long GetEntryCount() { return (long) m_vEntries.size(); } + Rectangle GetEntryRect( const long nPos ) const; + bool HasActive() { return m_bHasActive; } + long PointToPos( const Point& rPos ); + void SetScrollHdl( const Link& rLink ); + void DoScroll( long nDelta ); + void SetHyperlinkHdl( const Link& rLink ){ m_aClickHdl = rLink; } + virtual void RecalcAll(); + void RemoveUnlocked(); + + //----------------- + virtual void selectEntry( const long nPos ); + long addEntry( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage, + bool bLicenseMissing = false ); + void updateEntry( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage ); + void removeEntry( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage ); + + void prepareChecking(); + void checkEntries(); + + TheExtensionManager* getExtensionManager() const { return m_pManager; } + + //=================================================================================== + //These functions are used for automatic testing + + /** @return The count of the entries in the list box. */ + virtual sal_Int32 getItemCount() const; + + /** @return The index of the first selected entry in the list box. + When nothing is selected, which is the case when getItemCount returns '0', + then this function returns EXTENSION_LISTBOX_ENTRY_NOTFOUND */ + virtual sal_Int32 getSelIndex() const; + + /** @return The item name of the entry with the given index + The index starts with 0. + Throws an com::sun::star::lang::IllegalArgumentException, when the position is invalid. */ + virtual ::rtl::OUString getItemName( sal_Int32 index ) const; + + /** @return The version string of the entry with the given index + The index starts with 0. + Throws an com::sun::star::lang::IllegalArgumentException, when the position is invalid. */ + virtual ::rtl::OUString getItemVersion( sal_Int32 index ) const; + + /** @return The description string of the entry with the given index + The index starts with 0. + Throws an com::sun::star::lang::IllegalArgumentException, when the position is invalid. */ + virtual ::rtl::OUString getItemDescription( sal_Int32 index ) const; + + /** @return The publisher string of the entry with the given index + The index starts with 0. + Throws an com::sun::star::lang::IllegalArgumentException, when the position is invalid. */ + virtual ::rtl::OUString getItemPublisher( sal_Int32 index ) const; + + /** @return The link behind the publisher text of the entry with the given index + The index starts with 0. + Throws an com::sun::star::lang::IllegalArgumentException, when the position is invalid. */ + virtual ::rtl::OUString getItemPublisherLink( sal_Int32 index ) const; + + /** The entry at the given position will be selected + Index starts with 0. + Throws an com::sun::star::lang::IllegalArgumentException, when the position is invalid. */ + virtual void select( sal_Int32 pos ); + + /** The first found entry with the given name will be selected + When there was no entry found with the name, the selection doesn't change. + Please note that there might be more than one entry with the same + name, because: + 1. the name is not unique + 2. one extension can be installed as user and shared extension. + */ + virtual void select( const ::rtl::OUString & sName ); +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/dp_gui_service.cxx b/desktop/source/deployment/gui/dp_gui_service.cxx new file mode 100644 index 000000000000..c3457c629271 --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_service.cxx @@ -0,0 +1,380 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_gui_shared.hxx" +#include "dp_gui.h" +#include "dp_gui_theextmgr.hxx" +#include "cppuhelper/implbase2.hxx" +#include "cppuhelper/implementationentry.hxx" +#include "unotools/configmgr.hxx" +#include "comphelper/servicedecl.hxx" +#include "comphelper/unwrapargs.hxx" +#include <i18npool/mslangid.hxx> +#include "vcl/svapp.hxx" +#include "vcl/msgbox.hxx" +#include "com/sun/star/lang/XServiceInfo.hpp" +#include "com/sun/star/task/XJobExecutor.hpp" +#include "com/sun/star/ui/dialogs/XAsynchronousExecutableDialog.hpp" + +#include "boost/bind.hpp" +#include "license_dialog.hxx" +#include "dp_gui_dialog2.hxx" +#include "dp_gui_extensioncmdqueue.hxx" + +using namespace ::dp_misc; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +using ::rtl::OUString; + +namespace css = ::com::sun::star; +namespace dp_gui { + +//============================================================================== +class MyApp : public Application, private boost::noncopyable +{ +public: + MyApp(); + virtual ~MyApp(); + + // Application + virtual int Main(); +}; + +//______________________________________________________________________________ +MyApp::~MyApp() +{ +} + +//______________________________________________________________________________ +MyApp::MyApp() +{ +} + +//______________________________________________________________________________ +int MyApp::Main() +{ + return EXIT_SUCCESS; +} + +//############################################################################## + +namespace +{ + struct ProductName + : public rtl::Static< String, ProductName > {}; + struct Version + : public rtl::Static< String, Version > {}; + struct AboutBoxVersion + : public rtl::Static< String, AboutBoxVersion > {}; + struct OOOVendor + : public rtl::Static< String, OOOVendor > {}; + struct Extension + : public rtl::Static< String, Extension > {}; +} + +void ReplaceProductNameHookProc( String& rStr ) +{ + static int nAll = 0, nPro = 0; + + nAll++; + if ( rStr.SearchAscii( "%PRODUCT" ) != STRING_NOTFOUND ) + { + String &rProductName = ProductName::get(); + String &rVersion = Version::get(); + String &rAboutBoxVersion = AboutBoxVersion::get(); + String &rExtension = Extension::get(); + String &rOOOVendor = OOOVendor::get(); + + if ( !rProductName.Len() ) + { + rtl::OUString aTmp; + Any aRet = ::utl::ConfigManager::GetDirectConfigProperty( ::utl::ConfigManager::PRODUCTNAME ); + aRet >>= aTmp; + rProductName = aTmp; + + aRet = ::utl::ConfigManager::GetDirectConfigProperty( ::utl::ConfigManager::PRODUCTVERSION ); + aRet >>= aTmp; + rVersion = aTmp; + + aRet = ::utl::ConfigManager::GetDirectConfigProperty( ::utl::ConfigManager::ABOUTBOXPRODUCTVERSION ); + aRet >>= aTmp; + rAboutBoxVersion = aTmp; + + aRet = ::utl::ConfigManager::GetDirectConfigProperty( ::utl::ConfigManager::OOOVENDOR ); + aRet >>= aTmp; + rOOOVendor = aTmp; + + if ( !rExtension.Len() ) + { + aRet = ::utl::ConfigManager::GetDirectConfigProperty( ::utl::ConfigManager::PRODUCTEXTENSION ); + aRet >>= aTmp; + rExtension = aTmp; + } + } + + nPro++; + rStr.SearchAndReplaceAllAscii( "%PRODUCTNAME", rProductName ); + rStr.SearchAndReplaceAllAscii( "%PRODUCTVERSION", rVersion ); + rStr.SearchAndReplaceAllAscii( "%ABOUTBOXPRODUCTVERSION", rAboutBoxVersion ); + rStr.SearchAndReplaceAllAscii( "%OOOVENDOR", rOOOVendor ); + rStr.SearchAndReplaceAllAscii( "%PRODUCTEXTENSION", rExtension ); + } +} + +//============================================================================== +class ServiceImpl + : public ::cppu::WeakImplHelper2<ui::dialogs::XAsynchronousExecutableDialog, + task::XJobExecutor> +{ + Reference<XComponentContext> const m_xComponentContext; + boost::optional< Reference<awt::XWindow> > /* const */ m_parent; + boost::optional<OUString> /* const */ m_view; + /* if true then this service is running in an unopkg process and not in an office process */ + boost::optional<sal_Bool> /* const */ m_unopkg; + boost::optional<OUString> m_extensionURL; + OUString m_initialTitle; + bool m_bShowUpdateOnly; + +public: + ServiceImpl( Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ); + + // XAsynchronousExecutableDialog + virtual void SAL_CALL setDialogTitle( OUString const & aTitle ) + throw (RuntimeException); + virtual void SAL_CALL startExecuteModal( + Reference< ui::dialogs::XDialogClosedListener > const & xListener ) + throw (RuntimeException); + + // XJobExecutor + virtual void SAL_CALL trigger( OUString const & event ) + throw (RuntimeException); +}; + +//______________________________________________________________________________ +ServiceImpl::ServiceImpl( Sequence<Any> const& args, + Reference<XComponentContext> const& xComponentContext) + : m_xComponentContext(xComponentContext), + m_bShowUpdateOnly( false ) +{ + try { + comphelper::unwrapArgs( args, m_parent, m_view, m_unopkg ); + return; + } catch (css::lang::IllegalArgumentException & ) { + } + try { + comphelper::unwrapArgs( args, m_extensionURL); + } catch (css::lang::IllegalArgumentException & ) { + } + + ResHookProc pProc = ResMgr::GetReadStringHook(); + if ( !pProc ) + ResMgr::SetReadStringHook( ReplaceProductNameHookProc ); +} + +// XAsynchronousExecutableDialog +//______________________________________________________________________________ +void ServiceImpl::setDialogTitle( OUString const & title ) + throw (RuntimeException) +{ + if ( dp_gui::TheExtensionManager::s_ExtMgr.is() ) + { + const SolarMutexGuard guard; + ::rtl::Reference< ::dp_gui::TheExtensionManager > dialog( + ::dp_gui::TheExtensionManager::get( m_xComponentContext, + m_parent ? *m_parent : Reference<awt::XWindow>(), + m_extensionURL ? *m_extensionURL : OUString() ) ); + dialog->SetText( title ); + } + else + m_initialTitle = title; +} + +//______________________________________________________________________________ +void ServiceImpl::startExecuteModal( + Reference< ui::dialogs::XDialogClosedListener > const & xListener ) + throw (RuntimeException) +{ + bool bCloseDialog = true; // only used if m_bShowUpdateOnly is true + ::std::auto_ptr<Application> app; + //ToDo: synchronize access to s_dialog !!! + if (! dp_gui::TheExtensionManager::s_ExtMgr.is()) + { + const bool bAppUp = (GetpApp() != 0); + bool bOfficePipePresent; + try { + bOfficePipePresent = dp_misc::office_is_running(); + } + catch (Exception & exc) { + if (bAppUp) { + const SolarMutexGuard guard; + std::auto_ptr<ErrorBox> box( + new ErrorBox( Application::GetActiveTopWindow(), + WB_OK, exc.Message ) ); + box->Execute(); + } + throw; + } + + if (! bOfficePipePresent) { + OSL_ASSERT( ! bAppUp ); + app.reset( new MyApp ); + if (! InitVCL( Reference<lang::XMultiServiceFactory>( + m_xComponentContext->getServiceManager(), + UNO_QUERY_THROW ) )) + throw RuntimeException( OUSTR("Cannot initialize VCL!"), + static_cast<OWeakObject *>(this) ); + AllSettings as = app->GetSettings(); + OUString slang; + if (! (::utl::ConfigManager::GetDirectConfigProperty( + ::utl::ConfigManager::LOCALE ) >>= slang)) + throw RuntimeException( OUSTR("Cannot determine language!"), + static_cast<OWeakObject *>(this) ); + as.SetUILanguage( MsLangId::convertIsoStringToLanguage( slang ) ); + app->SetSettings( as ); + String sTitle = ::utl::ConfigManager::GetDirectConfigProperty( + ::utl::ConfigManager::PRODUCTNAME).get<OUString>() + + String(static_cast<sal_Unicode>(' ')) + + ::utl::ConfigManager::GetDirectConfigProperty( + ::utl::ConfigManager::PRODUCTVERSION).get<OUString>(); + app->SetDisplayName(sTitle); + ExtensionCmdQueue::syncRepositories( m_xComponentContext ); + } + } + else + { + // When m_bShowUpdateOnly is set, we are inside the office and the user clicked + // the update notification icon in the menu bar. We must not close the extensions + // dialog after displaying the update dialog when it has been visible before + if ( m_bShowUpdateOnly ) + bCloseDialog = ! dp_gui::TheExtensionManager::s_ExtMgr->isVisible(); + } + + { + const SolarMutexGuard guard; + ::rtl::Reference< ::dp_gui::TheExtensionManager > myExtMgr( + ::dp_gui::TheExtensionManager::get( + m_xComponentContext, + m_parent ? *m_parent : Reference<awt::XWindow>(), + m_extensionURL ? *m_extensionURL : OUString() ) ); + myExtMgr->createDialog( false ); + if (m_initialTitle.getLength() > 0) { + myExtMgr->SetText( m_initialTitle ); + m_initialTitle = OUString(); + } + if ( m_bShowUpdateOnly ) + { + myExtMgr->checkUpdates( true, !bCloseDialog ); + if ( bCloseDialog ) + myExtMgr->Close(); + else + myExtMgr->ToTop( TOTOP_RESTOREWHENMIN ); + } + else + { + myExtMgr->Show(); + myExtMgr->ToTop( TOTOP_RESTOREWHENMIN ); + } + } + + if (app.get() != 0) { + Application::Execute(); + DeInitVCL(); + } + + if (xListener.is()) + xListener->dialogClosed( + ui::dialogs::DialogClosedEvent( + static_cast< ::cppu::OWeakObject * >(this), + sal_Int16(0)) ); +} + +// XJobExecutor +//______________________________________________________________________________ +void ServiceImpl::trigger( OUString const &rEvent ) throw (RuntimeException) +{ + if ( rEvent == OUSTR("SHOW_UPDATE_DIALOG") ) + m_bShowUpdateOnly = true; + else + m_bShowUpdateOnly = false; + + startExecuteModal( Reference< ui::dialogs::XDialogClosedListener >() ); +} + +namespace sdecl = comphelper::service_decl; +sdecl::class_<ServiceImpl, sdecl::with_args<true> > serviceSI; +sdecl::ServiceDecl const serviceDecl( + serviceSI, + "com.sun.star.comp.deployment.ui.PackageManagerDialog", + "com.sun.star.deployment.ui.PackageManagerDialog" ); + +sdecl::class_<LicenseDialog, sdecl::with_args<true> > licenseSI; +sdecl::ServiceDecl const licenseDecl( + licenseSI, + "com.sun.star.comp.deployment.ui.LicenseDialog", + "com.sun.star.deployment.ui.LicenseDialog" ); + +sdecl::class_<UpdateRequiredDialogService, sdecl::with_args<true> > updateSI; +sdecl::ServiceDecl const updateDecl( + updateSI, + "com.sun.star.comp.deployment.ui.UpdateRequiredDialog", + "com.sun.star.deployment.ui.UpdateRequiredDialog" ); +} // namespace dp_gui + +extern "C" { + +void SAL_CALL component_getImplementationEnvironment( + const sal_Char ** ppEnvTypeName, uno_Environment ** ) +{ + *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; +} + +sal_Bool SAL_CALL component_writeInfo( + lang::XMultiServiceFactory * pServiceManager, + registry::XRegistryKey * pRegistryKey ) +{ + return component_writeInfoHelper( + pServiceManager, pRegistryKey, dp_gui::serviceDecl, dp_gui::licenseDecl, dp_gui::updateDecl ); +} + +void * SAL_CALL component_getFactory( + sal_Char const * pImplName, + lang::XMultiServiceFactory * pServiceManager, + registry::XRegistryKey * pRegistryKey ) +{ + return component_getFactoryHelper( + pImplName, pServiceManager, pRegistryKey, dp_gui::serviceDecl, dp_gui::licenseDecl, dp_gui::updateDecl ); +} + +} // extern "C" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/dp_gui_shared.hxx b/desktop/source/deployment/gui/dp_gui_shared.hxx new file mode 100644 index 000000000000..50eb9c393f45 --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_shared.hxx @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if !defined INCLUDED_DP_GUI_SHARED_HXX +#define INCLUDED_DP_GUI_SHARED_HXX + +#include "unotools/configmgr.hxx" +#include "rtl/instance.hxx" +#include "tools/resmgr.hxx" + + +namespace css = ::com::sun::star; + +namespace dp_gui { + +struct DeploymentGuiResMgr : + public ::rtl::StaticWithInit< ResMgr *, DeploymentGuiResMgr > { + ResMgr * operator () () { + return ResMgr::CreateResMgr( "deploymentgui" ); + } +}; + +struct BrandName : public ::rtl::StaticWithInit<const ::rtl::OUString, BrandName> { + const ::rtl::OUString operator () () { + return ::utl::ConfigManager::GetDirectConfigProperty( + ::utl::ConfigManager::PRODUCTNAME ).get< ::rtl::OUString >(); + } +}; + +class DpGuiResId : public ResId +{ +public: + DpGuiResId( USHORT nId ):ResId( nId, *DeploymentGuiResMgr::get() ) {} +}; + +} // namespace dp_gui + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/dp_gui_theextmgr.cxx b/desktop/source/deployment/gui/dp_gui_theextmgr.cxx new file mode 100644 index 000000000000..cac4ae05f65e --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_theextmgr.cxx @@ -0,0 +1,533 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "vcl/svapp.hxx" +#include "vcl/msgbox.hxx" + +#include "osl/mutex.hxx" + +#include "toolkit/helper/vclunohelper.hxx" + +#include "com/sun/star/beans/XPropertySet.hpp" + +#include "dp_gui_dialog2.hxx" +#include "dp_gui_extensioncmdqueue.hxx" +#include "dp_gui_theextmgr.hxx" +#include "dp_gui_theextmgr.hxx" +#include "dp_identifier.hxx" +#include "dp_update.hxx" + +#define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) + +#define USER_PACKAGE_MANAGER OUSTR("user") +#define SHARED_PACKAGE_MANAGER OUSTR("shared") +#define BUNDLED_PACKAGE_MANAGER OUSTR("bundled") + +using namespace ::com::sun::star; +using ::rtl::OUString; + +namespace dp_gui { + +//------------------------------------------------------------------------------ + +::rtl::Reference< TheExtensionManager > TheExtensionManager::s_ExtMgr; + +//------------------------------------------------------------------------------ +// TheExtensionManager +//------------------------------------------------------------------------------ + +TheExtensionManager::TheExtensionManager( Window *pParent, + const uno::Reference< uno::XComponentContext > &xContext ) : + m_xContext( xContext ), + m_pParent( pParent ), + m_pExtMgrDialog( NULL ), + m_pUpdReqDialog( NULL ), + m_pExecuteCmdQueue( NULL ) +{ + m_xExtensionManager = deployment::ExtensionManager::get( xContext ); + m_xExtensionManager->addModifyListener( this ); + + uno::Reference< lang::XMultiServiceFactory > xConfig( + xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.configuration.ConfigurationProvider"), xContext ), uno::UNO_QUERY_THROW); + uno::Any args[1]; + beans::PropertyValue aValue( OUSTR("nodepath"), 0, uno::Any( OUSTR("/org.openoffice.Office.OptionsDialog/Nodes") ), + beans::PropertyState_DIRECT_VALUE ); + args[0] <<= aValue; + m_xNameAccessNodes = uno::Reference< container::XNameAccess >( + xConfig->createInstanceWithArguments( OUSTR("com.sun.star.configuration.ConfigurationAccess"), + uno::Sequence< uno::Any >( args, 1 )), uno::UNO_QUERY_THROW); + + // get the 'get more extensions here' url + uno::Reference< container::XNameAccess > xNameAccessRepositories; + beans::PropertyValue aValue2( OUSTR("nodepath"), 0, uno::Any( OUSTR("/org.openoffice.Office.ExtensionManager/ExtensionRepositories") ), + beans::PropertyState_DIRECT_VALUE ); + args[0] <<= aValue2; + xNameAccessRepositories = uno::Reference< container::XNameAccess > ( + xConfig->createInstanceWithArguments( OUSTR("com.sun.star.configuration.ConfigurationAccess"), + uno::Sequence< uno::Any >( args, 1 )), uno::UNO_QUERY_THROW); + try + { //throws css::container::NoSuchElementException, css::lang::WrappedTargetException + uno::Any value = xNameAccessRepositories->getByName( OUSTR( "WebsiteLink" ) ); + m_sGetExtensionsURL = value.get< OUString > (); + } + catch ( uno::Exception& ) + {} + + if ( dp_misc::office_is_running() ) + { + // the registration should be done after the construction has been ended + // otherwise an exception prevents object creation, but it is registered as a listener + m_xDesktop.set( xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.frame.Desktop"), xContext ), uno::UNO_QUERY ); + if ( m_xDesktop.is() ) + m_xDesktop->addTerminateListener( this ); + } +} + +//------------------------------------------------------------------------------ +TheExtensionManager::~TheExtensionManager() +{ + if ( m_pUpdReqDialog ) + delete m_pUpdReqDialog; + if ( m_pExtMgrDialog ) + delete m_pExtMgrDialog; + if ( m_pExecuteCmdQueue ) + delete m_pExecuteCmdQueue; +} + +//------------------------------------------------------------------------------ +void TheExtensionManager::createDialog( const bool bCreateUpdDlg ) +{ + const SolarMutexGuard guard; + + if ( bCreateUpdDlg ) + { + if ( !m_pUpdReqDialog ) + { + m_pUpdReqDialog = new UpdateRequiredDialog( NULL, this ); + delete m_pExecuteCmdQueue; + m_pExecuteCmdQueue = new ExtensionCmdQueue( (DialogHelper*) m_pUpdReqDialog, this, m_xContext ); + createPackageList(); + } + } + else if ( !m_pExtMgrDialog ) + { + m_pExtMgrDialog = new ExtMgrDialog( m_pParent, this ); + delete m_pExecuteCmdQueue; + m_pExecuteCmdQueue = new ExtensionCmdQueue( (DialogHelper*) m_pExtMgrDialog, this, m_xContext ); + m_pExtMgrDialog->setGetExtensionsURL( m_sGetExtensionsURL ); + createPackageList(); + } +} + +//------------------------------------------------------------------------------ +void TheExtensionManager::Show() +{ + const SolarMutexGuard guard; + + getDialog()->Show(); +} + +//------------------------------------------------------------------------------ +void TheExtensionManager::SetText( const ::rtl::OUString &rTitle ) +{ + const SolarMutexGuard guard; + + getDialog()->SetText( rTitle ); +} + +//------------------------------------------------------------------------------ +void TheExtensionManager::ToTop( USHORT nFlags ) +{ + const SolarMutexGuard guard; + + getDialog()->ToTop( nFlags ); +} + +//------------------------------------------------------------------------------ +bool TheExtensionManager::Close() +{ + if ( m_pExtMgrDialog ) + return m_pExtMgrDialog->Close(); + else if ( m_pUpdReqDialog ) + return m_pUpdReqDialog->Close(); + else + return true; +} + +//------------------------------------------------------------------------------ +sal_Int16 TheExtensionManager::execute() +{ + sal_Int16 nRet = 0; + + if ( m_pUpdReqDialog ) + { + nRet = m_pUpdReqDialog->Execute(); + delete m_pUpdReqDialog; + m_pUpdReqDialog = NULL; + } + + return nRet; +} + +//------------------------------------------------------------------------------ +bool TheExtensionManager::isVisible() +{ + return getDialog()->IsVisible(); +} + +//------------------------------------------------------------------------------ +bool TheExtensionManager::checkUpdates( bool /* bShowUpdateOnly */, bool /*bParentVisible*/ ) +{ + std::vector< uno::Reference< deployment::XPackage > > vEntries; + uno::Sequence< uno::Sequence< uno::Reference< deployment::XPackage > > > xAllPackages; + + try { + xAllPackages = m_xExtensionManager->getAllExtensions( uno::Reference< task::XAbortChannel >(), + uno::Reference< ucb::XCommandEnvironment >() ); + } catch ( deployment::DeploymentException & ) { + return false; + } catch ( ucb::CommandFailedException & ) { + return false; + } catch ( ucb::CommandAbortedException & ) { + return false; + } catch ( lang::IllegalArgumentException & e ) { + throw uno::RuntimeException( e.Message, e.Context ); + } + + for ( sal_Int32 i = 0; i < xAllPackages.getLength(); ++i ) + { + uno::Reference< deployment::XPackage > xPackage = dp_misc::getExtensionWithHighestVersion(xAllPackages[i]); + OSL_ASSERT(xPackage.is()); + if ( xPackage.is() ) + { + vEntries.push_back( xPackage ); + } + } + + m_pExecuteCmdQueue->checkForUpdates( vEntries ); + return true; +} + +//------------------------------------------------------------------------------ +bool TheExtensionManager::installPackage( const OUString &rPackageURL, bool bWarnUser ) +{ + if ( rPackageURL.getLength() == 0 ) + return false; + + createDialog( false ); + + bool bInstall = true; + bool bInstallForAll = false; + + // DV! missing function is read only repository from extension manager + if ( !bWarnUser && ! m_xExtensionManager->isReadOnlyRepository( SHARED_PACKAGE_MANAGER ) ) + bInstall = getDialogHelper()->installForAllUsers( bInstallForAll ); + + if ( !bInstall ) + return false; + + if ( bInstallForAll ) + m_pExecuteCmdQueue->addExtension( rPackageURL, SHARED_PACKAGE_MANAGER, false ); + else + m_pExecuteCmdQueue->addExtension( rPackageURL, USER_PACKAGE_MANAGER, bWarnUser ); + + return true; +} + +//------------------------------------------------------------------------------ +bool TheExtensionManager::queryTermination() +{ + if ( dp_misc::office_is_running() ) + return true; + // the standalone application unopkg must not close ( and quit ) the dialog + // when there are still actions in the queue + return true; +} + +//------------------------------------------------------------------------------ +void TheExtensionManager::terminateDialog() +{ + if ( ! dp_misc::office_is_running() ) + { + const SolarMutexGuard guard; + delete m_pExtMgrDialog; + m_pExtMgrDialog = NULL; + delete m_pUpdReqDialog; + m_pUpdReqDialog = NULL; + Application::Quit(); + } +} + +//------------------------------------------------------------------------------ +void TheExtensionManager::createPackageList() +{ + uno::Sequence< uno::Sequence< uno::Reference< deployment::XPackage > > > xAllPackages; + + try { + xAllPackages = m_xExtensionManager->getAllExtensions( uno::Reference< task::XAbortChannel >(), + uno::Reference< ucb::XCommandEnvironment >() ); + } catch ( deployment::DeploymentException & ) { + return; + } catch ( ucb::CommandFailedException & ) { + return; + } catch ( ucb::CommandAbortedException & ) { + return; + } catch ( lang::IllegalArgumentException & e ) { + throw uno::RuntimeException( e.Message, e.Context ); + } + + for ( sal_Int32 i = 0; i < xAllPackages.getLength(); ++i ) + { + uno::Sequence< uno::Reference< deployment::XPackage > > xPackageList = xAllPackages[i]; + + for ( sal_Int32 j = 0; j < xPackageList.getLength(); ++j ) + { + uno::Reference< deployment::XPackage > xPackage = xPackageList[j]; + if ( xPackage.is() ) + { + PackageState eState = getPackageState( xPackage ); + getDialogHelper()->addPackageToList( xPackage ); + // When the package is enabled, we can stop here, otherwise we have to look for + // another version of this package + if ( ( eState == REGISTERED ) || ( eState == NOT_AVAILABLE ) ) + break; + } + } + } + + uno::Sequence< uno::Reference< deployment::XPackage > > xNoLicPackages; + xNoLicPackages = m_xExtensionManager->getExtensionsWithUnacceptedLicenses( SHARED_PACKAGE_MANAGER, + uno::Reference< ucb::XCommandEnvironment >() ); + for ( sal_Int32 i = 0; i < xNoLicPackages.getLength(); ++i ) + { + uno::Reference< deployment::XPackage > xPackage = xNoLicPackages[i]; + if ( xPackage.is() ) + { + getDialogHelper()->addPackageToList( xPackage, true ); + } + } +} + +//------------------------------------------------------------------------------ +PackageState TheExtensionManager::getPackageState( const uno::Reference< deployment::XPackage > &xPackage ) const +{ + try { + beans::Optional< beans::Ambiguous< sal_Bool > > option( + xPackage->isRegistered( uno::Reference< task::XAbortChannel >(), + uno::Reference< ucb::XCommandEnvironment >() ) ); + if ( option.IsPresent ) + { + ::beans::Ambiguous< sal_Bool > const & reg = option.Value; + if ( reg.IsAmbiguous ) + return AMBIGUOUS; + else + return reg.Value ? REGISTERED : NOT_REGISTERED; + } + else + return NOT_AVAILABLE; + } + catch ( uno::RuntimeException & ) { + throw; + } + catch ( uno::Exception & exc) { + (void) exc; + OSL_ENSURE( 0, ::rtl::OUStringToOString( exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); + return NOT_AVAILABLE; + } +} + +//------------------------------------------------------------------------------ +bool TheExtensionManager::isReadOnly( const uno::Reference< deployment::XPackage > &xPackage ) const +{ + if ( m_xExtensionManager.is() && xPackage.is() ) + { + return m_xExtensionManager->isReadOnlyRepository( xPackage->getRepositoryName() ); + } + else + return true; +} + +//------------------------------------------------------------------------------ +// The function investigates if the extension supports options. +bool TheExtensionManager::supportsOptions( const uno::Reference< deployment::XPackage > &xPackage ) const +{ + bool bOptions = false; + + if ( ! xPackage->isBundle() ) + return false; + + beans::Optional< OUString > aId = xPackage->getIdentifier(); + + //a bundle must always have an id + OSL_ASSERT( aId.IsPresent ); + + //iterate over all available nodes + uno::Sequence< OUString > seqNames = m_xNameAccessNodes->getElementNames(); + + for ( int i = 0; i < seqNames.getLength(); i++ ) + { + uno::Any anyNode = m_xNameAccessNodes->getByName( seqNames[i] ); + //If we have a node then then it must contain the set of leaves. This is part of OptionsDialog.xcs + uno::Reference< XInterface> xIntNode = anyNode.get< uno::Reference< XInterface > >(); + uno::Reference< container::XNameAccess > xNode( xIntNode, uno::UNO_QUERY_THROW ); + + uno::Any anyLeaves = xNode->getByName( OUSTR("Leaves") ); + uno::Reference< XInterface > xIntLeaves = anyLeaves.get< uno::Reference< XInterface > >(); + uno::Reference< container::XNameAccess > xLeaves( xIntLeaves, uno::UNO_QUERY_THROW ); + + //iterate over all available leaves + uno::Sequence< OUString > seqLeafNames = xLeaves->getElementNames(); + for ( int j = 0; j < seqLeafNames.getLength(); j++ ) + { + uno::Any anyLeaf = xLeaves->getByName( seqLeafNames[j] ); + uno::Reference< XInterface > xIntLeaf = anyLeaf.get< uno::Reference< XInterface > >(); + uno::Reference< beans::XPropertySet > xLeaf( xIntLeaf, uno::UNO_QUERY_THROW ); + //investigate the Id property if it matches the extension identifier which + //has been passed in. + uno::Any anyValue = xLeaf->getPropertyValue( OUSTR("Id") ); + + OUString sId = anyValue.get< OUString >(); + if ( sId == aId.Value ) + { + bOptions = true; + break; + } + } + if ( bOptions ) + break; + } + return bOptions; +} + +//------------------------------------------------------------------------------ +// XEventListener +void TheExtensionManager::disposing( lang::EventObject const & rEvt ) + throw ( uno::RuntimeException ) +{ + bool shutDown = (rEvt.Source == m_xDesktop); + + if ( shutDown && m_xDesktop.is() ) + { + m_xDesktop->removeTerminateListener( this ); + m_xDesktop.clear(); + } + + if ( shutDown ) + { + if ( dp_misc::office_is_running() ) + { + const SolarMutexGuard guard; + delete m_pExtMgrDialog; + m_pExtMgrDialog = NULL; + delete m_pUpdReqDialog; + m_pUpdReqDialog = NULL; + } + s_ExtMgr.clear(); + } +} + +//------------------------------------------------------------------------------ +// XTerminateListener +void TheExtensionManager::queryTermination( ::lang::EventObject const & ) + throw ( frame::TerminationVetoException, uno::RuntimeException ) +{ + DialogHelper *pDialogHelper = getDialogHelper(); + + if ( m_pExecuteCmdQueue->isBusy() || ( pDialogHelper && pDialogHelper->isBusy() ) ) + { + ToTop( TOTOP_RESTOREWHENMIN ); + throw frame::TerminationVetoException( + OUSTR("The office cannot be closed while the Extension Manager is running"), + uno::Reference<XInterface>(static_cast<frame::XTerminateListener*>(this), uno::UNO_QUERY)); + } + else + { + if ( m_pExtMgrDialog ) + m_pExtMgrDialog->Close(); + if ( m_pUpdReqDialog ) + m_pUpdReqDialog->Close(); + } +} + +//------------------------------------------------------------------------------ +void TheExtensionManager::notifyTermination( ::lang::EventObject const & rEvt ) + throw ( uno::RuntimeException ) +{ + disposing( rEvt ); +} + +//------------------------------------------------------------------------------ +// XModifyListener +void TheExtensionManager::modified( ::lang::EventObject const & /*rEvt*/ ) + throw ( uno::RuntimeException ) +{ + getDialogHelper()->prepareChecking(); + createPackageList(); + getDialogHelper()->checkEntries(); +} + +//------------------------------------------------------------------------------ +::rtl::Reference< TheExtensionManager > TheExtensionManager::get( const uno::Reference< uno::XComponentContext > &xContext, + const uno::Reference< awt::XWindow > &xParent, + const OUString & extensionURL ) +{ + if ( s_ExtMgr.is() ) + { + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + if ( extensionURL.getLength() ) + s_ExtMgr->installPackage( extensionURL, true ); + return s_ExtMgr; + } + + Window * pParent = DIALOG_NO_PARENT; + if ( xParent.is() ) + pParent = VCLUnoHelper::GetWindow(xParent); + + ::rtl::Reference<TheExtensionManager> that( new TheExtensionManager( pParent, xContext ) ); + + const SolarMutexGuard guard; + if ( ! s_ExtMgr.is() ) + { + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + s_ExtMgr = that; + } + + if ( extensionURL.getLength() ) + s_ExtMgr->installPackage( extensionURL, true ); + + return s_ExtMgr; +} + +} //namespace dp_gui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/dp_gui_theextmgr.hxx b/desktop/source/deployment/gui/dp_gui_theextmgr.hxx new file mode 100644 index 000000000000..8289a3469aa0 --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_theextmgr.hxx @@ -0,0 +1,133 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_DP_GUI_THEEXTMGR_HXX +#define INCLUDED_DP_GUI_THEEXTMGR_HXX + +#include "comphelper/sequence.hxx" + +#include "cppuhelper/implbase2.hxx" + +#include "com/sun/star/container/XNameAccess.hpp" +#include "com/sun/star/deployment/XExtensionManager.hpp" +#include "com/sun/star/deployment/ExtensionManager.hpp" +#include "com/sun/star/frame/XDesktop.hpp" +#include "com/sun/star/frame/XTerminateListener.hpp" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/util/XModifyListener.hpp" + +#include "dp_gui.h" +#include "dp_gui_dialog2.hxx" +#include "dp_gui_updatedata.hxx" + +//============================================================================== +namespace dp_gui { + +//------------------------------------------------------------------------------ +class ExtensionCmdQueue; + +//------------------------------------------------------------------------------ +class TheExtensionManager : + public ::cppu::WeakImplHelper2< ::com::sun::star::frame::XTerminateListener, + ::com::sun::star::util::XModifyListener > +{ +private: + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > m_xContext; + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDesktop > m_xDesktop; + ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XExtensionManager > m_xExtensionManager; + ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > m_xNameAccessNodes; + + Window *m_pParent; + ExtMgrDialog *m_pExtMgrDialog; + UpdateRequiredDialog *m_pUpdReqDialog; + ExtensionCmdQueue *m_pExecuteCmdQueue; + + ::rtl::OUString m_sGetExtensionsURL; + + void createPackageList(); + +public: + static ::rtl::Reference<TheExtensionManager> s_ExtMgr; + + TheExtensionManager( Window * pParent, + const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > &xContext ); + ~TheExtensionManager(); + + void createDialog( const bool bCreateUpdDlg ); + sal_Int16 execute(); + + Dialog* getDialog() { return m_pExtMgrDialog ? (Dialog*) m_pExtMgrDialog : (Dialog*) m_pUpdReqDialog; } + DialogHelper* getDialogHelper() { return m_pExtMgrDialog ? (DialogHelper*) m_pExtMgrDialog : (DialogHelper*) m_pUpdReqDialog; } + ExtensionCmdQueue* getCmdQueue() const { return m_pExecuteCmdQueue; } + + void SetText( const ::rtl::OUString &rTitle ); + void Show(); + void ToTop( USHORT nFlags ); + bool Close(); + bool isVisible(); + + //----------------- + bool checkUpdates( bool showUpdateOnly, bool parentVisible ); + bool installPackage( const ::rtl::OUString &rPackageURL, bool bWarnUser = false ); + + bool queryTermination(); + void terminateDialog(); + + // Tools + bool supportsOptions( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage ) const; + PackageState getPackageState( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage ) const; + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > getContext() const { return m_xContext; } + ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XExtensionManager > getExtensionManager() const { return m_xExtensionManager; } + bool isReadOnly( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage ) const; + + //----------------- + static ::rtl::Reference<TheExtensionManager> get( + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext> const & xContext, + ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindow> const & xParent = 0, + ::rtl::OUString const & view = ::rtl::OUString() ); + + // XEventListener + virtual void SAL_CALL disposing( ::com::sun::star::lang::EventObject const & evt ) + throw (::com::sun::star::uno::RuntimeException); + + // XTerminateListener + virtual void SAL_CALL queryTermination( ::com::sun::star::lang::EventObject const & evt ) + throw (::com::sun::star::frame::TerminationVetoException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL notifyTermination( ::com::sun::star::lang::EventObject const & evt ) + throw (::com::sun::star::uno::RuntimeException); + + // XModifyListener + virtual void SAL_CALL modified( ::com::sun::star::lang::EventObject const & evt ) + throw (::com::sun::star::uno::RuntimeException); +}; + +} // namespace dp_gui + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/dp_gui_thread.cxx b/desktop/source/deployment/gui/dp_gui_thread.cxx new file mode 100644 index 000000000000..1ad857ad7b86 --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_thread.cxx @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "sal/config.h" + +#include <cstddef> +#include <new> + +#include "osl/thread.hxx" +#include "salhelper/simplereferenceobject.hxx" + +#include "dp_gui_thread.hxx" + +using dp_gui::Thread; + +Thread::Thread() {} + +void Thread::launch() { + // Assumption is that osl::Thread::create returns normally iff it causes + // osl::Thread::run to start executing: + acquire(); + try { + create(); + } catch (...) { + release(); + throw; + } +} + +void * Thread::operator new(std::size_t size) + throw (std::bad_alloc) +{ + return SimpleReferenceObject::operator new(size); +} + +void Thread::operator delete(void * p) throw () { + SimpleReferenceObject::operator delete(p); +} + +Thread::~Thread() {} + +void Thread::run() { + try { + execute(); + } catch (...) { + // Work around the problem that onTerminated is not called if run throws + // an exception: + onTerminated(); + throw; + } +} + +void Thread::onTerminated() { + release(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/dp_gui_thread.hxx b/desktop/source/deployment/gui/dp_gui_thread.hxx new file mode 100644 index 000000000000..624624b0cb3f --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_thread.hxx @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_GUI_DP_GUI_THREAD_HXX +#define INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_GUI_DP_GUI_THREAD_HXX + +#include "sal/config.h" + +#include <cstddef> +#include <new> +#include "osl/thread.hxx" +#include "sal/types.h" +#include "salhelper/simplereferenceobject.hxx" + +/// @HTML + +namespace dp_gui { + +/** + A safe encapsulation of <code>osl::Thread</code>. +*/ +class Thread: public salhelper::SimpleReferenceObject, private osl::Thread { +public: + Thread(); + + /** + Launch the thread. + + <p>This function must be called at most once.</p> + */ + void launch(); + + using osl::Thread::join; + + static void * operator new(std::size_t size) throw (std::bad_alloc); + + static void operator delete(void * p) throw (); + +protected: + virtual ~Thread(); + + /** + The main function executed by the thread. + + <p>Any exceptions terminate the thread and are effectively ignored.</p> + */ + virtual void execute() = 0; + +private: + Thread(Thread &); // not defined + void operator =(Thread &); // not defined + + virtual void SAL_CALL run(); + + virtual void SAL_CALL onTerminated(); +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/dp_gui_updatedata.hxx b/desktop/source/deployment/gui/dp_gui_updatedata.hxx new file mode 100644 index 000000000000..d64fe351673d --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_updatedata.hxx @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#if ! defined INCLUDED_DP_GUI_UPDATEDATA_HXX +#define INCLUDED_DP_GUI_UPDATEDATA_HXX + +#include "sal/config.h" +#include "rtl/ustring.hxx" +#include "com/sun/star/uno/Reference.hxx" + +#include <boost/shared_ptr.hpp> + + +namespace com { namespace sun { namespace star { namespace deployment { + class XPackage; +}}}} +namespace com { namespace sun { namespace star { namespace xml { namespace dom { + class XNode; +}}}}} + + +namespace dp_gui { + +struct UpdateData +{ + UpdateData( ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > const & aExt): + bIsShared(false), aInstalledPackage(aExt){}; + + //When entries added to the listbox then there can be one for the user update and one + //for the shared update. However, both list entries will contain the same UpdateData. + //isShared is used to indicate which one is used for the shared entry. + bool bIsShared; + + //The currently installed extension which is going to be updated. If the extension exist in + //multiple repositories then it is the one with the highest version. + ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > aInstalledPackage; + + //The version of the update + ::rtl::OUString updateVersion; + + //For online update + // ====================== + // The content of the update information. + //Only if aUpdateInfo is set then there is an online update available with a better version + //than any of the currently installed extensions with the same identifier. + ::com::sun::star::uno::Reference< ::com::sun::star::xml::dom::XNode > aUpdateInfo; + //The URL of the locally downloaded extension. It will only be set if there were no errors + //during the download + ::rtl::OUString sLocalURL; + //The URL of the website wher the download can be obtained. + ::rtl::OUString sWebsiteURL; + + //For local update + //===================== + //The locale extension which is used as update for the user or shared repository. + //If set then the data for the online update (aUpdateInfo, sLocalURL, sWebsiteURL) + //are to be ignored. + ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > + aUpdateSource; +}; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/dp_gui_updatedialog.cxx b/desktop/source/deployment/gui/dp_gui_updatedialog.cxx new file mode 100644 index 000000000000..bd5282a251ad --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_updatedialog.cxx @@ -0,0 +1,1221 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "sal/config.h" + +#include <cstddef> +#include <limits> +#include <map> +#include <memory> +#include <utility> +#include <vector> + + +#include "boost/optional.hpp" +#include "com/sun/star/awt/Rectangle.hpp" +#include "com/sun/star/awt/WindowAttribute.hpp" +#include "com/sun/star/awt/WindowClass.hpp" +#include "com/sun/star/awt/WindowDescriptor.hpp" +#include "com/sun/star/awt/XThrobber.hpp" +#include "com/sun/star/awt/XToolkit.hpp" +#include "com/sun/star/awt/XWindow.hpp" +#include "com/sun/star/awt/XWindowPeer.hpp" +#include "com/sun/star/beans/NamedValue.hpp" +#include "com/sun/star/beans/Optional.hpp" +#include "com/sun/star/beans/PropertyValue.hpp" +#include "com/sun/star/container/XNameAccess.hpp" +#include "com/sun/star/deployment/DeploymentException.hpp" +#include "com/sun/star/deployment/UpdateInformationProvider.hpp" +#include "com/sun/star/deployment/XPackage.hpp" +#include "com/sun/star/deployment/XExtensionManager.hpp" +#include "com/sun/star/deployment/ExtensionManager.hpp" +#include "com/sun/star/deployment/XUpdateInformationProvider.hpp" +#include "com/sun/star/frame/XDesktop.hpp" +#include "com/sun/star/frame/XDispatch.hpp" +#include "com/sun/star/frame/XDispatchProvider.hpp" +#include "com/sun/star/lang/IllegalArgumentException.hpp" +#include "com/sun/star/lang/XMultiComponentFactory.hpp" +#include "com/sun/star/system/SystemShellExecuteFlags.hpp" +#include "com/sun/star/system/XSystemShellExecute.hpp" +#include "com/sun/star/task/XAbortChannel.hpp" +#include "com/sun/star/task/XJob.hpp" +#include "com/sun/star/ucb/CommandAbortedException.hpp" +#include "com/sun/star/ucb/CommandFailedException.hpp" +#include "com/sun/star/ucb/XCommandEnvironment.hpp" +#include "com/sun/star/uno/Any.hxx" +#include "com/sun/star/uno/Exception.hpp" +#include "com/sun/star/uno/Reference.hxx" +#include "com/sun/star/uno/RuntimeException.hpp" +#include "com/sun/star/uno/Sequence.hxx" +#include "com/sun/star/uno/XInterface.hpp" +#include "com/sun/star/util/URL.hpp" +#include "com/sun/star/util/XURLTransformer.hpp" +#include "com/sun/star/xml/dom/XElement.hpp" +#include "com/sun/star/xml/dom/XNode.hpp" +#include "osl/diagnose.h" +#include "rtl/bootstrap.hxx" +#include "rtl/ref.hxx" +#include "rtl/string.h" +#include "rtl/ustrbuf.hxx" +#include "rtl/ustring.h" +#include "rtl/ustring.hxx" +#include "sal/types.h" +#include "svtools/svlbitm.hxx" +#include "svtools/svlbox.hxx" +#include <svtools/controldims.hrc> +#include "svx/checklbx.hxx" +#include "tools/gen.hxx" +#include "tools/link.hxx" +#include "tools/resid.hxx" +#include "tools/resmgr.hxx" +#include "tools/solar.h" +#include "tools/string.hxx" +#include "vcl/button.hxx" +#include "vcl/dialog.hxx" +#include "vcl/fixed.hxx" +#include "vcl/image.hxx" +#include "vcl/msgbox.hxx" +#include "vcl/svapp.hxx" +#include "osl/mutex.hxx" + +#include "comphelper/processfactory.hxx" + +#include "dp_dependencies.hxx" +#include "dp_descriptioninfoset.hxx" +#include "dp_identifier.hxx" +#include "dp_version.hxx" +#include "dp_misc.h" +#include "dp_update.hxx" + +#include "dp_gui.h" +#include "dp_gui.hrc" +#include "dp_gui_thread.hxx" +#include "dp_gui_updatedata.hxx" +#include "dp_gui_updatedialog.hxx" +#include "dp_gui_shared.hxx" + +class KeyEvent; +class MouseEvent; +class Window; +namespace com { namespace sun { namespace star { namespace uno { + class XComponentContext; +} } } } + +namespace css = ::com::sun::star; + +using dp_gui::UpdateDialog; + +namespace { + +static sal_Unicode const LF = 0x000A; +static sal_Unicode const CR = 0x000D; + +enum Kind { ENABLED_UPDATE, DISABLED_UPDATE, GENERAL_ERROR, SPECIFIC_ERROR }; + +rtl::OUString confineToParagraph(rtl::OUString const & text) { + // Confine arbitrary text to a single paragraph in a dp_gui::AutoScrollEdit. + // This assumes that U+000A and U+000D are the only paragraph separators in + // a dp_gui::AutoScrollEdit, and that replacing them with a single space + // each is acceptable: + return text.replace(LF, ' ').replace(CR, ' '); +} +} + +struct UpdateDialog::DisabledUpdate { + rtl::OUString name; + css::uno::Sequence< rtl::OUString > unsatisfiedDependencies; + // We also want to show release notes and publisher for disabled updates + ::com::sun::star::uno::Reference< ::com::sun::star::xml::dom::XNode > aUpdateInfo; +}; + +struct UpdateDialog::SpecificError { + rtl::OUString name; + rtl::OUString message; +}; + +union UpdateDialog::IndexUnion{ + std::vector< dp_gui::UpdateData >::size_type enabledUpdate; + std::vector< UpdateDialog::DisabledUpdate >::size_type disabledUpdate; + std::vector< rtl::OUString >::size_type generalError; + std::vector< UpdateDialog::SpecificError >::size_type specificError; +}; + +struct UpdateDialog::Index { + static std::auto_ptr< UpdateDialog::Index const > newEnabledUpdate( + std::vector< dp_gui::UpdateData >::size_type n); + + static std::auto_ptr< UpdateDialog::Index const > newDisabledUpdate( + std::vector< UpdateDialog::DisabledUpdate >::size_type n); + + static std::auto_ptr< UpdateDialog::Index const > newGeneralError( + std::vector< rtl::OUString >::size_type n); + + static std::auto_ptr< UpdateDialog::Index const > newSpecificError( + std::vector< UpdateDialog::SpecificError >::size_type n); + + Kind kind; + IndexUnion index; + +private: + explicit Index(Kind theKind); +}; + +std::auto_ptr< UpdateDialog::Index const > +UpdateDialog::Index::newEnabledUpdate( + std::vector< dp_gui::UpdateData >::size_type n) +{ + UpdateDialog::Index * p = new UpdateDialog::Index(ENABLED_UPDATE); + p->index.enabledUpdate = n; + return std::auto_ptr< UpdateDialog::Index const >(p); +} + +std::auto_ptr< UpdateDialog::Index const > +UpdateDialog::Index::newDisabledUpdate( + std::vector< UpdateDialog::DisabledUpdate >::size_type n) +{ + UpdateDialog::Index * p = new UpdateDialog::Index(DISABLED_UPDATE); + p->index.disabledUpdate = n; + return std::auto_ptr< UpdateDialog::Index const >(p); +} + +std::auto_ptr< UpdateDialog::Index const > UpdateDialog::Index::newGeneralError( + std::vector< rtl::OUString >::size_type n) +{ + UpdateDialog::Index * p = new UpdateDialog::Index(GENERAL_ERROR); + p->index.generalError = n; + return std::auto_ptr< UpdateDialog::Index const >(p); +} + +std::auto_ptr< UpdateDialog::Index const > +UpdateDialog::Index::newSpecificError( + std::vector< UpdateDialog::SpecificError >::size_type n) +{ + UpdateDialog::Index * p = new UpdateDialog::Index(SPECIFIC_ERROR); + p->index.specificError = n; + return std::auto_ptr< UpdateDialog::Index const >(p); +} + +UpdateDialog::Index::Index(Kind theKind): kind(theKind) {} + +class UpdateDialog::Thread: public dp_gui::Thread { +public: + Thread( + css::uno::Reference< css::uno::XComponentContext > const & context, + UpdateDialog & dialog, + const std::vector< css::uno::Reference< css::deployment::XPackage > > & vExtensionList); + + void stop(); + +private: + Thread(UpdateDialog::Thread &); // not defined + void operator =(UpdateDialog::Thread &); // not defined + + virtual ~Thread(); + + virtual void execute(); + + void handleSpecificError( + css::uno::Reference< css::deployment::XPackage > const & package, + css::uno::Any const & exception) const; + + css::uno::Sequence< css::uno::Reference< css::xml::dom::XElement > > + getUpdateInformation( + css::uno::Reference< css::deployment::XPackage > const & package, + css::uno::Sequence< rtl::OUString > const & urls, + rtl::OUString const & identifier) const; + + ::rtl::OUString getUpdateDisplayString( + dp_gui::UpdateData const & data, ::rtl::OUString const & version = ::rtl::OUString()) const; + + void prepareUpdateData( + ::com::sun::star::uno::Reference< ::com::sun::star::xml::dom::XNode > const & updateInfo, + UpdateDialog::DisabledUpdate & out_du, + dp_gui::UpdateData & out_data) const; + + bool update( + UpdateDialog::DisabledUpdate const & du, + dp_gui::UpdateData const & data) const; + + css::uno::Reference< css::uno::XComponentContext > m_context; + UpdateDialog & m_dialog; + std::vector< css::uno::Reference< css::deployment::XPackage > > m_vExtensionList; + css::uno::Reference< css::deployment::XUpdateInformationProvider > m_updateInformation; + css::uno::Reference< css::task::XInteractionHandler > m_xInteractionHdl; + + // guarded by Application::GetSolarMutex(): + css::uno::Reference< css::task::XAbortChannel > m_abort; + bool m_stop; +}; + +UpdateDialog::Thread::Thread( + css::uno::Reference< css::uno::XComponentContext > const & context, + UpdateDialog & dialog, + const std::vector< css::uno::Reference< css::deployment::XPackage > > &vExtensionList): + m_context(context), + m_dialog(dialog), + m_vExtensionList(vExtensionList), + m_updateInformation( + css::deployment::UpdateInformationProvider::create(context)), + m_stop(false) +{ + if( m_context.is() ) + { + css::uno::Reference< css::lang::XMultiComponentFactory > xServiceManager( m_context->getServiceManager() ); + + if( xServiceManager.is() ) + { + m_xInteractionHdl = css::uno::Reference< css::task::XInteractionHandler > ( + xServiceManager->createInstanceWithContext( OUSTR( "com.sun.star.task.InteractionHandler" ), m_context), + css::uno::UNO_QUERY ); + if ( m_xInteractionHdl.is() ) + m_updateInformation->setInteractionHandler( m_xInteractionHdl ); + } + } +} + +void UpdateDialog::Thread::stop() { + css::uno::Reference< css::task::XAbortChannel > abort; + { + SolarMutexGuard g; + abort = m_abort; + m_stop = true; + } + if (abort.is()) { + abort->sendAbort(); + } + m_updateInformation->cancel(); +} + +UpdateDialog::Thread::~Thread() +{ + if ( m_xInteractionHdl.is() ) + m_updateInformation->setInteractionHandler( css::uno::Reference< css::task::XInteractionHandler > () ); +} + +void UpdateDialog::Thread::execute() +{ + { + SolarMutexGuard g; + if ( m_stop ) { + return; + } + } + css::uno::Reference<css::deployment::XExtensionManager> extMgr = + css::deployment::ExtensionManager::get(m_context); + + std::vector<std::pair<css::uno::Reference<css::deployment::XPackage>, css::uno::Any > > errors; + + dp_misc::UpdateInfoMap updateInfoMap = dp_misc::getOnlineUpdateInfos( + m_context, extMgr, m_updateInformation, &m_vExtensionList, errors); + + typedef std::vector<std::pair<css::uno::Reference<css::deployment::XPackage>, + css::uno::Any> >::const_iterator ITERROR; + for (ITERROR ite = errors.begin(); ite != errors.end(); ++ite ) + handleSpecificError(ite->first, ite->second); + + for (dp_misc::UpdateInfoMap::iterator i(updateInfoMap.begin()); i != updateInfoMap.end(); ++i) + { + dp_misc::UpdateInfo const & info = i->second; + UpdateData updateData(info.extension); + DisabledUpdate disableUpdate; + //determine if online updates meet the requirements + prepareUpdateData(info.info, disableUpdate, updateData); + + //determine if the update is installed in the user or shared repository + rtl::OUString sOnlineVersion; + if (info.info.is()) + sOnlineVersion = info.version; + rtl::OUString sVersionUser; + rtl::OUString sVersionShared; + rtl::OUString sVersionBundled; + css::uno::Sequence< css::uno::Reference< css::deployment::XPackage> > extensions; + try { + extensions = extMgr->getExtensionsWithSameIdentifier( + dp_misc::getIdentifier(info.extension), info.extension->getName(), + css::uno::Reference<css::ucb::XCommandEnvironment>()); + } catch (css::lang::IllegalArgumentException& ) { + OSL_ASSERT(0); + } + OSL_ASSERT(extensions.getLength() == 3); + if (extensions[0].is() ) + sVersionUser = extensions[0]->getVersion(); + if (extensions[1].is() ) + sVersionShared = extensions[1]->getVersion(); + if (extensions[2].is() ) + sVersionBundled = extensions[2]->getVersion(); + + bool bSharedReadOnly = extMgr->isReadOnlyRepository(OUSTR("shared")); + + dp_misc::UPDATE_SOURCE sourceUser = dp_misc::isUpdateUserExtension( + bSharedReadOnly, sVersionUser, sVersionShared, sVersionBundled, sOnlineVersion); + dp_misc::UPDATE_SOURCE sourceShared = dp_misc::isUpdateSharedExtension( + bSharedReadOnly, sVersionShared, sVersionBundled, sOnlineVersion); + + css::uno::Reference<css::deployment::XPackage> updateSource; + if (sourceUser != dp_misc::UPDATE_SOURCE_NONE) + { + if (sourceUser == dp_misc::UPDATE_SOURCE_SHARED) + { + updateData.aUpdateSource = extensions[1]; + updateData.updateVersion = extensions[1]->getVersion(); + } + else if (sourceUser == dp_misc::UPDATE_SOURCE_BUNDLED) + { + updateData.aUpdateSource = extensions[2]; + updateData.updateVersion = extensions[2]->getVersion(); + } + if (!update(disableUpdate, updateData)) + return; + } + + if (sourceShared != dp_misc::UPDATE_SOURCE_NONE) + { + if (sourceShared == dp_misc::UPDATE_SOURCE_BUNDLED) + { + updateData.aUpdateSource = extensions[2]; + updateData.updateVersion = extensions[2]->getVersion(); + } + updateData.bIsShared = true; + if (!update(disableUpdate, updateData)) + return; + } + } + + + SolarMutexGuard g; + if (!m_stop) { + m_dialog.checkingDone(); + } +} + +//Parameter package can be null +void UpdateDialog::Thread::handleSpecificError( + css::uno::Reference< css::deployment::XPackage > const & package, + css::uno::Any const & exception) const +{ + UpdateDialog::SpecificError data; + if (package.is()) + data.name = package->getDisplayName(); + css::uno::Exception e; + if (exception >>= e) { + data.message = e.Message; + } + SolarMutexGuard g; + if (!m_stop) { + m_dialog.addSpecificError(data); + } +} + +::rtl::OUString UpdateDialog::Thread::getUpdateDisplayString( + dp_gui::UpdateData const & data, ::rtl::OUString const & version) const +{ + OSL_ASSERT(data.aInstalledPackage.is()); + rtl::OUStringBuffer b(data.aInstalledPackage->getDisplayName()); + b.append(static_cast< sal_Unicode >(' ')); + { + SolarMutexGuard g; + if(!m_stop) + b.append(m_dialog.m_version); + } + b.append(static_cast< sal_Unicode >(' ')); + if (version.getLength()) + b.append(version); + else + b.append(data.updateVersion); + + if (data.sWebsiteURL.getLength()) + { + b.append(static_cast< sal_Unicode >(' ')); + { + SolarMutexGuard g; + if(!m_stop) + b.append(m_dialog.m_browserbased); + } + } + return b.makeStringAndClear(); +} + +/** out_data will only be filled if all dependencies are ok. + */ +void UpdateDialog::Thread::prepareUpdateData( + css::uno::Reference< css::xml::dom::XNode > const & updateInfo, + UpdateDialog::DisabledUpdate & out_du, + dp_gui::UpdateData & out_data) const +{ + if (!updateInfo.is()) + return; + dp_misc::DescriptionInfoset infoset(m_context, updateInfo); + OSL_ASSERT(infoset.getVersion().getLength() != 0); + css::uno::Sequence< css::uno::Reference< css::xml::dom::XElement > > ds( + dp_misc::Dependencies::check(infoset)); + + out_du.aUpdateInfo = updateInfo; + out_du.unsatisfiedDependencies.realloc(ds.getLength()); + for (sal_Int32 i = 0; i < ds.getLength(); ++i) { + out_du.unsatisfiedDependencies[i] = dp_misc::Dependencies::getErrorText(ds[i]); + } + + const ::boost::optional< ::rtl::OUString> updateWebsiteURL(infoset.getLocalizedUpdateWebsiteURL()); + + out_du.name = getUpdateDisplayString(out_data, infoset.getVersion()); + + if (out_du.unsatisfiedDependencies.getLength() == 0) + { + out_data.aUpdateInfo = updateInfo; + out_data.updateVersion = infoset.getVersion(); + if (updateWebsiteURL) + out_data.sWebsiteURL = *updateWebsiteURL; + } +} + +bool UpdateDialog::Thread::update( + UpdateDialog::DisabledUpdate const & du, + dp_gui::UpdateData const & data) const +{ + bool ret = false; + if (du.unsatisfiedDependencies.getLength() == 0) + { + SolarMutexGuard g; + if (!m_stop) { + m_dialog.addEnabledUpdate(getUpdateDisplayString(data), data); + } + ret = !m_stop; + } else { + SolarMutexGuard g; + if (!m_stop) { + m_dialog.addDisabledUpdate(du); + } + ret = !m_stop; + } + return ret; +} + +// UpdateDialog ---------------------------------------------------------- +UpdateDialog::UpdateDialog( + css::uno::Reference< css::uno::XComponentContext > const & context, + Window * parent, + const std::vector<css::uno::Reference< css::deployment::XPackage > > &vExtensionList, + std::vector< dp_gui::UpdateData > * updateData): + ModalDialog(parent,DpGuiResId(RID_DLG_UPDATE)), + m_context(context), + m_checking(this, DpGuiResId(RID_DLG_UPDATE_CHECKING)), + m_update(this, DpGuiResId(RID_DLG_UPDATE_UPDATE)), + m_updates( + *this, DpGuiResId(RID_DLG_UPDATE_UPDATES), + Image(DpGuiResId(RID_DLG_UPDATE_NORMALALERT))), + m_all(this, DpGuiResId(RID_DLG_UPDATE_ALL)), + m_description(this, DpGuiResId(RID_DLG_UPDATE_DESCRIPTION)), + m_PublisherLabel(this, DpGuiResId(RID_DLG_UPDATE_PUBLISHER_LABEL)), + m_PublisherLink(this, DpGuiResId(RID_DLG_UPDATE_PUBLISHER_LINK)), + m_ReleaseNotesLabel(this, DpGuiResId(RID_DLG_UPDATE_RELEASENOTES_LABEL)), + m_ReleaseNotesLink(this, DpGuiResId(RID_DLG_UPDATE_RELEASENOTES_LINK)), + m_descriptions(this, DpGuiResId(RID_DLG_UPDATE_DESCRIPTIONS)), + m_line(this, DpGuiResId(RID_DLG_UPDATE_LINE)), + m_help(this, DpGuiResId(RID_DLG_UPDATE_HELP)), + m_ok(this, DpGuiResId(RID_DLG_UPDATE_OK)), + m_cancel(this, DpGuiResId(RID_DLG_UPDATE_CANCEL)), + m_error(String(DpGuiResId(RID_DLG_UPDATE_ERROR))), + m_none(String(DpGuiResId(RID_DLG_UPDATE_NONE))), + m_noInstallable(String(DpGuiResId(RID_DLG_UPDATE_NOINSTALLABLE))), + m_failure(String(DpGuiResId(RID_DLG_UPDATE_FAILURE))), + m_unknownError(String(DpGuiResId(RID_DLG_UPDATE_UNKNOWNERROR))), + m_noDescription(String(DpGuiResId(RID_DLG_UPDATE_NODESCRIPTION))), + m_noInstall(String(DpGuiResId(RID_DLG_UPDATE_NOINSTALL))), + m_noDependency(String(DpGuiResId(RID_DLG_UPDATE_NODEPENDENCY))), + m_noDependencyCurVer(String(DpGuiResId(RID_DLG_UPDATE_NODEPENDENCY_CUR_VER))), + m_browserbased(String(DpGuiResId(RID_DLG_UPDATE_BROWSERBASED))), + m_version(String(DpGuiResId(RID_DLG_UPDATE_VERSION))), + m_updateData(*updateData), + m_thread( + new UpdateDialog::Thread( + context, *this, vExtensionList)), + m_nFirstLineDelta(0), + m_nOneLineMissing(0) + // TODO: check! +// , +// m_extensionManagerDialog(extensionManagerDialog) +{ + OSL_ASSERT(updateData != NULL); + + m_xExtensionManager = css::deployment::ExtensionManager::get( context ); + + css::uno::Reference< css::awt::XToolkit > toolkit; + try { + toolkit = css::uno::Reference< css::awt::XToolkit >( + (css::uno::Reference< css::lang::XMultiComponentFactory >( + m_context->getServiceManager(), + css::uno::UNO_QUERY_THROW)-> + createInstanceWithContext( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("com.sun.star.awt.Toolkit")), + m_context)), + css::uno::UNO_QUERY_THROW); + } catch (css::uno::RuntimeException &) { + throw; + } catch (css::uno::Exception & e) { + throw css::uno::RuntimeException(e.Message, e.Context); + } + Control c(this, DpGuiResId(RID_DLG_UPDATE_THROBBER)); + Point pos(c.GetPosPixel()); + Size size(c.GetSizePixel()); + try { + m_throbber = css::uno::Reference< css::awt::XThrobber >( + toolkit->createWindow( + css::awt::WindowDescriptor( + css::awt::WindowClass_SIMPLE, + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Throbber")), + GetComponentInterface(), 0, + css::awt::Rectangle( + pos.X(), pos.Y(), size.Width(), size.Height()), + css::awt::WindowAttribute::SHOW)), + css::uno::UNO_QUERY_THROW); + } catch (css::lang::IllegalArgumentException & e) { + throw css::uno::RuntimeException(e.Message, e.Context); + } + m_updates.SetSelectHdl(LINK(this, UpdateDialog, selectionHandler)); + m_all.SetToggleHdl(LINK(this, UpdateDialog, allHandler)); + m_ok.SetClickHdl(LINK(this, UpdateDialog, okHandler)); + m_cancel.SetClickHdl(LINK(this, UpdateDialog, cancelHandler)); + if ( ! dp_misc::office_is_running()) + m_help.Disable(); + FreeResource(); + + initDescription(); +} + +UpdateDialog::~UpdateDialog() { + for (USHORT i = 0; i < m_updates.getItemCount(); ++i) { + delete static_cast< UpdateDialog::Index const * >( + m_updates.GetEntryData(i)); + } +} + +BOOL UpdateDialog::Close() { + m_thread->stop(); + return ModalDialog::Close(); +} + +short UpdateDialog::Execute() { + m_throbber->start(); + m_thread->launch(); + return ModalDialog::Execute(); +} + +UpdateDialog::CheckListBox::CheckListBox( + UpdateDialog & dialog, ResId const & resource, + Image const & normalStaticImage): + SvxCheckListBox( + &dialog, resource, normalStaticImage), + m_dialog(dialog) +{} + +UpdateDialog::CheckListBox::~CheckListBox() {} + +USHORT UpdateDialog::CheckListBox::getItemCount() const { + ULONG i = GetEntryCount(); + OSL_ASSERT(i <= std::numeric_limits< USHORT >::max()); + return sal::static_int_cast< USHORT >(i); +} + +void UpdateDialog::CheckListBox::MouseButtonDown(MouseEvent const & event) { + // When clicking on a selected entry in an SvxCheckListBox, the entry's + // checkbox is toggled on mouse button down: + SvxCheckListBox::MouseButtonDown(event); + m_dialog.enableOk(); +} + +void UpdateDialog::CheckListBox::MouseButtonUp(MouseEvent const & event) { + // When clicking on an entry's checkbox in an SvxCheckListBox, the entry's + // checkbox is toggled on mouse button up: + SvxCheckListBox::MouseButtonUp(event); + m_dialog.enableOk(); +} + +void UpdateDialog::CheckListBox::KeyInput(KeyEvent const & event) { + SvxCheckListBox::KeyInput(event); + m_dialog.enableOk(); +} + +void UpdateDialog::insertItem( + rtl::OUString const & name, USHORT position, + std::auto_ptr< UpdateDialog::Index const > index, SvLBoxButtonKind kind) +{ + m_updates.InsertEntry( + name, position, + const_cast< void * >(static_cast< void const * >(index.release())), + kind); + //TODO #i72487#: UpdateDialog::Index potentially leaks as the exception + // behavior of SvxCheckListBox::InsertEntry is unspecified +} + +void UpdateDialog::addAdditional( + rtl::OUString const & name, USHORT position, + std::auto_ptr< UpdateDialog::Index const > index, SvLBoxButtonKind kind) +{ + m_all.Enable(); + if (m_all.IsChecked()) { + insertItem(name, position, index, kind); + m_update.Enable(); + m_updates.Enable(); + m_description.Enable(); + m_descriptions.Enable(); + } +} + +void UpdateDialog::addEnabledUpdate( + rtl::OUString const & name, dp_gui::UpdateData const & data) +{ + std::vector< dp_gui::UpdateData >::size_type n = m_enabledUpdates.size(); + m_enabledUpdates.push_back(data); + insertItem( + name, sal::static_int_cast< USHORT >(n), + UpdateDialog::Index::newEnabledUpdate(n), + SvLBoxButtonKind_enabledCheckbox); + // position overflow is rather harmless + m_updates.CheckEntryPos(sal::static_int_cast< USHORT >(n)); + //TODO #i72487#: fragile computation; insertItem should instead return + // pos + m_update.Enable(); + m_updates.Enable(); + m_description.Enable(); + m_descriptions.Enable(); +} + +void UpdateDialog::addDisabledUpdate(UpdateDialog::DisabledUpdate const & data) +{ + std::vector< UpdateDialog::DisabledUpdate >::size_type n = + m_disabledUpdates.size(); + m_disabledUpdates.push_back(data); + addAdditional( + data.name, sal::static_int_cast< USHORT >(m_enabledUpdates.size() + n), + UpdateDialog::Index::newDisabledUpdate(n), + SvLBoxButtonKind_disabledCheckbox); + // position overflow is rather harmless +} + +void UpdateDialog::addSpecificError(UpdateDialog::SpecificError const & data) { + std::vector< UpdateDialog::SpecificError >::size_type n = + m_specificErrors.size(); + m_specificErrors.push_back(data); + addAdditional( + data.name, LISTBOX_APPEND, UpdateDialog::Index::newSpecificError(n), + SvLBoxButtonKind_staticImage); +} + +void UpdateDialog::checkingDone() { + m_checking.Hide(); + m_throbber->stop(); + css::uno::Reference< css::awt::XWindow >( + m_throbber, css::uno::UNO_QUERY_THROW)->setVisible(false); + if (m_updates.getItemCount() == 0) + { + clearDescription(); + m_description.Enable(); + m_descriptions.Enable(); + showDescription( + ( m_disabledUpdates.empty() && m_generalErrors.empty() && m_specificErrors.empty() ) + ? m_none : m_noInstallable, false ); + } + enableOk(); +} + +void UpdateDialog::enableOk() { + if (!m_checking.IsVisible()) { + m_ok.Enable(m_updates.GetCheckedEntryCount() != 0); + } +} + +// ********************************************************************************* +void UpdateDialog::createNotifyJob( bool bPrepareOnly, + css::uno::Sequence< css::uno::Sequence< rtl::OUString > > &rItemList ) +{ + if ( !dp_misc::office_is_running() ) + return; + + // notify update check job + try + { + css::uno::Reference< css::lang::XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() ); + css::uno::Reference< css::lang::XMultiServiceFactory > xConfigProvider( + xFactory->createInstance( OUSTR( "com.sun.star.configuration.ConfigurationProvider" )), + css::uno::UNO_QUERY_THROW); + + css::beans::PropertyValue aProperty; + aProperty.Name = OUSTR( "nodepath" ); + aProperty.Value = css::uno::makeAny( OUSTR("org.openoffice.Office.Addons/AddonUI/OfficeHelp/UpdateCheckJob") ); + + css::uno::Sequence< css::uno::Any > aArgumentList( 1 ); + aArgumentList[0] = css::uno::makeAny( aProperty ); + + css::uno::Reference< css::container::XNameAccess > xNameAccess( + xConfigProvider->createInstanceWithArguments( + OUSTR("com.sun.star.configuration.ConfigurationAccess"), aArgumentList ), + css::uno::UNO_QUERY_THROW ); + + css::util::URL aURL; + xNameAccess->getByName(OUSTR("URL")) >>= aURL.Complete; + + css::uno::Reference < css::util::XURLTransformer > xTransformer( xFactory->createInstance( OUSTR( "com.sun.star.util.URLTransformer" ) ), + css::uno::UNO_QUERY_THROW ); + + xTransformer->parseStrict(aURL); + + css::uno::Reference < css::frame::XDesktop > xDesktop( xFactory->createInstance( OUSTR( "com.sun.star.frame.Desktop" ) ), + css::uno::UNO_QUERY_THROW ); + css::uno::Reference< css::frame::XDispatchProvider > xDispatchProvider( xDesktop->getCurrentFrame(), + css::uno::UNO_QUERY_THROW ); + css::uno::Reference< css::frame::XDispatch > xDispatch = xDispatchProvider->queryDispatch(aURL, rtl::OUString(), 0); + + if( xDispatch.is() ) + { + css::uno::Sequence< css::beans::PropertyValue > aPropList(2); + aProperty.Name = OUSTR( "updateList" ); + aProperty.Value = css::uno::makeAny( rItemList ); + aPropList[0] = aProperty; + aProperty.Name = OUSTR( "prepareOnly" ); + aProperty.Value = css::uno::makeAny( bPrepareOnly ); + aPropList[1] = aProperty; + + xDispatch->dispatch(aURL, aPropList ); + } + } + catch( const css::uno::Exception& e ) + { + dp_misc::TRACE( OUSTR("Caught exception: ") + + e.Message + OUSTR("\n thread terminated.\n\n")); + } +} + +// ********************************************************************************* +void UpdateDialog::notifyMenubar( bool bPrepareOnly, bool bRecheckOnly ) +{ + if ( !dp_misc::office_is_running() ) + return; + + css::uno::Sequence< css::uno::Sequence< rtl::OUString > > aItemList; + sal_Int32 nCount = 0; + + if ( ! bRecheckOnly ) + { + for ( sal_Int16 i = 0; i < m_updates.getItemCount(); ++i ) + { + css::uno::Sequence< rtl::OUString > aItem(2); + + UpdateDialog::Index const * p = static_cast< UpdateDialog::Index const * >(m_updates.GetEntryData(i)); + + if ( p->kind == ENABLED_UPDATE ) + { + dp_gui::UpdateData aUpdData = m_enabledUpdates[ p->index.enabledUpdate ]; + aItem[0] = dp_misc::getIdentifier( aUpdData.aInstalledPackage ); + + dp_misc::DescriptionInfoset aInfoset( m_context, aUpdData.aUpdateInfo ); + aItem[1] = aInfoset.getVersion(); + } + else if ( p->kind == DISABLED_UPDATE ) + continue; + else + continue; + + aItemList.realloc( nCount + 1 ); + aItemList[ nCount ] = aItem; + nCount += 1; + } + } + createNotifyJob( bPrepareOnly, aItemList ); +} + +// ********************************************************************************* + +void UpdateDialog::initDescription() +{ + m_PublisherLabel.Hide(); + m_PublisherLink.Hide(); + m_ReleaseNotesLabel.Hide(); + m_ReleaseNotesLink.Hide(); + m_descriptions.Hide(); + + Link aLink = LINK( this, UpdateDialog, hyperlink_clicked ); + m_PublisherLink.SetClickHdl( aLink ); + m_ReleaseNotesLink.SetClickHdl( aLink ); + + long nTextWidth = m_PublisherLabel.GetCtrlTextWidth( m_PublisherLabel.GetText() ); + long nTemp = m_ReleaseNotesLabel.GetTextWidth( m_ReleaseNotesLabel.GetText() ); + if ( nTemp > nTextWidth ) + nTextWidth = nTemp; + nTextWidth = nTextWidth * 110 / 100; + + Size aNewSize = m_PublisherLabel.GetSizePixel(); + if ( nTextWidth > aNewSize.Width() ) + { + long nDelta = nTextWidth - aNewSize.Width(); + aNewSize.Width() = nTextWidth; + m_PublisherLabel.SetSizePixel( aNewSize ); + m_ReleaseNotesLabel.SetSizePixel( aNewSize ); + + aNewSize = m_PublisherLink.GetSizePixel(); + aNewSize.Width() = aNewSize.Width() - nDelta; + Point aNewPos = m_PublisherLink.GetPosPixel(); + aNewPos.X() = aNewPos.X() + nDelta; + m_PublisherLink.SetPosSizePixel( aNewPos, aNewSize ); + aNewPos.Y() = m_ReleaseNotesLink.GetPosPixel().Y(); + m_ReleaseNotesLink.SetPosSizePixel( aNewPos, aNewSize ); + } + + m_aFirstLinePos = m_descriptions.GetPosPixel(); + m_aFirstLineSize = m_descriptions.GetSizePixel(); + Size aMarginSize = LogicToPixel( Size( RSC_SP_CTRL_GROUP_X, RSC_SP_CTRL_GROUP_Y ), MAP_APPFONT ); + Point aThirdLinePos = m_ReleaseNotesLabel.GetPosPixel(); + aThirdLinePos.Y() = aThirdLinePos.Y() + m_ReleaseNotesLabel.GetSizePixel().Height() + aMarginSize.Height(); + m_nFirstLineDelta = aThirdLinePos.Y() - m_aFirstLinePos.Y(); + m_nOneLineMissing = m_ReleaseNotesLabel.GetPosPixel().Y() - m_PublisherLabel.GetPosPixel().Y(); +} + +void UpdateDialog::clearDescription() +{ + String sEmpty; + m_PublisherLabel.Hide(); + m_PublisherLink.Hide(); + m_PublisherLink.SetDescription( sEmpty ); + m_PublisherLink.SetURL( sEmpty ); + m_ReleaseNotesLabel.Hide(); + m_ReleaseNotesLink.Hide(); + m_ReleaseNotesLink.SetURL( sEmpty ); + if ( m_PublisherLabel.GetPosPixel().Y() == m_ReleaseNotesLabel.GetPosPixel().Y() ) + { + Point aNewPos = m_ReleaseNotesLabel.GetPosPixel(); + aNewPos.Y() += m_nOneLineMissing; + m_ReleaseNotesLabel.SetPosPixel( aNewPos ); + aNewPos = m_ReleaseNotesLink.GetPosPixel(); + aNewPos.Y() += m_nOneLineMissing; + m_ReleaseNotesLink.SetPosPixel( aNewPos ); + } + m_descriptions.Hide(); + m_descriptions.Clear(); + m_descriptions.SetPosSizePixel( m_aFirstLinePos, m_aFirstLineSize ); +} + +bool UpdateDialog::showDescription(css::uno::Reference< css::xml::dom::XNode > const & aUpdateInfo) +{ + dp_misc::DescriptionInfoset infoset(m_context, aUpdateInfo); + return showDescription(infoset.getLocalizedPublisherNameAndURL(), + infoset.getLocalizedReleaseNotesURL()); +} + +bool UpdateDialog::showDescription(css::uno::Reference< css::deployment::XPackage > const & aExtension) +{ + OSL_ASSERT(aExtension.is()); + css::beans::StringPair pubInfo = aExtension->getPublisherInfo(); + return showDescription(std::make_pair(pubInfo.First, pubInfo.Second), + OUSTR("")); +} + +bool UpdateDialog::showDescription(std::pair< rtl::OUString, rtl::OUString > const & pairPublisher, + rtl::OUString const & sReleaseNotes) +{ + rtl::OUString sPub = pairPublisher.first; + rtl::OUString sURL = pairPublisher.second; + + if ( sPub.getLength() == 0 && sURL.getLength() == 0 && sReleaseNotes.getLength() == 0 ) + // nothing to show + return false; + + bool bPublisher = false; + if ( sPub.getLength() > 0 ) + { + m_PublisherLabel.Show(); + m_PublisherLink.Show(); + m_PublisherLink.SetDescription( sPub ); + m_PublisherLink.SetURL( sURL ); + bPublisher = true; + } + + if ( sReleaseNotes.getLength() > 0 ) + { + if ( !bPublisher ) + { + m_ReleaseNotesLabel.SetPosPixel( m_PublisherLabel.GetPosPixel() ); + m_ReleaseNotesLink.SetPosPixel( m_PublisherLink.GetPosPixel() ); + } + m_ReleaseNotesLabel.Show(); + m_ReleaseNotesLink.Show(); + m_ReleaseNotesLink.SetURL( sReleaseNotes ); + } + return true; +} + +bool UpdateDialog::showDescription( const String& rDescription, bool bWithPublisher ) +{ + if ( rDescription.Len() == 0 ) + // nothing to show + return false; + + if ( bWithPublisher ) + { + bool bOneLineMissing = !m_ReleaseNotesLabel.IsVisible() || !m_PublisherLabel.IsVisible(); + Point aNewPos = m_aFirstLinePos; + aNewPos.Y() += m_nFirstLineDelta; + if ( bOneLineMissing ) + aNewPos.Y() -= m_nOneLineMissing; + Size aNewSize = m_aFirstLineSize; + aNewSize.Height() -= m_nFirstLineDelta; + if ( bOneLineMissing ) + aNewSize.Height() += m_nOneLineMissing; + m_descriptions.SetPosSizePixel( aNewPos, aNewSize ); + } + m_descriptions.Show(); + m_descriptions.SetDescription( rDescription ); + return true; +} + +IMPL_LINK(UpdateDialog, selectionHandler, void *, EMPTYARG) +{ + rtl::OUStringBuffer b; + bool bInserted = false; + UpdateDialog::Index const * p = static_cast< UpdateDialog::Index const * >( + m_updates.GetEntryData(m_updates.GetSelectEntryPos())); + clearDescription(); + + if (p != NULL) + { + //When the index is greater or equal than the amount of enabled updates then the "Show all" + //button is probably checked. Then we show first all enabled and then the disabled + //updates. + USHORT pos = m_updates.GetSelectEntryPos(); + const std::vector< dp_gui::UpdateData >::size_type sizeEnabled = + m_enabledUpdates.size(); + const std::vector< UpdateDialog::DisabledUpdate >::size_type sizeDisabled = + m_disabledUpdates.size(); + if (pos < sizeEnabled) + { + if (m_enabledUpdates[pos].aUpdateSource.is()) + bInserted = showDescription(m_enabledUpdates[pos].aUpdateSource); + else + bInserted = showDescription(m_enabledUpdates[pos].aUpdateInfo); + } + else if (pos >= sizeEnabled + && pos < (sizeEnabled + sizeDisabled)) + bInserted = showDescription(m_disabledUpdates[pos - sizeEnabled].aUpdateInfo); + + switch (p->kind) + { + case ENABLED_UPDATE: + { + b.append(m_noDescription); + break; + } + case DISABLED_UPDATE: + { + UpdateDialog::DisabledUpdate & data = m_disabledUpdates[ + p->index.disabledUpdate]; + if (data.unsatisfiedDependencies.getLength() != 0) + { + // create error string for version mismatch + ::rtl::OUString sVersion( RTL_CONSTASCII_USTRINGPARAM("%VERSION") ); + sal_Int32 nPos = m_noDependencyCurVer.indexOf( sVersion ); + if ( nPos >= 0 ) + { + ::rtl::OUString sCurVersion( RTL_CONSTASCII_USTRINGPARAM( "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("version") ":Version:OOOPackageVersion}")); + ::rtl::Bootstrap::expandMacros(sCurVersion); + m_noDependencyCurVer = m_noDependencyCurVer.replaceAt( nPos, sVersion.getLength(), sCurVersion ); + } + + b.append(m_noInstall); + b.append(LF); + b.append(m_noDependency); + for (sal_Int32 i = 0; + i < data.unsatisfiedDependencies.getLength(); ++i) + { + b.append(LF); + b.appendAscii(RTL_CONSTASCII_STRINGPARAM(" ")); + // U+2003 EM SPACE would be better than two spaces, + // but some fonts do not contain it + b.append( + confineToParagraph( + data.unsatisfiedDependencies[i])); + } + b.append(LF); + b.appendAscii(RTL_CONSTASCII_STRINGPARAM(" ")); + b.append(m_noDependencyCurVer); + } + break; + } + case GENERAL_ERROR: + { + rtl::OUString & msg = m_generalErrors[p->index.generalError]; + b.append(m_failure); + b.append(LF); + b.append(msg.getLength() == 0 ? m_unknownError : msg); + break; + } + case SPECIFIC_ERROR: + { + UpdateDialog::SpecificError & data = m_specificErrors[ + p->index.specificError]; + b.append(m_failure); + b.append(LF); + b.append( + data.message.getLength() == 0 + ? m_unknownError : data.message); + break; + } + default: + OSL_ASSERT(false); + break; + } + } + + showDescription( b.makeStringAndClear(), bInserted ); + return 0; +} + +IMPL_LINK(UpdateDialog, allHandler, void *, EMPTYARG) { + if (m_all.IsChecked()) { + m_update.Enable(); + m_updates.Enable(); + m_description.Enable(); + m_descriptions.Enable(); + std::vector< UpdateDialog::DisabledUpdate >::size_type n1 = 0; + for (std::vector< UpdateDialog::DisabledUpdate >::iterator i( + m_disabledUpdates.begin()); + i != m_disabledUpdates.end(); ++i) + { + insertItem( + i->name, LISTBOX_APPEND, + UpdateDialog::Index::newDisabledUpdate(n1++), + SvLBoxButtonKind_disabledCheckbox); + } + std::vector< rtl::OUString >::size_type n2 = 0; + for (std::vector< rtl::OUString >::iterator i(m_generalErrors.begin()); + i != m_generalErrors.end(); ++i) + { + insertItem( + m_error, LISTBOX_APPEND, + UpdateDialog::Index::newGeneralError(n2++), + SvLBoxButtonKind_staticImage); + } + std::vector< UpdateDialog::SpecificError >::size_type n3 = 0; + for (std::vector< UpdateDialog::SpecificError >::iterator i( + m_specificErrors.begin()); + i != m_specificErrors.end(); ++i) + { + insertItem( + i->name, LISTBOX_APPEND, + UpdateDialog::Index::newSpecificError(n3++), + SvLBoxButtonKind_staticImage); + } + } else { + for (USHORT i = 0; i < m_updates.getItemCount();) { + UpdateDialog::Index const * p = + static_cast< UpdateDialog::Index const * >( + m_updates.GetEntryData(i)); + if (p->kind != ENABLED_UPDATE) { + m_updates.RemoveEntry(i); + //TODO #i72487#: UpdateDialog::Index potentially leaks as + // SvxCheckListBox::RemoveEntry's exception behavior is + // unspecified + delete p; + } else { + ++i; + } + } + + if (m_updates.getItemCount() == 0) + { + clearDescription(); + m_update.Disable(); + m_updates.Disable(); + if (m_checking.IsVisible()) + m_description.Disable(); + else + showDescription(m_noInstallable,false); + } + } + return 0; +} + +IMPL_LINK(UpdateDialog, okHandler, void *, EMPTYARG) +{ + //If users are going to update a shared extension then we need + //to warn them + typedef ::std::vector<UpdateData>::const_iterator CIT; + for (CIT i = m_enabledUpdates.begin(); i < m_enabledUpdates.end(); i++) + { + OSL_ASSERT(i->aInstalledPackage.is()); + //If the user has no write access to the shared folder then the update + //for a shared extension is disable, that is it cannot be in m_enabledUpdates + } + + + for (USHORT i = 0; i < m_updates.getItemCount(); ++i) { + UpdateDialog::Index const * p = + static_cast< UpdateDialog::Index const * >( + m_updates.GetEntryData(i)); + if (p->kind == ENABLED_UPDATE && m_updates.IsChecked(i)) { + m_updateData.push_back(m_enabledUpdates[p->index.enabledUpdate]); + } + } + + EndDialog(RET_OK); + return 0; +} + +IMPL_LINK(UpdateDialog, cancelHandler, void *, EMPTYARG) { + m_thread->stop(); + EndDialog(RET_CANCEL); + return 0; +} + +IMPL_LINK( UpdateDialog, hyperlink_clicked, svt::FixedHyperlink*, pHyperlink ) +{ + ::rtl::OUString sURL; + if ( pHyperlink ) + sURL = ::rtl::OUString( pHyperlink->GetURL() ); + if ( sURL.getLength() == 0 ) + return 0; + + try + { + css::uno::Reference< css::system::XSystemShellExecute > xSystemShellExecute( + m_context->getServiceManager()->createInstanceWithContext( + OUSTR( "com.sun.star.system.SystemShellExecute" ), + m_context), css::uno::UNO_QUERY_THROW); + //throws css::lang::IllegalArgumentException, css::system::SystemShellExecuteException + xSystemShellExecute->execute( + sURL, ::rtl::OUString(), css::system::SystemShellExecuteFlags::DEFAULTS); + } + catch (css::uno::Exception& ) + { + } + + return 1; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/dp_gui_updatedialog.hxx b/desktop/source/deployment/gui/dp_gui_updatedialog.hxx new file mode 100644 index 000000000000..f59cdd5eb13f --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_updatedialog.hxx @@ -0,0 +1,230 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_GUI_DP_GUI_UPDATEDIALOG_HXX +#define INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_GUI_DP_GUI_UPDATEDIALOG_HXX + +#include "sal/config.h" + +#include <memory> +#include <vector> +#include "com/sun/star/uno/Reference.hxx" +#include "com/sun/star/uno/Sequence.hxx" +#include "rtl/ref.hxx" +#include "rtl/ustring.hxx" +#include "svtools/svlbitm.hxx" +#include "svx/checklbx.hxx" +#include "tools/link.hxx" +#include "tools/solar.h" +#include "vcl/button.hxx" +#include "vcl/dialog.hxx" +#include "vcl/fixed.hxx" +#include <svtools/fixedhyper.hxx> + +#include "descedit.hxx" +#include "dp_gui_updatedata.hxx" + +/// @HTML + +class Image; +class KeyEvent; +class MouseEvent; +class ResId; +class Window; + +namespace com { namespace sun { namespace star { + namespace awt { class XThrobber; } + namespace deployment { class XExtensionManager; + class XPackage; } + namespace uno { class XComponentContext; } +} } } + +namespace dp_gui { +/** + The modal “Check for Updates” dialog. +*/ +class UpdateDialog: public ModalDialog { +public: + /** + Create an instance. + + <p>Exactly one of <code>selectedPackages</code> and + <code>packageManagers</code> must be non-null.</p> + + @param context + a non-null component context + + @param parent + the parent window, may be null + + @param vExtensionList + check for updates for the contained extensions. There must only be one extension with + a particular identifier. If one extension is installed in several repositories, then the + one with the highest version must be used, because it contains the latest known update + information. + */ + UpdateDialog( + com::sun::star::uno::Reference< com::sun::star::uno::XComponentContext > const & context, + Window * parent, + const std::vector< com::sun::star::uno::Reference< + com::sun::star::deployment::XPackage > > & vExtensionList, + std::vector< dp_gui::UpdateData > * updateData); + + ~UpdateDialog(); + + virtual BOOL Close(); + + virtual short Execute(); + + void notifyMenubar( bool bPrepareOnly, bool bRecheckOnly ); + static void createNotifyJob( bool bPrepareOnly, + com::sun::star::uno::Sequence< com::sun::star::uno::Sequence< rtl::OUString > > &rItemList ); + +private: + UpdateDialog(UpdateDialog &); // not defined + void operator =(UpdateDialog &); // not defined + + struct DisabledUpdate; + struct SpecificError; + union IndexUnion; + friend union IndexUnion; + struct Index; + friend struct Index; + class Thread; + friend class Thread; + + class CheckListBox: public SvxCheckListBox { + public: + CheckListBox( + UpdateDialog & dialog, ResId const & resource, + Image const & normalStaticImage); + + virtual ~CheckListBox(); + + USHORT getItemCount() const; + + private: + CheckListBox(UpdateDialog::CheckListBox &); // not defined + void operator =(UpdateDialog::CheckListBox &); // not defined + + virtual void MouseButtonDown(MouseEvent const & event); + + virtual void MouseButtonUp(MouseEvent const & event); + + virtual void KeyInput(KeyEvent const & event); + + UpdateDialog & m_dialog; + }; + + + friend class CheckListBox; + + void insertItem( + rtl::OUString const & name, USHORT position, + std::auto_ptr< UpdateDialog::Index const > index, + SvLBoxButtonKind kind); + + void addAdditional( + rtl::OUString const & name, USHORT position, + std::auto_ptr< UpdateDialog::Index const > index, + SvLBoxButtonKind kind); + + void addEnabledUpdate( + rtl::OUString const & name, dp_gui::UpdateData const & data); + + void addDisabledUpdate(UpdateDialog::DisabledUpdate const & data); + void addSpecificError(UpdateDialog::SpecificError const & data); + + void checkingDone(); + + void enableOk(); + + void initDescription(); + void clearDescription(); + bool showDescription(::com::sun::star::uno::Reference< + ::com::sun::star::deployment::XPackage > const & aExtension); + bool showDescription(std::pair< rtl::OUString, rtl::OUString > const & pairPublisher, + rtl::OUString const & sReleaseNotes); + bool showDescription( ::com::sun::star::uno::Reference< + ::com::sun::star::xml::dom::XNode > const & aUpdateInfo); + bool showDescription( const String& rDescription, bool bWithPublisher ); + bool isReadOnly( const ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > &xPackage ) const; + + DECL_LINK(selectionHandler, void *); + DECL_LINK(allHandler, void *); + DECL_LINK(okHandler, void *); + DECL_LINK(cancelHandler, void *); + DECL_LINK(hyperlink_clicked, svt::FixedHyperlink *); + + com::sun::star::uno::Reference< com::sun::star::uno::XComponentContext > + m_context; + FixedText m_checking; + com::sun::star::uno::Reference< com::sun::star::awt::XThrobber > m_throbber; + FixedText m_update; + UpdateDialog::CheckListBox m_updates; + CheckBox m_all; + FixedLine m_description; + FixedText m_PublisherLabel; + svt::FixedHyperlink m_PublisherLink; + FixedText m_ReleaseNotesLabel; + svt::FixedHyperlink m_ReleaseNotesLink; + dp_gui::DescriptionEdit m_descriptions; + FixedLine m_line; + HelpButton m_help; + PushButton m_ok; + CancelButton m_cancel; + rtl::OUString m_error; + rtl::OUString m_none; + rtl::OUString m_noInstallable; + rtl::OUString m_failure; + rtl::OUString m_unknownError; + rtl::OUString m_noDescription; + rtl::OUString m_noInstall; + rtl::OUString m_noDependency; + rtl::OUString m_noDependencyCurVer; + rtl::OUString m_browserbased; + rtl::OUString m_version; + std::vector< dp_gui::UpdateData > m_enabledUpdates; + std::vector< UpdateDialog::DisabledUpdate > m_disabledUpdates; + std::vector< rtl::OUString > m_generalErrors; + std::vector< UpdateDialog::SpecificError > m_specificErrors; + std::vector< dp_gui::UpdateData > & m_updateData; + rtl::Reference< UpdateDialog::Thread > m_thread; + ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XExtensionManager > m_xExtensionManager; + + Point m_aFirstLinePos; + Size m_aFirstLineSize; + long m_nFirstLineDelta; + long m_nOneLineMissing; +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/dp_gui_updatedialog.src b/desktop/source/deployment/gui/dp_gui_updatedialog.src new file mode 100644 index 000000000000..47497cb3846b --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_updatedialog.src @@ -0,0 +1,260 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "svtools/controldims.hrc" + +#include "dp_gui.hrc" + +#define LOCAL_WIDTH (60 * RSC_BS_CHARWIDTH) +#define LABEL_WIDTH (1 * RSC_BS_CHARWIDTH) +#define LOCAL_LIST_HEIGHT1 (6 * RSC_BS_CHARHEIGHT) + 4 +#define LOCAL_LIST_HEIGHT2 (7 * RSC_BS_CHARHEIGHT) + 3 + +ModalDialog RID_DLG_UPDATE { + HelpID = HID_DEPLOYMENT_GUI_UPDATE; + Size = MAP_APPFONT( + (RSC_SP_DLG_INNERBORDER_LEFT + LOCAL_WIDTH + + RSC_SP_DLG_INNERBORDER_RIGHT), + (RSC_SP_DLG_INNERBORDER_TOP + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + LOCAL_LIST_HEIGHT1 + RSC_SP_CTRL_GROUP_Y + + RSC_CD_CHECKBOX_HEIGHT + RSC_SP_CTRL_GROUP_Y + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + LOCAL_LIST_HEIGHT2 + RSC_SP_FLGR_SPACE_Y + + RSC_CD_FIXEDLINE_HEIGHT + RSC_SP_FLGR_SPACE_Y + + RSC_CD_PUSHBUTTON_HEIGHT + RSC_SP_DLG_INNERBORDER_BOTTOM)); + Text[en-US] = "Extension Update"; + Moveable = TRUE; + Closeable = TRUE; + FixedText RID_DLG_UPDATE_CHECKING { + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT + LOCAL_WIDTH * 2 / 3, + RSC_SP_DLG_INNERBORDER_TOP); + Size = MAP_APPFONT( + (LOCAL_WIDTH - LOCAL_WIDTH * 2 / 3 - RSC_SP_CTRL_DESC_X - + RSC_CD_FIXEDTEXT_HEIGHT), + RSC_CD_FIXEDTEXT_HEIGHT); + Text[en-US] = "Checking..."; + Right = TRUE; + NoLabel = TRUE; + }; + Control RID_DLG_UPDATE_THROBBER { + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT + LOCAL_WIDTH - RSC_CD_FIXEDTEXT_HEIGHT, + RSC_SP_DLG_INNERBORDER_TOP); + Size = MAP_APPFONT(RSC_CD_FIXEDTEXT_HEIGHT, RSC_CD_FIXEDTEXT_HEIGHT); + }; + FixedText RID_DLG_UPDATE_UPDATE { + Disable = TRUE; + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT, RSC_SP_DLG_INNERBORDER_TOP); + Size = MAP_APPFONT( + LOCAL_WIDTH * 2 / 3 - RSC_SP_CTRL_GROUP_X, RSC_CD_FIXEDTEXT_HEIGHT); + Text[en-US] = "~Available extension updates"; + }; + Control RID_DLG_UPDATE_UPDATES { + HelpId = HID_DEPLOYMENT_GUI_UPDATE_AVAILABLE_UPDATES; + Disable = TRUE; + Border = TRUE; + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT, + (RSC_SP_DLG_INNERBORDER_TOP + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y)); + Size = MAP_APPFONT(LOCAL_WIDTH, LOCAL_LIST_HEIGHT1); + TabStop = TRUE; + }; + CheckBox RID_DLG_UPDATE_ALL { + Disable = TRUE; + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT, + (RSC_SP_DLG_INNERBORDER_TOP + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + LOCAL_LIST_HEIGHT1 + RSC_SP_CTRL_GROUP_Y)); + Size = MAP_APPFONT(LOCAL_WIDTH, RSC_CD_CHECKBOX_HEIGHT); + Text[en-US] = "~Show all updates"; + }; + FixedLine RID_DLG_UPDATE_DESCRIPTION { + Disable = TRUE; + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT, + (RSC_SP_DLG_INNERBORDER_TOP + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + LOCAL_LIST_HEIGHT1 + RSC_SP_CTRL_GROUP_Y + + RSC_CD_CHECKBOX_HEIGHT + RSC_SP_CTRL_GROUP_Y)); + Size = MAP_APPFONT(LOCAL_WIDTH, RSC_CD_FIXEDTEXT_HEIGHT); + Text[en-US] = "Description"; + }; + FixedText RID_DLG_UPDATE_PUBLISHER_LABEL + { + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT, + (RSC_SP_DLG_INNERBORDER_TOP + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + LOCAL_LIST_HEIGHT1 + RSC_SP_CTRL_GROUP_Y + + RSC_CD_CHECKBOX_HEIGHT + RSC_SP_CTRL_GROUP_Y + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y)); + Size = MAP_APPFONT(LABEL_WIDTH, RSC_CD_FIXEDTEXT_HEIGHT); + Text[en-US] = "Publisher:"; + }; + FixedText RID_DLG_UPDATE_PUBLISHER_LINK + { + HelpId = HID_DEPLOYMENT_GUI_UPDATE_PUBLISHER; + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT + LABEL_WIDTH + RSC_SP_CTRL_DESC_X, + (RSC_SP_DLG_INNERBORDER_TOP + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + LOCAL_LIST_HEIGHT1 + RSC_SP_CTRL_GROUP_Y + + RSC_CD_CHECKBOX_HEIGHT + RSC_SP_CTRL_GROUP_Y + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y)); + Size = MAP_APPFONT(LOCAL_WIDTH - LABEL_WIDTH - RSC_SP_CTRL_DESC_X, RSC_CD_FIXEDTEXT_HEIGHT); + }; + FixedText RID_DLG_UPDATE_RELEASENOTES_LABEL + { + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT, + (RSC_SP_DLG_INNERBORDER_TOP + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + LOCAL_LIST_HEIGHT1 + RSC_SP_CTRL_GROUP_Y + + RSC_CD_CHECKBOX_HEIGHT + RSC_SP_CTRL_GROUP_Y + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + RSC_CD_FIXEDTEXT_HEIGHT + RSC_SP_CTRL_DESC_Y)); + Size = MAP_APPFONT(LABEL_WIDTH, RSC_CD_FIXEDTEXT_HEIGHT); + Text[en-US] = "What is new:"; + }; + FixedText RID_DLG_UPDATE_RELEASENOTES_LINK + { + HelpId = HID_DEPLOYMENT_GUI_UPDATE_RELEASENOTES; + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT + LABEL_WIDTH + RSC_SP_CTRL_DESC_X, + (RSC_SP_DLG_INNERBORDER_TOP + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + LOCAL_LIST_HEIGHT1 + RSC_SP_CTRL_GROUP_Y + + RSC_CD_CHECKBOX_HEIGHT + RSC_SP_CTRL_GROUP_Y + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + RSC_CD_FIXEDTEXT_HEIGHT + RSC_SP_CTRL_DESC_Y)); + Size = MAP_APPFONT(LOCAL_WIDTH - LABEL_WIDTH - RSC_SP_CTRL_DESC_X, RSC_CD_FIXEDTEXT_HEIGHT); + Text[en-US] = "Release Notes"; + }; + MultiLineEdit RID_DLG_UPDATE_DESCRIPTIONS { + Disable = TRUE; + Border = TRUE; + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT, + (RSC_SP_DLG_INNERBORDER_TOP + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + LOCAL_LIST_HEIGHT1 + RSC_SP_CTRL_GROUP_Y + + RSC_CD_CHECKBOX_HEIGHT + RSC_SP_CTRL_GROUP_Y + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y)); + Size = MAP_APPFONT(LOCAL_WIDTH, LOCAL_LIST_HEIGHT2); + ReadOnly = TRUE; + VScroll = TRUE; + IgnoreTab = TRUE; + }; + FixedLine RID_DLG_UPDATE_LINE { + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT, + (RSC_SP_DLG_INNERBORDER_TOP + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + LOCAL_LIST_HEIGHT1 + RSC_SP_CTRL_GROUP_Y + + RSC_CD_CHECKBOX_HEIGHT + RSC_SP_CTRL_GROUP_Y + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + LOCAL_LIST_HEIGHT2 + RSC_SP_FLGR_SPACE_Y)); + Size = MAP_APPFONT(LOCAL_WIDTH, RSC_CD_FIXEDLINE_HEIGHT); + }; + HelpButton RID_DLG_UPDATE_HELP { + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT, + (RSC_SP_DLG_INNERBORDER_TOP + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + LOCAL_LIST_HEIGHT1 + RSC_SP_CTRL_GROUP_Y + + RSC_CD_CHECKBOX_HEIGHT + RSC_SP_CTRL_GROUP_Y + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + LOCAL_LIST_HEIGHT2 + RSC_SP_FLGR_SPACE_Y + + RSC_CD_FIXEDLINE_HEIGHT + RSC_SP_FLGR_SPACE_Y)); + Size = MAP_APPFONT(RSC_CD_PUSHBUTTON_WIDTH, RSC_CD_PUSHBUTTON_HEIGHT); + }; + PushButton RID_DLG_UPDATE_OK { + Disable = TRUE; + Pos = MAP_APPFONT( + (RSC_SP_DLG_INNERBORDER_LEFT + LOCAL_WIDTH - RSC_CD_PUSHBUTTON_WIDTH - + RSC_SP_CTRL_GROUP_X - RSC_CD_PUSHBUTTON_WIDTH), + (RSC_SP_DLG_INNERBORDER_TOP + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + LOCAL_LIST_HEIGHT1 + RSC_SP_CTRL_GROUP_Y + + RSC_CD_CHECKBOX_HEIGHT + RSC_SP_CTRL_GROUP_Y + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + LOCAL_LIST_HEIGHT2 + RSC_SP_FLGR_SPACE_Y + + RSC_CD_FIXEDLINE_HEIGHT + RSC_SP_FLGR_SPACE_Y)); + Size = MAP_APPFONT(RSC_CD_PUSHBUTTON_WIDTH, RSC_CD_PUSHBUTTON_HEIGHT); + Text[en-US] = "~Install"; + DefButton = TRUE; + }; + CancelButton RID_DLG_UPDATE_CANCEL { + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT + LOCAL_WIDTH - RSC_CD_PUSHBUTTON_WIDTH, + (RSC_SP_DLG_INNERBORDER_TOP + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + LOCAL_LIST_HEIGHT1 + RSC_SP_CTRL_GROUP_Y + + RSC_CD_CHECKBOX_HEIGHT + RSC_SP_CTRL_GROUP_Y + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + LOCAL_LIST_HEIGHT2 + RSC_SP_FLGR_SPACE_Y + + RSC_CD_FIXEDLINE_HEIGHT + RSC_SP_FLGR_SPACE_Y)); + Size = MAP_APPFONT(RSC_CD_PUSHBUTTON_WIDTH, RSC_CD_PUSHBUTTON_HEIGHT); + }; + + Image RID_DLG_UPDATE_NORMALALERT { + ImageBitmap = Bitmap { + File = "caution_12.png"; + }; + }; + String RID_DLG_UPDATE_ERROR { + Text[en-US] = "Error"; + }; + String RID_DLG_UPDATE_NONE { + Text[en-US] = "No new updates are available."; + }; + String RID_DLG_UPDATE_NOINSTALLABLE { + Text[en-US] = "No installable updates are available. To see all updates, mark the check box 'Show all updates'."; + }; + String RID_DLG_UPDATE_FAILURE { + Text[en-US] = "An error occurred:"; + }; + String RID_DLG_UPDATE_UNKNOWNERROR { + Text[en-US] = "Unknown error."; + }; + String RID_DLG_UPDATE_NODESCRIPTION { + Text[en-US] = "No descriptions available for this extension."; + }; + String RID_DLG_UPDATE_NOINSTALL { + Text[en-US] = "The extension cannot be updated because:"; + }; + String RID_DLG_UPDATE_NODEPENDENCY { + Text[en-US] = "Required OpenOffice.org version doesn't match:"; + }; + String RID_DLG_UPDATE_NODEPENDENCY_CUR_VER { + Text[en-US] = "You have OpenOffice.org %VERSION"; + }; + String RID_DLG_UPDATE_BROWSERBASED { + Text[en-US] = "browser based update"; + }; + + String RID_DLG_UPDATE_VERSION { + Text[en-US] = "Version"; + }; +}; + +WarningBox RID_WARNINGBOX_UPDATE_SHARED_EXTENSION +{ + Buttons = WB_OK_CANCEL; + DefButton = WB_DEF_CANCEL; + Message[en-US] = "Make sure that no further users are working with the same " + "%PRODUCTNAME, when changing shared extensions in a multi user environment.\n" + "Click \'OK\' to update the extensions.\n" + "Click \'Cancel\' to stop updating the extensions."; +}; + diff --git a/desktop/source/deployment/gui/dp_gui_updateinstalldialog.cxx b/desktop/source/deployment/gui/dp_gui_updateinstalldialog.cxx new file mode 100644 index 000000000000..0fc88df8ecce --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_updateinstalldialog.cxx @@ -0,0 +1,759 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_gui_updatedata.hxx" + +#include "sal/config.h" +#include "osl/file.hxx" +#include "osl/conditn.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "tools/resid.hxx" +#include "tools/resmgr.hxx" +#include "tools/solar.h" +#include "tools/string.hxx" +#include "vcl/dialog.hxx" +#include "vcl/msgbox.hxx" +#include "vcl/svapp.hxx" +#include "osl/mutex.hxx" +#include "vcl/dialog.hxx" +#include "cppuhelper/implbase3.hxx" + +#include "com/sun/star/beans/PropertyValue.hpp" +#include "com/sun/star/beans/NamedValue.hpp" +#include "com/sun/star/xml/dom/XElement.hpp" +#include "com/sun/star/xml/dom/XNode.hpp" +#include "com/sun/star/xml/dom/XNodeList.hpp" +#include "com/sun/star/ucb/NameClash.hpp" +#include "com/sun/star/ucb/InteractiveAugmentedIOException.hpp" +#include "com/sun/star/ucb/XCommandEnvironment.hpp" +#include "com/sun/star/ucb/XProgressHandler.hpp" +#include "com/sun/star/deployment/XExtensionManager.hpp" +#include "com/sun/star/deployment/ExtensionManager.hpp" +#include "com/sun/star/deployment/XUpdateInformationProvider.hpp" +#include "com/sun/star/deployment/DependencyException.hpp" +#include "com/sun/star/deployment/LicenseException.hpp" +#include "com/sun/star/deployment/VersionException.hpp" +#include "com/sun/star/deployment/ui/LicenseDialog.hpp" +#include "com/sun/star/task/XInteractionHandler.hpp" +#include "com/sun/star/ui/dialogs/XExecutableDialog.hpp" +#include "com/sun/star/ui/dialogs/ExecutableDialogResults.hpp" +#include "com/sun/star/task/XInteractionAbort.hpp" +#include "com/sun/star/task/XInteractionApprove.hpp" + +#include "dp_descriptioninfoset.hxx" +#include "dp_gui.hrc" +#include "dp_gui_updateinstalldialog.hxx" +#include "dp_gui_shared.hxx" +#include "dp_gui_updatedata.hxx" +#include "dp_ucb.h" +#include "dp_misc.h" +#include "dp_version.hxx" +#include "dp_gui_thread.hxx" +#include "dp_gui_extensioncmdqueue.hxx" +#include "ucbhelper/content.hxx" +#include "osl/mutex.hxx" +#include "osl/mutex.hxx" +#include "rtl/ref.hxx" +#include "com/sun/star/uno/Sequence.h" +#include "comphelper/anytostring.hxx" +#include "toolkit/helper/vclunohelper.hxx" + +#include <vector> + +class Window; + +namespace cssu = ::com::sun::star::uno; +namespace css = ::com::sun::star; + +using ::rtl::OUString; + + +namespace dp_gui { + +class UpdateInstallDialog::Thread: public dp_gui::Thread { + friend class UpdateCommandEnv; +public: + Thread(cssu::Reference< cssu::XComponentContext > ctx, + UpdateInstallDialog & dialog, std::vector< dp_gui::UpdateData > & aVecUpdateData); + + void stop(); + + + +private: + Thread(Thread &); // not defined + void operator =(Thread &); // not defined + + virtual ~Thread(); + + virtual void execute(); + void downloadExtensions(); + void download(::rtl::OUString const & aUrls, UpdateData & aUpdatData); + void installExtensions(); + void removeTempDownloads(); + + UpdateInstallDialog & m_dialog; + cssu::Reference< css::deployment::XUpdateInformationProvider > + m_updateInformation; + + // guarded by Application::GetSolarMutex(): + cssu::Reference< css::task::XAbortChannel > m_abort; + cssu::Reference< cssu::XComponentContext > m_xComponentContext; + std::vector< dp_gui::UpdateData > & m_aVecUpdateData; + ::rtl::Reference<UpdateCommandEnv> m_updateCmdEnv; + + //A folder which is created in the temp directory in which then the updates are downloaded + ::rtl::OUString m_sDownloadFolder; + + bool m_stop; + +}; + +class UpdateCommandEnv + : public ::cppu::WeakImplHelper3< css::ucb::XCommandEnvironment, + css::task::XInteractionHandler, + css::ucb::XProgressHandler > +{ + friend class UpdateInstallDialog::Thread; + + UpdateInstallDialog & m_updateDialog; + ::rtl::Reference<UpdateInstallDialog::Thread> m_installThread; + cssu::Reference< cssu::XComponentContext > m_xContext; + +public: + virtual ~UpdateCommandEnv(); + UpdateCommandEnv( cssu::Reference< cssu::XComponentContext > const & xCtx, + UpdateInstallDialog & updateDialog, + ::rtl::Reference<UpdateInstallDialog::Thread>const & thread); + + // XCommandEnvironment + virtual cssu::Reference<css::task::XInteractionHandler > SAL_CALL + getInteractionHandler() throw (cssu::RuntimeException); + virtual cssu::Reference<css::ucb::XProgressHandler > + SAL_CALL getProgressHandler() throw (cssu::RuntimeException); + + // XInteractionHandler + virtual void SAL_CALL handle( + cssu::Reference<css::task::XInteractionRequest > const & xRequest ) + throw (cssu::RuntimeException); + + // XProgressHandler + virtual void SAL_CALL push( cssu::Any const & Status ) + throw (cssu::RuntimeException); + virtual void SAL_CALL update( cssu::Any const & Status ) + throw (cssu::RuntimeException); + virtual void SAL_CALL pop() throw (cssu::RuntimeException); +}; + + +UpdateInstallDialog::Thread::Thread( + cssu::Reference< cssu::XComponentContext> xCtx, + UpdateInstallDialog & dialog, + std::vector< dp_gui::UpdateData > & aVecUpdateData): + m_dialog(dialog), + m_xComponentContext(xCtx), + m_aVecUpdateData(aVecUpdateData), + m_updateCmdEnv(new UpdateCommandEnv(xCtx, m_dialog, this)), + m_stop(false) +{} + +void UpdateInstallDialog::Thread::stop() { + cssu::Reference< css::task::XAbortChannel > abort; + { + SolarMutexGuard g; + abort = m_abort; + m_stop = true; + } + if (abort.is()) { + abort->sendAbort(); + } +} + +UpdateInstallDialog::Thread::~Thread() {} + +void UpdateInstallDialog::Thread::execute() +{ + try { + downloadExtensions(); + installExtensions(); + } + catch (...) + { + } + + //clean up the temp directories + try { + removeTempDownloads(); + } catch( ... ) { + } + + { + //make sure m_dialog is still alive + SolarMutexGuard g; + if (! m_stop) + m_dialog.updateDone(); + } + //UpdateCommandEnv keeps a reference to Thread and prevents destruction. Therefore remove it. + m_updateCmdEnv->m_installThread.clear(); +} + + +UpdateInstallDialog::UpdateInstallDialog( + Window * parent, + std::vector<dp_gui::UpdateData> & aVecUpdateData, + cssu::Reference< cssu::XComponentContext > const & xCtx): + ModalDialog( + parent, + DpGuiResId(RID_DLG_UPDATEINSTALL)), + + m_thread(new Thread(xCtx, *this, aVecUpdateData)), + m_xComponentContext(xCtx), + m_bError(false), + m_bNoEntry(true), + m_bActivated(false), + m_sInstalling(String(DpGuiResId(RID_DLG_UPDATE_INSTALL_INSTALLING))), + m_sFinished(String(DpGuiResId(RID_DLG_UPDATE_INSTALL_FINISHED))), + m_sNoErrors(String(DpGuiResId(RID_DLG_UPDATE_INSTALL_NO_ERRORS))), + m_sErrorDownload(String(DpGuiResId(RID_DLG_UPDATE_INSTALL_ERROR_DOWNLOAD))), + m_sErrorInstallation(String(DpGuiResId(RID_DLG_UPDATE_INSTALL_ERROR_INSTALLATION))), + m_sErrorLicenseDeclined(String(DpGuiResId(RID_DLG_UPDATE_INSTALL_ERROR_LIC_DECLINED))), + m_sNoInstall(String(DpGuiResId(RID_DLG_UPDATE_INSTALL_EXTENSION_NOINSTALL))), + m_sThisErrorOccurred(String(DpGuiResId(RID_DLG_UPDATE_INSTALL_THIS_ERROR_OCCURRED))), + m_ft_action(this, DpGuiResId(RID_DLG_UPDATE_INSTALL_DOWNLOADING)), + m_statusbar(this,DpGuiResId(RID_DLG_UPDATE_INSTALL_STATUSBAR)), + m_ft_extension_name(this, DpGuiResId(RID_DLG_UPDATE_INSTALL_EXTENSION_NAME)), + m_ft_results(this, DpGuiResId(RID_DLG_UPDATE_INSTALL_RESULTS)), + m_mle_info(this, DpGuiResId(RID_DLG_UPDATE_INSTALL_INFO)), + m_line(this, DpGuiResId(RID_DLG_UPDATE_INSTALL_LINE)), + m_help(this, DpGuiResId(RID_DLG_UPDATE_INSTALL_HELP)), + m_ok(this, DpGuiResId(RID_DLG_UPDATE_INSTALL_OK)), + m_cancel(this, DpGuiResId(RID_DLG_UPDATE_INSTALL_ABORT)) +{ + FreeResource(); + + m_xExtensionManager = css::deployment::ExtensionManager::get( xCtx ); + + m_cancel.SetClickHdl(LINK(this, UpdateInstallDialog, cancelHandler)); + m_mle_info.EnableCursor(FALSE); + if ( ! dp_misc::office_is_running()) + m_help.Disable(); +} + +UpdateInstallDialog::~UpdateInstallDialog() {} + +BOOL UpdateInstallDialog::Close() +{ + m_thread->stop(); + return ModalDialog::Close(); +} + +short UpdateInstallDialog::Execute() +{ + m_thread->launch(); + return ModalDialog::Execute(); +} + + +// make sure the solar mutex is locked before calling +void UpdateInstallDialog::updateDone() +{ + if (!m_bError) + m_mle_info.InsertText(m_sNoErrors); + m_ok.Enable(); + m_ok.GrabFocus(); + m_cancel.Disable(); +} +// make sure the solar mutex is locked before calling +//sets an error message in the text area +void UpdateInstallDialog::setError(INSTALL_ERROR err, ::rtl::OUString const & sExtension, + OUString const & exceptionMessage) +{ + String sError; + m_bError = true; + + switch (err) + { + case ERROR_DOWNLOAD: + sError = m_sErrorDownload; + break; + case ERROR_INSTALLATION: + sError = m_sErrorInstallation; + break; + case ERROR_LICENSE_DECLINED: + sError = m_sErrorLicenseDeclined; + break; + + default: + OSL_ASSERT(0); + } + + sError.SearchAndReplace(String(OUSTR("%NAME")), String(sExtension), 0); + //We want to have an empty line between the error messages. However, + //there shall be no empty line after the last entry. + if (m_bNoEntry) + m_bNoEntry = false; + else + m_mle_info.InsertText(OUSTR("\n")); + m_mle_info.InsertText(sError); + //Insert more information about the error + if (exceptionMessage.getLength()) + m_mle_info.InsertText(m_sThisErrorOccurred + exceptionMessage + OUSTR("\n")); + + m_mle_info.InsertText(m_sNoInstall); + m_mle_info.InsertText(OUSTR("\n")); +} + +void UpdateInstallDialog::setError(OUString const & exceptionMessage) +{ + m_bError = true; + m_mle_info.InsertText(exceptionMessage + OUSTR("\n")); +} + +IMPL_LINK(UpdateInstallDialog, cancelHandler, void *, EMPTYARG) +{ + m_thread->stop(); + EndDialog(RET_CANCEL); + return 0; +} + +//------------------------------------------------------------------------------------------------ + +void UpdateInstallDialog::Thread::downloadExtensions() +{ + try + { + //create the download directory in the temp folder + OUString sTempDir; + if (::osl::FileBase::getTempDirURL(sTempDir) != ::osl::FileBase::E_None) + throw cssu::Exception(OUSTR("Could not get URL for the temp directory. No extensions will be installed."), 0); + + //create a unique name for the directory + OUString tempEntry, destFolder; + if (::osl::File::createTempFile(&sTempDir, 0, &tempEntry ) != ::osl::File::E_None) + throw cssu::Exception(OUSTR("Could not create a temporary file in ") + sTempDir + + OUSTR(". No extensions will be installed"), 0 ); + + tempEntry = tempEntry.copy( tempEntry.lastIndexOf( '/' ) + 1 ); + + destFolder = dp_misc::makeURL( sTempDir, tempEntry ); + destFolder += OUSTR("_"); + m_sDownloadFolder = destFolder; + try + { + dp_misc::create_folder(0, destFolder, m_updateCmdEnv.get(), true ); + } catch (cssu::Exception & e) + { + throw cssu::Exception(e.Message + OUSTR(" No extensions will be installed."), 0); + } + + + sal_uInt16 count = 0; + typedef std::vector<UpdateData>::iterator It; + for (It i = m_aVecUpdateData.begin(); i != m_aVecUpdateData.end(); ++i) + { + UpdateData & curData = *i; + + if (!curData.aUpdateInfo.is() || curData.aUpdateSource.is()) + continue; + //We assume that m_aVecUpdateData contains only information about extensions which + //can be downloaded directly. + OSL_ASSERT(curData.sWebsiteURL.getLength() == 0); + + //update the name of the extension which is to be downloaded + { + SolarMutexGuard g; + if (m_stop) { + return; + } + m_dialog.m_ft_extension_name.SetText(curData.aInstalledPackage->getDisplayName()); + sal_uInt16 prog = (sal::static_int_cast<sal_uInt16>(100) * ++count) / + sal::static_int_cast<sal_uInt16>(m_aVecUpdateData.size()); + m_dialog.m_statusbar.SetValue(prog); + } + dp_misc::DescriptionInfoset info(m_xComponentContext, curData.aUpdateInfo); + //remember occurring exceptions in case we need to print out error information + ::std::vector< ::std::pair<OUString, cssu::Exception> > vecExceptions; + cssu::Sequence<OUString> seqDownloadURLs = info.getUpdateDownloadUrls(); + OSL_ENSURE(seqDownloadURLs.getLength() > 0, "No download URL provided!"); + for (sal_Int32 j = 0; j < seqDownloadURLs.getLength(); j++) + { + try + { + OSL_ENSURE(seqDownloadURLs[j].getLength() > 0, "Download URL is empty!"); + download(seqDownloadURLs[j], curData); + if (curData.sLocalURL.getLength() > 0) + break; + } + catch ( cssu::Exception & e ) + { + vecExceptions.push_back( ::std::make_pair(seqDownloadURLs[j], e)); + //There can be several different errors, for example, the URL is wrong, webserver cannot be reached, + //name cannot be resolved. The UCB helper API does not specify different special exceptions for these + //cases. Therefore ignore and continue. + continue; + } + } + //update the progress and display download error + { + SolarMutexGuard g; + if (m_stop) { + return; + } + if (curData.sLocalURL.getLength() == 0) + { + //Construct a string of all messages contained in the exceptions plus the respective download URLs + ::rtl::OUStringBuffer buf(256); + typedef ::std::vector< ::std::pair<OUString, cssu::Exception > >::const_iterator CIT; + for (CIT j = vecExceptions.begin(); j != vecExceptions.end(); j++) + { + if (j != vecExceptions.begin()) + buf.appendAscii("\n"); + buf.append(OUSTR("Could not download ")); + buf.append(j->first); + buf.appendAscii(". "); + buf.append(j->second.Message); + } + m_dialog.setError(UpdateInstallDialog::ERROR_DOWNLOAD, curData.aInstalledPackage->getDisplayName(), + buf.makeStringAndClear()); + } + } + + } + } + catch (cssu::Exception & e) + { + SolarMutexGuard g; + if (m_stop) { + return; + } + m_dialog.setError(e.Message); + } +} +void UpdateInstallDialog::Thread::installExtensions() +{ + //Update the fix text in the dialog to "Installing extensions..." + { + SolarMutexGuard g; + if (m_stop) { + return; + } + m_dialog.m_ft_action.SetText(m_dialog.m_sInstalling); + m_dialog.m_statusbar.SetValue(0); + } + + sal_uInt16 count = 0; + typedef std::vector<UpdateData>::iterator It; + for (It i = m_aVecUpdateData.begin(); i != m_aVecUpdateData.end(); ++i, ++count) + { + //update the name of the extension which is to be installed + { + SolarMutexGuard g; + if (m_stop) { + return; + } + //we only show progress after an extension has been installed. + if (count > 0) { + m_dialog.m_statusbar.SetValue( + (sal::static_int_cast<sal_uInt16>(100) * count) / + sal::static_int_cast<sal_uInt16>(m_aVecUpdateData.size())); + } + m_dialog.m_ft_extension_name.SetText(i->aInstalledPackage->getDisplayName()); + } +// TimeValue v = {1, 0}; +// osl::Thread::wait(v); + bool bError = false; + bool bLicenseDeclined = false; + cssu::Reference<css::deployment::XPackage> xExtension; + UpdateData & curData = *i; + cssu::Exception exc; + try + { + cssu::Reference< css::task::XAbortChannel > xAbortChannel( + curData.aInstalledPackage->createAbortChannel() ); + { + SolarMutexGuard g; + if (m_stop) { + return; + } + m_abort = xAbortChannel; + } + if (!curData.aUpdateSource.is() && curData.sLocalURL.getLength()) + { + css::beans::NamedValue prop(OUSTR("EXTENSION_UPDATE"), css::uno::makeAny(OUSTR("1"))); + if (!curData.bIsShared) + xExtension = m_dialog.getExtensionManager()->addExtension( + curData.sLocalURL, css::uno::Sequence<css::beans::NamedValue>(&prop, 1), + OUSTR("user"), xAbortChannel, m_updateCmdEnv.get()); + else + xExtension = m_dialog.getExtensionManager()->addExtension( + curData.sLocalURL, css::uno::Sequence<css::beans::NamedValue>(&prop, 1), + OUSTR("shared"), xAbortChannel, m_updateCmdEnv.get()); + } + else if (curData.aUpdateSource.is()) + { + OSL_ASSERT(curData.aUpdateSource.is()); + //I am not sure if we should obtain the install properties and pass them into + //add extension. Currently it contains only "SUPPRESS_LICENSE". So it it could happen + //that a license is displayed when updating from the shared repository, although the + //shared extension was installed using "SUPPRESS_LICENSE". + css::beans::NamedValue prop(OUSTR("EXTENSION_UPDATE"), css::uno::makeAny(OUSTR("1"))); + if (!curData.bIsShared) + xExtension = m_dialog.getExtensionManager()->addExtension( + curData.aUpdateSource->getURL(), css::uno::Sequence<css::beans::NamedValue>(&prop, 1), + OUSTR("user"), xAbortChannel, m_updateCmdEnv.get()); + else + xExtension = m_dialog.getExtensionManager()->addExtension( + curData.aUpdateSource->getURL(), css::uno::Sequence<css::beans::NamedValue>(&prop, 1), + OUSTR("shared"), xAbortChannel, m_updateCmdEnv.get()); + } + } + catch (css::deployment::DeploymentException & de) + { + if (de.Cause.has<css::deployment::LicenseException>()) + { + bLicenseDeclined = true; + } + else + { + exc = de.Cause.get<cssu::Exception>(); + bError = true; + } + } + catch (cssu::Exception& e) + { + exc = e; + bError = true; + } + + if (bLicenseDeclined) + { + SolarMutexGuard g; + if (m_stop) { + return; + } + m_dialog.setError(UpdateInstallDialog::ERROR_LICENSE_DECLINED, + curData.aInstalledPackage->getDisplayName(), OUString()); + } + else if (!xExtension.is() || bError) + { + SolarMutexGuard g; + if (m_stop) { + return; + } + m_dialog.setError(UpdateInstallDialog::ERROR_INSTALLATION, + curData.aInstalledPackage->getDisplayName(), exc.Message); + } + } + { + SolarMutexGuard g; + if (m_stop) { + return; + } + m_dialog.m_statusbar.SetValue(100); + m_dialog.m_ft_extension_name.SetText(OUString()); + m_dialog.m_ft_action.SetText(m_dialog.m_sFinished); + } +} + +void UpdateInstallDialog::Thread::removeTempDownloads() +{ + if (m_sDownloadFolder.getLength()) + { + dp_misc::erase_path(m_sDownloadFolder, + cssu::Reference<css::ucb::XCommandEnvironment>(),false /* no throw: ignore errors */ ); + //remove also the temp file which we have used to create the unique name + OUString tempFile = m_sDownloadFolder.copy(0, m_sDownloadFolder.getLength() - 1); + dp_misc::erase_path(tempFile, cssu::Reference<css::ucb::XCommandEnvironment>(),false); + m_sDownloadFolder = OUString(); + } +} + + +void UpdateInstallDialog::Thread::download(OUString const & sDownloadURL, UpdateData & aUpdateData) +{ + { + SolarMutexGuard g; + if (m_stop) { + return; + } + } + + OSL_ASSERT(m_sDownloadFolder.getLength()); + OUString destFolder, tempEntry; + if (::osl::File::createTempFile( + &m_sDownloadFolder, + 0, &tempEntry ) != ::osl::File::E_None) + { + //ToDo feedback in window that download of this component failed + throw cssu::Exception(OUSTR("Could not create temporary file in folder ") + destFolder + OUSTR("."), 0); + } + tempEntry = tempEntry.copy( tempEntry.lastIndexOf( '/' ) + 1 ); + + destFolder = dp_misc::makeURL( m_sDownloadFolder, tempEntry ); + destFolder += OUSTR("_"); + + ::ucbhelper::Content destFolderContent; + dp_misc::create_folder( &destFolderContent, destFolder, m_updateCmdEnv.get() ); + + ::ucbhelper::Content sourceContent; + dp_misc::create_ucb_content( &sourceContent, sDownloadURL, m_updateCmdEnv.get() ); + + const OUString sTitle(sourceContent.getPropertyValue( + dp_misc::StrTitle::get() ).get<OUString>() ); + + if (destFolderContent.transferContent( + sourceContent, ::ucbhelper::InsertOperation_COPY, + sTitle, css::ucb::NameClash::OVERWRITE )) + { + //the user may have cancelled the dialog because downloading took to long + { + SolarMutexGuard g; + if (m_stop) { + return; + } + //all errors should be handeld by the command environment. + aUpdateData.sLocalURL = destFolder + OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) ) + sTitle; + } + } +} + + +// ------------------------------------------------------------------------------------------------------- + +UpdateCommandEnv::UpdateCommandEnv( cssu::Reference< cssu::XComponentContext > const & xCtx, + UpdateInstallDialog & updateDialog, + ::rtl::Reference<UpdateInstallDialog::Thread>const & thread) + : m_updateDialog( updateDialog ), + m_installThread(thread), + m_xContext(xCtx) +{ +} + +UpdateCommandEnv::~UpdateCommandEnv() +{ +} + + +// XCommandEnvironment +//______________________________________________________________________________ +cssu::Reference<css::task::XInteractionHandler> UpdateCommandEnv::getInteractionHandler() +throw (cssu::RuntimeException) +{ + return this; +} + +//______________________________________________________________________________ +cssu::Reference<css::ucb::XProgressHandler> UpdateCommandEnv::getProgressHandler() +throw (cssu::RuntimeException) +{ + return this; +} + +// XInteractionHandler +void UpdateCommandEnv::handle( + cssu::Reference< css::task::XInteractionRequest> const & xRequest ) + throw (cssu::RuntimeException) +{ + cssu::Any request( xRequest->getRequest() ); + OSL_ASSERT( request.getValueTypeClass() == cssu::TypeClass_EXCEPTION ); + dp_misc::TRACE(OUSTR("[dp_gui_cmdenv.cxx] incoming request:\n") + + ::comphelper::anyToString(request) + OUSTR("\n\n")); + + css::deployment::VersionException verExc; + bool approve = false; + bool abort = false; + + if (request >>= verExc) + { //We must catch the version exception during the update, + //because otherwise the user would be confronted with the dialogs, asking + //them if they want to replace an already installed version of the same extension. + //During an update we assume that we always want to replace the old version with the + //new version. + approve = true; + } + + if (approve == false && abort == false) + { + //forward to interaction handler for main dialog. + handleInteractionRequest( m_xContext, xRequest ); + } + else + { + // select: + cssu::Sequence< cssu::Reference< css::task::XInteractionContinuation > > conts( + xRequest->getContinuations() ); + cssu::Reference< css::task::XInteractionContinuation > const * pConts = + conts.getConstArray(); + sal_Int32 len = conts.getLength(); + for ( sal_Int32 pos = 0; pos < len; ++pos ) + { + if (approve) { + cssu::Reference< css::task::XInteractionApprove > xInteractionApprove( + pConts[ pos ], cssu::UNO_QUERY ); + if (xInteractionApprove.is()) { + xInteractionApprove->select(); + // don't query again for ongoing continuations: + approve = false; + } + } + else if (abort) { + cssu::Reference< css::task::XInteractionAbort > xInteractionAbort( + pConts[ pos ], cssu::UNO_QUERY ); + if (xInteractionAbort.is()) { + xInteractionAbort->select(); + // don't query again for ongoing continuations: + abort = false; + } + } + } + } +} + +// XProgressHandler +void UpdateCommandEnv::push( cssu::Any const & /*Status*/ ) +throw (cssu::RuntimeException) +{ +} + + +void UpdateCommandEnv::update( cssu::Any const & /*Status */) +throw (cssu::RuntimeException) +{ +} + +void UpdateCommandEnv::pop() throw (cssu::RuntimeException) +{ +} + + +} //end namespace dp_gui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/dp_gui_updateinstalldialog.hxx b/desktop/source/deployment/gui/dp_gui_updateinstalldialog.hxx new file mode 100644 index 000000000000..a7b11ef355ec --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_updateinstalldialog.hxx @@ -0,0 +1,145 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_GUI_DP_GUI_INSTALLDIALOG_HXX +#define INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_GUI_DP_GUI_INSTALLDIALOG_HXX + +#include "sal/config.h" +#include "vcl/button.hxx" +#include "vcl/fixed.hxx" +#include "vcl/dialog.hxx" +#include "svtools/prgsbar.hxx" +#include "rtl/ref.hxx" +#include <vector> + +#include "dp_gui_autoscrolledit.hxx" +/// @HTML + +namespace com { namespace sun { namespace star { namespace deployment { + class XExtensionManager; +}}}} +namespace com { namespace sun { namespace star { namespace uno { + class XComponentContext; +}}}} +namespace com { namespace sun { namespace star { namespace xml { namespace dom { + class XNode; +}}}}} +namespace com { namespace sun { namespace star { namespace xml { namespace xpath { + class XXPathAPI; +}}}}} + +class Window; +namespace osl { + class Condition; +} + +namespace dp_gui { + + struct UpdateData; + class UpdateCommandEnv; + + +/** + The modal “Download and Installation” dialog. +*/ +class UpdateInstallDialog: public ModalDialog { +public: + /** + Create an instance. + + @param parent + the parent window, may be null + */ + UpdateInstallDialog(Window * parent, std::vector<UpdateData> & aVecUpdateData, + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > const & xCtx); + + ~UpdateInstallDialog(); + + BOOL Close(); + virtual short Execute(); + +private: + UpdateInstallDialog(UpdateInstallDialog &); // not defined + void operator =(UpdateInstallDialog &); // not defined + + class Thread; + friend class Thread; + friend class UpdateCommandEnv; + + DECL_LINK(cancelHandler, void *); + + //signals in the dialog that we have finished. + void updateDone(); + //Writes a particular error into the info listbox. + enum INSTALL_ERROR + { + ERROR_DOWNLOAD, + ERROR_INSTALLATION, + ERROR_LICENSE_DECLINED + }; + void setError(INSTALL_ERROR err, ::rtl::OUString const & sExtension, ::rtl::OUString const & exceptionMessage); + void setError(::rtl::OUString const & exceptionMessage); + ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XExtensionManager > getExtensionManager() const + { return m_xExtensionManager; } + + rtl::Reference< Thread > m_thread; + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > m_xComponentContext; + ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XExtensionManager > m_xExtensionManager; + //Signals that an error occurred during download and installation + bool m_bError; + bool m_bNoEntry; + bool m_bActivated; + + ::rtl::OUString m_sInstalling; + ::rtl::OUString m_sFinished; + ::rtl::OUString m_sNoErrors; + ::rtl::OUString m_sErrorDownload; + ::rtl::OUString m_sErrorInstallation; + ::rtl::OUString m_sErrorLicenseDeclined; + ::rtl::OUString m_sNoInstall; + ::rtl::OUString m_sThisErrorOccurred; + + FixedText m_ft_action; + ProgressBar m_statusbar; + FixedText m_ft_extension_name; + FixedText m_ft_results; + AutoScrollEdit m_mle_info; + FixedLine m_line; + HelpButton m_help; + OKButton m_ok; + CancelButton m_cancel; +}; + + + + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/dp_gui_updateinstalldialog.src b/desktop/source/deployment/gui/dp_gui_updateinstalldialog.src new file mode 100644 index 000000000000..d77dd256582c --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_updateinstalldialog.src @@ -0,0 +1,203 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "svtools/controldims.hrc" + +#include "dp_gui.hrc" + + +#define LOCAL_WIDTH (60 * RSC_BS_CHARWIDTH) +#define LOCAL_LIST_HEIGHT (7 * RSC_BS_CHARHEIGHT) +#define LOCAL_BUTTON_WIDTH 80 + +ModalDialog RID_DLG_UPDATEINSTALL { + HelpId = HID_DEPLOYMENT_GUI_UPDATEINSTALL; + Size = MAP_APPFONT( + (RSC_SP_DLG_INNERBORDER_LEFT + LOCAL_WIDTH + + RSC_SP_DLG_INNERBORDER_RIGHT), + (RSC_SP_DLG_INNERBORDER_TOP + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + RSC_CD_CHECKBOX_HEIGHT + + RSC_SP_CTRL_DESC_Y + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_Y + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_FLGR_SPACE_Y + LOCAL_LIST_HEIGHT + + RSC_SP_FLGR_SPACE_Y + RSC_CD_FIXEDLINE_HEIGHT + + RSC_SP_FLGR_SPACE_Y + RSC_CD_PUSHBUTTON_HEIGHT + + RSC_SP_DLG_INNERBORDER_BOTTOM)); + Text[en-US] = "Download and Installation"; + Moveable = TRUE; + Closeable = TRUE; + FixedText RID_DLG_UPDATE_INSTALL_DOWNLOADING { + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT, RSC_SP_DLG_INNERBORDER_TOP); + Size = MAP_APPFONT(LOCAL_WIDTH, RSC_CD_FIXEDTEXT_HEIGHT); + Text[en-US] = "Downloading extensions..."; + NoLabel = TRUE; + }; + + Window RID_DLG_UPDATE_INSTALL_STATUSBAR { + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT, + (RSC_SP_DLG_INNERBORDER_TOP + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y)); + + Size = MAP_APPFONT(LOCAL_WIDTH, RSC_CD_CHECKBOX_HEIGHT); + Border = TRUE; + }; + + FixedText RID_DLG_UPDATE_INSTALL_EXTENSION_NAME { + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT, + RSC_SP_DLG_INNERBORDER_TOP + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + RSC_CD_CHECKBOX_HEIGHT + RSC_SP_CTRL_DESC_Y); + Size = MAP_APPFONT(LOCAL_WIDTH, RSC_CD_FIXEDTEXT_HEIGHT); + Text[en-US] = ""; + NoLabel = TRUE; + }; + + FixedText RID_DLG_UPDATE_INSTALL_RESULTS { + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT, + RSC_SP_DLG_INNERBORDER_TOP + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + RSC_CD_CHECKBOX_HEIGHT + + RSC_SP_CTRL_DESC_Y + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_Y); + Size = MAP_APPFONT(LOCAL_WIDTH, RSC_CD_FIXEDTEXT_HEIGHT); + Text[en-US] = "Result"; + }; + + MultiLineEdit RID_DLG_UPDATE_INSTALL_INFO { + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT, + RSC_SP_DLG_INNERBORDER_TOP + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + RSC_CD_CHECKBOX_HEIGHT + + RSC_SP_CTRL_DESC_Y + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_Y + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y); + + Size = MAP_APPFONT(LOCAL_WIDTH, LOCAL_LIST_HEIGHT); + Border = TRUE; + ReadOnly = TRUE; + VScroll = TRUE; + TabStop = FALSE; + }; + + FixedLine RID_DLG_UPDATE_INSTALL_LINE { + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT, + RSC_SP_DLG_INNERBORDER_TOP + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + RSC_CD_CHECKBOX_HEIGHT + + RSC_SP_CTRL_DESC_Y + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_Y + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + LOCAL_LIST_HEIGHT + + RSC_SP_FLGR_SPACE_Y); + + Size = MAP_APPFONT(LOCAL_WIDTH, RSC_CD_FIXEDLINE_HEIGHT); + }; + + OKButton RID_DLG_UPDATE_INSTALL_OK { + Disable = TRUE; + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT + LOCAL_WIDTH - LOCAL_BUTTON_WIDTH - + RSC_SP_CTRL_GROUP_X - RSC_CD_PUSHBUTTON_WIDTH, + RSC_SP_DLG_INNERBORDER_TOP + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + RSC_CD_CHECKBOX_HEIGHT + + RSC_SP_CTRL_DESC_Y + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_Y + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + LOCAL_LIST_HEIGHT + + RSC_SP_FLGR_SPACE_Y + RSC_CD_FIXEDLINE_HEIGHT + + RSC_SP_FLGR_SPACE_Y); + + + Size = MAP_APPFONT(RSC_CD_PUSHBUTTON_WIDTH, RSC_CD_PUSHBUTTON_HEIGHT); + Text[en-US] = "OK"; + }; + + CancelButton RID_DLG_UPDATE_INSTALL_ABORT { + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT + LOCAL_WIDTH - LOCAL_BUTTON_WIDTH, + RSC_SP_DLG_INNERBORDER_TOP + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + RSC_CD_CHECKBOX_HEIGHT + + RSC_SP_CTRL_DESC_Y + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_Y + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + LOCAL_LIST_HEIGHT + + RSC_SP_FLGR_SPACE_Y + RSC_CD_FIXEDLINE_HEIGHT + + RSC_SP_FLGR_SPACE_Y); + + Size = MAP_APPFONT(LOCAL_BUTTON_WIDTH, RSC_CD_PUSHBUTTON_HEIGHT); + Text[en-US] = "Cancel Update"; + DefButton = TRUE; + }; + + HelpButton RID_DLG_UPDATE_INSTALL_HELP { + Pos = MAP_APPFONT( + RSC_SP_DLG_INNERBORDER_LEFT, + RSC_SP_DLG_INNERBORDER_TOP + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + RSC_CD_CHECKBOX_HEIGHT + + RSC_SP_CTRL_DESC_Y + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_Y + RSC_CD_FIXEDTEXT_HEIGHT + + RSC_SP_CTRL_DESC_Y + LOCAL_LIST_HEIGHT + + RSC_SP_FLGR_SPACE_Y + RSC_CD_FIXEDLINE_HEIGHT + + RSC_SP_FLGR_SPACE_Y); + Size = MAP_APPFONT(RSC_CD_PUSHBUTTON_WIDTH, RSC_CD_PUSHBUTTON_HEIGHT); + }; + + + String RID_DLG_UPDATE_INSTALL_INSTALLING { + Text[en-US] = "Installing extensions..."; + }; + + String RID_DLG_UPDATE_INSTALL_FINISHED { + Text[en-US] = "Installation finished"; + }; + + String RID_DLG_UPDATE_INSTALL_NO_ERRORS { + Text[en-US] = "No errors."; + }; + + String RID_DLG_UPDATE_INSTALL_ERROR_DOWNLOAD { + Text[en-US] = "Error while downloading extension %NAME. "; + }; + + String RID_DLG_UPDATE_INSTALL_THIS_ERROR_OCCURRED { + Text[en-US] = "The error message is: "; + }; + + + String RID_DLG_UPDATE_INSTALL_ERROR_INSTALLATION { + Text[en-US] = "Error while installing extension %NAME. "; + }; + + String RID_DLG_UPDATE_INSTALL_ERROR_LIC_DECLINED { + Text[en-US] = "The license agreement for extension %NAME was refused. "; + }; + + String RID_DLG_UPDATE_INSTALL_EXTENSION_NOINSTALL{ + Text[en-US] = "The extension will not be installed."; + }; + +}; + diff --git a/desktop/source/deployment/gui/dp_gui_versionboxes.src b/desktop/source/deployment/gui/dp_gui_versionboxes.src new file mode 100644 index 000000000000..878521ad6dd2 --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_versionboxes.src @@ -0,0 +1,76 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "dp_gui.hrc" + +WarningBox RID_WARNINGBOX_VERSION_LESS { + Buttons = WB_OK_CANCEL; + DefButton = WB_DEF_CANCEL; + Message[en-US] = "You are about to install version $NEW of the extension \'$NAME\'.\n" + "The newer version $DEPLOYED is already installed.\n" + "Click \'OK\' to replace the installed extension.\n" + "Click \'Cancel\' to stop the installation."; +}; + +String RID_STR_WARNINGBOX_VERSION_LESS_DIFFERENT_NAMES { + Text [en-US] = "You are about to install version $NEW of the extension \'$NAME\'.\n" + "The newer version $DEPLOYED, named \'$OLDNAME\', is already installed.\n" + "Click \'OK\' to replace the installed extension.\n" + "Click \'Cancel\' to stop the installation."; +}; + +WarningBox RID_WARNINGBOX_VERSION_EQUAL { + Buttons = WB_OK_CANCEL; + DefButton = WB_DEF_CANCEL; + Message[en-US] = "You are about to install version $NEW of the extension \'$NAME\'.\n" + "That version is already installed.\n" + "Click \'OK\' to replace the installed extension.\n" + "Click \'Cancel\' to stop the installation."; +}; + +String RID_STR_WARNINGBOX_VERSION_EQUAL_DIFFERENT_NAMES { + Text [en-US] = "You are about to install version $NEW of the extension \'$NAME\'.\n" + "That version, named \'$OLDNAME\', is already installed.\n" + "Click \'OK\' to replace the installed extension.\n" + "Click \'Cancel\' to stop the installation."; +}; + +WarningBox RID_WARNINGBOX_VERSION_GREATER { + Buttons = WB_OK_CANCEL; + DefButton = WB_DEF_OK; + Message[en-US] = "You are about to install version $NEW of the extension \'$NAME\'.\n" + "The older version $DEPLOYED is already installed.\n" + "Click \'OK\' to replace the installed extension.\n" + "Click \'Cancel\' to stop the installation."; +}; + +String RID_STR_WARNINGBOX_VERSION_GREATER_DIFFERENT_NAMES { + TEXT [en-US] = "You are about to install version $NEW of the extension \'$NAME\'.\n" + "The older version $DEPLOYED, named \'$OLDNAME\', is already installed.\n" + "Click \'OK\' to replace the installed extension.\n" + "Click \'Cancel\' to stop the installation."; +};
\ No newline at end of file diff --git a/desktop/source/deployment/gui/license_dialog.cxx b/desktop/source/deployment/gui/license_dialog.cxx new file mode 100644 index 000000000000..32faa7123b5b --- /dev/null +++ b/desktop/source/deployment/gui/license_dialog.cxx @@ -0,0 +1,325 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "cppuhelper/implbase2.hxx" +#include "cppuhelper/implementationentry.hxx" +#include "unotools/configmgr.hxx" +#include "comphelper/servicedecl.hxx" +#include "comphelper/unwrapargs.hxx" +#include "i18npool/mslangid.hxx" +#include "vcl/svapp.hxx" +#include "vcl/msgbox.hxx" +#include "toolkit/helper/vclunohelper.hxx" +#include "com/sun/star/lang/XServiceInfo.hpp" +#include "com/sun/star/task/XJobExecutor.hpp" +#include "svtools/svmedit.hxx" +#include "svl/lstner.hxx" +#include "svtools/xtextedt.hxx" +#include <vcl/scrbar.hxx> +#include "vcl/threadex.hxx" + + + +#include "boost/bind.hpp" +#include "dp_gui_shared.hxx" +#include "license_dialog.hxx" +#include "dp_gui.hrc" + +using namespace ::dp_misc; +namespace cssu = ::com::sun::star::uno; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using ::rtl::OUString; + +namespace dp_gui { + +class LicenseView : public MultiLineEdit, public SfxListener +{ + BOOL mbEndReached; + Link maEndReachedHdl; + Link maScrolledHdl; + +public: + LicenseView( Window* pParent, const ResId& rResId ); + ~LicenseView(); + + void ScrollDown( ScrollType eScroll ); + + BOOL IsEndReached() const; + BOOL EndReached() const { return mbEndReached; } + void SetEndReached( BOOL bEnd ) { mbEndReached = bEnd; } + + void SetEndReachedHdl( const Link& rHdl ) { maEndReachedHdl = rHdl; } + const Link& GetAutocompleteHdl() const { return maEndReachedHdl; } + + void SetScrolledHdl( const Link& rHdl ) { maScrolledHdl = rHdl; } + const Link& GetScrolledHdl() const { return maScrolledHdl; } + + virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ); + +protected: + using MultiLineEdit::Notify; +}; + +struct LicenseDialogImpl : public ModalDialog +{ + cssu::Reference<cssu::XComponentContext> m_xComponentContext; + FixedText m_ftHead; + FixedText m_ftBody1; + FixedText m_ftBody1Txt; + FixedText m_ftBody2; + FixedText m_ftBody2Txt; + FixedImage m_fiArrow1; + FixedImage m_fiArrow2; + LicenseView m_mlLicense; + PushButton m_pbDown; + FixedLine m_flBottom; + + OKButton m_acceptButton; + CancelButton m_declineButton; + + DECL_LINK(PageDownHdl, PushButton*); + DECL_LINK(ScrolledHdl, LicenseView*); + DECL_LINK(EndReachedHdl, LicenseView*); + + bool m_bLicenseRead; + + virtual ~LicenseDialogImpl(); + + LicenseDialogImpl( + Window * pParent, + css::uno::Reference< css::uno::XComponentContext > const & xContext, + const ::rtl::OUString & sExtensionName, + const ::rtl::OUString & sLicenseText); + + virtual void Activate(); + +}; + +LicenseView::LicenseView( Window* pParent, const ResId& rResId ) + : MultiLineEdit( pParent, rResId ) +{ + SetLeftMargin( 5 ); + mbEndReached = IsEndReached(); + StartListening( *GetTextEngine() ); +} + +LicenseView::~LicenseView() +{ + maEndReachedHdl = Link(); + maScrolledHdl = Link(); + EndListeningAll(); +} + +void LicenseView::ScrollDown( ScrollType eScroll ) +{ + ScrollBar* pScroll = GetVScrollBar(); + if ( pScroll ) + pScroll->DoScrollAction( eScroll ); +} + +BOOL LicenseView::IsEndReached() const +{ + BOOL bEndReached; + + ExtTextView* pView = GetTextView(); + ExtTextEngine* pEdit = GetTextEngine(); + ULONG nHeight = pEdit->GetTextHeight(); + Size aOutSize = pView->GetWindow()->GetOutputSizePixel(); + Point aBottom( 0, aOutSize.Height() ); + + if ( (ULONG) pView->GetDocPos( aBottom ).Y() >= nHeight - 1 ) + bEndReached = TRUE; + else + bEndReached = FALSE; + + return bEndReached; +} + +void LicenseView::Notify( SfxBroadcaster&, const SfxHint& rHint ) +{ + if ( rHint.IsA( TYPE(TextHint) ) ) + { + BOOL bLastVal = EndReached(); + ULONG nId = ((const TextHint&)rHint).GetId(); + + if ( nId == TEXT_HINT_PARAINSERTED ) + { + if ( bLastVal ) + mbEndReached = IsEndReached(); + } + else if ( nId == TEXT_HINT_VIEWSCROLLED ) + { + if ( ! mbEndReached ) + mbEndReached = IsEndReached(); + maScrolledHdl.Call( this ); + } + + if ( EndReached() && !bLastVal ) + { + maEndReachedHdl.Call( this ); + } + } +} + +//============================================================================================================== + +LicenseDialogImpl::LicenseDialogImpl( + Window * pParent, + cssu::Reference< cssu::XComponentContext > const & xContext, + const ::rtl::OUString & sExtensionName, + const ::rtl::OUString & sLicenseText): + ModalDialog(pParent, DpGuiResId(RID_DLG_LICENSE)) + ,m_xComponentContext(xContext) + ,m_ftHead(this, DpGuiResId(FT_LICENSE_HEADER)) + ,m_ftBody1(this, DpGuiResId(FT_LICENSE_BODY_1)) + ,m_ftBody1Txt(this, DpGuiResId(FT_LICENSE_BODY_1_TXT)) + ,m_ftBody2(this, DpGuiResId(FT_LICENSE_BODY_2)) + ,m_ftBody2Txt(this, DpGuiResId(FT_LICENSE_BODY_2_TXT)) + ,m_fiArrow1(this, DpGuiResId(FI_LICENSE_ARROW1)) + ,m_fiArrow2(this, DpGuiResId(FI_LICENSE_ARROW2)) + ,m_mlLicense(this, DpGuiResId(ML_LICENSE)) + ,m_pbDown(this, DpGuiResId(PB_LICENSE_DOWN)) + ,m_flBottom(this, DpGuiResId(FL_LICENSE)) + ,m_acceptButton(this, DpGuiResId(BTN_LICENSE_ACCEPT)) + ,m_declineButton(this, DpGuiResId(BTN_LICENSE_DECLINE)) + ,m_bLicenseRead(false) + +{ + + FreeResource(); + + m_acceptButton.SetUniqueId(UID_BTN_LICENSE_ACCEPT); + m_fiArrow1.Show(true); + m_fiArrow2.Show(false); + m_mlLicense.SetText(sLicenseText); + m_ftHead.SetText(m_ftHead.GetText() + OUString('\n') + sExtensionName); + + m_mlLicense.SetEndReachedHdl( LINK(this, LicenseDialogImpl, EndReachedHdl) ); + m_mlLicense.SetScrolledHdl( LINK(this, LicenseDialogImpl, ScrolledHdl) ); + m_pbDown.SetClickHdl( LINK(this, LicenseDialogImpl, PageDownHdl) ); + + // We want a automatic repeating page down button + WinBits aStyle = m_pbDown.GetStyle(); + aStyle |= WB_REPEAT; + m_pbDown.SetStyle( aStyle ); +} + +LicenseDialogImpl::~LicenseDialogImpl() +{ +} + +void LicenseDialogImpl::Activate() +{ + if (!m_bLicenseRead) + { + //Only enable the scroll down button if the license text does not fit into the window + if (m_mlLicense.IsEndReached()) + { + m_pbDown.Disable(); + m_acceptButton.Enable(); + m_acceptButton.GrabFocus(); + } + else + { + m_pbDown.Enable(); + m_pbDown.GrabFocus(); + m_acceptButton.Disable(); + } + } +} + +IMPL_LINK( LicenseDialogImpl, ScrolledHdl, LicenseView *, EMPTYARG ) +{ + + if (m_mlLicense.IsEndReached()) + m_pbDown.Disable(); + else + m_pbDown.Enable(); + + return 0; +} + +IMPL_LINK( LicenseDialogImpl, PageDownHdl, PushButton *, EMPTYARG ) +{ + m_mlLicense.ScrollDown( SCROLL_PAGEDOWN ); + return 0; +} + +IMPL_LINK( LicenseDialogImpl, EndReachedHdl, LicenseView *, EMPTYARG ) +{ + m_acceptButton.Enable(); + m_acceptButton.GrabFocus(); + m_fiArrow1.Show(false); + m_fiArrow2.Show(true); + m_bLicenseRead = true; + return 0; +} + +//================================================================================= + + + + +LicenseDialog::LicenseDialog( Sequence<Any> const& args, + Reference<XComponentContext> const& xComponentContext) + : m_xComponentContext(xComponentContext) +{ + comphelper::unwrapArgs( args, m_parent, m_sExtensionName, m_sLicenseText ); +} + +// XExecutableDialog +//______________________________________________________________________________ +void LicenseDialog::setTitle( OUString const & ) throw (RuntimeException) +{ + +} + +//______________________________________________________________________________ +sal_Int16 LicenseDialog::execute() throw (RuntimeException) +{ + return vcl::solarthread::syncExecute( + boost::bind( &LicenseDialog::solar_execute, this)); +} + +sal_Int16 LicenseDialog::solar_execute() +{ + std::auto_ptr<LicenseDialogImpl> dlg( + new LicenseDialogImpl( + VCLUnoHelper::GetWindow(m_parent), + m_xComponentContext, m_sExtensionName, m_sLicenseText)); + + return dlg->Execute(); +} + +} // namespace dp_gui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/license_dialog.hxx b/desktop/source/deployment/gui/license_dialog.hxx new file mode 100644 index 000000000000..cb43f74ee528 --- /dev/null +++ b/desktop/source/deployment/gui/license_dialog.hxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_GUI_LICENSE_DIALOG_HXX +#define INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_GUI_LICENSE_DIALOG_HXX + +#include "dp_gui.h" +#include "cppuhelper/implbase1.hxx" +#include "com/sun/star/lang/XServiceInfo.hpp" +#include "com/sun/star/task/XJobExecutor.hpp" +#include "com/sun/star/ui/dialogs/XExecutableDialog.hpp" + +#include "boost/bind.hpp" + +using namespace ::dp_misc; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using ::rtl::OUString; + +namespace dp_gui { + +class LicenseDialog + : public ::cppu::WeakImplHelper1<ui::dialogs::XExecutableDialog> +// task::XJobExecutor> +{ + Reference<XComponentContext> const m_xComponentContext; + Reference<awt::XWindow> /* const */ m_parent; + OUString m_sExtensionName; + OUString /* const */ m_sLicenseText; + OUString m_initialTitle; + + sal_Int16 solar_execute(); + +public: + LicenseDialog( Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ); + + // XExecutableDialog + virtual void SAL_CALL setTitle( OUString const & title ) + throw (RuntimeException); + virtual sal_Int16 SAL_CALL execute() throw (RuntimeException); + + //// XJobExecutor + //virtual void SAL_CALL trigger( OUString const & event ) + // throw (RuntimeException); +}; +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/makefile.mk b/desktop/source/deployment/gui/makefile.mk new file mode 100644 index 000000000000..9f1a50134248 --- /dev/null +++ b/desktop/source/deployment/gui/makefile.mk @@ -0,0 +1,108 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/.. + +PRJNAME = desktop +TARGET = deploymentgui +ENABLE_EXCEPTIONS = TRUE +#USE_DEFFILE = TRUE +NO_BSYMBOLIC = TRUE +USE_PCH := +ENABLE_PCH := +PRJINC:=..$/.. + +.IF "$(GUI)"=="OS2" +TARGET = deplgui +.ENDIF + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/source$/deployment$/inc$/dp_misc.mk +DLLPRE = + +SLOFILES = \ + $(SLO)$/dp_gui_service.obj \ + $(SLO)$/dp_gui_extlistbox.obj \ + $(SLO)$/dp_gui_dialog2.obj \ + $(SLO)$/dp_gui_theextmgr.obj \ + $(SLO)$/license_dialog.obj \ + $(SLO)$/dp_gui_dependencydialog.obj \ + $(SLO)$/dp_gui_thread.obj \ + $(SLO)$/dp_gui_updatedialog.obj \ + $(SLO)$/dp_gui_updateinstalldialog.obj \ + $(SLO)$/dp_gui_autoscrolledit.obj \ + $(SLO)$/dp_gui_extensioncmdqueue.obj \ + $(SLO)$/descedit.obj + +SHL1TARGET = $(TARGET)$(DLLPOSTFIX).uno +SHL1VERSIONMAP = $(SOLARENV)/src/component.map + +SHL1STDLIBS = \ + $(SALLIB) \ + $(SALHELPERLIB) \ + $(CPPULIB) \ + $(CPPUHELPERLIB) \ + $(UCBHELPERLIB) \ + $(COMPHELPERLIB) \ + $(UNOTOOLSLIB) \ + $(TOOLSLIB) \ + $(I18NISOLANGLIB) \ + $(TKLIB) \ + $(VCLLIB) \ + $(SVTOOLLIB) \ + $(SVLLIB) \ + $(SVXLIB) \ + $(SVXCORELIB) \ + $(SFXLIB) \ + $(DEPLOYMENTMISCLIB) \ + $(OLE32LIB) + +SHL1DEPN = +SHL1IMPLIB = i$(TARGET) +SHL1LIBS = $(SLB)$/$(TARGET).lib +SHL1DEF = $(MISC)$/$(SHL1TARGET).def + +DEF1NAME = $(SHL1TARGET) +#DEFLIB1NAME = $(TARGET) +#DEF1DEPN = + +SRS1NAME = $(TARGET) +SRC1FILES = \ + dp_gui_dialog.src \ + dp_gui_dialog2.src \ + dp_gui_backend.src \ + dp_gui_dependencydialog.src \ + dp_gui_updatedialog.src \ + dp_gui_versionboxes.src \ + dp_gui_updateinstalldialog.src + +RESLIB1NAME = $(TARGET) +RESLIB1SRSFILES = $(SRS)$/$(TARGET).srs +RESLIB1IMAGES= $(PRJ)$/res + +.INCLUDE : target.mk + diff --git a/desktop/source/deployment/inc/db.hxx b/desktop/source/deployment/inc/db.hxx new file mode 100644 index 000000000000..22e9e357b549 --- /dev/null +++ b/desktop/source/deployment/inc/db.hxx @@ -0,0 +1,147 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef BERKELEYDBPROXY_DB_HXX_ +#define BERKELEYDBPROXY_DB_HXX_ + +#include <boost/noncopyable.hpp> + +#ifdef SYSTEM_DB +#include <db.h> +#else +#include <berkeleydb/db.h> +#endif + +#include <rtl/string.hxx> +#include "dp_misc_api.hxx" + +extern "C" { + typedef void *(*db_malloc_fcn_type)(size_t); + typedef void *(*db_realloc_fcn_type)(void *, size_t); + typedef void (*db_free_fcn_type)(void *); +} + +namespace berkeleydbproxy { + + class DbEnv; + class Dbc; + class Dbt; + + class DESKTOP_DEPLOYMENTMISC_DLLPUBLIC DbException + { + rtl::OString what_; + public: + explicit DbException(rtl::OString const & theWhat) + : what_(theWhat) + {} + + const char *what() const + { return what_.getStr(); } + int get_errno() const + { return 0; } + }; + + + class DESKTOP_DEPLOYMENTMISC_DLLPUBLIC DbEnv : boost::noncopyable + { + friend class Db; + + private: + DB_ENV* m_pDBENV; + + public: + static char *strerror(int); + }; + + class DESKTOP_DEPLOYMENTMISC_DLLPUBLIC Db : boost::noncopyable + { + private: + DB* m_pDBP; + + public: + Db(DbEnv* dbbenv,u_int32_t flags); + ~Db(); + + int close(u_int32_t flags); + + int open(DB_TXN *txnid, + const char *file, + const char *database, + DBTYPE type, + u_int32_t flags, + int mode); + + int sync(u_int32_t flags); + int del(Dbt *key, u_int32_t flags); + + int get(DB_TXN* txnid, Dbt *key, Dbt *data, u_int32_t flags); + int put(DB_TXN* txnid, Dbt *key, Dbt *data, u_int32_t flags); + + int cursor(DB_TXN *txnid, Dbc **cursorp, u_int32_t flags); + }; + + class DESKTOP_DEPLOYMENTMISC_DLLPUBLIC Dbc : boost::noncopyable + { + friend class Db; + friend class Dbt; + + private: + DBC* m_pDBC; + + SAL_DLLPRIVATE explicit Dbc(DBC* pDBC); + SAL_DLLPRIVATE ~Dbc(); + + public: + int close(); + + int get(Dbt *key, Dbt *data, u_int32_t flags); + }; + + class DESKTOP_DEPLOYMENTMISC_DLLPUBLIC Dbt: private DBT + { + friend class Db; + friend class Dbc; + + public: + Dbt(void *data_arg, u_int32_t size_arg); + + Dbt(); + Dbt(const Dbt & other); + Dbt & operator=(const Dbt & other); + + ~Dbt(); + + void *get_data() const; + void set_data(void *value); + + u_int32_t get_size() const; + void set_size(u_int32_t value); + }; +} + +#endif +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/inc/dp_dependencies.hxx b/desktop/source/deployment/inc/dp_dependencies.hxx new file mode 100644 index 000000000000..07221e173520 --- /dev/null +++ b/desktop/source/deployment/inc/dp_dependencies.hxx @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_INC_DP_DEPENDENCIES_HXX +#define INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_INC_DP_DEPENDENCIES_HXX + +#include "sal/config.h" +#include "com/sun/star/uno/Reference.hxx" +#include "com/sun/star/uno/Sequence.hxx" +#include "dp_misc_api.hxx" + +/// @HTML + +namespace com { namespace sun { namespace star { namespace xml { namespace dom { + class XElement; +} } } } } +namespace dp_misc { class DescriptionInfoset; } +namespace rtl { class OUString; } + +namespace dp_misc { + +/** + Dependency handling. +*/ +namespace Dependencies { + /** + Check for unsatisfied dependencies. + + @param infoset + the infoset containing the dependencies to check + + @return + a list of the unsatisfied dependencies from <code>infoset</code> (in no + specific order) + */ + DESKTOP_DEPLOYMENTMISC_DLLPUBLIC + ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< + ::com::sun::star::xml::dom::XElement > > + check(::dp_misc::DescriptionInfoset const & infoset); + + /** + Obtain the (human-readable) error message of a failed dependency. + + @param dependency + a dependency represented as a non-null XML element + + @return + the name of the dependency; will never be empty, as a localized + “unknown” is substituted for an empty/missing name + */ + DESKTOP_DEPLOYMENTMISC_DLLPUBLIC ::rtl::OUString getErrorText( + ::com::sun::star::uno::Reference< + ::com::sun::star::xml::dom::XElement > const & dependency); +} + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/inc/dp_descriptioninfoset.hxx b/desktop/source/deployment/inc/dp_descriptioninfoset.hxx new file mode 100644 index 000000000000..d16e9127af8a --- /dev/null +++ b/desktop/source/deployment/inc/dp_descriptioninfoset.hxx @@ -0,0 +1,302 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_INC_DP_DESCRIPTIONINFOSET_HXX +#define INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_INC_DP_DESCRIPTIONINFOSET_HXX + +#include "sal/config.h" + +#include "boost/optional.hpp" +#include "com/sun/star/uno/Reference.hxx" +#include "com/sun/star/uno/Sequence.hxx" +#include "sal/types.h" +#include "dp_misc_api.hxx" + +/// @HTML + +namespace com { namespace sun { namespace star { + namespace lang { struct Locale; } + namespace uno { class XComponentContext; } + namespace xml { + namespace dom { + class XNode; + class XNodeList; + } + namespace xpath { class XXPathAPI; } + } +} } } +namespace rtl { class OUString; } + +namespace dp_misc { + +struct DESKTOP_DEPLOYMENTMISC_DLLPUBLIC SimpleLicenseAttributes +{ + ::rtl::OUString acceptBy; + //Attribute suppress-on-update. Default is false. + bool suppressOnUpdate; + //Attribute suppress-if-required. Default is false. + bool suppressIfRequired; +}; + + +/** + Access to the content of an XML <code>description</code> element. + + <p>This works for <code>description</code> elements in both the + <code>description.xml</code> file and online update information formats.</p> +*/ +class DESKTOP_DEPLOYMENTMISC_DLLPUBLIC DescriptionInfoset { +public: + /** + Create an instance. + + @param context + a non-null component context + + @param element + a <code>description</code> element; may be null (equivalent to an element + with no content) + */ + DescriptionInfoset( + ::com::sun::star::uno::Reference< + ::com::sun::star::uno::XComponentContext > const & context, + ::com::sun::star::uno::Reference< + ::com::sun::star::xml::dom::XNode > const & element); + + ~DescriptionInfoset(); + + /** + Return the identifier. + + @return + the identifier, or an empty <code>optional</code> if none is specified + */ + ::boost::optional< ::rtl::OUString > getIdentifier() const; + + /** + Return the textual version representation. + + @return + textual version representation + */ + ::rtl::OUString getVersion() const; + + /** + Returns a list of supported platforms. + + If the extension does not specify a platform by leaving out the platform element + then we assume that the extension supports all platforms. In this case the returned + sequence will have one element, which is "all". + If the platform element is present but does not specify a platform then an empty + sequence is returned. Examples for invalid platform elements: + <pre> + <platform />, <platform value="" />, <platfrom value=","> + </pre> + + The value attribute can contain various platform tokens. They must be separated by + commas.Each token will be stripped from leading and trailing white space (trim()). + */ + ::com::sun::star::uno::Sequence< ::rtl::OUString > getSupportedPlaforms() const; + + /** + Returns the localized publisher name and the corresponding URL. + + In case there is no publisher element then a pair of two empty strings is returned. + */ + ::std::pair< ::rtl::OUString, ::rtl::OUString > getLocalizedPublisherNameAndURL() const; + + /** + Returns the URL for the release notes corresponding to the office's locale. + + In case there is no release-notes element then an empty string is returned. + */ + ::rtl::OUString getLocalizedReleaseNotesURL() const; + + /** returns the relative path to the license file. + + In case there is no simple-license element then an empty string is returned. + */ + ::rtl::OUString getLocalizedLicenseURL() const; + + /** returns the attributes of the simple-license element + + As long as there is a simple-license element, the function will return + the structure. If it does not exist, then the optional object is uninitialized. + */ + ::boost::optional<SimpleLicenseAttributes> getSimpleLicenseAttributes() const; + + /** returns the localized display name of the extensions. + + In case there is no localized display-name then an empty string is returned. + */ + ::rtl::OUString getLocalizedDisplayName() const; + + /** + returns the download website URL from the update information. + + There can be multiple URLs where each is assigned to a particular locale. + The function returs the URL which locale matches best the one used in the office. + + The return value is an optional because it may be necessary to find out if there + was a value provided or not. This is necessary to flag the extension in the update dialog + properly as "browser based update". The return value will only then not be initialized + if there is no <code><update-website></code>. If the element exists, then it must + have at least one child element containing an URL. + + The <code><update-website></code> and <code><update-download></code> + elements are mutually exclusiv. + + @return + the download website URL, or an empty <code>optional</code> if none is + specified + */ + ::boost::optional< ::rtl::OUString > getLocalizedUpdateWebsiteURL() const; + + /** returns the relative URL to the description. + + The URL is relative to the root directory of the extensions. + */ + ::rtl::OUString getLocalizedDescriptionURL() const; + /** + Return the dependencies. + + @return + dependencies; will never be null + */ + ::com::sun::star::uno::Reference< ::com::sun::star::xml::dom::XNodeList > + getDependencies() const; + + /** + Return the update information URLs. + + @return + update information URLs + */ + ::com::sun::star::uno::Sequence< ::rtl::OUString > + getUpdateInformationUrls() const; + + /** + Return the download URLs from the update information. + + Because the <code><update-download></code> and the <code><update-website></code> + elements are mutually exclusive one may need to determine exacty if the element + was provided. + + @return + download URLs + */ + ::com::sun::star::uno::Sequence< ::rtl::OUString > + getUpdateDownloadUrls() const; + + /** + Returns the URL for the icon image. + */ + ::rtl::OUString getIconURL( sal_Bool bHighContrast ) const; + + bool hasDescription() const; + +private: + SAL_DLLPRIVATE ::boost::optional< ::rtl::OUString > getOptionalValue( + ::rtl::OUString const & expression) const; + + SAL_DLLPRIVATE ::com::sun::star::uno::Sequence< ::rtl::OUString > getUrls( + ::rtl::OUString const & expression) const; + + /** Retrieves a child element which as lang attribute which matches the office locale. + + Only top-level children are taken into account. It is also assumed that they are all + of the same element type and have a lang attribute. The matching algoritm is according + to RFC 3066, with the exception that only one variant is allowed. + @param parent + the expression used to obtain the parent of the localized children. It can be null. + Then a null reference is returned. + */ + SAL_DLLPRIVATE ::com::sun::star::uno::Reference< ::com::sun::star::xml::dom::XNode > + getLocalizedChild( ::rtl::OUString const & sParent) const; + SAL_DLLPRIVATE ::com::sun::star::uno::Reference< ::com::sun::star::xml::dom::XNode> + matchFullLocale(::com::sun::star::uno::Reference< + ::com::sun::star::xml::dom::XNode > const & xParent, ::rtl::OUString const & sLocale) const; + SAL_DLLPRIVATE ::com::sun::star::uno::Reference< ::com::sun::star::xml::dom::XNode> + matchCountryAndLanguage(::com::sun::star::uno::Reference< + ::com::sun::star::xml::dom::XNode > const & xParent, + ::com::sun::star::lang::Locale const & officeLocale) const; + SAL_DLLPRIVATE ::com::sun::star::uno::Reference< ::com::sun::star::xml::dom::XNode> + matchLanguage( + ::com::sun::star::uno::Reference< ::com::sun::star::xml::dom::XNode > const & xParent, + ::com::sun::star::lang::Locale const & officeLocale) const; + + /** If there is no child element with a locale matching the office locale, then we use + the first child. In the case of the simple-license we also use the former default locale, which + was determined by the default-license-id (/description/registration/simple-license/@default-license-id) + and the license-id attributes (/description/registration/simple-license/license-text/@license-id). + However, since OOo 2.4 we use also the first child as default for the license + unless the two attributes are present. + */ + SAL_DLLPRIVATE ::com::sun::star::uno::Reference< ::com::sun::star::xml::dom::XNode> + getChildWithDefaultLocale( + ::com::sun::star::uno::Reference< ::com::sun::star::xml::dom::XNode > const & xParent) const; + /** + @param out_bParentExists + indicates if the element node specified in sXPathParent exists. + */ + SAL_DLLPRIVATE ::rtl::OUString getLocalizedHREFAttrFromChild( + ::rtl::OUString const & sXPathParent, bool * out_bParentExists) const; + + static SAL_DLLPRIVATE ::rtl::OUString + localeToString(::com::sun::star::lang::Locale const & locale); + + /** Gets the node value for a given expression. The expression is used in + m_xpath-selectSingleNode. The value of the returned node is return value + of this function. + */ + SAL_DLLPRIVATE ::rtl::OUString + getNodeValueFromExpression(::rtl::OUString const & expression) const; + + ::com::sun::star::uno::Reference< + ::com::sun::star::xml::dom::XNode > m_element; + ::com::sun::star::uno::Reference< + ::com::sun::star::xml::xpath::XXPathAPI > m_xpath; +}; + +inline bool DescriptionInfoset::hasDescription() const +{ + return m_element.is(); +} + +/** creates a DescriptionInfoset object. + + The argument sExtensionFolderURL is a file URL to extension folder containing + the description.xml. + */ +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +DescriptionInfoset getDescriptionInfoset(::rtl::OUString const & sExtensionFolderURL); +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/inc/dp_identifier.hxx b/desktop/source/deployment/inc/dp_identifier.hxx new file mode 100644 index 000000000000..f58b7663a173 --- /dev/null +++ b/desktop/source/deployment/inc/dp_identifier.hxx @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_INC_DP_IDENTIFIER_HXX +#define INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_INC_DP_IDENTIFIER_HXX + +#include "sal/config.h" + +#include "boost/optional.hpp" +#include "com/sun/star/uno/Reference.hxx" + +#include "dp_misc_api.hxx" + +namespace com { namespace sun { namespace star { namespace deployment { + class XPackage; +} } } } +namespace rtl { class OUString; } + +namespace dp_misc { + +/** + Generates an identifier from an optional identifier. + + @param optional + an optional identifier + + @param fileName + a file name + + @return + the given optional identifier if present, otherwise a legacy identifier based + on the given file name +*/ +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC ::rtl::OUString generateIdentifier( + ::boost::optional< ::rtl::OUString > const & optional, + ::rtl::OUString const & fileName); + +/** + Gets the identifier of a package. + + @param package + a non-null package + + @return + the explicit identifier of the given package if present, otherwise the + implicit legacy identifier of the given package + + @throws com::sun::star::uno::RuntimeException +*/ +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC ::rtl::OUString getIdentifier( + ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > + const & package); + +/** + Generates a legacy identifier based on a file name. + + @param fileName + a file name + + @return + a legacy identifier based on the given file name +*/ +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC ::rtl::OUString generateLegacyIdentifier( + ::rtl::OUString const & fileName); + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/inc/dp_interact.h b/desktop/source/deployment/inc/dp_interact.h new file mode 100644 index 000000000000..7a59e944f6af --- /dev/null +++ b/desktop/source/deployment/inc/dp_interact.h @@ -0,0 +1,153 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_INTERACT_H +#define INCLUDED_DP_INTERACT_H + +#include "rtl/ref.hxx" +#include "cppuhelper/implbase1.hxx" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/ucb/XCommandEnvironment.hpp" +#include "com/sun/star/task/XAbortChannel.hpp" +#include "dp_misc_api.hxx" + +namespace css = ::com::sun::star; + +namespace dp_misc +{ + +inline void progressUpdate( + ::rtl::OUString const & status, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) +{ + if (xCmdEnv.is()) { + css::uno::Reference<css::ucb::XProgressHandler> xProgressHandler( + xCmdEnv->getProgressHandler() ); + if (xProgressHandler.is()) { + xProgressHandler->update( css::uno::makeAny(status) ); + } + } +} + +//============================================================================== +class ProgressLevel +{ + css::uno::Reference<css::ucb::XProgressHandler> m_xProgressHandler; + +public: + inline ~ProgressLevel(); + inline ProgressLevel( + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv, + ::rtl::OUString const & status ); + + inline void update( ::rtl::OUString const & status ) const; + inline void update( css::uno::Any const & status ) const; +}; + +//______________________________________________________________________________ +inline ProgressLevel::ProgressLevel( + css::uno::Reference< css::ucb::XCommandEnvironment > const & xCmdEnv, + ::rtl::OUString const & status ) +{ + if (xCmdEnv.is()) + m_xProgressHandler = xCmdEnv->getProgressHandler(); + if (m_xProgressHandler.is()) + m_xProgressHandler->push( css::uno::makeAny(status) ); +} + +//______________________________________________________________________________ +inline ProgressLevel::~ProgressLevel() +{ + if (m_xProgressHandler.is()) + m_xProgressHandler->pop(); +} + +//______________________________________________________________________________ +inline void ProgressLevel::update( ::rtl::OUString const & status ) const +{ + if (m_xProgressHandler.is()) + m_xProgressHandler->update( css::uno::makeAny(status) ); +} + +//______________________________________________________________________________ +inline void ProgressLevel::update( css::uno::Any const & status ) const +{ + if (m_xProgressHandler.is()) + m_xProgressHandler->update( status ); +} + +//############################################################################## + +/** @return true if ia handler is present and any selection has been chosen + */ +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC bool interactContinuation( + css::uno::Any const & request, + css::uno::Type const & continuation, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv, + bool * pcont, bool * pabort ); + +//############################################################################## + +//============================================================================== +class DESKTOP_DEPLOYMENTMISC_DLLPUBLIC AbortChannel : + public ::cppu::WeakImplHelper1<css::task::XAbortChannel> +{ + bool m_aborted; + css::uno::Reference<css::task::XAbortChannel> m_xNext; + +public: + inline AbortChannel() : m_aborted( false ) {} + inline static AbortChannel * get( + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel ) + { return static_cast<AbortChannel *>(xAbortChannel.get()); } + + inline bool isAborted() const { return m_aborted; } + + // XAbortChannel + virtual void SAL_CALL sendAbort() throw (css::uno::RuntimeException); + + class SAL_DLLPRIVATE Chain + { + const ::rtl::Reference<AbortChannel> m_abortChannel; + public: + inline Chain( + ::rtl::Reference<AbortChannel> const & abortChannel, + css::uno::Reference<css::task::XAbortChannel> const & xNext ) + : m_abortChannel( abortChannel ) + { if (m_abortChannel.is()) m_abortChannel->m_xNext = xNext; } + inline ~Chain() + { if (m_abortChannel.is()) m_abortChannel->m_xNext.clear(); } + }; + friend class Chain; +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/inc/dp_misc.h b/desktop/source/deployment/inc/dp_misc.h new file mode 100644 index 000000000000..9e912531e9f8 --- /dev/null +++ b/desktop/source/deployment/inc/dp_misc.h @@ -0,0 +1,182 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_MISC_H +#define INCLUDED_DP_MISC_H + +#include "rtl/ustrbuf.hxx" +#include "rtl/instance.hxx" +#include "osl/mutex.hxx" +#include "osl/process.h" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/lang/XComponent.hpp" +#include "com/sun/star/lang/DisposedException.hpp" +#include "com/sun/star/deployment/XPackageRegistry.hpp" +#include "com/sun/star/ucb/XCommandEnvironment.hpp" +#include "com/sun/star/awt/XWindow.hpp" +#include "dp_misc_api.hxx" + +#define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) +#define ARLEN(x) (sizeof (x) / sizeof *(x)) + +namespace dp_misc { + +const sal_Char CR = 0x0d; +const sal_Char LF = 0x0a; + +//============================================================================== +class MutexHolder +{ + mutable ::osl::Mutex m_mutex; +protected: + inline ::osl::Mutex & getMutex() const { return m_mutex; } +}; + +//============================================================================== +inline void try_dispose( ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface> const & x ) +{ + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent> xComp( x, ::com::sun::star::uno::UNO_QUERY ); + if (xComp.is()) + xComp->dispose(); +} + +//############################################################################## + +//============================================================================== +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +::rtl::OUString expandUnoRcTerm( ::rtl::OUString const & term ); + +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +::rtl::OUString makeRcTerm( ::rtl::OUString const & url ); + +//============================================================================== +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +::rtl::OUString expandUnoRcUrl( ::rtl::OUString const & url ); + +//============================================================================== + +/** appends a relative path to a url. + + The relative path must already be correctly encoded for use in an URL. + If the URL starts with vnd.sun.star.expand then the relative path will + be again encoded for use in an "expand" URL. + */ +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC ::rtl::OUString makeURL( + ::rtl::OUString const & baseURL, ::rtl::OUString const & relPath ); + + +/** appends a relative path to a url. + + This is the same as makeURL, but the relative Path must me a segment + of an system path. + */ +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC ::rtl::OUString makeURLAppendSysPathSegment( + ::rtl::OUString const & baseURL, ::rtl::OUString const & relPath ); + +//============================================================================== +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC ::rtl::OUString generateRandomPipeId(); + +class AbortChannel; +//============================================================================== +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface> resolveUnoURL( + ::rtl::OUString const & connectString, + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext> const & xLocalContext, + AbortChannel * abortChannel = 0 ); + +//============================================================================== +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC bool office_is_running(); + +//============================================================================== +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +oslProcess raiseProcess( ::rtl::OUString const & appURL, + ::com::sun::star::uno::Sequence< ::rtl::OUString > const & args ); + +//============================================================================== + +/** writes the argument string to the console. + On Linux/Unix/etc. it converts the UTF16 string to an ANSI string using + osl_getThreadTextEncoding() as target encoding. On Windows it uses WriteFile + with the standard out stream. unopkg.com reads the data and prints them out using + WriteConsoleW. +*/ +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +void writeConsole(::rtl::OUString const & sText); + +/** writes the argument string to the console. + On Linux/Unix/etc. the string is passed into fprintf without any conversion. + On Windows the string is converted to UTF16 assuming the argument is UTF8 + encoded. The UTF16 string is written to stdout with WriteFile. unopkg.com + reads the data and prints them out using WriteConsoleW. +*/ +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +void writeConsole(::rtl::OString const & sText); + +/** writes the argument to the console using the error stream. + Otherwise the same as writeConsole. +*/ +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +void writeConsoleError(::rtl::OUString const & sText); + + +/** writes the argument to the console using the error stream. + Otherwise the same as writeConsole. +*/ +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +void writeConsoleError(::rtl::OString const & sText); + + +/** reads from the console. + On Linux/Unix/etc. it uses fgets to read char values and converts them to OUString + using osl_getThreadTextEncoding as target encoding. The returned string has a maximum + size of 1024 and does NOT include leading and trailing white space(applied OUString::trim()) +*/ +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +::rtl::OUString readConsole(); + +/** print the text to the console in a debug build. + The argument is forwarded to writeConsole. The function does not add new line. + The code is only executed if OSL_DEBUG_LEVEL > 1 +*/ +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +void TRACE(::rtl::OUString const & sText); +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +void TRACE(::rtl::OString const & sText); + +/** registers or revokes shared or bundled extensions which have been + recently added or removed. +*/ +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +void syncRepositories(::com::sun::star::uno::Reference< + ::com::sun::star::ucb::XCommandEnvironment> const & xCmdEnv); + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/inc/dp_misc.mk b/desktop/source/deployment/inc/dp_misc.mk new file mode 100644 index 000000000000..829a6bb96bbf --- /dev/null +++ b/desktop/source/deployment/inc/dp_misc.mk @@ -0,0 +1,42 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +# To be included after settings.mk + +# Although the deployment shared library is a UNO component, it also exports +# some C++ functionality: +.IF "$(OS)" == "WNT" +.IF "$(COM)" == "GCC" +DEPLOYMENTMISCLIB = -ldeploymentmisc$(DLLPOSTFIX) +.ELSE +DEPLOYMENTMISCLIB = ideploymentmisc$(DLLPOSTFIX).lib +.ENDIF +.ELIF "$(OS)" == "OS2" +DEPLOYMENTMISCLIB = ideploymentmisc$(DLLPOSTFIX).lib +.ELSE +DEPLOYMENTMISCLIB = -ldeploymentmisc$(DLLPOSTFIX) +.ENDIF diff --git a/desktop/source/deployment/inc/dp_misc_api.hxx b/desktop/source/deployment/inc/dp_misc_api.hxx new file mode 100644 index 000000000000..fbc248a1dfb2 --- /dev/null +++ b/desktop/source/deployment/inc/dp_misc_api.hxx @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_INC_DP_MISC_API_HXX +#define INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_INC_DP_MISC_API_HXX + +#include "sal/config.h" +#include "sal/types.h" + +#if defined DESKTOP_DEPLOYMENTMISC_DLLIMPLEMENTATION +#define DESKTOP_DEPLOYMENTMISC_DLLPUBLIC SAL_DLLPUBLIC_EXPORT +#else +#define DESKTOP_DEPLOYMENTMISC_DLLPUBLIC SAL_DLLPUBLIC_IMPORT +#endif + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/inc/dp_persmap.h b/desktop/source/deployment/inc/dp_persmap.h new file mode 100644 index 000000000000..16392c464bf1 --- /dev/null +++ b/desktop/source/deployment/inc/dp_persmap.h @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_PERSMAP_H +#define INCLUDED_DP_PERSMAP_H + +#include "rtl/ustring.hxx" +#include "db.hxx" +#include <hash_map> + +using namespace berkeleydbproxy; + +namespace dp_misc +{ + +typedef ::std::hash_map< + ::rtl::OString, ::rtl::OString, ::rtl::OStringHash > t_string2string_map; + +//============================================================================== +class PersistentMap +{ + ::rtl::OUString m_sysPath; + mutable Db m_db; + void throw_rtexc( int err, char const * msg = 0 ) const; + +public: + ~PersistentMap(); + PersistentMap( ::rtl::OUString const & url, bool readOnly ); + /** in mem db */ + PersistentMap(); + + bool has( ::rtl::OString const & key ) const; + bool get( ::rtl::OString * value, ::rtl::OString const & key ) const; + t_string2string_map getEntries() const; + void put( ::rtl::OString const & key, ::rtl::OString const & value ); + bool erase( ::rtl::OString const & key, bool flush_immediately = true ); +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/inc/dp_platform.hxx b/desktop/source/deployment/inc/dp_platform.hxx new file mode 100644 index 000000000000..b2b9fad07f49 --- /dev/null +++ b/desktop/source/deployment/inc/dp_platform.hxx @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_PLATFORM_HXX +#define INCLUDED_DP_PLATFORM_HXX + + +#include "dp_misc_api.hxx" + +#include "com/sun/star/uno/Sequence.hxx" +#include "rtl/ustring.hxx" + +namespace dp_misc +{ + + +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC ::rtl::OUString const & getPlatformString(); + +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC + bool platform_fits( ::rtl::OUString const & platform_string ); + +/** determines if the current platform corresponds to one of the platform strings. + +*/ +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +bool hasValidPlatform( ::com::sun::star::uno::Sequence< ::rtl::OUString > const & platformStrings); + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/inc/dp_resource.h b/desktop/source/deployment/inc/dp_resource.h new file mode 100644 index 000000000000..132e5df375a6 --- /dev/null +++ b/desktop/source/deployment/inc/dp_resource.h @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_RESOURCE_H +#define INCLUDED_DP_RESOURCE_H + +#include "tools/resmgr.hxx" +#include "tools/string.hxx" +#include "tools/resid.hxx" +#include "com/sun/star/lang/Locale.hpp" +#include "dp_misc.h" +#include <memory> +#include "dp_misc_api.hxx" + +namespace dp_misc { + +//============================================================================== +ResId getResId( USHORT id ); + +//============================================================================== +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC String getResourceString( USHORT id ); + +template <typename Unique, USHORT id> +struct StaticResourceString : + public ::rtl::StaticWithInit<const ::rtl::OUString, Unique> { + const ::rtl::OUString operator () () { return getResourceString(id); } +}; + +//============================================================================== +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +::com::sun::star::lang::Locale toLocale( ::rtl::OUString const & slang ); + +//============================================================================== +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +::com::sun::star::lang::Locale getOfficeLocale(); + +//============================================================================== +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +::rtl::OUString getOfficeLocaleString(); + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/inc/dp_ucb.h b/desktop/source/deployment/inc/dp_ucb.h new file mode 100644 index 000000000000..22d54de5885a --- /dev/null +++ b/desktop/source/deployment/inc/dp_ucb.h @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_UCB_H +#define INCLUDED_DP_UCB_H + +#include <list> +#include "rtl/byteseq.hxx" +#include "rtl/instance.hxx" +#include "com/sun/star/ucb/XCommandEnvironment.hpp" +#include "dp_misc_api.hxx" + +namespace ucbhelper +{ +class Content; +} + +namespace css = ::com::sun::star; + +namespace dp_misc { + +struct DESKTOP_DEPLOYMENTMISC_DLLPUBLIC StrTitle : + public rtl::StaticWithInit<const rtl::OUString, StrTitle> +{ + const rtl::OUString operator () (); +}; + +//============================================================================== +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC bool create_ucb_content( + ::ucbhelper::Content * ucb_content, + ::rtl::OUString const & url, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv, + bool throw_exc = true ); + +//============================================================================== +/** @return true if previously non-existing folder has been created + */ +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC bool create_folder( + ::ucbhelper::Content * ucb_content, + ::rtl::OUString const & url, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv, + bool throw_exc = true ); + +//============================================================================== +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC bool erase_path( + ::rtl::OUString const & url, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv, + bool throw_exc = true ); + +//============================================================================== +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +::rtl::ByteSequence readFile( ::ucbhelper::Content & ucb_content ); + +//============================================================================== +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +bool readLine( ::rtl::OUString * res, ::rtl::OUString const & startingWith, + ::ucbhelper::Content & ucb_content, rtl_TextEncoding textenc ); + +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +bool readProperties( ::std::list< ::std::pair< ::rtl::OUString, ::rtl::OUString> > & out_result, + ::ucbhelper::Content & ucb_content); + + + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/inc/dp_update.hxx b/desktop/source/deployment/inc/dp_update.hxx new file mode 100644 index 000000000000..1f22b2bb8d40 --- /dev/null +++ b/desktop/source/deployment/inc/dp_update.hxx @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_UPDATE_HXX +#define INCLUDED_DP_UPDATE_HXX + + +#include "com/sun/star/deployment/XPackage.hpp" +#include "com/sun/star/deployment/XExtensionManager.hpp" +#include "com/sun/star/deployment/XUpdateInformationProvider.hpp" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/xml/dom/XNode.hpp" + +#include "rtl/ustrbuf.hxx" +#include "dp_misc_api.hxx" + +#include <map> +#include <vector> + +namespace dp_misc { + +/** returns the default update URL (for the update information) which + is used when an extension does not provide its own URL. +*/ +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +::rtl::OUString getExtensionDefaultUpdateURL(); + +enum UPDATE_SOURCE +{ + UPDATE_SOURCE_NONE, + UPDATE_SOURCE_SHARED, + UPDATE_SOURCE_BUNDLED, + UPDATE_SOURCE_ONLINE +}; + +/* determine if an update is available which is installed in the + user repository. + + If the return value is UPDATE_SOURCE_NONE, then no update is + available, otherwise the return value determine from which the + repository the update is used. +*/ +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +UPDATE_SOURCE isUpdateUserExtension( + bool bReadOnlyShared, + ::rtl::OUString const & userVersion, + ::rtl::OUString const & sharedVersion, + ::rtl::OUString const & bundledVersion, + ::rtl::OUString const & onlineVersion); + +/* determine if an update is available which is installed in the + shared repository. + + If the return value is UPDATE_SOURCE_NONE, then no update is + available, otherwise the return value determine from which the + repository the update is used. +*/ +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +UPDATE_SOURCE isUpdateSharedExtension( + bool bReadOnlyShared, + ::rtl::OUString const & sharedVersion, + ::rtl::OUString const & bundledVersion, + ::rtl::OUString const & onlineVersion); + +/* determines the extension with the highest identifier and returns it + + */ +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage> +getExtensionWithHighestVersion( + ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Reference< + ::com::sun::star::deployment::XPackage> > const & seqExtensionsWithSameId); + + +struct UpdateInfo +{ + UpdateInfo( ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage> const & ext); + ::com::sun::star::uno::Reference< + ::com::sun::star::deployment::XPackage> extension; +//version of the update + ::rtl::OUString version; + ::com::sun::star::uno::Reference< ::com::sun::star::xml::dom::XNode > info; +}; + +typedef std::map< ::rtl::OUString, UpdateInfo > UpdateInfoMap; + +/* + @param extensionList + List of extension for which online update information are to be obtained. If NULL, then + for update information are obtained for all installed extension. There may be only one extension + with a particular identifier contained in the list. If one extension is installed + in several repositories, then the one with the highest version must be used, because it contains + the more recent URLs for getting the update information (if at all). + @param out_errors + the first member of the pair is the extension and the second the exception that was produced + when processing the extension. + + @return + A map of UpdateInfo instances. If the parameter extensionList was given, then the map contains + at only information for those extensions. + */ +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +UpdateInfoMap getOnlineUpdateInfos( + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext> const &xContext, + ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XExtensionManager> const & xExtMgr, + ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XUpdateInformationProvider > const & updateInformation, + std::vector< ::com::sun::star::uno::Reference< ::com::sun::star::deployment::XPackage > > const * extensionList, + ::std::vector< ::std::pair< ::com::sun::star::uno::Reference< + ::com::sun::star::deployment::XPackage>, ::com::sun::star::uno::Any> > & out_errors); + +/* retunrs the highest version from the provided arguments. +*/ +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC +::rtl::OUString getHighestVersion( + ::rtl::OUString const & userVersion, + ::rtl::OUString const & sharedVersion, + ::rtl::OUString const & bundledVersion, + ::rtl::OUString const & onlineVersion); + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/inc/dp_version.hxx b/desktop/source/deployment/inc/dp_version.hxx new file mode 100644 index 000000000000..f335b986c5e3 --- /dev/null +++ b/desktop/source/deployment/inc/dp_version.hxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_INC_DP_VERSION_HXX +#define INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_INC_DP_VERSION_HXX + +#include "sal/config.h" +#include "com/sun/star/uno/Reference.hxx" +#include "dp_misc_api.hxx" + +namespace com { namespace sun { namespace star { namespace deployment { + class XPackage; +} } } } +namespace rtl { class OUString; } + +namespace dp_misc { + +enum Order { LESS, EQUAL, GREATER }; + +DESKTOP_DEPLOYMENTMISC_DLLPUBLIC Order compareVersions( + ::rtl::OUString const & version1, ::rtl::OUString const & version2); +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/inc/dp_xml.h b/desktop/source/deployment/inc/dp_xml.h new file mode 100644 index 000000000000..4e178e1b37bf --- /dev/null +++ b/desktop/source/deployment/inc/dp_xml.h @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_XML_H +#define INCLUDED_DP_XML_H + +#include "rtl/ref.hxx" +#include "rtl/ustrbuf.hxx" +#include "cppuhelper/implbase1.hxx" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/xml/input/XRoot.hpp" +#include "com/sun/star/xml/sax/XDocumentHandler.hpp" + + +namespace ucbhelper +{ +class Content; +} + +namespace css = ::com::sun::star; + +namespace dp_misc +{ + +//============================================================================== +void xml_parse( + css::uno::Reference< css::xml::sax::XDocumentHandler > const & xDocHandler, + ::ucbhelper::Content & ucb_content, + css::uno::Reference< css::uno::XComponentContext > const & xContext ); + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/makefile.mk b/desktop/source/deployment/makefile.mk new file mode 100644 index 000000000000..6d83a5c1004b --- /dev/null +++ b/desktop/source/deployment/makefile.mk @@ -0,0 +1,112 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/.. + +PRJNAME = desktop +TARGET = deployment +ENABLE_EXCEPTIONS = TRUE +#USE_DEFFILE = TRUE +NO_BSYMBOLIC = TRUE + +.IF "$(GUI)"=="OS2" +TARGET = deploy +.ENDIF + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/source$/deployment$/inc$/dp_misc.mk + +.IF "$(SYSTEM_DB)" == "YES" +CFLAGS+=-DSYSTEM_DB -I$(DB_INCLUDES) +.ENDIF + +INCPRE += inc + +DLLPRE = + +SHL1TARGET = $(TARGET)$(DLLPOSTFIX).uno +SHL1VERSIONMAP = $(SOLARENV)/src/component.map + +SHL1LIBS = \ + $(SLB)$/deployment_manager.lib \ + $(SLB)$/deployment_registry.lib \ + $(SLB)$/deployment_registry_executable.lib \ + $(SLB)$/deployment_registry_component.lib \ + $(SLB)$/deployment_registry_configuration.lib \ + $(SLB)$/deployment_registry_package.lib \ + $(SLB)$/deployment_registry_script.lib \ + $(SLB)$/deployment_registry_sfwk.lib \ + $(SLB)$/deployment_registry_help.lib + +SHL1OBJS = \ + $(SLO)$/dp_log.obj \ + $(SLO)$/dp_persmap.obj \ + $(SLO)$/dp_services.obj \ + $(SLO)$/dp_xml.obj + +SHL1STDLIBS = \ + $(SALLIB) \ + $(CPPULIB) \ + $(CPPUHELPERLIB) \ + $(UCBHELPERLIB) \ + $(COMPHELPERLIB) \ + $(TOOLSLIB) \ + $(XMLSCRIPTLIB) \ + $(SVLLIB) \ + $(UNOTOOLSLIB) \ + $(DEPLOYMENTMISCLIB) \ + $(HELPLINKERLIB) + +SHL1DEPN = +SHL1IMPLIB = i$(TARGET) +SHL1DEF = $(MISC)$/$(SHL1TARGET).def + +DEF1NAME = $(SHL1TARGET) + +SLOFILES = $(LIB1OBJFILES) + +RESLIB1NAME = $(TARGET) + +RESLIB1SRSFILES = \ + $(SRS)$/deployment_registry_configuration.srs \ + $(SRS)$/deployment_registry_component.srs \ + $(SRS)$/deployment_registry_script.srs \ + $(SRS)$/deployment_registry_sfwk.srs \ + $(SRS)$/deployment_registry_package.srs \ + $(SRS)$/deployment_registry_help.srs \ + $(SRS)$/deployment_registry.srs \ + $(SRS)$/deployment_manager.srs \ + $(SRS)$/deployment_unopkg.srs + +.IF "$(GUI)"=="OS2" +RESLIB1SRSFILES += $(SRS)$/deplmisc.srs +.ELSE +RESLIB1SRSFILES += $(SRS)$/deployment_misc.srs +.ENDIF + +.INCLUDE : target.mk + diff --git a/desktop/source/deployment/manager/dp_activepackages.cxx b/desktop/source/deployment/manager/dp_activepackages.cxx new file mode 100644 index 000000000000..dabc1e37cf24 --- /dev/null +++ b/desktop/source/deployment/manager/dp_activepackages.cxx @@ -0,0 +1,209 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_desktop.hxx" + +#include "sal/config.h" + +#include <cstddef> +#include <utility> +#include <vector> + +#include "osl/diagnose.h" +#include "rtl/strbuf.hxx" +#include "rtl/string.hxx" +#include "rtl/textenc.h" +#include "rtl/uri.h" +#include "rtl/uri.hxx" +#include "rtl/ustring.hxx" +#include <hash_map> + +#include "dp_identifier.hxx" +#include "dp_persmap.h" + +#include "dp_activepackages.hxx" + +// Old format of database entry: +// key: UTF8(filename) +// value: UTF8(tempname ";" mediatype) +// New format of database entry: +// key: 0xFF UTF8(identifier) +// value: UTF8(tempname) 0xFF UTF8(filename) 0xFF UTF8(mediatype) + +namespace { + +static char const separator = static_cast< char >( + static_cast< unsigned char >(0xFF)); + +static char const legacyPrefix[] = "org.openoffice.legacy."; + +::rtl::OString oldKey(::rtl::OUString const & fileName) { + return ::rtl::OUStringToOString(fileName, RTL_TEXTENCODING_UTF8); +} + +::rtl::OString newKey(::rtl::OUString const & id) { + ::rtl::OStringBuffer b; + b.append(separator); + b.append(::rtl::OUStringToOString(id, RTL_TEXTENCODING_UTF8)); + return b.makeStringAndClear(); +} + +::dp_manager::ActivePackages::Data decodeOldData( + ::rtl::OUString const & fileName, ::rtl::OString const & value) +{ + ::dp_manager::ActivePackages::Data d; + sal_Int32 i = value.indexOf(';'); + OSL_ASSERT(i >= 0); + d.temporaryName = ::rtl::OUString(value.getStr(), i, RTL_TEXTENCODING_UTF8); + d.fileName = fileName; + d.mediaType = ::rtl::OUString( + value.getStr() + i + 1, value.getLength() - i - 1, + RTL_TEXTENCODING_UTF8); + return d; +} + +::dp_manager::ActivePackages::Data decodeNewData(::rtl::OString const & value) { + ::dp_manager::ActivePackages::Data d; + sal_Int32 i1 = value.indexOf(separator); + OSL_ASSERT(i1 >= 0); + d.temporaryName = ::rtl::OUString( + value.getStr(), i1, RTL_TEXTENCODING_UTF8); + sal_Int32 i2 = value.indexOf(separator, i1 + 1); + OSL_ASSERT(i2 >= 0); + d.fileName = ::rtl::OUString( + value.getStr() + i1 + 1, i2 - i1 - 1, RTL_TEXTENCODING_UTF8); + sal_Int32 i3 = value.indexOf(separator, i2 + 1); + + if (i3 < 0) + { + //Before ActivePackages::Data::version was added + d.mediaType = ::rtl::OUString( + value.getStr() + i2 + 1, value.getLength() - i2 - 1, + RTL_TEXTENCODING_UTF8); + } + else + { + sal_Int32 i4 = value.indexOf(separator, i3 + 1); + d.mediaType = ::rtl::OUString( + value.getStr() + i2 + 1, i3 - i2 -1, RTL_TEXTENCODING_UTF8); + d.version = ::rtl::OUString( + value.getStr() + i3 + 1, i4 - i3 - 1, + RTL_TEXTENCODING_UTF8); + d.failedPrerequisites = ::rtl::OUString( + value.getStr() + i4 + 1, value.getLength() - i4 - 1, + RTL_TEXTENCODING_UTF8); + } + return d; +} + +} + +namespace dp_manager { + +ActivePackages::ActivePackages() {} + +ActivePackages::ActivePackages(::rtl::OUString const & url, bool readOnly): + m_map(url, readOnly) {} + +ActivePackages::~ActivePackages() {} + +bool ActivePackages::has( + ::rtl::OUString const & id, ::rtl::OUString const & fileName) const +{ + return get(NULL, id, fileName); +} + +bool ActivePackages::get( + Data * data, ::rtl::OUString const & id, ::rtl::OUString const & fileName) + const +{ + ::rtl::OString v; + if (m_map.get(&v, newKey(id))) { + if (data != NULL) { + *data = decodeNewData(v); + } + return true; + } else if (m_map.get(&v, oldKey(fileName))) { + if (data != NULL) { + *data = decodeOldData(fileName, v); + } + return true; + } else { + return false; + } +} + +ActivePackages::Entries ActivePackages::getEntries() const { + Entries es; + ::dp_misc::t_string2string_map m(m_map.getEntries()); + for (::dp_misc::t_string2string_map::const_iterator i(m.begin()); + i != m.end(); ++i) + { + if (i->first.getLength() > 0 && i->first[0] == separator) { + es.push_back( + ::std::make_pair( + ::rtl::OUString( + i->first.getStr() + 1, i->first.getLength() - 1, + RTL_TEXTENCODING_UTF8), + decodeNewData(i->second))); + } else { + ::rtl::OUString fn( + ::rtl::OStringToOUString(i->first, RTL_TEXTENCODING_UTF8)); + es.push_back( + ::std::make_pair( + ::dp_misc::generateLegacyIdentifier(fn), + decodeOldData(fn, i->second))); + } + } + return es; +} + +void ActivePackages::put(::rtl::OUString const & id, Data const & data) { + ::rtl::OStringBuffer b; + b.append( + ::rtl::OUStringToOString(data.temporaryName, RTL_TEXTENCODING_UTF8)); + b.append(separator); + b.append(::rtl::OUStringToOString(data.fileName, RTL_TEXTENCODING_UTF8)); + b.append(separator); + b.append(::rtl::OUStringToOString(data.mediaType, RTL_TEXTENCODING_UTF8)); + b.append(separator); + b.append(::rtl::OUStringToOString(data.version, RTL_TEXTENCODING_UTF8)); + b.append(separator); + b.append(::rtl::OUStringToOString(data.failedPrerequisites, RTL_TEXTENCODING_UTF8)); + m_map.put(newKey(id), b.makeStringAndClear()); +} + +void ActivePackages::erase( + ::rtl::OUString const & id, ::rtl::OUString const & fileName) +{ + m_map.erase(newKey(id), true) || m_map.erase(oldKey(fileName), true); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/manager/dp_activepackages.hxx b/desktop/source/deployment/manager/dp_activepackages.hxx new file mode 100644 index 000000000000..2a4d18686346 --- /dev/null +++ b/desktop/source/deployment/manager/dp_activepackages.hxx @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_MANAGER_DP_ACTIVEPACKAGES_HXX +#define INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_MANAGER_DP_ACTIVEPACKAGES_HXX + +#include "sal/config.h" + +#include <utility> +#include <vector> + +#include "dp_persmap.h" + +namespace rtl { class OUString; } + +namespace dp_manager { + +class ActivePackages { +public: + struct Data { + Data(): failedPrerequisites(::rtl::OUString::valueOf((sal_Int32)0)) + {} + /* name of the temporary file (shared, user extension) or the name of + the folder of the bundled extension. + It does not contain the trailing '_' of the folder. + UTF-8 encoded + */ + ::rtl::OUString temporaryName; + /* The file name (shared, user) or the folder name (bundled) + If the key is the file name, then file name is not encoded. + If the key is the idendifier then the file name is UTF-8 encoded. + */ + ::rtl::OUString fileName; + ::rtl::OUString mediaType; + ::rtl::OUString version; + /* If this string contains the value according to + com::sun::star::deployment::Prerequisites or "0". That is, if + the value is > 0 then + the call to XPackage::checkPrerequisites failed. + In this case the extension must not be registered. + */ + ::rtl::OUString failedPrerequisites; + }; + + typedef ::std::vector< ::std::pair< ::rtl::OUString, Data > > Entries; + + ActivePackages(); + + ActivePackages(::rtl::OUString const & url, bool readOnly); + + ~ActivePackages(); + + bool has(::rtl::OUString const & id, ::rtl::OUString const & fileName) + const; + + bool get( + Data * data, ::rtl::OUString const & id, + ::rtl::OUString const & fileName) const; + + Entries getEntries() const; + + void put(::rtl::OUString const & id, Data const & value); + + void erase(::rtl::OUString const & id, ::rtl::OUString const & fileName); + +private: + ActivePackages(ActivePackages &); // not defined + void operator =(ActivePackages &); // not defined + + ::dp_misc::PersistentMap m_map; +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/manager/dp_commandenvironments.cxx b/desktop/source/deployment/manager/dp_commandenvironments.cxx new file mode 100644 index 000000000000..e159382f2c7b --- /dev/null +++ b/desktop/source/deployment/manager/dp_commandenvironments.cxx @@ -0,0 +1,293 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "com/sun/star/deployment/VersionException.hpp" +#include "com/sun/star/deployment/LicenseException.hpp" +#include "com/sun/star/deployment/InstallException.hpp" +#include "com/sun/star/deployment/DependencyException.hpp" +#include "com/sun/star/deployment/PlatformException.hpp" +#include "com/sun/star/task/XInteractionApprove.hpp" +#include "com/sun/star/task/XInteractionAbort.hpp" +#include "com/sun/star/task/XInteractionHandler.hpp" +#include "com/sun/star/ucb/XCommandEnvironment.hpp" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "dp_commandenvironments.hxx" + +namespace deployment = com::sun::star::deployment; +namespace lang = com::sun::star::lang; +namespace task = com::sun::star::task; +namespace ucb = com::sun::star::ucb; +namespace uno = com::sun::star::uno; +namespace css = com::sun::star; + +#define OUSTR(s) rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s)) + +using ::com::sun::star::uno::Reference; +using ::rtl::OUString; + +namespace dp_manager { + +BaseCommandEnv::BaseCommandEnv() +{ +} + +BaseCommandEnv::BaseCommandEnv( + Reference< task::XInteractionHandler> const & handler) + : m_forwardHandler(handler) +{ +} + +BaseCommandEnv::~BaseCommandEnv() +{ +} +// XCommandEnvironment +//______________________________________________________________________________ +Reference<task::XInteractionHandler> BaseCommandEnv::getInteractionHandler() +throw (uno::RuntimeException) +{ + return this; +} + +//______________________________________________________________________________ +Reference<ucb::XProgressHandler> BaseCommandEnv::getProgressHandler() +throw (uno::RuntimeException) +{ + return this; +} + +void BaseCommandEnv::handle( + Reference< task::XInteractionRequest> const & /*xRequest*/ ) + throw (uno::RuntimeException) +{ +} + +void BaseCommandEnv::handle_(bool approve, bool abort, + Reference< task::XInteractionRequest> const & xRequest ) +{ + if (approve == false && abort == false) + { + //not handled so far -> forwarding + if (m_forwardHandler.is()) + m_forwardHandler->handle(xRequest); + else + return; //cannot handle + } + else + { + // select: + uno::Sequence< Reference< task::XInteractionContinuation > > conts( + xRequest->getContinuations() ); + Reference< task::XInteractionContinuation > const * pConts = + conts.getConstArray(); + sal_Int32 len = conts.getLength(); + for ( sal_Int32 pos = 0; pos < len; ++pos ) + { + if (approve) { + Reference< task::XInteractionApprove > xInteractionApprove( + pConts[ pos ], uno::UNO_QUERY ); + if (xInteractionApprove.is()) { + xInteractionApprove->select(); + // don't query again for ongoing continuations: + approve = false; + } + } + else if (abort) { + Reference< task::XInteractionAbort > xInteractionAbort( + pConts[ pos ], uno::UNO_QUERY ); + if (xInteractionAbort.is()) { + xInteractionAbort->select(); + // don't query again for ongoing continuations: + abort = false; + } + } + } + } + +} + +// XProgressHandler +void BaseCommandEnv::push( uno::Any const & /*Status*/ ) +throw (uno::RuntimeException) +{ +} + +void BaseCommandEnv::update( uno::Any const & /*Status */) +throw (uno::RuntimeException) +{ +} + +void BaseCommandEnv::pop() throw (uno::RuntimeException) +{ +} +//============================================================================== + +TmpRepositoryCommandEnv::TmpRepositoryCommandEnv() +{ +} + +TmpRepositoryCommandEnv::TmpRepositoryCommandEnv( + css::uno::Reference< css::task::XInteractionHandler> const & handler): + BaseCommandEnv(handler) +{ +} +// XInteractionHandler +void TmpRepositoryCommandEnv::handle( + Reference< task::XInteractionRequest> const & xRequest ) + throw (uno::RuntimeException) +{ + uno::Any request( xRequest->getRequest() ); + OSL_ASSERT( request.getValueTypeClass() == uno::TypeClass_EXCEPTION ); + + deployment::VersionException verExc; + deployment::LicenseException licExc; + deployment::InstallException instExc; + + bool approve = false; + bool abort = false; + + if ((request >>= verExc) + || (request >>= licExc) + || (request >>= instExc)) + { + approve = true; + } + + handle_(approve, abort, xRequest); +} +//================================================================================ + +LicenseCommandEnv::LicenseCommandEnv( + css::uno::Reference< css::task::XInteractionHandler> const & handler, + bool bSuppressLicense, + OUString const & repository): + BaseCommandEnv(handler), m_repository(repository), + m_bSuppressLicense(bSuppressLicense) +{ +} +// XInteractionHandler +void LicenseCommandEnv::handle( + Reference< task::XInteractionRequest> const & xRequest ) + throw (uno::RuntimeException) +{ + uno::Any request( xRequest->getRequest() ); + OSL_ASSERT( request.getValueTypeClass() == uno::TypeClass_EXCEPTION ); + + deployment::LicenseException licExc; + + bool approve = false; + bool abort = false; + + if (request >>= licExc) + { + if (m_bSuppressLicense + || m_repository.equals(OUSTR("bundled")) + || licExc.AcceptBy.equals(OUSTR("admin"))) + { + //always approve in bundled case, because we do not support + //showing licenses anyway. + //The "admin" already accepted the license when installing the + // shared extension + approve = true; + } + } + + handle_(approve, abort, xRequest); +} + +//================================================================================ +//================================================================================ + +NoLicenseCommandEnv::NoLicenseCommandEnv( + css::uno::Reference< css::task::XInteractionHandler> const & handler): + BaseCommandEnv(handler) +{ +} +// XInteractionHandler +void NoLicenseCommandEnv::handle( + Reference< task::XInteractionRequest> const & xRequest ) + throw (uno::RuntimeException) +{ + uno::Any request( xRequest->getRequest() ); + OSL_ASSERT( request.getValueTypeClass() == uno::TypeClass_EXCEPTION ); + + deployment::LicenseException licExc; + + bool approve = false; + bool abort = false; + + if (request >>= licExc) + { + approve = true; + } + handle_(approve, abort, xRequest); +} + +// SilentCheckPrerequisitesCommandEnv::SilentCheckPrerequisitesCommandEnv( +// css::uno::Reference< css::task::XInteractionHandler> const & handler): +// BaseCommandEnv(handler) +// { +// } +SilentCheckPrerequisitesCommandEnv::SilentCheckPrerequisitesCommandEnv() +{ +} + +void SilentCheckPrerequisitesCommandEnv::handle( + Reference< task::XInteractionRequest> const & xRequest ) + throw (uno::RuntimeException) +{ + uno::Any request( xRequest->getRequest() ); + OSL_ASSERT( request.getValueTypeClass() == uno::TypeClass_EXCEPTION ); + + deployment::LicenseException licExc; + deployment::PlatformException platformExc; + deployment::DependencyException depExc; + bool approve = false; + bool abort = false; + + if (request >>= licExc) + { + approve = true; + handle_(approve, abort, xRequest); + } + else if ((request >>= platformExc) + || (request >>= depExc)) + { + m_Exception = request; + } + else + { + m_UnknownException = request; + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/manager/dp_commandenvironments.hxx b/desktop/source/deployment/manager/dp_commandenvironments.hxx new file mode 100644 index 000000000000..59349c469af0 --- /dev/null +++ b/desktop/source/deployment/manager/dp_commandenvironments.hxx @@ -0,0 +1,161 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_COMMANDENVIRONMENTS_HXX +#define INCLUDED_DP_COMMANDENVIRONMENTS_HXX + +#include "cppuhelper/compbase3.hxx" +#include "ucbhelper/content.hxx" +#include "com/sun/star/uno/Type.hxx" + +namespace css = ::com::sun::star; + +namespace dp_manager { + +/** + This command environment is to be used when an extension is temporarily + stored in the "tmp" repository. It prevents all kind of user interaction. + */ +class BaseCommandEnv + : public ::cppu::WeakImplHelper3< css::ucb::XCommandEnvironment, + css::task::XInteractionHandler, + css::ucb::XProgressHandler > +{ +protected: + css::uno::Reference< css::uno::XComponentContext > m_xContext; + css::uno::Reference< css::task::XInteractionHandler> m_forwardHandler; + + void handle_(bool approve, bool abort, + css::uno::Reference< css::task::XInteractionRequest> const & xRequest ); +public: + virtual ~BaseCommandEnv(); + BaseCommandEnv(); + BaseCommandEnv( + css::uno::Reference< css::task::XInteractionHandler> const & handler); + + // XCommandEnvironment + virtual css::uno::Reference<css::task::XInteractionHandler > SAL_CALL + getInteractionHandler() throw (css::uno::RuntimeException); + virtual css::uno::Reference<css::ucb::XProgressHandler > + SAL_CALL getProgressHandler() throw (css::uno::RuntimeException); + + // XInteractionHandler + virtual void SAL_CALL handle( + css::uno::Reference<css::task::XInteractionRequest > const & xRequest ) + throw (css::uno::RuntimeException); + + // XProgressHandler + virtual void SAL_CALL push( css::uno::Any const & Status ) + throw (css::uno::RuntimeException); + virtual void SAL_CALL update( css::uno::Any const & Status ) + throw (css::uno::RuntimeException); + virtual void SAL_CALL pop() throw (css::uno::RuntimeException); +}; + +class TmpRepositoryCommandEnv : public BaseCommandEnv +{ +public: + TmpRepositoryCommandEnv(); + TmpRepositoryCommandEnv(css::uno::Reference< css::task::XInteractionHandler> const & handler); + +// XInteractionHandler + virtual void SAL_CALL handle( + css::uno::Reference<css::task::XInteractionRequest > const & xRequest ) + throw (css::uno::RuntimeException); + +}; + +/** this class is for use in XPackageManager::synchronize. + + It handles particular license cases. + */ +class LicenseCommandEnv : public BaseCommandEnv +{ +private: + ::rtl::OUString m_repository; + bool m_bSuppressLicense; +public: + LicenseCommandEnv() : m_bSuppressLicense(false) {}; + LicenseCommandEnv( + css::uno::Reference< css::task::XInteractionHandler> const & handler, + bool bSuppressLicense, + ::rtl::OUString const & repository); + +// XInteractionHandler + virtual void SAL_CALL handle( + css::uno::Reference<css::task::XInteractionRequest > const & xRequest ) + throw (css::uno::RuntimeException); + +}; + +/** this class is for use in XPackageManager::checkPrerequisites + + It always prohibits a license interaction + */ +class NoLicenseCommandEnv : public BaseCommandEnv +{ + +public: + NoLicenseCommandEnv(){}; + NoLicenseCommandEnv(css::uno::Reference< css::task::XInteractionHandler> const & handler); + +// XInteractionHandler + virtual void SAL_CALL handle( + css::uno::Reference<css::task::XInteractionRequest > const & xRequest ) + throw (css::uno::RuntimeException); + +}; + +/* For use in XExtensionManager::addExtension in the call to + XPackage::checkPrerequisites + It prevents all user interactions. The license is always accepted. + It remembers if there was a platform or a dependency exception in + the member m_bException. if there was any other exception then m_bUnknownException + is set. + + */ +class SilentCheckPrerequisitesCommandEnv : public BaseCommandEnv +{ +public: + SilentCheckPrerequisitesCommandEnv(); + // XInteractionHandler + virtual void SAL_CALL handle( + css::uno::Reference<css::task::XInteractionRequest > const & xRequest ) + throw (css::uno::RuntimeException); + + // Set to true if a PlatformException or a DependencyException were handled. + css::uno::Any m_Exception; + // Set to true if an unknown exception was handled. + css::uno::Any m_UnknownException; +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/manager/dp_extensionmanager.cxx b/desktop/source/deployment/manager/dp_extensionmanager.cxx new file mode 100644 index 000000000000..0f8498877f77 --- /dev/null +++ b/desktop/source/deployment/manager/dp_extensionmanager.cxx @@ -0,0 +1,1502 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include <cppuhelper/implbase1.hxx> + +#include "comphelper/servicedecl.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "rtl/bootstrap.hxx" +#include "com/sun/star/deployment/ExtensionManager.hpp" +#include "com/sun/star/deployment/XExtensionManager.hpp" +#include "com/sun/star/deployment/thePackageManagerFactory.hpp" +#include "com/sun/star/deployment/XPackageManager.hpp" +#include "com/sun/star/deployment/XPackageManagerFactory.hpp" +#include "com/sun/star/deployment/XPackage.hpp" +#include "com/sun/star/deployment/InstallException.hpp" +#include "com/sun/star/deployment/VersionException.hpp" +#include "com/sun/star/deployment/LicenseException.hpp" +#include "com/sun/star/lang/XServiceInfo.hpp" +#include "com/sun/star/registry/XRegistryKey.hpp" +#include "com/sun/star/beans/Optional.hpp" +#include "com/sun/star/task/XInteractionApprove.hpp" +#include "com/sun/star/beans/Ambiguous.hpp" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/io/XInputStream.hpp" +#include "com/sun/star/util/XModifyBroadcaster.hpp" +#include "comphelper/sequence.hxx" +#include "xmlscript/xml_helper.hxx" +#include "osl/diagnose.h" +#include "dp_interact.h" +#include "dp_resource.h" +#include "dp_ucb.h" +#include "dp_identifier.hxx" +#include "dp_descriptioninfoset.hxx" +#include "dp_extensionmanager.hxx" +#include "dp_commandenvironments.hxx" +#include "dp_properties.hxx" +#include "boost/bind.hpp" + +#include <list> +#include <hash_map> +#include <algorithm> + +namespace deploy = com::sun::star::deployment; +namespace lang = com::sun::star::lang; +namespace registry = com::sun::star::registry; +namespace task = com::sun::star::task; +namespace ucb = com::sun::star::ucb; +namespace uno = com::sun::star::uno; +namespace beans = com::sun::star::beans; +namespace util = com::sun::star::util; +namespace css = com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::rtl::OUString; + +namespace { + +struct CompIdentifiers +{ + bool operator() (::std::vector<Reference<deploy::XPackage> > const & a, + ::std::vector<Reference<deploy::XPackage> > const & b) + { + if (getName(a).compareTo(getName(b)) < 0) + return true; + return false; + } + + OUString getName(::std::vector<Reference<deploy::XPackage> > const & a); +}; + +OUString CompIdentifiers::getName(::std::vector<Reference<deploy::XPackage> > const & a) +{ + OSL_ASSERT(a.size() == 3); + //get the first non-null reference + Reference<deploy::XPackage> extension; + ::std::vector<Reference<deploy::XPackage> >::const_iterator it = a.begin(); + for (; it != a.end(); it++) + { + if (it->is()) + { + extension = *it; + break; + } + } + OSL_ASSERT(extension.is()); + return extension->getDisplayName(); +} + +void writeLastModified(OUString & url, Reference<ucb::XCommandEnvironment> const & xCmdEnv) +{ + //Write the lastmodified file + try { + ::rtl::Bootstrap::expandMacros(url); + ::ucbhelper::Content ucbStamp(url, xCmdEnv ); + dp_misc::erase_path( url, xCmdEnv ); + ::rtl::OString stamp("1" ); + Reference<css::io::XInputStream> xData( + ::xmlscript::createInputStream( + ::rtl::ByteSequence( + reinterpret_cast<sal_Int8 const *>(stamp.getStr()), + stamp.getLength() ) ) ); + ucbStamp.writeStream( xData, true /* replace existing */ ); + } + catch(...) + { + uno::Any exc(::cppu::getCaughtException()); + throw deploy::DeploymentException( + OUSTR("Failed to update") + url, 0, exc); + } +} + +class ExtensionRemoveGuard +{ + css::uno::Reference<css::deployment::XPackage> m_extension; + css::uno::Reference<css::deployment::XPackageManager> m_xPackageManager; + +public: + ExtensionRemoveGuard( + css::uno::Reference<css::deployment::XPackage> const & extension, + css::uno::Reference<css::deployment::XPackageManager> const & xPackageManager): + m_extension(extension), m_xPackageManager(xPackageManager) {} + ~ExtensionRemoveGuard(); + + void reset(css::uno::Reference<css::deployment::XPackage> const & extension) { + m_extension = extension; + } +}; + +ExtensionRemoveGuard::~ExtensionRemoveGuard() +{ + try { + if (m_xPackageManager.is() && m_extension.is()) + m_xPackageManager->removePackage( + dp_misc::getIdentifier(m_extension), ::rtl::OUString(), + css::uno::Reference<css::task::XAbortChannel>(), + css::uno::Reference<css::ucb::XCommandEnvironment>()); + } catch (...) { + OSL_ASSERT(0); + } +} + +} + +namespace dp_manager { + +//------------------------------------------------------------------------------ + +//ToDo: bundled extension +ExtensionManager::ExtensionManager( Reference< uno::XComponentContext > const& xContext) : + ::cppu::WeakComponentImplHelper1< css::deployment::XExtensionManager >(getMutex()), + m_xContext( xContext ) +{ + Reference<deploy::XPackageManagerFactory> xPackageManagerFactory( + deploy::thePackageManagerFactory::get(m_xContext)); + m_userRepository = xPackageManagerFactory->getPackageManager(OUSTR("user")); + m_sharedRepository = xPackageManagerFactory->getPackageManager(OUSTR("shared")); + m_bundledRepository = xPackageManagerFactory->getPackageManager(OUSTR("bundled")); + m_tmpRepository = xPackageManagerFactory->getPackageManager(OUSTR("tmp")); + + m_repositoryNames.push_back(OUSTR("user")); + m_repositoryNames.push_back(OUSTR("shared")); + m_repositoryNames.push_back(OUSTR("bundled")); +} + +//------------------------------------------------------------------------------ + +ExtensionManager::~ExtensionManager() +{ +} + +Reference<task::XAbortChannel> ExtensionManager::createAbortChannel() + throw (uno::RuntimeException) +{ + return new dp_misc::AbortChannel; +} + +css::uno::Reference<css::deployment::XPackageManager> +ExtensionManager::getPackageManager(::rtl::OUString const & repository) + throw (css::lang::IllegalArgumentException) +{ + Reference<deploy::XPackageManager> xPackageManager; + if (repository.equals(OUSTR("user"))) + xPackageManager = m_userRepository; + else if (repository.equals(OUSTR("shared"))) + xPackageManager = m_sharedRepository; + else if (repository.equals(OUSTR("bundled"))) + xPackageManager = m_bundledRepository; + else + throw lang::IllegalArgumentException( + OUSTR("No valid repository name provided."), + static_cast<cppu::OWeakObject*>(this), 0); + return xPackageManager; +} + +/* + Enters the XPackage objects into a map. They must be all from the + same repository. The value type of the map is a vector, where each vector + represents an extension with a particular identifier. The first member + represents the user extension, the second the shared extension and the + third the bundled extension. + */ +void ExtensionManager::addExtensionsToMap( + id2extensions & mapExt, + uno::Sequence<Reference<deploy::XPackage> > const & seqExt, + OUString const & repository) +{ + //Determine the index in the vector where these extensions are to be + //added. + ::std::list<OUString>::const_iterator citNames = + m_repositoryNames.begin(); + int index = 0; + for (;citNames != m_repositoryNames.end(); citNames++, index++) + { + if (citNames->equals(repository)) + break; + } + + for (int i = 0; i < seqExt.getLength(); i++) + { + Reference<deploy::XPackage> const & xExtension = seqExt[i]; + OUString id = dp_misc::getIdentifier(xExtension); + id2extensions::iterator ivec = mapExt.find(id); + if (ivec == mapExt.end()) + { + ::std::vector<Reference<deploy::XPackage> > vec(3); + vec[index] = xExtension; + mapExt[id] = vec; + } + else + { + ivec->second[index] = xExtension; + } + } +} + +/* + returns a list containing extensions with the same identifier from + all repositories (user, shared, bundled). If one repository does not + have this extension, then the list contains an empty Reference. The list + is ordered according to the priority of the repostories: + 1. user + 2. shared + 3. bundled + + The number of elements is always three, unless the number of repository + changes. + */ +::std::list<Reference<deploy::XPackage> > + ExtensionManager::getExtensionsWithSameId( + OUString const & identifier, OUString const & fileName, + Reference< ucb::XCommandEnvironment> const & /*xCmdEnv*/) + +{ + ::std::list<Reference<deploy::XPackage> > extensionList; + Reference<deploy::XPackageManager> lRepos[] = { + m_userRepository, m_sharedRepository, m_bundledRepository }; + for (int i(0); i != SAL_N_ELEMENTS(lRepos); ++i) + { + Reference<deploy::XPackage> xPackage; + try + { + xPackage = lRepos[i]->getDeployedPackage( + identifier, fileName, Reference<ucb::XCommandEnvironment>()); + } + catch(lang::IllegalArgumentException &) + { + // thrown if the extension does not exist in this repository + } + extensionList.push_back(xPackage); + } + OSL_ASSERT(extensionList.size() == 3); + return extensionList; +} + +uno::Sequence<Reference<deploy::XPackage> > +ExtensionManager::getExtensionsWithSameIdentifier( + OUString const & identifier, + OUString const & fileName, + Reference< ucb::XCommandEnvironment> const & xCmdEnv ) + throw ( + deploy::DeploymentException, + ucb::CommandFailedException, + lang::IllegalArgumentException, + uno::RuntimeException) +{ + try + { + ::std::list<Reference<deploy::XPackage> > listExtensions = + getExtensionsWithSameId( + identifier, fileName, xCmdEnv); + sal_Bool bHasExtension = false; + + //throw an IllegalArgumentException if there is no extension at all. + typedef ::std::list<Reference<deploy::XPackage> >::const_iterator CIT; + for (CIT i = listExtensions.begin(); i != listExtensions.end(); i++) + bHasExtension |= i->is(); + if (!bHasExtension) + throw lang::IllegalArgumentException( + OUSTR("Could not find extension: ") + identifier + OUSTR(", ") + fileName, + static_cast<cppu::OWeakObject*>(this), -1); + + return comphelper::containerToSequence< + Reference<deploy::XPackage>, + ::std::list<Reference<deploy::XPackage> > + > (listExtensions); + } + catch (deploy::DeploymentException & ) + { + throw; + } + catch ( ucb::CommandFailedException & ) + { + throw; + } + catch (lang::IllegalArgumentException &) + { + throw; + } + catch (...) + { + uno::Any exc = ::cppu::getCaughtException(); + throw deploy::DeploymentException( + OUSTR("Extension Manager: exception during getExtensionsWithSameIdentifier"), + static_cast<OWeakObject*>(this), exc); + } +} + +bool ExtensionManager::isUserDisabled( + OUString const & identifier, OUString const & fileName) +{ + ::std::list<Reference<deploy::XPackage> > listExtensions; + + try { + listExtensions = getExtensionsWithSameId(identifier, fileName); + } catch (lang::IllegalArgumentException & ) { + } + OSL_ASSERT(listExtensions.size() == 3); + + return isUserDisabled( ::comphelper::containerToSequence< + Reference<deploy::XPackage>, + ::std::list<Reference<deploy::XPackage> > + > (listExtensions)); +} + +bool ExtensionManager::isUserDisabled( + uno::Sequence<Reference<deploy::XPackage> > const & seqExtSameId) +{ + OSL_ASSERT(seqExtSameId.getLength() == 3); + Reference<deploy::XPackage> const & userExtension = seqExtSameId[0]; + if (userExtension.is()) + { + beans::Optional<beans::Ambiguous<sal_Bool> > reg = + userExtension->isRegistered(Reference<task::XAbortChannel>(), + Reference<ucb::XCommandEnvironment>()); + //If the value is ambiguous is than we assume that the extension + //is enabled, but something went wrong during enabling. We do not + //automatically disable user extensions. + if (reg.IsPresent && + ! reg.Value.IsAmbiguous && ! reg.Value.Value) + return true; + } + return false; +} + +/* + This method determines the active extension (XPackage.registerPackage) with a + particular identifier. + + The parameter bUserDisabled determines if the user extension is disabled. + + When the user repository contains an extension with the given identifier and + it is not disabled by the user, then it is always registered. Otherwise an + extension is only registered when there is no registered extension in one of + the repositories with a higher priority. That is, if the extension is from + the shared repository and an active extension with the same identifer is in + the user repository, then the extension is not registered. Similarly a + bundled extension is not registered if there is an active extension with the + same identifier in the shared or user repository. +*/ +void ExtensionManager::activateExtension( + OUString const & identifier, OUString const & fileName, + bool bUserDisabled, + bool bStartup, + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) +{ + ::std::list<Reference<deploy::XPackage> > listExtensions; + try { + listExtensions = getExtensionsWithSameId(identifier, fileName); + } catch (lang::IllegalArgumentException &) { + } + OSL_ASSERT(listExtensions.size() == 3); + + activateExtension( + ::comphelper::containerToSequence< + Reference<deploy::XPackage>, + ::std::list<Reference<deploy::XPackage> > + > (listExtensions), + bUserDisabled, bStartup, xAbortChannel, xCmdEnv); + + fireModified(); +} + +void ExtensionManager::activateExtension( + uno::Sequence<Reference<deploy::XPackage> > const & seqExt, + bool bUserDisabled, + bool bStartup, + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) +{ + bool bActive = false; + sal_Int32 len = seqExt.getLength(); + for (sal_Int32 i = 0; i < len; i++) + { + Reference<deploy::XPackage> const & aExt = seqExt[i]; + if (aExt.is()) + { + //get the registration value of the current iteration + beans::Optional<beans::Ambiguous<sal_Bool> > optReg = + aExt->isRegistered(xAbortChannel, xCmdEnv); + //If nothing can be registered then break + if (!optReg.IsPresent) + break; + + //Check if this is a disabled user extension, + if (i == 0 && bUserDisabled) + { + aExt->revokePackage(xAbortChannel, xCmdEnv); + continue; + } + + //If we have already determined an active extension then we must + //make sure to unregister all extensions with the same id in + //repositories with a lower priority + if (bActive) + { + aExt->revokePackage(xAbortChannel, xCmdEnv); + } + else + { + //This is the first extension in the ordered list, which becomes + //the active extension + bActive = true; + //Register if not already done. + //reregister if the value is ambiguous, which indicates that + //something went wrong during last registration. + aExt->registerPackage(bStartup, xAbortChannel, xCmdEnv); + } + } + } +} + +Reference<deploy::XPackage> ExtensionManager::backupExtension( + OUString const & identifier, OUString const & fileName, + Reference<deploy::XPackageManager> const & xPackageManager, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) +{ + Reference<deploy::XPackage> xBackup; + Reference<ucb::XCommandEnvironment> tmpCmdEnv( + new TmpRepositoryCommandEnv(xCmdEnv->getInteractionHandler())); + Reference<deploy::XPackage> xOldExtension; + xOldExtension = xPackageManager->getDeployedPackage( + identifier, fileName, tmpCmdEnv); + + if (xOldExtension.is()) + { + xBackup = m_tmpRepository->addPackage( + xOldExtension->getURL(), uno::Sequence<beans::NamedValue>(), + OUString(), Reference<task::XAbortChannel>(), tmpCmdEnv); + + OSL_ENSURE(xBackup.is(), "Failed to backup extension"); + } + return xBackup; +} + +//The supported package types are actually determined by the registry. However +//creating a registry +//(desktop/source/deployment/registry/dp_registry.cxx:PackageRegistryImpl) will +//create all the backends, so that the registry can obtain from them the package +//types. Creating the registry will also set up the registry folder containing +//all the subfolders for the respective backends. +//Because all repositories support the same backends, we can just delegate this +//call to one of the repositories. +uno::Sequence< Reference<deploy::XPackageTypeInfo> > +ExtensionManager::getSupportedPackageTypes() + throw (uno::RuntimeException) +{ + return m_userRepository->getSupportedPackageTypes(); +} +//Do some necessary checks and user interaction. This function does not +//aquire the extension manager mutex and that mutex must not be aquired +//when this function is called. doChecksForAddExtension does synchronous +//user interactions which may require aquiring the solar mutex. +//Returns true if the extension can be installed. +bool ExtensionManager::doChecksForAddExtension( + Reference<deploy::XPackageManager> const & xPackageMgr, + uno::Sequence<beans::NamedValue> const & properties, + css::uno::Reference<css::deployment::XPackage> const & xTmpExtension, + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv, + Reference<deploy::XPackage> & out_existingExtension ) + throw (deploy::DeploymentException, + ucb::CommandFailedException, + ucb::CommandAbortedException, + lang::IllegalArgumentException, + uno::RuntimeException) +{ + try + { + Reference<deploy::XPackage> xOldExtension; + const OUString sIdentifier = dp_misc::getIdentifier(xTmpExtension); + const OUString sFileName = xTmpExtension->getName(); + const OUString sDisplayName = xTmpExtension->getDisplayName(); + const OUString sVersion = xTmpExtension->getVersion(); + + try + { + xOldExtension = xPackageMgr->getDeployedPackage( + sIdentifier, sFileName, xCmdEnv); + out_existingExtension = xOldExtension; + } + catch (lang::IllegalArgumentException &) + { + } + bool bCanInstall = false; + + //This part is not guarded against other threads removing, adding, disabling ... + //etc. the same extension. + //checkInstall is safe because it notifies the user if the extension is not yet + //installed in the same repository. Because addExtension has its own guard + //(m_addMutex), another thread cannot add the extension in the meantime. + //checkUpdate is called if the same extension exists in the same + //repository. The user is asked if they want to replace it. Another + //thread + //could already remove the extension. So asking the user was not + //necessary. No harm is done. The other thread may also ask the user + //if he wants to remove the extension. This depends on the + //XCommandEnvironment which it passes to removeExtension. + if (xOldExtension.is()) + { + //throws a CommandFailedException if the user cancels + //the action. + checkUpdate(sVersion, sDisplayName,xOldExtension, xCmdEnv); + } + else + { + //throws a CommandFailedException if the user cancels + //the action. + checkInstall(sDisplayName, xCmdEnv); + } + //Prevent showing the license if requested. + Reference<ucb::XCommandEnvironment> _xCmdEnv(xCmdEnv); + ExtensionProperties props(OUString(), properties, Reference<ucb::XCommandEnvironment>()); + + dp_misc::DescriptionInfoset info(dp_misc::getDescriptionInfoset(xTmpExtension->getURL())); + const ::boost::optional<dp_misc::SimpleLicenseAttributes> licenseAttributes = + info.getSimpleLicenseAttributes(); + + if (licenseAttributes && licenseAttributes->suppressIfRequired + && props.isSuppressedLicense()) + _xCmdEnv = Reference<ucb::XCommandEnvironment>( + new NoLicenseCommandEnv(xCmdEnv->getInteractionHandler())); + + bCanInstall = xTmpExtension->checkPrerequisites( + xAbortChannel, _xCmdEnv, xOldExtension.is() || props.isExtensionUpdate()) == 0 ? true : false; + + return bCanInstall; + } + catch (deploy::DeploymentException& ) { + throw; + } catch (ucb::CommandFailedException & ) { + throw; + } catch (ucb::CommandAbortedException & ) { + throw; + } catch (lang::IllegalArgumentException &) { + throw; + } catch (uno::RuntimeException &) { + throw; + } catch (uno::Exception &) { + uno::Any excOccurred = ::cppu::getCaughtException(); + deploy::DeploymentException exc( + OUSTR("Extension Manager: exception in doChecksForAddExtension"), + static_cast<OWeakObject*>(this), excOccurred); + throw exc; + } catch (...) { + throw uno::RuntimeException( + OUSTR("Extension Manager: unexpected exception in doChecksForAddExtension"), + static_cast<OWeakObject*>(this)); + } +} + +// Only add to shared and user repository +Reference<deploy::XPackage> ExtensionManager::addExtension( + OUString const & url, uno::Sequence<beans::NamedValue> const & properties, + OUString const & repository, + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) + throw (deploy::DeploymentException, + ucb::CommandFailedException, + ucb::CommandAbortedException, + lang::IllegalArgumentException, + uno::RuntimeException) +{ + Reference<deploy::XPackage> xNewExtension; + //Determine the repository to use + Reference<deploy::XPackageManager> xPackageManager; + if (repository.equals(OUSTR("user"))) + xPackageManager = m_userRepository; + else if (repository.equals(OUSTR("shared"))) + xPackageManager = m_sharedRepository; + else + throw lang::IllegalArgumentException( + OUSTR("No valid repository name provided."), + static_cast<cppu::OWeakObject*>(this), 0); + //We must make sure that the xTmpExtension is not create twice, because this + //would remove the first one. + ::osl::MutexGuard addGuard(m_addMutex); + + Reference<deploy::XPackage> xTmpExtension = + getTempExtension(url, xAbortChannel, xCmdEnv); + //Make sure the extension is removed from the tmp repository in case + //of an exception + ExtensionRemoveGuard tmpExtensionRemoveGuard(xTmpExtension, m_tmpRepository); + const OUString sIdentifier = dp_misc::getIdentifier(xTmpExtension); + const OUString sFileName = xTmpExtension->getName(); + Reference<deploy::XPackage> xOldExtension; + Reference<deploy::XPackage> xExtensionBackup; + + uno::Any excOccurred2; + bool bUserDisabled = false; + bool bCanInstall = doChecksForAddExtension( + xPackageManager, + properties, + xTmpExtension, + xAbortChannel, + xCmdEnv, + xOldExtension ); + + { + // In this garded section (getMutex) we must not use the argument xCmdEnv + // because it may bring up dialogs (XInteractionHandler::handle) this + //may potententially deadlock. See issue + //http://qa.openoffice.org/issues/show_bug.cgi?id=114933 + //By not providing xCmdEnv the underlying APIs will throw an exception if + //the XInteractionRequest cannot be handled + ::osl::MutexGuard guard(getMutex()); + + if (bCanInstall) + { + try + { + bUserDisabled = isUserDisabled(sIdentifier, sFileName); + if (xOldExtension.is()) + { + try + { + xOldExtension->revokePackage( + xAbortChannel, Reference<ucb::XCommandEnvironment>()); + //save the old user extension in case the user aborts + //store the extension in the tmp repository, this will overwrite + //xTmpPackage (same identifier). Do not let the user abort or + //interact + //importing the old extension in the tmp repository will remove + //the xTmpExtension + //no command environment supplied, only this class shall interact + //with the user! + xExtensionBackup = m_tmpRepository->importExtension( + xOldExtension, Reference<task::XAbortChannel>(), + Reference<ucb::XCommandEnvironment>()); + tmpExtensionRemoveGuard.reset(xExtensionBackup); + //xTmpExtension will later be used to check the dependencies + //again. However, only xExtensionBackup will be later removed + //from the tmp repository + xTmpExtension = xExtensionBackup; + OSL_ASSERT(xTmpExtension.is()); + } + catch (lang::DisposedException &) + { + //Another thread might have removed the extension meanwhile + } + } + //check again dependencies but prevent user interaction, + //We can disregard the license, because the user must have already + //accepted it, when we called checkPrerequisites the first time + SilentCheckPrerequisitesCommandEnv * pSilentCommandEnv = + new SilentCheckPrerequisitesCommandEnv(); + Reference<ucb::XCommandEnvironment> silentCommandEnv(pSilentCommandEnv); + + sal_Int32 failedPrereq = xTmpExtension->checkPrerequisites( + xAbortChannel, silentCommandEnv, true); + if (failedPrereq == 0) + { + xNewExtension = xPackageManager->addPackage( + url, properties, OUString(), xAbortChannel, + Reference<ucb::XCommandEnvironment>()); + //If we add a user extension and there is already one which was + //disabled by a user, then the newly installed one is enabled. If we + //add to another repository then the user extension remains + //disabled. + bool bUserDisabled2 = bUserDisabled; + if (repository.equals(OUSTR("user"))) + bUserDisabled2 = false; + + activateExtension( + dp_misc::getIdentifier(xNewExtension), + xNewExtension->getName(), bUserDisabled2, false, xAbortChannel, + Reference<ucb::XCommandEnvironment>()); + } + else + { + if (pSilentCommandEnv->m_Exception.hasValue()) + ::cppu::throwException(pSilentCommandEnv->m_Exception); + else if ( pSilentCommandEnv->m_UnknownException.hasValue()) + ::cppu::throwException(pSilentCommandEnv->m_UnknownException); + else + throw deploy::DeploymentException ( + OUSTR("Extension Manager: exception during addExtension, ckeckPrerequisites failed"), + static_cast<OWeakObject*>(this), uno::Any()); + } + } + catch (deploy::DeploymentException& ) { + excOccurred2 = ::cppu::getCaughtException(); + } catch (ucb::CommandFailedException & ) { + excOccurred2 = ::cppu::getCaughtException(); + } catch (ucb::CommandAbortedException & ) { + excOccurred2 = ::cppu::getCaughtException(); + } catch (lang::IllegalArgumentException &) { + excOccurred2 = ::cppu::getCaughtException(); + } catch (uno::RuntimeException &) { + excOccurred2 = ::cppu::getCaughtException(); + } catch (...) { + excOccurred2 = ::cppu::getCaughtException(); + deploy::DeploymentException exc( + OUSTR("Extension Manager: exception during addExtension, url: ") + + url, static_cast<OWeakObject*>(this), excOccurred2); + excOccurred2 <<= exc; + } + } + + if (excOccurred2.hasValue()) + { + //It does not matter what exception is thrown. We try to + //recover the original status. + //If the user aborted installation then a ucb::CommandAbortedException + //is thrown. + //Use a private AbortChannel so the user cannot interrupt. + try + { + if (xExtensionBackup.is()) + { + Reference<deploy::XPackage> xRestored = + xPackageManager->importExtension( + xExtensionBackup, Reference<task::XAbortChannel>(), + Reference<ucb::XCommandEnvironment>()); + } + activateExtension( + sIdentifier, sFileName, bUserDisabled, false, + Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>()); + } + catch (...) + { + } + ::cppu::throwException(excOccurred2); + } + } // leaving the garded section (getMutex()) + + try + { + fireModified(); + + }catch (deploy::DeploymentException& ) { + throw; + } catch (ucb::CommandFailedException & ) { + throw; + } catch (ucb::CommandAbortedException & ) { + throw; + } catch (lang::IllegalArgumentException &) { + throw; + } catch (uno::RuntimeException &) { + throw; + } catch (uno::Exception &) { + uno::Any excOccurred = ::cppu::getCaughtException(); + deploy::DeploymentException exc( + OUSTR("Extension Manager: exception in doChecksForAddExtension"), + static_cast<OWeakObject*>(this), excOccurred); + throw exc; + } catch (...) { + throw uno::RuntimeException( + OUSTR("Extension Manager: unexpected exception in doChecksForAddExtension"), + static_cast<OWeakObject*>(this)); + } + + return xNewExtension; +} + +void ExtensionManager::removeExtension( + OUString const & identifier, OUString const & fileName, + OUString const & repository, + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) + throw (deploy::DeploymentException, + ucb::CommandFailedException, + ucb::CommandAbortedException, + lang::IllegalArgumentException, + uno::RuntimeException) +{ + uno::Any excOccurred1; + Reference<deploy::XPackage> xExtensionBackup; + Reference<deploy::XPackageManager> xPackageManager; + bool bUserDisabled = false; + ::osl::MutexGuard guard(getMutex()); + try + { +//Determine the repository to use + if (repository.equals(OUSTR("user"))) + xPackageManager = m_userRepository; + else if (repository.equals(OUSTR("shared"))) + xPackageManager = m_sharedRepository; + else + throw lang::IllegalArgumentException( + OUSTR("No valid repository name provided."), + static_cast<cppu::OWeakObject*>(this), 0); + + bUserDisabled = isUserDisabled(identifier, fileName); + //Backup the extension, in case the user cancels the action + xExtensionBackup = backupExtension( + identifier, fileName, xPackageManager, xCmdEnv); + + //revoke the extension if it is active + Reference<deploy::XPackage> xOldExtension = + xPackageManager->getDeployedPackage( + identifier, fileName, xCmdEnv); + xOldExtension->revokePackage(xAbortChannel, xCmdEnv); + + xPackageManager->removePackage( + identifier, fileName, xAbortChannel, xCmdEnv); + activateExtension(identifier, fileName, bUserDisabled, false, + xAbortChannel, xCmdEnv); + fireModified(); + } + catch (deploy::DeploymentException& ) { + excOccurred1 = ::cppu::getCaughtException(); + } catch (ucb::CommandFailedException & ) { + excOccurred1 = ::cppu::getCaughtException(); + } catch (ucb::CommandAbortedException & ) { + excOccurred1 = ::cppu::getCaughtException(); + } catch (lang::IllegalArgumentException &) { + excOccurred1 = ::cppu::getCaughtException(); + } catch (uno::RuntimeException &) { + excOccurred1 = ::cppu::getCaughtException(); + } catch (...) { + excOccurred1 = ::cppu::getCaughtException(); + deploy::DeploymentException exc( + OUSTR("Extension Manager: exception during removeEtension"), + static_cast<OWeakObject*>(this), excOccurred1); + excOccurred1 <<= exc; + } + + if (excOccurred1.hasValue()) + { + //User aborted installation, restore the previous situation. + //Use a private AbortChannel so the user cannot interrupt. + try + { + Reference<ucb::XCommandEnvironment> tmpCmdEnv( + new TmpRepositoryCommandEnv(xCmdEnv->getInteractionHandler())); + if (xExtensionBackup.is()) + { + Reference<deploy::XPackage> xRestored = + xPackageManager->importExtension( + xExtensionBackup, Reference<task::XAbortChannel>(), + tmpCmdEnv); + activateExtension( + identifier, fileName, bUserDisabled, false, + Reference<task::XAbortChannel>(), + tmpCmdEnv); + + m_tmpRepository->removePackage( + dp_misc::getIdentifier(xExtensionBackup), + xExtensionBackup->getName(), xAbortChannel, xCmdEnv); + fireModified(); + } + } + catch (...) + { + } + ::cppu::throwException(excOccurred1); + } + + if (xExtensionBackup.is()) + m_tmpRepository->removePackage( + dp_misc::getIdentifier(xExtensionBackup), + xExtensionBackup->getName(), xAbortChannel, xCmdEnv); +} + +// Only enable extensions from shared and user repository +void ExtensionManager::enableExtension( + Reference<deploy::XPackage> const & extension, + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv) + throw (deploy::DeploymentException, + ucb::CommandFailedException, + ucb::CommandAbortedException, + lang::IllegalArgumentException, + uno::RuntimeException) +{ + ::osl::MutexGuard guard(getMutex()); + bool bUserDisabled = false; + uno::Any excOccurred; + try + { + if (!extension.is()) + return; + OUString repository = extension->getRepositoryName(); + if (!repository.equals(OUSTR("user"))) + throw lang::IllegalArgumentException( + OUSTR("No valid repository name provided."), + static_cast<cppu::OWeakObject*>(this), 0); + + bUserDisabled = isUserDisabled(dp_misc::getIdentifier(extension), + extension->getName()); + + activateExtension(dp_misc::getIdentifier(extension), + extension->getName(), false, false, + xAbortChannel, xCmdEnv); + } + catch (deploy::DeploymentException& ) { + excOccurred = ::cppu::getCaughtException(); + } catch (ucb::CommandFailedException & ) { + excOccurred = ::cppu::getCaughtException(); + } catch (ucb::CommandAbortedException & ) { + excOccurred = ::cppu::getCaughtException(); + } catch (lang::IllegalArgumentException &) { + excOccurred = ::cppu::getCaughtException(); + } catch (uno::RuntimeException &) { + excOccurred = ::cppu::getCaughtException(); + } catch (...) { + excOccurred = ::cppu::getCaughtException(); + deploy::DeploymentException exc( + OUSTR("Extension Manager: exception during enableExtension"), + static_cast<OWeakObject*>(this), excOccurred); + excOccurred <<= exc; + } + + if (excOccurred.hasValue()) + { + try + { + activateExtension(dp_misc::getIdentifier(extension), + extension->getName(), bUserDisabled, false, + xAbortChannel, xCmdEnv); + } + catch (...) + { + } + ::cppu::throwException(excOccurred); + } +} + +/** + */ +sal_Int32 ExtensionManager::checkPrerequisitesAndEnable( + Reference<deploy::XPackage> const & extension, + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv) + throw (deploy::DeploymentException, + ucb::CommandFailedException, + ucb::CommandAbortedException, + lang::IllegalArgumentException, + uno::RuntimeException) +{ + try + { + if (!extension.is()) + return 0; + ::osl::MutexGuard guard(getMutex()); + sal_Int32 ret = 0; + Reference<deploy::XPackageManager> mgr = + getPackageManager(extension->getRepositoryName()); + ret = mgr->checkPrerequisites(extension, xAbortChannel, xCmdEnv); + if (ret) + { + //There are some unfulfilled prerequisites, try to revoke + extension->revokePackage(xAbortChannel, xCmdEnv); + } + const OUString id(dp_misc::getIdentifier(extension)); + activateExtension(id, extension->getName(), + isUserDisabled(id, extension->getName()), false, + xAbortChannel, xCmdEnv); + return ret; + } + catch (deploy::DeploymentException& ) { + throw; + } catch (ucb::CommandFailedException & ) { + throw; + } catch (ucb::CommandAbortedException & ) { + throw; + } catch (lang::IllegalArgumentException &) { + throw; + } catch (uno::RuntimeException &) { + throw; + } catch (...) { + uno::Any excOccurred = ::cppu::getCaughtException(); + deploy::DeploymentException exc( + OUSTR("Extension Manager: exception during disableExtension"), + static_cast<OWeakObject*>(this), excOccurred); + throw exc; + } +} + +void ExtensionManager::disableExtension( + Reference<deploy::XPackage> const & extension, + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) + throw (deploy::DeploymentException, + ucb::CommandFailedException, + ucb::CommandAbortedException, + lang::IllegalArgumentException, + uno::RuntimeException) +{ + ::osl::MutexGuard guard(getMutex()); + uno::Any excOccurred; + bool bUserDisabled = false; + try + { + if (!extension.is()) + return; + const OUString repository( extension->getRepositoryName()); + if (!repository.equals(OUSTR("user"))) + throw lang::IllegalArgumentException( + OUSTR("No valid repository name provided."), + static_cast<cppu::OWeakObject*>(this), 0); + + const OUString id(dp_misc::getIdentifier(extension)); + bUserDisabled = isUserDisabled(id, extension->getName()); + + activateExtension(id, extension->getName(), true, false, + xAbortChannel, xCmdEnv); + } + catch (deploy::DeploymentException& ) { + excOccurred = ::cppu::getCaughtException(); + } catch (ucb::CommandFailedException & ) { + excOccurred = ::cppu::getCaughtException(); + } catch (ucb::CommandAbortedException & ) { + excOccurred = ::cppu::getCaughtException(); + } catch (lang::IllegalArgumentException &) { + excOccurred = ::cppu::getCaughtException(); + } catch (uno::RuntimeException &) { + excOccurred = ::cppu::getCaughtException(); + } catch (...) { + excOccurred = ::cppu::getCaughtException(); + deploy::DeploymentException exc( + OUSTR("Extension Manager: exception during disableExtension"), + static_cast<OWeakObject*>(this), excOccurred); + excOccurred <<= exc; + } + + if (excOccurred.hasValue()) + { + try + { + activateExtension(dp_misc::getIdentifier(extension), + extension->getName(), bUserDisabled, false, + xAbortChannel, xCmdEnv); + } + catch (...) + { + } + ::cppu::throwException(excOccurred); + } +} + +uno::Sequence< Reference<deploy::XPackage> > + ExtensionManager::getDeployedExtensions( + OUString const & repository, + Reference<task::XAbortChannel> const &xAbort, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) + throw (deploy::DeploymentException, + ucb::CommandFailedException, + ucb::CommandAbortedException, + lang::IllegalArgumentException, + uno::RuntimeException) +{ + return getPackageManager(repository)->getDeployedPackages( + xAbort, xCmdEnv); +} + +Reference<deploy::XPackage> + ExtensionManager::getDeployedExtension( + OUString const & repository, + OUString const & identifier, + OUString const & filename, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) + throw (deploy::DeploymentException, + ucb::CommandFailedException, + lang::IllegalArgumentException, + uno::RuntimeException) +{ + return getPackageManager(repository)->getDeployedPackage( + identifier, filename, xCmdEnv); +} + +uno::Sequence< uno::Sequence<Reference<deploy::XPackage> > > + ExtensionManager::getAllExtensions( + Reference<task::XAbortChannel> const & xAbort, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) + throw (deploy::DeploymentException, + ucb::CommandFailedException, + ucb::CommandAbortedException, + lang::IllegalArgumentException, + uno::RuntimeException) +{ + try + { + id2extensions mapExt; + + uno::Sequence<Reference<deploy::XPackage> > userExt = + m_userRepository->getDeployedPackages(xAbort, xCmdEnv); + addExtensionsToMap(mapExt, userExt, OUSTR("user")); + uno::Sequence<Reference<deploy::XPackage> > sharedExt = + m_sharedRepository->getDeployedPackages(xAbort, xCmdEnv); + addExtensionsToMap(mapExt, sharedExt, OUSTR("shared")); + uno::Sequence<Reference<deploy::XPackage> > bundledExt = + m_bundledRepository->getDeployedPackages(xAbort, xCmdEnv); + addExtensionsToMap(mapExt, bundledExt, OUSTR("bundled")); + + //copy the values of the map to a vector for sorting + ::std::vector< ::std::vector<Reference<deploy::XPackage> > > + vecExtensions; + id2extensions::const_iterator mapIt = mapExt.begin(); + for (;mapIt != mapExt.end(); ++mapIt) + vecExtensions.push_back(mapIt->second); + + //sort the element according to the identifier + ::std::sort(vecExtensions.begin(), vecExtensions.end(), CompIdentifiers()); + + ::std::vector< ::std::vector<Reference<deploy::XPackage> > >::const_iterator + citVecVec = vecExtensions.begin(); + sal_Int32 j = 0; + uno::Sequence< uno::Sequence<Reference<deploy::XPackage> > > seqSeq(vecExtensions.size()); + for (;citVecVec != vecExtensions.end(); citVecVec++, j++) + { + seqSeq[j] = comphelper::containerToSequence(*citVecVec); + } + return seqSeq; + + } catch (deploy::DeploymentException& ) { + throw; + } catch (ucb::CommandFailedException & ) { + throw; + } catch (ucb::CommandAbortedException & ) { + throw; + } catch (lang::IllegalArgumentException &) { + throw; + } catch (uno::RuntimeException &) { + throw; + } catch (...) { + uno::Any exc = ::cppu::getCaughtException(); + throw deploy::DeploymentException( + OUSTR("Extension Manager: exception during enableExtension"), + static_cast<OWeakObject*>(this), exc); + } +} + +//only to be called from unopkg!!! +void ExtensionManager::reinstallDeployedExtensions( + OUString const & repository, + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) + throw (deploy::DeploymentException, + ucb::CommandFailedException, ucb::CommandAbortedException, + lang::IllegalArgumentException, uno::RuntimeException) +{ + try + { + Reference<deploy::XPackageManager> + xPackageManager = getPackageManager(repository); + + ::osl::MutexGuard guard(getMutex()); + xPackageManager->reinstallDeployedPackages(xAbortChannel, xCmdEnv); + //We must sync here, otherwise we will get exceptions when extensions + //are removed. + dp_misc::syncRepositories(xCmdEnv); + const uno::Sequence< Reference<deploy::XPackage> > extensions( + xPackageManager->getDeployedPackages(xAbortChannel, xCmdEnv)); + + for ( sal_Int32 pos = 0; pos < extensions.getLength(); ++pos ) + { + try + { + const OUString id = dp_misc::getIdentifier(extensions[ pos ]); + const OUString fileName = extensions[ pos ]->getName(); + OSL_ASSERT(id.getLength()); + activateExtension(id, fileName, false, false, xAbortChannel, xCmdEnv ); + } + catch (lang::DisposedException &) + { + } + } + } catch (deploy::DeploymentException& ) { + throw; + } catch (ucb::CommandFailedException & ) { + throw; + } catch (ucb::CommandAbortedException & ) { + throw; + } catch (lang::IllegalArgumentException &) { + throw; + } catch (uno::RuntimeException &) { + throw; + } catch (...) { + uno::Any exc = ::cppu::getCaughtException(); + throw deploy::DeploymentException( + OUSTR("Extension Manager: exception during enableExtension"), + static_cast<OWeakObject*>(this), exc); + } +} + +sal_Bool ExtensionManager::synchronize( + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) + throw (deploy::DeploymentException, + ucb::CommandFailedException, + ucb::CommandAbortedException, + lang::IllegalArgumentException, + uno::RuntimeException) +{ + try + { + sal_Bool bModified = sal_False; + + ::osl::MutexGuard guard(getMutex()); + String sSynchronizingShared(StrSyncRepository::get()); + sSynchronizingShared.SearchAndReplaceAllAscii( "%NAME", OUSTR("shared")); + dp_misc::ProgressLevel progressShared(xCmdEnv, sSynchronizingShared); + bModified = m_sharedRepository->synchronize(xAbortChannel, xCmdEnv); + progressShared.update(OUSTR("\n\n")); + + String sSynchronizingBundled(StrSyncRepository::get()); + sSynchronizingBundled.SearchAndReplaceAllAscii( "%NAME", OUSTR("bundled")); + dp_misc::ProgressLevel progressBundled(xCmdEnv, sSynchronizingBundled); + bModified |= m_bundledRepository->synchronize(xAbortChannel, xCmdEnv); + progressBundled.update(OUSTR("\n\n")); + + //Always determine the active extension. This is necessary for the + //first-start optimization. The setup creates the registration data for the + //bundled extensions (brand_layer/share/prereg/bundled), which is copied to the user + //installation (user_installation/extension/bundled) when a user starts OOo + //for the first time after running setup. All bundled extensions are registered + //at that moment. However, extensions with the same identifier can be in the + //shared or user repository, in which case the respective bundled extensions must + //be revoked. + try + { + const uno::Sequence<uno::Sequence<Reference<deploy::XPackage> > > + seqSeqExt = getAllExtensions(xAbortChannel, xCmdEnv); + for (sal_Int32 i = 0; i < seqSeqExt.getLength(); i++) + { + uno::Sequence<Reference<deploy::XPackage> > const & seqExt = + seqSeqExt[i]; + activateExtension(seqExt, isUserDisabled(seqExt), true, + xAbortChannel, xCmdEnv); + } + } + catch (...) + { + //We catch the exception, so we can write the lastmodified file + //so we will no repeat this everytime OOo starts. + OSL_ENSURE(0, "Extensions Manager: synchronize"); + } + OUString lastSyncBundled(RTL_CONSTASCII_USTRINGPARAM( + "$BUNDLED_EXTENSIONS_USER/lastsynchronized")); + writeLastModified(lastSyncBundled, xCmdEnv); + OUString lastSyncShared(RTL_CONSTASCII_USTRINGPARAM( + "$SHARED_EXTENSIONS_USER/lastsynchronized")); + writeLastModified(lastSyncShared, xCmdEnv); + return bModified; + } catch (deploy::DeploymentException& ) { + throw; + } catch (ucb::CommandFailedException & ) { + throw; + } catch (ucb::CommandAbortedException & ) { + throw; + } catch (lang::IllegalArgumentException &) { + throw; + } catch (uno::RuntimeException &) { + throw; + } catch (...) { + uno::Any exc = ::cppu::getCaughtException(); + throw deploy::DeploymentException( + OUSTR("Extension Manager: exception in synchronize"), + static_cast<OWeakObject*>(this), exc); + } +} + +// Notify the user when a new extension is to be installed. This is only the +// case when one uses the system integration to install an extension (double +// clicking on .oxt file etc.)). The function must only be called if there is no +// extension with the same identifier already deployed. Then the checkUpdate +// function will inform the user that the extension is about to be installed In +// case the user cancels the installation a CommandFailed exception is +// thrown. +void ExtensionManager::checkInstall( + OUString const & displayName, + Reference<ucb::XCommandEnvironment> const & cmdEnv) +{ + uno::Any request( + deploy::InstallException( + OUSTR("Extension ") + displayName + + OUSTR(" is about to be installed."), + static_cast<OWeakObject *>(this), displayName)); + bool approve = false, abort = false; + if (! dp_misc::interactContinuation( + request, task::XInteractionApprove::static_type(), + cmdEnv, &approve, &abort )) + { + OSL_ASSERT( !approve && !abort ); + throw deploy::DeploymentException( + dp_misc::getResourceString(RID_STR_ERROR_WHILE_ADDING) + displayName, + static_cast<OWeakObject *>(this), request ); + } + if (abort || !approve) + throw ucb::CommandFailedException( + dp_misc::getResourceString(RID_STR_ERROR_WHILE_ADDING) + displayName, + static_cast<OWeakObject *>(this), request ); +} + +/* The function will make the user interaction in case there is an extension +installed with the same id. This function may only be called if there is already +an extension. +*/ +void ExtensionManager::checkUpdate( + OUString const & newVersion, + OUString const & newDisplayName, + Reference<deploy::XPackage> const & oldExtension, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) +{ + // package already deployed, interact --force: + uno::Any request( + (deploy::VersionException( + dp_misc::getResourceString( + RID_STR_PACKAGE_ALREADY_ADDED ) + newDisplayName, + static_cast<OWeakObject *>(this), newVersion, newDisplayName, + oldExtension ) ) ); + bool replace = false, abort = false; + if (! dp_misc::interactContinuation( + request, task::XInteractionApprove::static_type(), + xCmdEnv, &replace, &abort )) { + OSL_ASSERT( !replace && !abort ); + throw deploy::DeploymentException( + dp_misc::getResourceString( + RID_STR_ERROR_WHILE_ADDING) + newDisplayName, + static_cast<OWeakObject *>(this), request ); + } + if (abort || !replace) + throw ucb::CommandFailedException( + dp_misc::getResourceString( + RID_STR_PACKAGE_ALREADY_ADDED) + newDisplayName, + static_cast<OWeakObject *>(this), request ); +} + +Reference<deploy::XPackage> ExtensionManager::getTempExtension( + OUString const & url, + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<ucb::XCommandEnvironment> const & /*xCmdEnv*/) + +{ + Reference<ucb::XCommandEnvironment> tmpCmdEnvA(new TmpRepositoryCommandEnv()); + Reference<deploy::XPackage> xTmpPackage = m_tmpRepository->addPackage( + url, uno::Sequence<beans::NamedValue>(),OUString(), xAbortChannel, tmpCmdEnvA); + if (!xTmpPackage.is()) + { + throw deploy::DeploymentException( + OUSTR("Extension Manager: Failed to create temporary XPackage for url: ") + url, + static_cast<OWeakObject*>(this), uno::Any()); + + } + return xTmpPackage; +} + +uno::Sequence<Reference<deploy::XPackage> > SAL_CALL +ExtensionManager::getExtensionsWithUnacceptedLicenses( + OUString const & repository, + Reference<ucb::XCommandEnvironment> const & xCmdEnv) + throw (deploy::DeploymentException, + uno::RuntimeException) +{ + Reference<deploy::XPackageManager> + xPackageManager = getPackageManager(repository); + ::osl::MutexGuard guard(getMutex()); + return xPackageManager->getExtensionsWithUnacceptedLicenses(xCmdEnv); +} + +sal_Bool ExtensionManager::isReadOnlyRepository(::rtl::OUString const & repository) + throw (uno::RuntimeException) +{ + return getPackageManager(repository)->isReadOnly(); +} +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace sdecl = comphelper::service_decl; +sdecl::class_<ExtensionManager> servicePIP; +extern sdecl::ServiceDecl const serviceDecl( + servicePIP, + // a private one: + "com.sun.star.comp.deployment.ExtensionManager", + "com.sun.star.comp.deployment.ExtensionManager"); + +//------------------------------------------------------------------------------ +bool singleton_entries( + uno::Reference< registry::XRegistryKey > const & xRegistryKey ) +{ + try { + uno::Reference< registry::XRegistryKey > xKey( + xRegistryKey->createKey( + serviceDecl.getImplementationName() + + // xxx todo: use future generated function to get singleton name + OUSTR("/UNO/SINGLETONS/" + "com.sun.star.deployment.ExtensionManager") ) ); + xKey->setStringValue( serviceDecl.getSupportedServiceNames()[0] ); + return true; + } + catch (registry::InvalidRegistryException & exc) { + (void) exc; // avoid warnings + OSL_ENSURE( 0, ::rtl::OUStringToOString( + exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); + return false; + } +} + +// XModifyBroadcaster +//______________________________________________________________________________ +void ExtensionManager::addModifyListener( + Reference<util::XModifyListener> const & xListener ) + throw (uno::RuntimeException) +{ + check(); + rBHelper.addListener( ::getCppuType( &xListener ), xListener ); +} + +//______________________________________________________________________________ +void ExtensionManager::removeModifyListener( + Reference<util::XModifyListener> const & xListener ) + throw (uno::RuntimeException) +{ + check(); + rBHelper.removeListener( ::getCppuType( &xListener ), xListener ); +} + +void ExtensionManager::check() +{ + ::osl::MutexGuard guard( getMutex() ); + if (rBHelper.bInDispose || rBHelper.bDisposed) { + throw lang::DisposedException( + OUSTR("ExtensionManager instance has already been disposed!"), + static_cast<OWeakObject *>(this) ); + } +} + +void ExtensionManager::fireModified() +{ + ::cppu::OInterfaceContainerHelper * pContainer = rBHelper.getContainer( + util::XModifyListener::static_type() ); + if (pContainer != 0) { + pContainer->forEach<util::XModifyListener>( + boost::bind(&util::XModifyListener::modified, _1, + lang::EventObject(static_cast<OWeakObject *>(this))) ); + } +} + +} // namespace dp_manager + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/manager/dp_extensionmanager.hxx b/desktop/source/deployment/manager/dp_extensionmanager.hxx new file mode 100644 index 000000000000..8677f960ef91 --- /dev/null +++ b/desktop/source/deployment/manager/dp_extensionmanager.hxx @@ -0,0 +1,314 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_EXTENSIONMANAGER_H +#define INCLUDED_DP_EXTENSIONMANAGER_H + +#include "dp_manager.hrc" +#include "dp_misc.h" +#include "dp_interact.h" +#include "dp_activepackages.hxx" +#include "rtl/ref.hxx" +#include "cppuhelper/compbase1.hxx" +#include "ucbhelper/content.hxx" +#include "com/sun/star/deployment/XPackageRegistry.hpp" +#include "com/sun/star/deployment/XPackageManager.hpp" +#include "osl/mutex.hxx" +#include <list> + +namespace css = ::com::sun::star; + +namespace dp_manager { + +typedef ::std::hash_map< + ::rtl::OUString, + ::std::vector<css::uno::Reference<css::deployment::XPackage> >, + ::rtl::OUStringHash > id2extensions; + +class ExtensionManager : private ::dp_misc::MutexHolder, + public ::cppu::WeakComponentImplHelper1< css::deployment::XExtensionManager > +{ +public: + ExtensionManager( css::uno::Reference< css::uno::XComponentContext >const& xContext); + virtual ~ExtensionManager(); + + static css::uno::Sequence< ::rtl::OUString > getServiceNames(); + static ::rtl::OUString getImplName(); + + void check(); + void fireModified(); + +public: + +// XModifyBroadcaster + virtual void SAL_CALL addModifyListener( + css::uno::Reference<css::util::XModifyListener> const & xListener ) + throw (css::uno::RuntimeException); + virtual void SAL_CALL removeModifyListener( + css::uno::Reference<css::util::XModifyListener> const & xListener ) + throw (css::uno::RuntimeException); + +//XExtensionManager + virtual css::uno::Sequence< + css::uno::Reference<css::deployment::XPackageTypeInfo> > SAL_CALL + getSupportedPackageTypes() + throw (css::uno::RuntimeException); + + virtual css::uno::Reference<css::task::XAbortChannel> SAL_CALL + createAbortChannel() throw (css::uno::RuntimeException); + + virtual css::uno::Reference<css::deployment::XPackage> SAL_CALL addExtension( + ::rtl::OUString const & url, + css::uno::Sequence<css::beans::NamedValue> const & properties, + ::rtl::OUString const & repository, + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::lang::IllegalArgumentException, + css::uno::RuntimeException); + + virtual void SAL_CALL removeExtension( + ::rtl::OUString const & identifier, + ::rtl::OUString const & filename, + ::rtl::OUString const & repository, + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::lang::IllegalArgumentException, + css::uno::RuntimeException); + + virtual void SAL_CALL enableExtension( + css::uno::Reference<css::deployment::XPackage> const & extension, + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::lang::IllegalArgumentException, + css::uno::RuntimeException); + + virtual void SAL_CALL disableExtension( + css::uno::Reference<css::deployment::XPackage> const & extension, + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::lang::IllegalArgumentException, + css::uno::RuntimeException); + + virtual sal_Int32 SAL_CALL checkPrerequisitesAndEnable( + css::uno::Reference<css::deployment::XPackage> const & extension, + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::lang::IllegalArgumentException, + css::uno::RuntimeException); + + virtual css::uno::Sequence< css::uno::Reference<css::deployment::XPackage> > + SAL_CALL getDeployedExtensions( + ::rtl::OUString const & repository, + css::uno::Reference<css::task::XAbortChannel> const &, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::lang::IllegalArgumentException, + css::uno::RuntimeException); + + virtual css::uno::Reference< css::deployment::XPackage> + SAL_CALL getDeployedExtension( + ::rtl::OUString const & repository, + ::rtl::OUString const & identifier, + ::rtl::OUString const & filename, + css::uno::Reference< css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw ( + css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::lang::IllegalArgumentException, + css::uno::RuntimeException); + + virtual css::uno::Sequence<css::uno::Reference<css::deployment::XPackage> > + SAL_CALL getExtensionsWithSameIdentifier( + ::rtl::OUString const & identifier, + ::rtl::OUString const & filename, + css::uno::Reference< css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw ( + css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::lang::IllegalArgumentException, + css::uno::RuntimeException); + + virtual css::uno::Sequence< css::uno::Sequence<css::uno::Reference<css::deployment::XPackage> > > + SAL_CALL getAllExtensions( + css::uno::Reference<css::task::XAbortChannel> const &, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::lang::IllegalArgumentException, + css::uno::RuntimeException); + + virtual void SAL_CALL reinstallDeployedExtensions( + ::rtl::OUString const & repository, + css::uno::Reference< css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference< css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw ( + css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::lang::IllegalArgumentException, + css::uno::RuntimeException); + + virtual sal_Bool SAL_CALL synchronize( + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::lang::IllegalArgumentException, + css::uno::RuntimeException); + + virtual css::uno::Sequence<css::uno::Reference<css::deployment::XPackage> > SAL_CALL + getExtensionsWithUnacceptedLicenses( + ::rtl::OUString const & repository, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv) + throw (css::deployment::DeploymentException, + css::uno::RuntimeException); + + virtual sal_Bool SAL_CALL isReadOnlyRepository(::rtl::OUString const & repository) + throw (css::uno::RuntimeException); + +private: + + struct StrSyncRepository : public ::dp_misc::StaticResourceString< + StrSyncRepository, RID_STR_SYNCHRONIZING_REPOSITORY> {}; + + struct ExtensionInfos + { + ::rtl::OUString identifier; + ::rtl::OUString fileName; + ::rtl::OUString displayName; + ::rtl::OUString version; + }; + + css::uno::Reference< css::uno::XComponentContext> m_xContext; + + css::uno::Reference<css::deployment::XPackageManager> m_userRepository; + css::uno::Reference<css::deployment::XPackageManager> m_sharedRepository; + css::uno::Reference<css::deployment::XPackageManager> m_bundledRepository; + css::uno::Reference<css::deployment::XPackageManager> m_tmpRepository; + + //only to be used within addExtension + ::osl::Mutex m_addMutex; + /* contains the names of all repositories (except tmp) in order of there + priority. That is, the first element is "user" follod by "shared" and + then "bundled" + */ + ::std::list< ::rtl::OUString > m_repositoryNames; + + bool isUserDisabled(::rtl::OUString const & identifier, + ::rtl::OUString const & filename); + + bool isUserDisabled( + css::uno::Sequence<css::uno::Reference<css::deployment::XPackage> > const & seqExtSameId); + + void activateExtension( + ::rtl::OUString const & identifier, + ::rtl::OUString const & fileName, + bool bUserDisabled, bool bStartup, + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv); + + void activateExtension( + css::uno::Sequence<css::uno::Reference<css::deployment::XPackage> > const & seqExt, + bool bUserDisabled, bool bStartup, + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ); + + ::std::list<css::uno::Reference<css::deployment::XPackage> > + getExtensionsWithSameId(::rtl::OUString const & identifier, + ::rtl::OUString const & fileName, + css::uno::Reference< css::ucb::XCommandEnvironment> const & xCmdEnv = + css::uno::Reference< css::ucb::XCommandEnvironment>()); + + css::uno::Reference<css::deployment::XPackage> backupExtension( + ::rtl::OUString const & identifier, ::rtl::OUString const & fileName, + css::uno::Reference<css::deployment::XPackageManager> const & xPackageManager, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv); + + void checkInstall( + ::rtl::OUString const & displayName, + css::uno::Reference<css::ucb::XCommandEnvironment> const & cmdEnv); + + void checkUpdate( + ::rtl::OUString const & newVersion, + ::rtl::OUString const & newDisplayName, + css::uno::Reference<css::deployment::XPackage> const & oldExtension, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv); + + css::uno::Reference<css::deployment::XPackage> getTempExtension( + ::rtl::OUString const & url, + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv); + + void addExtensionsToMap( + id2extensions & mapExt, + css::uno::Sequence<css::uno::Reference<css::deployment::XPackage> > const & seqExt, + ::rtl::OUString const & repository); + + css::uno::Reference<css::deployment::XPackageManager> + getPackageManager(::rtl::OUString const & repository) + throw (css::lang::IllegalArgumentException); + + bool doChecksForAddExtension( + css::uno::Reference<css::deployment::XPackageManager> const & xPackageMgr, + css::uno::Sequence<css::beans::NamedValue> const & properties, + css::uno::Reference<css::deployment::XPackage> const & xTmpExtension, + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv, + css::uno::Reference<css::deployment::XPackage> & out_existingExtension ) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::lang::IllegalArgumentException, + css::uno::RuntimeException); + +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/manager/dp_informationprovider.cxx b/desktop/source/deployment/manager/dp_informationprovider.cxx new file mode 100644 index 000000000000..8021efe9dd3c --- /dev/null +++ b/desktop/source/deployment/manager/dp_informationprovider.cxx @@ -0,0 +1,395 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include <cppuhelper/implbase3.hxx> + +#include "comphelper/servicedecl.hxx" + +#include "com/sun/star/deployment/UpdateInformationProvider.hpp" +#include "com/sun/star/deployment/XPackage.hpp" +#include "com/sun/star/deployment/XPackageInformationProvider.hpp" +#include "com/sun/star/deployment/ExtensionManager.hpp" +#include "com/sun/star/deployment/XUpdateInformationProvider.hpp" +#include "com/sun/star/lang/XServiceInfo.hpp" +#include "com/sun/star/registry/XRegistryKey.hpp" +#include "com/sun/star/task/XAbortChannel.hpp" +#include "com/sun/star/ucb/CommandFailedException.hpp" +#include "com/sun/star/ucb/XCommandEnvironment.hpp" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/xml/dom/XElement.hpp" +#include "com/sun/star/xml/dom/XNode.hpp" + +#include "com/sun/star/uno/Reference.hxx" +#include "rtl/ustring.hxx" +#include "ucbhelper/content.hxx" + +#include "dp_dependencies.hxx" +#include "dp_descriptioninfoset.hxx" +#include "dp_identifier.hxx" +#include "dp_version.hxx" +#include "dp_misc.h" +#include "dp_update.hxx" + +namespace beans = com::sun::star::beans ; +namespace deployment = com::sun::star::deployment ; +namespace lang = com::sun::star::lang ; +namespace registry = com::sun::star::registry ; +namespace task = com::sun::star::task ; +namespace css_ucb = com::sun::star::ucb ; +namespace uno = com::sun::star::uno ; +namespace xml = com::sun::star::xml ; + +#define UNISTRING(s) rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s)) + +namespace dp_info { + +class PackageInformationProvider : + public ::cppu::WeakImplHelper3< deployment::XPackageInformationProvider, + css_ucb::XCommandEnvironment, + task::XInteractionHandler > +{ + public: + PackageInformationProvider( uno::Reference< uno::XComponentContext >const& xContext); + virtual ~PackageInformationProvider(); + + static uno::Sequence< rtl::OUString > getServiceNames(); + static rtl::OUString getImplName(); + + // XInteractionHandler + virtual void SAL_CALL handle( const uno::Reference< task::XInteractionRequest >& Request ) + throw( uno::RuntimeException ); + // XCommandEnvironment + virtual uno::Reference< task::XInteractionHandler > SAL_CALL getInteractionHandler() + throw ( uno::RuntimeException ) { return static_cast<task::XInteractionHandler*>(this); }; + + virtual uno::Reference< css_ucb::XProgressHandler > SAL_CALL getProgressHandler() + throw ( uno::RuntimeException ) { return uno::Reference< css_ucb::XProgressHandler >(); }; + + // XPackageInformationProvider + virtual rtl::OUString SAL_CALL getPackageLocation( const rtl::OUString& extensionId ) + throw ( uno::RuntimeException ); + virtual uno::Sequence< uno::Sequence< rtl::OUString > > SAL_CALL isUpdateAvailable( const rtl::OUString& extensionId ) + throw ( uno::RuntimeException ); + virtual uno::Sequence< uno::Sequence< rtl::OUString > > SAL_CALL getExtensionList() + throw ( uno::RuntimeException ); +//--------- +private: + + uno::Reference< uno::XComponentContext> mxContext; + + rtl::OUString getPackageLocation( const rtl::OUString& repository, + const rtl::OUString& _sExtensionId ); + + uno::Reference< deployment::XUpdateInformationProvider > mxUpdateInformation; +}; + +//------------------------------------------------------------------------------ + +PackageInformationProvider::PackageInformationProvider( uno::Reference< uno::XComponentContext > const& xContext) : + mxContext( xContext ), + mxUpdateInformation( deployment::UpdateInformationProvider::create( xContext ) ) +{ +} + +//------------------------------------------------------------------------------ + +PackageInformationProvider::~PackageInformationProvider() +{ +} + +//------------------------------------------------------------------------------ +void SAL_CALL PackageInformationProvider::handle( uno::Reference< task::XInteractionRequest > const & rRequest) + throw (uno::RuntimeException) +{ + uno::Sequence< uno::Reference< task::XInteractionContinuation > > xContinuations = rRequest->getContinuations(); + if ( xContinuations.getLength() == 1 ) + { + xContinuations[0]->select(); + } +} + +//------------------------------------------------------------------------------ +rtl::OUString PackageInformationProvider::getPackageLocation( + const rtl::OUString & repository, + const rtl::OUString& _rExtensionId ) +{ + rtl::OUString aLocationURL; + uno::Reference<deployment::XExtensionManager> xManager = + deployment::ExtensionManager::get(mxContext); + + if ( xManager.is() ) + { + const uno::Sequence< uno::Reference< deployment::XPackage > > packages( + xManager->getDeployedExtensions( + repository, + uno::Reference< task::XAbortChannel >(), + static_cast < XCommandEnvironment *> (this) ) ); + + for ( int pos = packages.getLength(); pos--; ) + { + try + { + const rtl::OUString aName = packages[ pos ]->getName(); + const beans::Optional< rtl::OUString > aID = packages[ pos ]->getIdentifier(); + if ( aID.IsPresent && aID.Value.compareTo( _rExtensionId ) == 0 ) + { + aLocationURL = packages[ pos ]->getURL(); + break; + } + } + catch ( uno::RuntimeException & ) {} + } + } + + return aLocationURL; +} + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +rtl::OUString SAL_CALL +PackageInformationProvider::getPackageLocation( const rtl::OUString& _sExtensionId ) + throw ( uno::RuntimeException ) +{ + rtl::OUString aLocationURL = getPackageLocation( UNISTRING("user"), _sExtensionId ); + + if ( aLocationURL.getLength() == 0 ) + { + aLocationURL = getPackageLocation( UNISTRING("shared"), _sExtensionId ); + } + if ( aLocationURL.getLength() == 0 ) + { + aLocationURL = getPackageLocation( UNISTRING("bundled"), _sExtensionId ); + } + if ( aLocationURL.getLength() ) + { + ::ucbhelper::Content aContent( aLocationURL, NULL ); + aLocationURL = aContent.getURL(); + } + return aLocationURL; +} + +//------------------------------------------------------------------------------ + +uno::Sequence< uno::Sequence< rtl::OUString > > SAL_CALL +PackageInformationProvider::isUpdateAvailable( const rtl::OUString& _sExtensionId ) + throw ( uno::RuntimeException ) +{ + uno::Sequence< uno::Sequence< rtl::OUString > > aList; + + uno::Reference<deployment::XExtensionManager> extMgr = + deployment::ExtensionManager::get(mxContext); + + if (!extMgr.is()) + { + OSL_ASSERT(0); + return aList; + } + std::vector<std::pair<uno::Reference<deployment::XPackage>, uno::Any > > errors; + dp_misc::UpdateInfoMap updateInfoMap; + if (_sExtensionId.getLength()) + { + std::vector<uno::Reference<deployment::XPackage> > vecExtensions; + uno::Reference<deployment::XPackage> extension; + try + { + extension = dp_misc::getExtensionWithHighestVersion( + extMgr->getExtensionsWithSameIdentifier( + _sExtensionId, _sExtensionId, uno::Reference<css_ucb::XCommandEnvironment>())); + vecExtensions.push_back(extension); + } + catch (lang::IllegalArgumentException &) + { + OSL_ASSERT(0); + } + updateInfoMap = dp_misc::getOnlineUpdateInfos( + mxContext, extMgr, mxUpdateInformation, &vecExtensions, errors); + } + else + { + updateInfoMap = dp_misc::getOnlineUpdateInfos( + mxContext, extMgr, mxUpdateInformation, NULL, errors); + } + + int nCount = 0; + for (dp_misc::UpdateInfoMap::iterator i(updateInfoMap.begin()); i != updateInfoMap.end(); ++i) + { + dp_misc::UpdateInfo const & info = i->second; + + rtl::OUString sOnlineVersion; + if (info.info.is()) + { + // check, if there are unsatisfied dependencies and ignore this online update + dp_misc::DescriptionInfoset infoset(mxContext, info.info); + uno::Sequence< uno::Reference< xml::dom::XElement > > + ds( dp_misc::Dependencies::check( infoset ) ); + if ( ! ds.getLength() ) + sOnlineVersion = info.version; + } + + rtl::OUString sVersionUser; + rtl::OUString sVersionShared; + rtl::OUString sVersionBundled; + uno::Sequence< uno::Reference< deployment::XPackage> > extensions; + try { + extensions = extMgr->getExtensionsWithSameIdentifier( + dp_misc::getIdentifier(info.extension), info.extension->getName(), + uno::Reference<css_ucb::XCommandEnvironment>()); + } catch (lang::IllegalArgumentException& ) { + OSL_ASSERT(0); + } + OSL_ASSERT(extensions.getLength() == 3); + if (extensions[0].is() ) + sVersionUser = extensions[0]->getVersion(); + if (extensions[1].is() ) + sVersionShared = extensions[1]->getVersion(); + if (extensions[2].is() ) + sVersionBundled = extensions[2]->getVersion(); + + bool bSharedReadOnly = extMgr->isReadOnlyRepository(OUSTR("shared")); + + dp_misc::UPDATE_SOURCE sourceUser = dp_misc::isUpdateUserExtension( + bSharedReadOnly, sVersionUser, sVersionShared, sVersionBundled, sOnlineVersion); + dp_misc::UPDATE_SOURCE sourceShared = dp_misc::isUpdateSharedExtension( + bSharedReadOnly, sVersionShared, sVersionBundled, sOnlineVersion); + + rtl::OUString updateVersionUser; + rtl::OUString updateVersionShared; + if (sourceUser != dp_misc::UPDATE_SOURCE_NONE) + updateVersionUser = dp_misc::getHighestVersion( + rtl::OUString(), sVersionShared, sVersionBundled, sOnlineVersion); + if (sourceShared != dp_misc::UPDATE_SOURCE_NONE) + updateVersionShared = dp_misc::getHighestVersion( + rtl::OUString(), rtl::OUString(), sVersionBundled, sOnlineVersion); + rtl::OUString updateVersion; + if (dp_misc::compareVersions(updateVersionUser, updateVersionShared) == dp_misc::GREATER) + updateVersion = updateVersionUser; + else + updateVersion = updateVersionShared; + if (updateVersion.getLength()) + { + + rtl::OUString aNewEntry[2]; + aNewEntry[0] = i->first; + aNewEntry[1] = updateVersion; + aList.realloc( ++nCount ); + aList[ nCount-1 ] = ::uno::Sequence< rtl::OUString >( aNewEntry, 2 ); + } + } + return aList; +} + +//------------------------------------------------------------------------------ +uno::Sequence< uno::Sequence< rtl::OUString > > SAL_CALL PackageInformationProvider::getExtensionList() + throw ( uno::RuntimeException ) +{ + const uno::Reference<deployment::XExtensionManager> mgr = + deployment::ExtensionManager::get(mxContext); + + if (!mgr.is()) + return uno::Sequence< uno::Sequence< rtl::OUString > >(); + + const uno::Sequence< uno::Sequence< uno::Reference<deployment::XPackage > > > + allExt = mgr->getAllExtensions( + uno::Reference< task::XAbortChannel >(), + static_cast < XCommandEnvironment *> (this) ); + + uno::Sequence< uno::Sequence< rtl::OUString > > retList; + + sal_Int32 cAllIds = allExt.getLength(); + retList.realloc(cAllIds); + + for (sal_Int32 i = 0; i < cAllIds; i++) + { + //The inner sequence contains extensions with the same identifier from + //all the different repositories, that is user, share, bundled. + const uno::Sequence< uno::Reference< deployment::XPackage > > & + seqExtension = allExt[i]; + sal_Int32 cExt = seqExtension.getLength(); + OSL_ASSERT(cExt == 3); + for (sal_Int32 j = 0; j < cExt; j++) + { + //ToDo according to the old code the first found extenions is used + //even if another one with the same id has a better version. + uno::Reference< deployment::XPackage > const & xExtension( seqExtension[j] ); + if (xExtension.is()) + { + rtl::OUString aNewEntry[2]; + aNewEntry[0] = dp_misc::getIdentifier(xExtension); + aNewEntry[1] = xExtension->getVersion(); + retList[i] = ::uno::Sequence< rtl::OUString >( aNewEntry, 2 ); + break; + } + } + } + return retList; +} + + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +namespace sdecl = comphelper::service_decl; +sdecl::class_<PackageInformationProvider> servicePIP; +extern sdecl::ServiceDecl const serviceDecl( + servicePIP, + // a private one: + "com.sun.star.comp.deployment.PackageInformationProvider", + "com.sun.star.comp.deployment.PackageInformationProvider" ); + +//------------------------------------------------------------------------------ +bool singleton_entries( + uno::Reference< registry::XRegistryKey > const & xRegistryKey ) +{ + try { + uno::Reference< registry::XRegistryKey > xKey( + xRegistryKey->createKey( + serviceDecl.getImplementationName() + + // xxx todo: use future generated function to get singleton name + UNISTRING("/UNO/SINGLETONS/" + "com.sun.star.deployment.PackageInformationProvider") ) ); + xKey->setStringValue( serviceDecl.getSupportedServiceNames()[0] ); + return true; + } + catch (registry::InvalidRegistryException & exc) { + (void) exc; // avoid warnings + OSL_ENSURE( 0, ::rtl::OUStringToOString( + exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); + return false; + } +} + +} // namespace dp_info + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/manager/dp_manager.cxx b/desktop/source/deployment/manager/dp_manager.cxx new file mode 100644 index 000000000000..c75cb6375643 --- /dev/null +++ b/desktop/source/deployment/manager/dp_manager.cxx @@ -0,0 +1,1675 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_ucb.h" +#include "dp_resource.h" +#include "dp_platform.hxx" +#include "dp_manager.h" +#include "dp_identifier.hxx" +#include "rtl/ustrbuf.hxx" +#include "rtl/string.hxx" +#include "rtl/uri.hxx" +#include "rtl/bootstrap.hxx" +#include "osl/diagnose.h" +#include "osl/file.hxx" +#include "osl/security.hxx" +#include "cppuhelper/weakref.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "cppuhelper/implbase1.hxx" +#include "cppuhelper/interfacecontainer.hxx" +#include "comphelper/servicedecl.hxx" +#include "comphelper/sequence.hxx" +#include "xmlscript/xml_helper.hxx" +#include "svl/inettype.hxx" +#include "com/sun/star/lang/DisposedException.hpp" +#include "com/sun/star/lang/WrappedTargetRuntimeException.hpp" +#include "com/sun/star/beans/UnknownPropertyException.hpp" +#include "com/sun/star/util/XUpdatable.hpp" +#include "com/sun/star/sdbc/XResultSet.hpp" +#include "com/sun/star/sdbc/XRow.hpp" +#include "com/sun/star/ucb/XContentAccess.hpp" +#include "com/sun/star/ucb/NameClash.hpp" +#include "com/sun/star/deployment/VersionException.hpp" +#include "com/sun/star/deployment/InstallException.hpp" +#include "com/sun/star/deployment/Prerequisites.hpp" +#include "com/sun/star/task/XInteractionApprove.hpp" +#include "com/sun/star/ucb/UnsupportedCommandException.hpp" +#include "boost/bind.hpp" +#include "tools/urlobj.hxx" + +#include "osl/file.hxx" +#include <vector> +#include <list> +#include "dp_descriptioninfoset.hxx" +#include "dp_commandenvironments.hxx" +#include "dp_properties.hxx" + +using namespace ::dp_misc; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using ::rtl::OUString; + +namespace dp_log { +extern comphelper::service_decl::ServiceDecl const serviceDecl; +} + +namespace dp_registry { +Reference<deployment::XPackageRegistry> create( + OUString const & context, + OUString const & cachePath, bool readOnly, + Reference<XComponentContext> const & xComponentContext ); +} + +namespace dp_manager { + +struct MatchTempDir +{ + OUString m_str; + MatchTempDir( OUString const & str ) : m_str( str ) {} + bool operator () ( ActivePackages::Entries::value_type const & v ) const { + return v.second.temporaryName.equalsIgnoreAsciiCase( m_str ); + } +}; + + +namespace { +OUString getExtensionFolder(OUString const & parentFolder, + Reference<ucb::XCommandEnvironment> const & xCmdEnv) +{ + ::ucbhelper::Content tempFolder( + parentFolder, xCmdEnv ); + Reference<sdbc::XResultSet> xResultSet( + tempFolder.createCursor( + Sequence<OUString>( &StrTitle::get(), 1 ), + ::ucbhelper::INCLUDE_FOLDERS_ONLY ) ); + + OUString title; + while (xResultSet->next()) + { + title = Reference<sdbc::XRow>( + xResultSet, UNO_QUERY_THROW )->getString(1 /* Title */ ) ; + break; + } + return title; +} +} +//______________________________________________________________________________ +void PackageManagerImpl::initActivationLayer( + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + if (m_activePackages.getLength() == 0) + { + OSL_ASSERT( m_registryCache.getLength() == 0 ); + // documents temp activation: + m_activePackagesDB.reset( new ActivePackages ); + ::ucbhelper::Content ucbContent; + if (create_ucb_content( &ucbContent, m_context, xCmdEnv, + false /* no throw */ )) + { + // scan for all entries in m_packagesDir: + Reference<sdbc::XResultSet> xResultSet( + ucbContent.createCursor( + Sequence<OUString>( &StrTitle::get(), 1 ), + ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS ) ); + while (xResultSet->next()) + { + Reference<sdbc::XRow> xRow( xResultSet, UNO_QUERY_THROW ); + OUString title( xRow->getString( 1 /* Title */ ) ); + // xxx todo: remove workaround for tdoc + if (title.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( + "this_is_a_dummy_stream_just_there_" + "as_a_workaround_for_a_" + "temporary_limitation_of_the_" + "storage_api_implementation") )) + continue; + if (title.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( + "META-INF") ) ) + continue; + + ::ucbhelper::Content sourceContent( + Reference<XContentAccess>( + xResultSet, UNO_QUERY_THROW )->queryContent(), + xCmdEnv ); + + OUString mediaType( detectMediaType( sourceContent, + false /* no throw */) ); + if (mediaType.getLength() >0) + { + ActivePackages::Data dbData; + insertToActivationLayer( + Sequence<css::beans::NamedValue>(),mediaType, sourceContent, + title, &dbData ); + + insertToActivationLayerDB( title, dbData ); + //TODO #i73136#: insertToActivationLayerDB needs id not + // title, but the whole m_activePackages.getLength()==0 + // case (i.e., document-relative deployment) currently + // does not work, anyway. + } + } + } + } + else + { + // user|share: + OSL_ASSERT( m_activePackages.getLength() > 0 ); + m_activePackages_expanded = expandUnoRcUrl( m_activePackages ); + m_registrationData_expanded = expandUnoRcUrl(m_registrationData); + if (!m_readOnly) + create_folder( 0, m_activePackages_expanded, xCmdEnv, true); + + OUString dbName; + if (m_context.equals(OUSTR("user"))) + dbName = m_activePackages_expanded + OUSTR(".db"); + else + { + //Create the extension data base in the user installation + create_folder( 0, m_registrationData_expanded, xCmdEnv, true); + dbName = m_registrationData_expanded + OUSTR("/extensions.db"); + } + //The data base can always be written because it it always in the user installation + m_activePackagesDB.reset( + new ActivePackages( dbName, false ) ); + + if (! m_readOnly && ! m_context.equals(OUSTR("bundled"))) + { + // clean up activation layer, scan for zombie temp dirs: + ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() ); + + ::ucbhelper::Content tempFolder( + m_activePackages_expanded, xCmdEnv ); + Reference<sdbc::XResultSet> xResultSet( + tempFolder.createCursor( + Sequence<OUString>( &StrTitle::get(), 1 ), + ::ucbhelper::INCLUDE_DOCUMENTS_ONLY ) ); + // get all temp directories: + ::std::vector<OUString> tempEntries; + ::std::vector<OUString> removedEntries; + while (xResultSet->next()) + { + OUString title( + Reference<sdbc::XRow>( + xResultSet, UNO_QUERY_THROW )->getString( + 1 /* Title */ ) ); + + const char extensionRemoved[] = "removed"; + if (title.endsWithAsciiL( + extensionRemoved, sizeof(extensionRemoved) - 1)) + { + //save the file name withouth the "removed" part + sal_Int32 index = title.lastIndexOfAsciiL( + extensionRemoved, sizeof(extensionRemoved) - 1); + OUString remFile = title.copy(0, index); + removedEntries.push_back(::rtl::Uri::encode( + remFile, rtl_UriCharClassPchar, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ) ); + } + else + { + tempEntries.push_back( ::rtl::Uri::encode( + title, rtl_UriCharClassPchar, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ) ); + } + } + + bool bShared = m_context.equals(OUSTR("shared")) ? true : false; + for ( ::std::size_t pos = 0; pos < tempEntries.size(); ++pos ) + { + OUString const & tempEntry = tempEntries[ pos ]; + const MatchTempDir match( tempEntry ); + if (::std::find_if( id2temp.begin(), id2temp.end(), match ) == + id2temp.end()) + { + const OUString url( + makeURL(m_activePackages_expanded, tempEntry ) ); + + //In case of shared extensions, new entries are regarded as + //added extensions if there is no xxx.tmpremoved file. + if (bShared) + { + if (::std::find(removedEntries.begin(), removedEntries.end(), tempEntry) == + removedEntries.end()) + { + continue; + } + else + { + //Make sure only the same user removes the extension, who + //previously unregistered it. This is avoid races if multiple instances + //of OOo are running which all have write access to the shared installation. + //For example, a user removes the extension, but keeps OOo + //running. Parts of the extension may still be loaded and used by OOo. + //Therefore the extension is only deleted the next time the extension manager is + //run after restarting OOo. While OOo is still running, another user starts OOo + //which would deleted the extension files. If the same user starts another + //instance of OOo then the lock file will prevent this. + OUString aUserName; + ::osl::Security aSecurity; + aSecurity.getUserName( aUserName ); + ucbhelper::Content remFileContent( + url + OUSTR("removed"), Reference<XCommandEnvironment>()); + ::rtl::ByteSequence data = dp_misc::readFile(remFileContent); + ::rtl::OString osData(reinterpret_cast<const sal_Char*>(data.getConstArray()), + data.getLength()); + OUString sData = ::rtl::OStringToOUString( + osData, RTL_TEXTENCODING_UTF8); + if (!sData.equals(aUserName)) + continue; + } + } + // temp entry not needed anymore: + erase_path( url + OUSTR("_"), + Reference<XCommandEnvironment>(), + false /* no throw: ignore errors */ ); + erase_path( url, Reference<XCommandEnvironment>(), + false /* no throw: ignore errors */ ); + //delete the xxx.tmpremoved file + erase_path(url + OUSTR("removed"), + Reference<XCommandEnvironment>(), false); + } + } + } + } +} + +//______________________________________________________________________________ +void PackageManagerImpl::initRegistryBackends() +{ + if (m_registryCache.getLength() > 0) + create_folder( 0, m_registryCache, + Reference<XCommandEnvironment>(), false); + m_xRegistry.set( ::dp_registry::create( + m_context, m_registryCache, false, + m_xComponentContext ) ); +} + +//______________________________________________________________________________ +Reference<deployment::XPackageManager> PackageManagerImpl::create( + Reference<XComponentContext> const & xComponentContext, + OUString const & context ) +{ + PackageManagerImpl * that = new PackageManagerImpl( + xComponentContext, context ); + Reference<deployment::XPackageManager> xPackageManager( that ); + + OUString packages, logFile, stampURL; + if (context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("user") )) { + that->m_activePackages = OUSTR( + "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/uno_packages"); + that->m_registrationData = OUSTR( + "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE"); + that->m_registryCache = OUSTR( + "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/registry"); + logFile = OUSTR( + "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/log.txt"); + //We use the extension .sys for the file because on Windows Vista a sys + //(as well as exe and dll) file + //will not be written in the VirtualStore. For example if the process has no + //admin right once cannot write to the %programfiles% folder. However, when + //virtualization is used, the file will be written into the VirtualStore and + //it appears as if one could write to %programfiles%. When we test for write + //access to the office/shared folder for shared extensions then this typically + //fails because a normal user typically cannot write to this folder. However, + //using virtualization it appears that he/she can. Then a shared extension can + //be installed but is only visible for the user (because the extension is in + //the virtual store). + stampURL = OUSTR( + "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/stamp.sys"); + } + else if (context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("shared") )) { + that->m_activePackages = OUSTR( + "vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE/uno_packages"); + that->m_registrationData = OUSTR( + "vnd.sun.star.expand:$SHARED_EXTENSIONS_USER"); + that->m_registryCache = OUSTR( + "vnd.sun.star.expand:$SHARED_EXTENSIONS_USER/registry"); + logFile = OUSTR( + "vnd.sun.star.expand:$SHARED_EXTENSIONS_USER/log.txt"); + stampURL = OUSTR( + "vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE/stamp.sys"); + } + else if (context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("bundled") )) { + that->m_activePackages = OUSTR( + "vnd.sun.star.expand:$BUNDLED_EXTENSIONS"); + that->m_registrationData = OUSTR( + "vnd.sun.star.expand:$BUNDLED_EXTENSIONS_USER"); + that->m_registryCache = OUSTR( + "vnd.sun.star.expand:$BUNDLED_EXTENSIONS_USER/registry"); + logFile = OUSTR( + "vnd.sun.star.expand:$BUNDLED_EXTENSIONS_USER/log.txt"); + //No stamp file. We assume that bundled is always readonly. It must not be + //modified from ExtensionManager but only by the installer + } + else if (context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("tmp") )) { + that->m_activePackages = OUSTR( + "vnd.sun.star.expand:$TMP_EXTENSIONS/extensions"); + that->m_registrationData = OUSTR( + "vnd.sun.star.expand:$TMP_EXTENSIONS"); + that->m_registryCache = OUSTR( + "vnd.sun.star.expand:$TMP_EXTENSIONS/registry"); + stampURL = OUSTR( + "vnd.sun.star.expand:$TMP_EXTENSIONS/stamp.sys"); + } + else if (! context.matchAsciiL( + RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.tdoc:/") )) { + throw lang::IllegalArgumentException( + OUSTR("invalid context given: ") + context, + Reference<XInterface>(), static_cast<sal_Int16>(-1) ); + } + + Reference<XCommandEnvironment> xCmdEnv; + + try { + //There is no stampURL for the bundled folder + if (stampURL.getLength() > 0) + { +#define CURRENT_STAMP "1" + try { + //The osl file API does not allow to find out if one can write + //into a folder. Therefore we try to write a file. Then we delete + //it, so that it does not hinder uninstallation of OOo + // probe writing: + ::ucbhelper::Content ucbStamp( stampURL, xCmdEnv ); + ::rtl::OString stamp( + RTL_CONSTASCII_STRINGPARAM(CURRENT_STAMP) ); + Reference<io::XInputStream> xData( + ::xmlscript::createInputStream( + ::rtl::ByteSequence( + reinterpret_cast<sal_Int8 const *>(stamp.getStr()), + stamp.getLength() ) ) ); + ucbStamp.writeStream( xData, true /* replace existing */ ); + that->m_readOnly = false; + erase_path( stampURL, xCmdEnv ); + } + catch (RuntimeException &) { + try { + erase_path( stampURL, xCmdEnv ); + } catch (...) + { + } + throw; + } + catch (Exception &) { + that->m_readOnly = true; + } + } + + if (!that->m_readOnly && logFile.getLength() > 0) + { + const Any any_logFile(logFile); + that->m_xLogFile.set( + that->m_xComponentContext->getServiceManager() + ->createInstanceWithArgumentsAndContext( + dp_log::serviceDecl.getSupportedServiceNames()[0], + Sequence<Any>( &any_logFile, 1 ), + that->m_xComponentContext ), + UNO_QUERY_THROW ); + xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv, that->m_xLogFile ) ); + } + + that->initRegistryBackends(); + that->initActivationLayer( xCmdEnv ); + + return xPackageManager; + + } + catch (RuntimeException &) { + throw; + } + catch (Exception &) { + Any exc( ::cppu::getCaughtException() ); + ::rtl::OUStringBuffer buf; + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("[context=\"") ); + buf.append( context ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( + "\"] caught unexpected exception!") ); + throw lang::WrappedTargetRuntimeException( + buf.makeStringAndClear(), Reference<XInterface>(), exc ); + } +} + +//______________________________________________________________________________ +PackageManagerImpl::~PackageManagerImpl() +{ +} + +//______________________________________________________________________________ +void PackageManagerImpl::fireModified() +{ + ::cppu::OInterfaceContainerHelper * pContainer = rBHelper.getContainer( + util::XModifyListener::static_type() ); + if (pContainer != 0) { + pContainer->forEach<util::XModifyListener>( + boost::bind(&util::XModifyListener::modified, _1, + lang::EventObject(static_cast<OWeakObject *>(this))) ); + } +} + +//______________________________________________________________________________ +void PackageManagerImpl::disposing() +{ + try { +// // xxx todo: guarding? +// ::osl::MutexGuard guard( getMutex() ); + try_dispose( m_xLogFile ); + m_xLogFile.clear(); + try_dispose( m_xRegistry ); + m_xRegistry.clear(); + m_activePackagesDB.reset(0); + m_xComponentContext.clear(); + + t_pm_helper::disposing(); + + } + catch (RuntimeException &) { + throw; + } + catch (Exception &) { + Any exc( ::cppu::getCaughtException() ); + throw lang::WrappedTargetRuntimeException( + OUSTR("caught unexpected exception while disposing..."), + static_cast<OWeakObject *>(this), exc ); + } +} + +// XComponent +//______________________________________________________________________________ +void PackageManagerImpl::dispose() throw (RuntimeException) +{ + check(); + WeakComponentImplHelperBase::dispose(); +} + +//______________________________________________________________________________ +void PackageManagerImpl::addEventListener( + Reference<lang::XEventListener> const & xListener ) throw (RuntimeException) +{ + check(); + WeakComponentImplHelperBase::addEventListener( xListener ); +} + +//______________________________________________________________________________ +void PackageManagerImpl::removeEventListener( + Reference<lang::XEventListener> const & xListener ) throw (RuntimeException) +{ + check(); + WeakComponentImplHelperBase::removeEventListener( xListener ); +} + +// XPackageManager +//______________________________________________________________________________ +OUString PackageManagerImpl::getContext() throw (RuntimeException) +{ + check(); + return m_context; +} + +//______________________________________________________________________________ +Sequence< Reference<deployment::XPackageTypeInfo> > +PackageManagerImpl::getSupportedPackageTypes() throw (RuntimeException) +{ + OSL_ASSERT( m_xRegistry.is() ); + return m_xRegistry->getSupportedPackageTypes(); +} + +//______________________________________________________________________________ +Reference<task::XAbortChannel> PackageManagerImpl::createAbortChannel() + throw (RuntimeException) +{ + check(); + return new AbortChannel; +} + +// XModifyBroadcaster +//______________________________________________________________________________ +void PackageManagerImpl::addModifyListener( + Reference<util::XModifyListener> const & xListener ) + throw (RuntimeException) +{ + check(); + rBHelper.addListener( ::getCppuType( &xListener ), xListener ); +} + +//______________________________________________________________________________ +void PackageManagerImpl::removeModifyListener( + Reference<util::XModifyListener> const & xListener ) + throw (RuntimeException) +{ + check(); + rBHelper.removeListener( ::getCppuType( &xListener ), xListener ); +} + +//______________________________________________________________________________ +OUString PackageManagerImpl::detectMediaType( + ::ucbhelper::Content const & ucbContent_, bool throw_exc ) +{ + ::ucbhelper::Content ucbContent(ucbContent_); + OUString url( ucbContent.getURL() ); + OUString mediaType; + if (url.matchAsciiL( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.tdoc:") ) || + url.matchAsciiL( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.pkg:") )) + { + try { + ucbContent.getPropertyValue( OUSTR("MediaType") ) >>= mediaType; + } + catch (beans::UnknownPropertyException &) { + } + OSL_ENSURE( mediaType.getLength() > 0, "### no media-type?!" ); + } + if (mediaType.getLength() == 0) + { + try { + Reference<deployment::XPackage> xPackage( + m_xRegistry->bindPackage( + url, OUString(), false, OUString(), ucbContent.getCommandEnvironment() ) ); + const Reference<deployment::XPackageTypeInfo> xPackageType( + xPackage->getPackageType() ); + OSL_ASSERT( xPackageType.is() ); + if (xPackageType.is()) + mediaType = xPackageType->getMediaType(); + } + catch (lang::IllegalArgumentException & exc) { + if (throw_exc) + throw; + (void) exc; + OSL_ENSURE( 0, ::rtl::OUStringToOString( + exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); + } + } + return mediaType; +} + +//______________________________________________________________________________ +OUString PackageManagerImpl::insertToActivationLayer( + Sequence<beans::NamedValue> const & properties, + OUString const & mediaType, ::ucbhelper::Content const & sourceContent_, + OUString const & title, ActivePackages::Data * dbData ) +{ + ::ucbhelper::Content sourceContent(sourceContent_); + Reference<XCommandEnvironment> xCmdEnv( + sourceContent.getCommandEnvironment() ); + OUString destFolder, tempEntry; + if (::osl::File::createTempFile( + m_activePackages_expanded.getLength() == 0 + ? 0 : &m_activePackages_expanded, + 0, &tempEntry ) != ::osl::File::E_None) + throw RuntimeException( + OUSTR("::osl::File::createTempFile() failed!"), 0 ); + if (m_activePackages_expanded.getLength() == 0) { + destFolder = tempEntry; + } + else { + tempEntry = tempEntry.copy( tempEntry.lastIndexOf( '/' ) + 1 ); + // tweak user|share to macrofied url: + destFolder = makeURL( m_activePackages, tempEntry ); + } + destFolder += OUSTR("_"); + + // prepare activation folder: + ::ucbhelper::Content destFolderContent; + create_folder( &destFolderContent, destFolder, xCmdEnv ); + + // copy content into activation temp dir: + if (mediaType.matchIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM( + "application/vnd.sun.star.package-bundle") ) || + // xxx todo: more sophisticated parsing + mediaType.matchIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM( + "application/vnd.sun.star.legacy-package-bundle") )) + { + // inflate content: + ::rtl::OUStringBuffer buf; + if (!sourceContent.isFolder()) + { + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.zip://") ); + buf.append( ::rtl::Uri::encode( sourceContent.getURL(), + rtl_UriCharClassRegName, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ) ); + } + else + { + //Folder. No need to unzip, just copy + buf.append(sourceContent.getURL()); + } + buf.append( static_cast<sal_Unicode>('/') ); + sourceContent = ::ucbhelper::Content( + buf.makeStringAndClear(), xCmdEnv ); + } + if (! destFolderContent.transferContent( + sourceContent, ::ucbhelper::InsertOperation_COPY, + title, NameClash::OVERWRITE )) + throw RuntimeException( OUSTR("UCB transferContent() failed!"), 0 ); + + + // write to DB: + //bundled extensions should only be added by the synchronizeAddedExtensions + //functions. Moreover, there is no "temporary folder" for bundled extensions. + OSL_ASSERT(!m_context.equals(OUSTR("bundled"))); + OUString sFolderUrl = makeURLAppendSysPathSegment(destFolderContent.getURL(), title); + DescriptionInfoset info = + dp_misc::getDescriptionInfoset(sFolderUrl); + dbData->temporaryName = tempEntry; + dbData->fileName = title; + dbData->mediaType = mediaType; + dbData->version = info.getVersion(); + + //No write the properties file next to the extension + ExtensionProperties props(sFolderUrl, properties, xCmdEnv); + props.write(); + return destFolder; +} + +//______________________________________________________________________________ +void PackageManagerImpl::insertToActivationLayerDB( + OUString const & id, ActivePackages::Data const & dbData ) +{ + //access to the database must be guarded. See removePackage + const ::osl::MutexGuard guard( getMutex() ); + m_activePackagesDB->put( id, dbData ); +} + +//______________________________________________________________________________ +/* The function returns true if there is an extension with the same id already + installed which needs to be uninstalled, before the new extension can be installed. +*/ +bool PackageManagerImpl::isInstalled( + Reference<deployment::XPackage> const & package) +{ + OUString id(dp_misc::getIdentifier(package)); + OUString fn(package->getName()); + bool bInstalled = false; + if (m_activePackagesDB->has( id, fn )) + { + bInstalled = true; + } + return bInstalled; +} + +// XPackageManager +//______________________________________________________________________________ +Reference<deployment::XPackage> PackageManagerImpl::importExtension( + Reference<deployment::XPackage> const & extension, + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<XCommandEnvironment> const & xCmdEnv_ ) + throw (deployment::DeploymentException, CommandFailedException, + CommandAbortedException, lang::IllegalArgumentException, + RuntimeException) +{ + return addPackage(extension->getURL(), Sequence<beans::NamedValue>(), + OUString(), xAbortChannel, xCmdEnv_); +} + +/* The function adds an extension but does not register it!!! + It may not do any user interaction. This is done in XExtensionManager::addExtension +*/ +Reference<deployment::XPackage> PackageManagerImpl::addPackage( + OUString const & url, + css::uno::Sequence<css::beans::NamedValue> const & properties, + OUString const & mediaType_, + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<XCommandEnvironment> const & xCmdEnv_ ) + throw (deployment::DeploymentException, CommandFailedException, + CommandAbortedException, lang::IllegalArgumentException, + RuntimeException) +{ + check(); + if (m_readOnly) + { + OUString message; + if (m_context == OUSTR("shared")) + message = OUSTR("You need write permissions to install a shared extension!"); + else + message = OUSTR("You need write permissions to install this extension!"); + throw deployment::DeploymentException( + message, static_cast<OWeakObject *>(this), Any() ); + } + Reference<XCommandEnvironment> xCmdEnv; + if (m_xLogFile.is()) + xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) ); + else + xCmdEnv.set( xCmdEnv_ ); + + try { + ::ucbhelper::Content sourceContent; + create_ucb_content( &sourceContent, url, xCmdEnv ); // throws exc + const OUString title(sourceContent.getPropertyValue( + StrTitle::get() ).get<OUString>() ); + const OUString title_enc( ::rtl::Uri::encode( + title, rtl_UriCharClassPchar, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ) ); + OUString destFolder; + + OUString mediaType(mediaType_); + if (mediaType.getLength() == 0) + mediaType = detectMediaType( sourceContent ); + + Reference<deployment::XPackage> xPackage; + // copy file: + progressUpdate( + getResourceString(RID_STR_COPYING_PACKAGE) + title, xCmdEnv ); + if (m_activePackages.getLength() == 0) + { + ::ucbhelper::Content docFolderContent; + create_folder( &docFolderContent, m_context, xCmdEnv ); + // copy into document, first: + if (! docFolderContent.transferContent( + sourceContent, ::ucbhelper::InsertOperation_COPY, + OUString(), + NameClash::ASK /* xxx todo: ASK not needed? */)) + throw RuntimeException( + OUSTR("UCB transferContent() failed!"), 0 ); + // set media-type: + ::ucbhelper::Content docContent( + makeURL( m_context, title_enc ), xCmdEnv ); + //TODO #i73136#: using title instead of id can lead to + // clashes, but the whole m_activePackages.getLength()==0 + // case (i.e., document-relative deployment) currently does + // not work, anyway. + docContent.setPropertyValue( + OUSTR("MediaType"), Any(mediaType) ); + + // xxx todo: obsolete in the future + try { + docFolderContent.executeCommand( OUSTR("flush"), Any() ); + } + catch (UnsupportedCommandException &) { + } + } + ActivePackages::Data dbData; + destFolder = insertToActivationLayer( + properties, mediaType, sourceContent, title, &dbData ); + + + // bind activation package: + //Because every shared/user extension will be unpacked in a folder, + //which was created with a unique name we will always have two different + //XPackage objects, even if the second extension is the same. + //Therefore bindPackage does not need a guard here. + xPackage = m_xRegistry->bindPackage( + makeURL( destFolder, title_enc ), mediaType, false, OUString(), xCmdEnv ); + + OSL_ASSERT( xPackage.is() ); + if (xPackage.is()) + { + bool install = false; + try + { + OUString const id = dp_misc::getIdentifier( xPackage ); + + ::osl::MutexGuard g(m_addMutex); + if (isInstalled(xPackage)) + { + //Do not guard the complete function with the getMutex + removePackage(id, xPackage->getName(), xAbortChannel, + xCmdEnv); + } + install = true; + insertToActivationLayerDB(id, dbData); + } + catch (...) + { + deletePackageFromCache( xPackage, destFolder ); + throw; + } + if (!install) + { + deletePackageFromCache( xPackage, destFolder ); + } + //ToDo: We should notify only if the extension is registered + fireModified(); + } + return xPackage; + } + catch (RuntimeException &) { + throw; + } + catch (CommandFailedException & exc) { + logIntern( Any(exc) ); + throw; + } + catch (CommandAbortedException & exc) { + logIntern( Any(exc) ); + throw; + } + catch (deployment::DeploymentException & exc) { + logIntern( Any(exc) ); + throw; + } + catch (Exception &) { + Any exc( ::cppu::getCaughtException() ); + logIntern( exc ); + throw deployment::DeploymentException( + getResourceString(RID_STR_ERROR_WHILE_ADDING) + url, + static_cast<OWeakObject *>(this), exc ); + } +} +void PackageManagerImpl::deletePackageFromCache( + Reference<deployment::XPackage> const & xPackage, + OUString const & destFolder) +{ + try_dispose( xPackage ); + + //we remove the package from the uno cache + //no service from the package may be loaded at this time!!! + erase_path( destFolder, Reference<XCommandEnvironment>(), + false /* no throw: ignore errors */ ); + //rm last character '_' + OUString url = destFolder.copy(0, destFolder.getLength() - 1); + erase_path( url, Reference<XCommandEnvironment>(), + false /* no throw: ignore errors */ ); + +} +//______________________________________________________________________________ +void PackageManagerImpl::removePackage( + OUString const & id, ::rtl::OUString const & fileName, + Reference<task::XAbortChannel> const & /*xAbortChannel*/, + Reference<XCommandEnvironment> const & xCmdEnv_ ) + throw (deployment::DeploymentException, CommandFailedException, + CommandAbortedException, lang::IllegalArgumentException, + RuntimeException) +{ + check(); + + Reference<XCommandEnvironment> xCmdEnv; + if (m_xLogFile.is()) + xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) ); + else + xCmdEnv.set( xCmdEnv_ ); + + try { + Reference<deployment::XPackage> xPackage; + { + const ::osl::MutexGuard guard(getMutex()); + //Check if this extension exist and throw an IllegalArgumentException + //if it does not + //If the files of the extension are already removed, or there is a + //different extension at the same place, for example after updating the + //extension, then the returned object is that which uses the database data. + xPackage = getDeployedPackage_(id, fileName, xCmdEnv ); + + + //Because the extension is only removed the next time the extension + //manager runs after restarting OOo, we need to indicate that a + //shared extension was "deleted". When a user starts OOo, then it + //will check if something changed in the shared repository. Based on + //the flag file it will then recognize, that the extension was + //deleted and can then update the extnesion database of the shared + //extensions in the user installation. + if ( xPackage.is() && !m_readOnly && !xPackage->isRemoved() && m_context.equals(OUSTR("shared"))) + { + ActivePackages::Data val; + m_activePackagesDB->get( & val, id, fileName); + OSL_ASSERT(val.temporaryName.getLength()); + OUString url(makeURL(m_activePackages_expanded, + val.temporaryName + OUSTR("removed"))); + ::ucbhelper::Content contentRemoved(url, xCmdEnv ); + OUString aUserName; + ::osl::Security aSecurity; + aSecurity.getUserName( aUserName ); + + ::rtl::OString stamp = ::rtl::OUStringToOString(aUserName, RTL_TEXTENCODING_UTF8); + Reference<css::io::XInputStream> xData( + ::xmlscript::createInputStream( + ::rtl::ByteSequence( + reinterpret_cast<sal_Int8 const *>(stamp.getStr()), + stamp.getLength() ) ) ); + contentRemoved.writeStream( xData, true /* replace existing */ ); + } + m_activePackagesDB->erase( id, fileName ); // to be removed upon next start + } + try_dispose( xPackage ); + + fireModified(); + } + catch (RuntimeException &) { + throw; + } + catch (lang::IllegalArgumentException &) { + throw; + } + catch (CommandFailedException & exc) { + logIntern( Any(exc) ); + throw; + } + catch (CommandAbortedException & exc) { + logIntern( Any(exc) ); + throw; + } + catch (deployment::DeploymentException & exc) { + logIntern( Any(exc) ); + throw; + } + catch (Exception &) { + Any exc( ::cppu::getCaughtException() ); + logIntern( exc ); + throw deployment::DeploymentException( + getResourceString(RID_STR_ERROR_WHILE_REMOVING) + id, + static_cast<OWeakObject *>(this), exc ); + } +} + +//______________________________________________________________________________ +OUString PackageManagerImpl::getDeployPath( ActivePackages::Data const & data ) +{ + ::rtl::OUStringBuffer buf; + buf.append( data.temporaryName ); + //The bundled extensions are not contained in an additional folder + //with a unique name. data.temporaryName contains already the + //UTF8 encoded folder name. See PackageManagerImpl::synchronize + if (!m_context.equals(OUSTR("bundled"))) + { + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("_/") ); + buf.append( ::rtl::Uri::encode( data.fileName, rtl_UriCharClassPchar, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ) ); + } + return makeURL( m_activePackages, buf.makeStringAndClear() ); +} + +//______________________________________________________________________________ +Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage_( + OUString const & id, OUString const & fileName, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + ActivePackages::Data val; + if (m_activePackagesDB->get( &val, id, fileName )) + { + return getDeployedPackage_( id, val, xCmdEnv, false ); + } + throw lang::IllegalArgumentException( + getResourceString(RID_STR_NO_SUCH_PACKAGE) + id, + static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) ); +} + +//______________________________________________________________________________ +Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage_( + OUString const & id, ActivePackages::Data const & data, + Reference<XCommandEnvironment> const & xCmdEnv, bool ignoreAlienPlatforms ) +{ + if (ignoreAlienPlatforms) + { + String type, subType; + INetContentTypeParameterList params; + if (INetContentTypes::parse( data.mediaType, type, subType, ¶ms )) + { + INetContentTypeParameter const * param = params.find( + ByteString("platform") ); + if (param != 0 && !platform_fits( param->m_sValue )) + throw lang::IllegalArgumentException( + getResourceString(RID_STR_NO_SUCH_PACKAGE) + id, + static_cast<OWeakObject *>(this), + static_cast<sal_Int16>(-1) ); + } + } + Reference<deployment::XPackage> xExtension; + try + { + //Ignore extensions where XPackage::checkPrerequisites failed. + //They must not be usable for this user. + if (data.failedPrerequisites.equals(OUSTR("0"))) + { + xExtension = m_xRegistry->bindPackage( + getDeployPath( data ), data.mediaType, false, OUString(), xCmdEnv ); + } + } + catch (deployment::InvalidRemovedParameterException& e) + { + xExtension = e.Extension; + } + return xExtension; +} + +//______________________________________________________________________________ +Sequence< Reference<deployment::XPackage> > +PackageManagerImpl::getDeployedPackages_( + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + ::std::vector< Reference<deployment::XPackage> > packages; + ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() ); + ActivePackages::Entries::const_iterator iPos( id2temp.begin() ); + ActivePackages::Entries::const_iterator const iEnd( id2temp.end() ); + for ( ; iPos != iEnd; ++iPos ) + { + if (! iPos->second.failedPrerequisites.equals(OUSTR("0"))) + continue; + try { + packages.push_back( + getDeployedPackage_( + iPos->first, iPos->second, xCmdEnv, + true /* xxx todo: think of GUI: + ignore other platforms than the current one */ ) ); + } + catch (lang::IllegalArgumentException & exc) { + // ignore + (void) exc; // avoid warnings + OSL_ENSURE( 0, ::rtl::OUStringToOString( + exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); + } + catch (deployment::DeploymentException& exc) { + // ignore + (void) exc; // avoid warnings + OSL_ENSURE( 0, ::rtl::OUStringToOString( + exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); + } + } + return comphelper::containerToSequence(packages); +} + +//______________________________________________________________________________ +Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage( + OUString const & id, ::rtl::OUString const & fileName, + Reference<XCommandEnvironment> const & xCmdEnv_ ) + throw (deployment::DeploymentException, CommandFailedException, + lang::IllegalArgumentException, RuntimeException) +{ + check(); + Reference<XCommandEnvironment> xCmdEnv; + if (m_xLogFile.is()) + xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) ); + else + xCmdEnv.set( xCmdEnv_ ); + + try { + const ::osl::MutexGuard guard( getMutex() ); + return getDeployedPackage_( id, fileName, xCmdEnv ); + } + catch (RuntimeException &) { + throw; + } + catch (CommandFailedException & exc) { + logIntern( Any(exc) ); + throw; + } + catch (lang::IllegalArgumentException & exc) { + logIntern( Any(exc) ); + throw; + } + catch (deployment::DeploymentException & exc) { + logIntern( Any(exc) ); + throw; + } + catch (Exception &) { + Any exc( ::cppu::getCaughtException() ); + logIntern( exc ); + throw deployment::DeploymentException( + // ought never occur... + OUSTR("error while accessing deployed package: ") + id, + static_cast<OWeakObject *>(this), exc ); + } +} + +//______________________________________________________________________________ +Sequence< Reference<deployment::XPackage> > +PackageManagerImpl::getDeployedPackages( + Reference<task::XAbortChannel> const &, + Reference<XCommandEnvironment> const & xCmdEnv_ ) + throw (deployment::DeploymentException, CommandFailedException, + CommandAbortedException, lang::IllegalArgumentException, + RuntimeException) +{ + check(); + Reference<XCommandEnvironment> xCmdEnv; + if (m_xLogFile.is()) + xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) ); + else + xCmdEnv.set( xCmdEnv_ ); + + try { + const ::osl::MutexGuard guard( getMutex() ); + return getDeployedPackages_( xCmdEnv ); + } + catch (RuntimeException &) { + throw; + } + catch (CommandFailedException & exc) { + logIntern( Any(exc) ); + throw; + } + catch (CommandAbortedException & exc) { + logIntern( Any(exc) ); + throw; + } + catch (deployment::DeploymentException & exc) { + logIntern( Any(exc) ); + throw; + } + catch (Exception &) { + Any exc( ::cppu::getCaughtException() ); + logIntern( exc ); + throw deployment::DeploymentException( + // ought never occur... + OUSTR("error while getting all deployed packages: ") + m_context, + static_cast<OWeakObject *>(this), exc ); + } +} + +//______________________________________________________________________________ + + +//ToDo: the function must not call registerPackage, do this in +//XExtensionManager.reinstallDeployedExtensions +void PackageManagerImpl::reinstallDeployedPackages( + Reference<task::XAbortChannel> const & /*xAbortChannel*/, + Reference<XCommandEnvironment> const & xCmdEnv_ ) + throw (deployment::DeploymentException, + CommandFailedException, CommandAbortedException, + lang::IllegalArgumentException, RuntimeException) +{ + check(); + if (office_is_running()) + throw RuntimeException( + OUSTR("You must close any running Office process before " + "reinstalling packages!"), static_cast<OWeakObject *>(this) ); + + Reference<XCommandEnvironment> xCmdEnv; + if (m_xLogFile.is()) + xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) ); + else + xCmdEnv.set( xCmdEnv_ ); + + try { + ProgressLevel progress( + xCmdEnv, OUSTR("Reinstalling all deployed packages...") ); + + try_dispose( m_xRegistry ); + m_xRegistry.clear(); + if (m_registryCache.getLength() > 0) + erase_path( m_registryCache, xCmdEnv ); + initRegistryBackends(); + Reference<util::XUpdatable> xUpdatable( m_xRegistry, UNO_QUERY ); + if (xUpdatable.is()) + xUpdatable->update(); + + //registering is done by the ExtensionManager service. + } + catch (RuntimeException &) { + throw; + } + catch (CommandFailedException & exc) { + logIntern( Any(exc) ); + throw; + } + catch (CommandAbortedException & exc) { + logIntern( Any(exc) ); + throw; + } + catch (deployment::DeploymentException & exc) { + logIntern( Any(exc) ); + throw; + } + catch (Exception &) { + Any exc( ::cppu::getCaughtException() ); + logIntern( exc ); + throw deployment::DeploymentException( + OUSTR("Error while reinstalling all previously deployed " + "packages of context ") + m_context, + static_cast<OWeakObject *>(this), exc ); + } +} + + +::sal_Bool SAL_CALL PackageManagerImpl::isReadOnly( ) + throw (::com::sun::star::uno::RuntimeException) +{ + return m_readOnly; +} +bool PackageManagerImpl::synchronizeRemovedExtensions( + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<css::ucb::XCommandEnvironment> const & xCmdEnv) +{ + + //find all which are in the extension data base but which + //are removed already. + OSL_ASSERT(!m_context.equals(OUSTR("user"))); + bool bModified = false; + ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() ); + + typedef ActivePackages::Entries::const_iterator ITActive; + bool bShared = m_context.equals(OUSTR("shared")); + + for (ITActive i = id2temp.begin(); i != id2temp.end(); ++i) + { + try + { + //Get the URL to the extensions folder, first make the url for the + //shared repository including the temporary name + OUString url = makeURL(m_activePackages, i->second.temporaryName); + if (bShared) + url = makeURLAppendSysPathSegment( url + OUSTR("_"), i->second.fileName); + + bool bRemoved = false; + //Check if the URL to the extension is still the same + ::ucbhelper::Content contentExtension; + + if (!create_ucb_content( + &contentExtension, url, + Reference<XCommandEnvironment>(), false)) + { + bRemoved = true; + } + + //The folder is in the extension database, but it can still be deleted. + //look for the xxx.tmpremoved file + //There can also be the case that a different extension was installed + //in a "temp" folder with name that is already used. + if (!bRemoved && bShared) + { + ::ucbhelper::Content contentRemoved; + + if (create_ucb_content( + &contentRemoved, + m_activePackages_expanded + OUSTR("/") + + i->second.temporaryName + OUSTR("removed"), + Reference<XCommandEnvironment>(), false)) + { + bRemoved = true; + } + } + + if (!bRemoved) + { + //There may be another extensions at the same place + dp_misc::DescriptionInfoset infoset = + dp_misc::getDescriptionInfoset(url); + OSL_ENSURE(infoset.hasDescription() && infoset.getIdentifier(), + "Extension Manager: bundled and shared extensions " + "must have an identifer and a version"); + if (infoset.hasDescription() && + infoset.getIdentifier() && + (! i->first.equals(*(infoset.getIdentifier())) + || ! i->second.version.equals(infoset.getVersion()))) + { + bRemoved = true; + } + + } + if (bRemoved) + { + Reference<deployment::XPackage> xPackage = m_xRegistry->bindPackage( + url, i->second.mediaType, true, i->first, xCmdEnv ); + OSL_ASSERT(xPackage.is()); //Even if the files are removed, we must get the object. + xPackage->revokePackage(xAbortChannel, xCmdEnv); + removePackage(xPackage->getIdentifier().Value, xPackage->getName(), + xAbortChannel, xCmdEnv); + bModified |= true; + } + } + catch( uno::Exception & ) + { + OSL_ASSERT(0); + } + } + return bModified; +} + + +bool PackageManagerImpl::synchronizeAddedExtensions( + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<css::ucb::XCommandEnvironment> const & xCmdEnv) +{ + bool bModified = false; + ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() ); + //check if the folder exist at all. The shared extension folder + //may not exist for a normal user. + if (!create_ucb_content( + NULL, m_activePackages_expanded, Reference<css::ucb::XCommandEnvironment>(), false)) + return bModified; + ::ucbhelper::Content tempFolder( + m_activePackages_expanded, xCmdEnv ); + + Reference<sdbc::XResultSet> xResultSet( + tempFolder.createCursor( + Sequence<OUString>( &StrTitle::get(), 1 ), + ::ucbhelper::INCLUDE_FOLDERS_ONLY ) ); + + while (xResultSet->next()) + { + try + { + OUString title( + Reference<sdbc::XRow>( + xResultSet, UNO_QUERY_THROW )->getString( + 1 /* Title */ ) ); + //The temporary folders of user and shared have an '_' at then end. + //But the name in ActivePackages.temporaryName is saved without. + OUString title2 = title; + bool bNotBundled = !m_context.equals(OUSTR("bundled")); + if (bNotBundled) + { + OSL_ASSERT(title2[title2.getLength() -1] == '_'); + title2 = title2.copy(0, title2.getLength() -1); + } + OUString titleEncoded = ::rtl::Uri::encode( + title2, rtl_UriCharClassPchar, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8); + + //It it sufficient to check for the folder name, because when the administor + //installed the extension it was already checked if there is one with the + //same identifier. + const MatchTempDir match(titleEncoded); + if (::std::find_if( id2temp.begin(), id2temp.end(), match ) == + id2temp.end()) + { + + // The folder was not found in the data base, so it must be + // an added extension + OUString url(m_activePackages_expanded + OUSTR("/") + titleEncoded); + OUString sExtFolder; + if (bNotBundled) //that is, shared + { + //Check if the extension was not "deleted" already which is indicated + //by a xxx.tmpremoved file + ::ucbhelper::Content contentRemoved; + if (create_ucb_content(&contentRemoved, url + OUSTR("removed"), + Reference<XCommandEnvironment>(), false)) + continue; + sExtFolder = getExtensionFolder( + m_activePackages_expanded + + OUString(OUSTR("/")) + titleEncoded + OUSTR("_"), xCmdEnv); + url = makeURLAppendSysPathSegment(m_activePackages_expanded, title); + url = makeURLAppendSysPathSegment(url, sExtFolder); + } + Reference<deployment::XPackage> xPackage = m_xRegistry->bindPackage( + url, OUString(), false, OUString(), xCmdEnv ); + if (xPackage.is()) + { + //Prepare the database entry + ActivePackages::Data dbData; + + dbData.temporaryName = titleEncoded; + if (bNotBundled) + dbData.fileName = sExtFolder; + else + dbData.fileName = title; + dbData.mediaType = xPackage->getPackageType()->getMediaType(); + dbData.version = xPackage->getVersion(); + OSL_ENSURE(dbData.version.getLength() > 0, + "Extension Manager: bundled and shared extensions must have " + "an identifier and a version"); + + OUString id = dp_misc::getIdentifier( xPackage ); + + //We provide a special command environment that will prevent + //showing a license if simple-licens/@accept-by = "admin" + //It will also prevent showing the license for bundled extensions + //which is not supported. + OSL_ASSERT(!m_context.equals(OUSTR("user"))); + + // shall the license be suppressed? + DescriptionInfoset info = + dp_misc::getDescriptionInfoset(url); + ::boost::optional<dp_misc::SimpleLicenseAttributes> + attr = info.getSimpleLicenseAttributes(); + ExtensionProperties props(url,xCmdEnv); + bool bNoLicense = false; + if (attr && attr->suppressIfRequired && props.isSuppressedLicense()) + bNoLicense = true; + + Reference<ucb::XCommandEnvironment> licCmdEnv( + new LicenseCommandEnv(xCmdEnv->getInteractionHandler(), + bNoLicense, m_context)); + sal_Int32 failedPrereq = xPackage->checkPrerequisites( + xAbortChannel, licCmdEnv, false); + //Remember that this failed. For example, the user + //could have declined the license. Then the next time the + //extension folder is investigated we do not want to + //try to install the extension again. + dbData.failedPrerequisites = OUString::valueOf(failedPrereq); + insertToActivationLayerDB(id, dbData); + bModified |= true; + } + } + } + catch (uno::Exception &) + { + OSL_ASSERT(0); + } + } + return bModified; +} + +sal_Bool PackageManagerImpl::synchronize( + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<css::ucb::XCommandEnvironment> const & xCmdEnv) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::uno::RuntimeException) +{ + check(); + bool bModified = false; + if (m_context.equals(OUSTR("user"))) + return bModified; + bModified |= + synchronizeRemovedExtensions(xAbortChannel, xCmdEnv); + bModified |= synchronizeAddedExtensions(xAbortChannel, xCmdEnv); + + return bModified; +} + +Sequence< Reference<deployment::XPackage> > PackageManagerImpl::getExtensionsWithUnacceptedLicenses( + Reference<ucb::XCommandEnvironment> const & xCmdEnv) + throw (deployment::DeploymentException, RuntimeException) +{ + ::std::vector<Reference<deployment::XPackage> > vec; + + try + { + const ::osl::MutexGuard guard( getMutex() ); + // clean up activation layer, scan for zombie temp dirs: + ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() ); + + ActivePackages::Entries::const_iterator i = id2temp.begin(); + bool bShared = m_context.equals(OUSTR("shared")); + + for (; i != id2temp.end(); ++i ) + { + //Get the database entry + ActivePackages::Data const & dbData = i->second; + sal_Int32 failedPrereq = dbData.failedPrerequisites.toInt32(); + //If the installation failed for other reason then the license then we + //ignore it. + if (failedPrereq ^= deployment::Prerequisites::LICENSE) + continue; + + //Prepare the URL to the extension + OUString url = makeURL(m_activePackages, i->second.temporaryName); + if (bShared) + url = makeURLAppendSysPathSegment( url + OUSTR("_"), i->second.fileName); + + Reference<deployment::XPackage> p = m_xRegistry->bindPackage( + url, OUString(), false, OUString(), xCmdEnv ); + + if (p.is()) + vec.push_back(p); + + } + return ::comphelper::containerToSequence(vec); + } + catch (deployment::DeploymentException &) + { + throw; + } + catch (RuntimeException&) + { + throw; + } + catch (...) + { + Any exc = ::cppu::getCaughtException(); + deployment::DeploymentException de( + OUSTR("PackageManagerImpl::getExtensionsWithUnacceptedLicenses"), + static_cast<OWeakObject*>(this), exc); + exc <<= de; + ::cppu::throwException(exc); + } + + return ::comphelper::containerToSequence(vec); +} + +sal_Int32 PackageManagerImpl::checkPrerequisites( + css::uno::Reference<css::deployment::XPackage> const & extension, + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::lang::IllegalArgumentException, + css::uno::RuntimeException) +{ + try + { + if (!extension.is()) + return 0; + if (!m_context.equals(extension->getRepositoryName())) + throw lang::IllegalArgumentException( + OUSTR("PackageManagerImpl::checkPrerequisites: extension is not" + " from this repository."), 0, 0); + + ActivePackages::Data dbData; + OUString id = dp_misc::getIdentifier(extension); + if (m_activePackagesDB->get( &dbData, id, OUString())) + { + //If the license was already displayed, then do not show it again + Reference<ucb::XCommandEnvironment> _xCmdEnv = xCmdEnv; + sal_Int32 prereq = dbData.failedPrerequisites.toInt32(); + if ( !(prereq & deployment::Prerequisites::LICENSE)) + _xCmdEnv = new NoLicenseCommandEnv(xCmdEnv->getInteractionHandler()); + + sal_Int32 failedPrereq = extension->checkPrerequisites( + xAbortChannel, _xCmdEnv, false); + dbData.failedPrerequisites = OUString::valueOf(failedPrereq); + insertToActivationLayerDB(id, dbData); + } + else + { + throw lang::IllegalArgumentException( + OUSTR("PackageManagerImpl::checkPrerequisites: unknown extension"), + 0, 0); + + } + return 0; + } + catch (deployment::DeploymentException& ) { + throw; + } catch (ucb::CommandFailedException & ) { + throw; + } catch (ucb::CommandAbortedException & ) { + throw; + } catch (lang::IllegalArgumentException &) { + throw; + } catch (uno::RuntimeException &) { + throw; + } catch (...) { + uno::Any excOccurred = ::cppu::getCaughtException(); + deployment::DeploymentException exc( + OUSTR("PackageManagerImpl::checkPrerequisites: exception "), + static_cast<OWeakObject*>(this), excOccurred); + throw exc; + } +} + +//############################################################################## + +//______________________________________________________________________________ +PackageManagerImpl::CmdEnvWrapperImpl::~CmdEnvWrapperImpl() +{ +} + +//______________________________________________________________________________ +PackageManagerImpl::CmdEnvWrapperImpl::CmdEnvWrapperImpl( + Reference<XCommandEnvironment> const & xUserCmdEnv, + Reference<XProgressHandler> const & xLogFile ) + : m_xLogFile( xLogFile ) +{ + if (xUserCmdEnv.is()) { + m_xUserProgress.set( xUserCmdEnv->getProgressHandler() ); + m_xUserInteractionHandler.set( xUserCmdEnv->getInteractionHandler() ); + } +} + +// XCommandEnvironment +//______________________________________________________________________________ +Reference<task::XInteractionHandler> +PackageManagerImpl::CmdEnvWrapperImpl::getInteractionHandler() + throw (RuntimeException) +{ + return m_xUserInteractionHandler; +} + +//______________________________________________________________________________ +Reference<XProgressHandler> +PackageManagerImpl::CmdEnvWrapperImpl::getProgressHandler() + throw (RuntimeException) +{ + return this; +} + +// XProgressHandler +//______________________________________________________________________________ +void PackageManagerImpl::CmdEnvWrapperImpl::push( Any const & Status ) + throw (RuntimeException) +{ + if (m_xLogFile.is()) + m_xLogFile->push( Status ); + if (m_xUserProgress.is()) + m_xUserProgress->push( Status ); +} + +//______________________________________________________________________________ +void PackageManagerImpl::CmdEnvWrapperImpl::update( Any const & Status ) + throw (RuntimeException) +{ + if (m_xLogFile.is()) + m_xLogFile->update( Status ); + if (m_xUserProgress.is()) + m_xUserProgress->update( Status ); +} + +//______________________________________________________________________________ +void PackageManagerImpl::CmdEnvWrapperImpl::pop() throw (RuntimeException) +{ + if (m_xLogFile.is()) + m_xLogFile->pop(); + if (m_xUserProgress.is()) + m_xUserProgress->pop(); +} + +} // namespace dp_manager + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/manager/dp_manager.h b/desktop/source/deployment/manager/dp_manager.h new file mode 100644 index 000000000000..3b335d7e2362 --- /dev/null +++ b/desktop/source/deployment/manager/dp_manager.h @@ -0,0 +1,296 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_MANAGER_H +#define INCLUDED_DP_MANAGER_H + +#include "dp_manager.hrc" +#include "dp_misc.h" +#include "dp_interact.h" +#include "dp_activepackages.hxx" +#include "rtl/ref.hxx" +#include "cppuhelper/compbase1.hxx" +#include "cppuhelper/implbase2.hxx" +#include "ucbhelper/content.hxx" +#include "com/sun/star/deployment/XPackageRegistry.hpp" +#include "com/sun/star/deployment/XPackageManager.hpp" +#include <memory> + + +namespace css = ::com::sun::star; + +namespace dp_manager { + +typedef ::cppu::WeakComponentImplHelper1< + css::deployment::XPackageManager > t_pm_helper; + +//============================================================================== +class PackageManagerImpl : private ::dp_misc::MutexHolder, public t_pm_helper +{ + css::uno::Reference<css::uno::XComponentContext> m_xComponentContext; + ::rtl::OUString m_context; + ::rtl::OUString m_registrationData; + ::rtl::OUString m_registrationData_expanded; + ::rtl::OUString m_registryCache; + bool m_readOnly; + + ::rtl::OUString m_activePackages; + ::rtl::OUString m_activePackages_expanded; + ::std::auto_ptr< ActivePackages > m_activePackagesDB; + //This mutex is only used for synchronization in addPackage + ::osl::Mutex m_addMutex; + css::uno::Reference<css::ucb::XProgressHandler> m_xLogFile; + inline void logIntern( css::uno::Any const & status ); + void fireModified(); + + css::uno::Reference<css::deployment::XPackageRegistry> m_xRegistry; + + void initRegistryBackends(); + void initActivationLayer( + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ); + ::rtl::OUString detectMediaType( + ::ucbhelper::Content const & ucbContent, bool throw_exc = true ); + ::rtl::OUString insertToActivationLayer( + css::uno::Sequence<css::beans::NamedValue> const & properties, + ::rtl::OUString const & mediaType, + ::ucbhelper::Content const & sourceContent, + ::rtl::OUString const & title, ActivePackages::Data * dbData ); + void insertToActivationLayerDB( + ::rtl::OUString const & id, ActivePackages::Data const & dbData ); + + void deletePackageFromCache( + css::uno::Reference<css::deployment::XPackage> const & xPackage, + ::rtl::OUString const & destFolder ); + + bool isInstalled( + css::uno::Reference<css::deployment::XPackage> const & package); + + bool synchronizeRemovedExtensions( + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv); + + bool synchronizeAddedExtensions( + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv); + + class CmdEnvWrapperImpl + : public ::cppu::WeakImplHelper2< css::ucb::XCommandEnvironment, + css::ucb::XProgressHandler > + { + css::uno::Reference<css::ucb::XProgressHandler> m_xLogFile; + css::uno::Reference<css::ucb::XProgressHandler> m_xUserProgress; + css::uno::Reference<css::task::XInteractionHandler> + m_xUserInteractionHandler; + + public: + virtual ~CmdEnvWrapperImpl(); + CmdEnvWrapperImpl( + css::uno::Reference<css::ucb::XCommandEnvironment> + const & xUserCmdEnv, + css::uno::Reference<css::ucb::XProgressHandler> const & xLogFile ); + + // XCommandEnvironment + virtual css::uno::Reference<css::task::XInteractionHandler> SAL_CALL + getInteractionHandler() throw (css::uno::RuntimeException); + virtual css::uno::Reference<css::ucb::XProgressHandler> SAL_CALL + getProgressHandler() throw (css::uno::RuntimeException); + + // XProgressHandler + virtual void SAL_CALL push( css::uno::Any const & Status ) + throw (css::uno::RuntimeException); + virtual void SAL_CALL update( css::uno::Any const & Status ) + throw (css::uno::RuntimeException); + virtual void SAL_CALL pop() throw (css::uno::RuntimeException); + }; + +protected: + inline void check(); + virtual void SAL_CALL disposing(); + + virtual ~PackageManagerImpl(); + inline PackageManagerImpl( + css::uno::Reference<css::uno::XComponentContext> + const & xComponentContext, ::rtl::OUString const & context ) + : t_pm_helper( getMutex() ), + m_xComponentContext( xComponentContext ), + m_context( context ), + m_readOnly( true ) + {} + +public: + static css::uno::Reference<css::deployment::XPackageManager> create( + css::uno::Reference<css::uno::XComponentContext> + const & xComponentContext, ::rtl::OUString const & context ); + + // XComponent + virtual void SAL_CALL dispose() throw (css::uno::RuntimeException); + virtual void SAL_CALL addEventListener( + css::uno::Reference<css::lang::XEventListener> const & xListener ) + throw (css::uno::RuntimeException); + virtual void SAL_CALL removeEventListener( + css::uno::Reference<css::lang::XEventListener> const & xListener ) + throw (css::uno::RuntimeException); + + // XModifyBroadcaster + virtual void SAL_CALL addModifyListener( + css::uno::Reference<css::util::XModifyListener> const & xListener ) + throw (css::uno::RuntimeException); + virtual void SAL_CALL removeModifyListener( + css::uno::Reference<css::util::XModifyListener> const & xListener ) + throw (css::uno::RuntimeException); + + // XPackageManager + virtual ::rtl::OUString SAL_CALL getContext() + throw (css::uno::RuntimeException); + virtual css::uno::Sequence< + css::uno::Reference<css::deployment::XPackageTypeInfo> > SAL_CALL + getSupportedPackageTypes() throw (css::uno::RuntimeException); + + virtual css::uno::Reference<css::task::XAbortChannel> SAL_CALL + createAbortChannel() throw (css::uno::RuntimeException); + + virtual css::uno::Reference<css::deployment::XPackage> SAL_CALL addPackage( + ::rtl::OUString const & url, + css::uno::Sequence<css::beans::NamedValue> const & properties, + ::rtl::OUString const & mediaType, + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::lang::IllegalArgumentException, + css::uno::RuntimeException); + + virtual css::uno::Reference<css::deployment::XPackage> SAL_CALL importExtension( + css::uno::Reference<css::deployment::XPackage> const & extension, + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::lang::IllegalArgumentException, + css::uno::RuntimeException); + + virtual void SAL_CALL removePackage( + ::rtl::OUString const & id, ::rtl::OUString const & fileName, + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::lang::IllegalArgumentException, + css::uno::RuntimeException); + + ::rtl::OUString getDeployPath( ActivePackages::Data const & data ); + css::uno::Reference<css::deployment::XPackage> SAL_CALL getDeployedPackage_( + ::rtl::OUString const & id, ::rtl::OUString const & fileName, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ); + css::uno::Reference<css::deployment::XPackage> getDeployedPackage_( + ::rtl::OUString const & id, ActivePackages::Data const & data, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv, + bool ignoreAlienPlatforms = false ); + virtual css::uno::Reference<css::deployment::XPackage> SAL_CALL + getDeployedPackage( + ::rtl::OUString const & id, ::rtl::OUString const & fileName, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::lang::IllegalArgumentException, css::uno::RuntimeException); + + css::uno::Sequence< css::uno::Reference<css::deployment::XPackage> > + getDeployedPackages_( + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ); + virtual css::uno::Sequence< css::uno::Reference<css::deployment::XPackage> > + SAL_CALL getDeployedPackages( + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::lang::IllegalArgumentException, + css::uno::RuntimeException); + + virtual void SAL_CALL reinstallDeployedPackages( + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::lang::IllegalArgumentException, + css::uno::RuntimeException); + + virtual ::sal_Bool SAL_CALL isReadOnly( ) + throw (::com::sun::star::uno::RuntimeException); + + virtual ::sal_Bool SAL_CALL synchronize( + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::uno::RuntimeException); + + virtual css::uno::Sequence<css::uno::Reference<css::deployment::XPackage> > SAL_CALL + getExtensionsWithUnacceptedLicenses( + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv) + throw (css::deployment::DeploymentException, + css::uno::RuntimeException); + + virtual sal_Int32 SAL_CALL checkPrerequisites( + css::uno::Reference<css::deployment::XPackage> const & extension, + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::lang::IllegalArgumentException, + css::uno::RuntimeException); + }; + +//______________________________________________________________________________ +inline void PackageManagerImpl::check() +{ + ::osl::MutexGuard guard( getMutex() ); + if (rBHelper.bInDispose || rBHelper.bDisposed) + throw css::lang::DisposedException( + OUSTR("PackageManager instance has already been disposed!"), + static_cast< ::cppu::OWeakObject * >(this) ); +} + +//______________________________________________________________________________ +inline void PackageManagerImpl::logIntern( css::uno::Any const & status ) +{ + if (m_xLogFile.is()) + m_xLogFile->update( status ); +} + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/manager/dp_manager.hrc b/desktop/source/deployment/manager/dp_manager.hrc new file mode 100644 index 000000000000..6131cc381abf --- /dev/null +++ b/desktop/source/deployment/manager/dp_manager.hrc @@ -0,0 +1,39 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_MANAGER_HRC +#define INCLUDED_DP_MANAGER_HRC + +#include "deployment.hrc" + +#define RID_STR_ERROR_WHILE_ADDING (RID_DEPLOYMENT_MANAGER_START+0) +#define RID_STR_ERROR_WHILE_REMOVING (RID_DEPLOYMENT_MANAGER_START+1) +#define RID_STR_PACKAGE_ALREADY_ADDED (RID_DEPLOYMENT_MANAGER_START+2) +#define RID_STR_COPYING_PACKAGE (RID_DEPLOYMENT_MANAGER_START+3) +#define RID_STR_NO_SUCH_PACKAGE (RID_DEPLOYMENT_MANAGER_START+4) +#define RID_STR_SYNCHRONIZING_REPOSITORY (RID_DEPLOYMENT_MANAGER_START+5) +#endif diff --git a/desktop/source/deployment/manager/dp_manager.src b/desktop/source/deployment/manager/dp_manager.src new file mode 100644 index 000000000000..7d38b880c37a --- /dev/null +++ b/desktop/source/deployment/manager/dp_manager.src @@ -0,0 +1,59 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "dp_manager.hrc" + + +String RID_STR_COPYING_PACKAGE +{ + Text [ en-US ] = "Copying: "; +}; + +String RID_STR_ERROR_WHILE_ADDING +{ + Text [ en-US ] = "Error while adding: "; +}; + +String RID_STR_ERROR_WHILE_REMOVING +{ + Text [ en-US ] = "Error while removing: "; +}; + +String RID_STR_PACKAGE_ALREADY_ADDED +{ + Text [ en-US ] = "Extension has already been added: "; +}; + +String RID_STR_NO_SUCH_PACKAGE +{ + Text [ en-US ] = "There is no such extension deployed: "; +}; + +String RID_STR_SYNCHRONIZING_REPOSITORY +{ + Text [ en-US ] = "Synchronizing repository for %NAME extensions"; +}; diff --git a/desktop/source/deployment/manager/dp_managerfac.cxx b/desktop/source/deployment/manager/dp_managerfac.cxx new file mode 100644 index 000000000000..55bd259a276d --- /dev/null +++ b/desktop/source/deployment/manager/dp_managerfac.cxx @@ -0,0 +1,202 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_manager.h" +#include "dp_resource.h" +#include "cppuhelper/compbase1.hxx" +#include "comphelper/servicedecl.hxx" +#include "com/sun/star/deployment/thePackageManagerFactory.hpp" + + +using namespace ::dp_misc; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using ::rtl::OUString; + +namespace dp_manager { +namespace factory { + +typedef ::cppu::WeakComponentImplHelper1< + deployment::XPackageManagerFactory > t_pmfac_helper; + +//============================================================================== +class PackageManagerFactoryImpl : private MutexHolder, public t_pmfac_helper +{ + Reference<XComponentContext> m_xComponentContext; + + Reference<deployment::XPackageManager> m_xUserMgr; + Reference<deployment::XPackageManager> m_xSharedMgr; + Reference<deployment::XPackageManager> m_xBundledMgr; + typedef ::std::hash_map< + OUString, WeakReference<deployment::XPackageManager>, + ::rtl::OUStringHash > t_string2weakref; + t_string2weakref m_managers; + +protected: + inline void check(); + virtual void SAL_CALL disposing(); + +public: + virtual ~PackageManagerFactoryImpl(); + PackageManagerFactoryImpl( + Reference<XComponentContext> const & xComponentContext ); + + // XPackageManagerFactory + virtual Reference<deployment::XPackageManager> SAL_CALL getPackageManager( + OUString const & context ) throw (RuntimeException); +}; + +//============================================================================== +namespace sdecl = comphelper::service_decl; +sdecl::class_<PackageManagerFactoryImpl> servicePMFI; +extern sdecl::ServiceDecl const serviceDecl( + servicePMFI, + // a private one: + "com.sun.star.comp.deployment.PackageManagerFactory", + "com.sun.star.comp.deployment.PackageManagerFactory" ); + +//============================================================================== +bool singleton_entries( + Reference<registry::XRegistryKey> const & xRegistryKey ) +{ + try { + Reference<registry::XRegistryKey> xKey( + xRegistryKey->createKey( + serviceDecl.getImplementationName() + + // xxx todo: use future generated function to get singleton name + OUSTR("/UNO/SINGLETONS/" + "com.sun.star.deployment.thePackageManagerFactory") ) ); + xKey->setStringValue( serviceDecl.getSupportedServiceNames()[0] ); + return true; + } + catch (registry::InvalidRegistryException & exc) { + (void) exc; // avoid warnings + OSL_ENSURE( 0, ::rtl::OUStringToOString( + exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); + return false; + } +} + +//______________________________________________________________________________ +PackageManagerFactoryImpl::PackageManagerFactoryImpl( + Reference<XComponentContext> const & xComponentContext ) + : t_pmfac_helper( getMutex() ), + m_xComponentContext( xComponentContext ) +{ +} + +//______________________________________________________________________________ +PackageManagerFactoryImpl::~PackageManagerFactoryImpl() +{ +} + +//______________________________________________________________________________ +inline void PackageManagerFactoryImpl::check() +{ + ::osl::MutexGuard guard( getMutex() ); + if (rBHelper.bInDispose || rBHelper.bDisposed) + { + throw lang::DisposedException( + OUSTR("PackageManagerFactory instance has already been disposed!"), + static_cast<OWeakObject *>(this) ); + } +} + +//______________________________________________________________________________ +void PackageManagerFactoryImpl::disposing() +{ + // dispose all managers: + ::osl::MutexGuard guard( getMutex() ); + t_string2weakref::const_iterator iPos( m_managers.begin() ); + t_string2weakref::const_iterator const iEnd( m_managers.end() ); + for ( ; iPos != iEnd; ++iPos ) + try_dispose( iPos->second ); + m_managers = t_string2weakref(); + // the below are already disposed: + m_xUserMgr.clear(); + m_xSharedMgr.clear(); + m_xBundledMgr.clear(); +} + +// XPackageManagerFactory +//______________________________________________________________________________ +Reference<deployment::XPackageManager> +PackageManagerFactoryImpl::getPackageManager( OUString const & context ) + throw (RuntimeException) +{ + Reference< deployment::XPackageManager > xRet; + ::osl::ResettableMutexGuard guard( getMutex() ); + check(); + t_string2weakref::const_iterator const iFind( m_managers.find( context ) ); + if (iFind != m_managers.end()) { + xRet = iFind->second; + if (xRet.is()) + return xRet; + } + + guard.clear(); + xRet.set( PackageManagerImpl::create( m_xComponentContext, context ) ); + guard.reset(); + ::std::pair< t_string2weakref::iterator, bool > insertion( + m_managers.insert( t_string2weakref::value_type( context, xRet ) ) ); + if (insertion.second) + { + OSL_ASSERT( insertion.first->second.get() == xRet ); + // hold user, shared mgrs for whole process: live deployment + if (context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("user") )) + m_xUserMgr = xRet; + else if (context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("shared") )) + m_xSharedMgr = xRet; + else if (context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("bundled") )) + m_xBundledMgr = xRet; + } + else + { + Reference< deployment::XPackageManager > xAlreadyIn( + insertion.first->second ); + if (xAlreadyIn.is()) + { + guard.clear(); + try_dispose( xRet ); + xRet = xAlreadyIn; + } + else + { + insertion.first->second = xRet; + } + } + return xRet; +} + +} // namespace factory +} // namespace dp_manager + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/manager/dp_properties.cxx b/desktop/source/deployment/manager/dp_properties.cxx new file mode 100644 index 000000000000..a2a568287f16 --- /dev/null +++ b/desktop/source/deployment/manager/dp_properties.cxx @@ -0,0 +1,171 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "com/sun/star/ucb/XCommandEnvironment.hpp" +#include "com/sun/star/lang/IllegalArgumentException.hpp" +#include "xmlscript/xml_helper.hxx" +#include "ucbhelper/content.hxx" +#include <list> + +#include "dp_ucb.h" +#include "rtl/ustrbuf.hxx" +#include "dp_properties.hxx" + +namespace lang = com::sun::star::lang; +namespace task = com::sun::star::task; +namespace ucb = com::sun::star::ucb; +namespace uno = com::sun::star::uno; +namespace css = com::sun::star; + +#define OUSTR(s) rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s)) + +using ::com::sun::star::uno::Reference; +using ::rtl::OUString; + +#define PROP_SUPPRESS_LICENSE "SUPPRESS_LICENSE" +#define PROP_EXTENSION_UPDATE "EXTENSION_UPDATE" + +namespace dp_manager { + +//Reading the file +ExtensionProperties::ExtensionProperties( + OUString const & urlExtension, + Reference<ucb::XCommandEnvironment> const & xCmdEnv) : + m_xCmdEnv(xCmdEnv) +{ + m_propFileUrl = urlExtension + OUSTR("properties"); + + ::std::list< ::std::pair< OUString, OUString> > props; + if (! dp_misc::create_ucb_content(NULL, m_propFileUrl, 0, false)) + return; + + ::ucbhelper::Content contentProps(m_propFileUrl, m_xCmdEnv); + dp_misc::readProperties(props, contentProps); + + typedef ::std::list< ::std::pair< OUString, OUString> >::const_iterator CI; + for (CI i = props.begin(); i != props.end(); i++) + { + if (i->first.equals(OUSTR(PROP_SUPPRESS_LICENSE))) + m_prop_suppress_license = i->second; + } +} + +//Writing the file +ExtensionProperties::ExtensionProperties( + OUString const & urlExtension, + uno::Sequence<css::beans::NamedValue> const & properties, + Reference<ucb::XCommandEnvironment> const & xCmdEnv) : + m_xCmdEnv(xCmdEnv) +{ + m_propFileUrl = urlExtension + OUSTR("properties"); + + for (sal_Int32 i = 0; i < properties.getLength(); i++) + { + css::beans::NamedValue const & v = properties[i]; + if (v.Name.equals(OUSTR(PROP_SUPPRESS_LICENSE))) + { + m_prop_suppress_license = getPropertyValue(v); + } + else if (v.Name.equals(OUSTR(PROP_EXTENSION_UPDATE))) + { + m_prop_extension_update = getPropertyValue(v); + } + else + { + throw lang::IllegalArgumentException( + OUSTR("Extension Manager: unknown property"), 0, -1); + } + } +} + +OUString ExtensionProperties::getPropertyValue(css::beans::NamedValue const & v) +{ + OUString value(OUSTR("0")); + if (v.Value >>= value) + { + if (value.equals(OUSTR("1"))) + value = OUSTR("1"); + } + else + { + throw lang::IllegalArgumentException( + OUSTR("Extension Manager: wrong property value"), 0, -1); + } + return value; +} +void ExtensionProperties::write() +{ + ::ucbhelper::Content contentProps(m_propFileUrl, m_xCmdEnv); + ::rtl::OUStringBuffer buf; + + if (m_prop_suppress_license) + { + buf.append(OUSTR(PROP_SUPPRESS_LICENSE)); + buf.append(OUSTR("=")); + buf.append(*m_prop_suppress_license); + } + + ::rtl::OString stamp = ::rtl::OUStringToOString( + buf.makeStringAndClear(), RTL_TEXTENCODING_UTF8); + Reference<css::io::XInputStream> xData( + ::xmlscript::createInputStream( + ::rtl::ByteSequence( + reinterpret_cast<sal_Int8 const *>(stamp.getStr()), + stamp.getLength() ) ) ); + contentProps.writeStream( xData, true /* replace existing */ ); +} + +bool ExtensionProperties::isSuppressedLicense() +{ + bool ret = false; + if (m_prop_suppress_license) + { + if (m_prop_suppress_license->equals(OUSTR("1"))) + ret = true; + } + return ret; +} + +bool ExtensionProperties::isExtensionUpdate() +{ + bool ret = false; + if (m_prop_extension_update) + { + if (m_prop_extension_update->equals(OUSTR("1"))) + ret = true; + } + return ret; +} + +} // namespace dp_manager + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/manager/dp_properties.hxx b/desktop/source/deployment/manager/dp_properties.hxx new file mode 100644 index 000000000000..103227f29226 --- /dev/null +++ b/desktop/source/deployment/manager/dp_properties.hxx @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_PROPERTIES_HXX +#define INCLUDED_DP_PROPERTIES_HXX + + + +#include "com/sun/star/beans/NamedValue.hpp" +#include "com/sun/star/ucb/XCommandEnvironment.hpp" +#include "boost/optional.hpp" + + +namespace css = ::com::sun::star; + +namespace dp_manager { + + + +/** + + */ +class ExtensionProperties +{ +protected: + ::rtl::OUString m_propFileUrl; + const css::uno::Reference<css::ucb::XCommandEnvironment> m_xCmdEnv; + ::boost::optional< ::rtl::OUString> m_prop_suppress_license; + ::boost::optional< ::rtl::OUString> m_prop_extension_update; + + ::rtl::OUString getPropertyValue(css::beans::NamedValue const & v); +public: + + virtual ~ExtensionProperties() {}; + ExtensionProperties(::rtl::OUString const & urlExtension, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv); + + ExtensionProperties(::rtl::OUString const & urlExtension, + css::uno::Sequence<css::beans::NamedValue> const & properties, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv); + + void write(); + + bool isSuppressedLicense(); + + bool isExtensionUpdate(); +}; +} + + + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/manager/makefile.mk b/desktop/source/deployment/manager/makefile.mk new file mode 100644 index 000000000000..4dc6405e34bf --- /dev/null +++ b/desktop/source/deployment/manager/makefile.mk @@ -0,0 +1,55 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/.. + +PRJNAME = desktop +TARGET = deployment_manager +ENABLE_EXCEPTIONS = TRUE + +.INCLUDE : settings.mk + +.IF "$(SYSTEM_DB)" == "YES" +CFLAGS+=-DSYSTEM_DB -I$(DB_INCLUDES) +.ENDIF + +SRS1NAME = $(TARGET) +SRC1FILES = \ + dp_manager.src + +SLOFILES = \ + $(SLO)$/dp_activepackages.obj \ + $(SLO)$/dp_manager.obj \ + $(SLO)$/dp_managerfac.obj \ + $(SLO)$/dp_informationprovider.obj \ + $(SLO)$/dp_extensionmanager.obj \ + $(SLO)$/dp_commandenvironments.obj \ + $(SLO)$/dp_properties.obj + +.INCLUDE : ..$/target.pmk +.INCLUDE : target.mk + diff --git a/desktop/source/deployment/misc/db.cxx b/desktop/source/deployment/misc/db.cxx new file mode 100644 index 000000000000..6ba2c25bc92c --- /dev/null +++ b/desktop/source/deployment/misc/db.cxx @@ -0,0 +1,274 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include <db.hxx> + +#include <rtl/alloc.h> +#include <cstring> +#include <errno.h> + +namespace berkeleydbproxy { + +//---------------------------------------------------------------------------- + namespace db_internal + { + static void raise_error(int dberr, const char * where); + + static inline int check_error(int dberr, const char * where) + { + if (dberr) raise_error(dberr,where); + return dberr; + } + } + +//---------------------------------------------------------------------------- + +char *DbEnv::strerror(int error) { + return (db_strerror(error)); +} + +//---------------------------------------------------------------------------- + +Db::Db(DbEnv* pDbenv,u_int32_t flags) +: m_pDBP(0) +{ + db_internal::check_error( db_create(&m_pDBP,pDbenv ? pDbenv->m_pDBENV:0,flags),"Db::Db" ); +} + + +Db::~Db() +{ + if (m_pDBP) + { + // should not happen + // TODO: add assert + } + +} + + +int Db::close(u_int32_t flags) +{ + int error = m_pDBP->close(m_pDBP,flags); + m_pDBP = 0; + return db_internal::check_error(error,"Db::close"); +} + +int Db::open(DB_TXN *txnid, + const char *file, + const char *database, + DBTYPE type, + u_int32_t flags, + int mode) +{ + int err = m_pDBP->open(m_pDBP,txnid,file,database,type,flags,mode); + return db_internal::check_error( err,"Db::open" ); +} + + +int Db::get(DB_TXN *txnid, Dbt *key, Dbt *data, u_int32_t flags) +{ + int err = m_pDBP->get(m_pDBP,txnid,key,data,flags); + + // these are non-exceptional outcomes + if (err != DB_NOTFOUND && err != DB_KEYEMPTY) + db_internal::check_error( err,"Db::get" ); + + return err; +} + +int Db::put(DB_TXN* txnid, Dbt *key, Dbt *data, u_int32_t flags) +{ + int err = m_pDBP->put(m_pDBP,txnid,key,data,flags); + + if (err != DB_KEYEXIST) // this is a non-exceptional outcome + db_internal::check_error( err,"Db::put" ); + return err; +} + +int Db::cursor(DB_TXN *txnid, Dbc **cursorp, u_int32_t flags) +{ + DBC * dbc = 0; + int error = m_pDBP->cursor(m_pDBP,txnid,&dbc,flags); + + if (!db_internal::check_error(error,"Db::cursor")) + *cursorp = new Dbc(dbc); + + return error; +} + + +#define DB_INCOMPLETE (-30999)/* Sync didn't finish. */ + +int Db::sync(u_int32_t flags) +{ + int err; + DB *db = m_pDBP; + + if (!db) { + db_internal::check_error(EINVAL,"Db::sync"); + return (EINVAL); + } + if ((err = db->sync(db, flags)) != 0 && err != DB_INCOMPLETE) { + db_internal::check_error(err, "Db::sync"); + return (err); + } + return (err); +} + +int Db::del(Dbt *key, u_int32_t flags) +{ + DB *db = m_pDBP; + int err; + + if ((err = db->del(db, 0, key, flags)) != 0) { + // DB_NOTFOUND is a "normal" return, so should not be + // thrown as an error + // + if (err != DB_NOTFOUND) { + db_internal::check_error(err, "Db::del"); + return (err); + } + } + return (err); +} + +//---------------------------------------------------------------------------- + +Dbc::Dbc(DBC * dbc) +: m_pDBC(dbc) +{ +} + +Dbc::~Dbc() +{ +} + +int Dbc::close() +{ + int err = m_pDBC->c_close(m_pDBC); + delete this; + return db_internal::check_error( err,"Dbcursor::close" ); +} + +int Dbc::get(Dbt *key, Dbt *data, u_int32_t flags) +{ + int err = m_pDBC->c_get(m_pDBC,key,data,flags); + + // these are non-exceptional outcomes + if (err != DB_NOTFOUND && err != DB_KEYEMPTY) + db_internal::check_error( err, "Dbcursor::get" ); + + return err; +} + +//---------------------------------------------------------------------------- + +Dbt::Dbt() +{ + using namespace std; + DBT * thispod = this; + memset(thispod, 0, sizeof *thispod); +} + + +Dbt::Dbt(void *data_arg, u_int32_t size_arg) +{ + using namespace std; + DBT * thispod = this; + memset(thispod, 0, sizeof *thispod); + this->set_data(data_arg); + this->set_size(size_arg); +} + +Dbt::Dbt(const Dbt & other) +{ + using namespace std; + const DBT *otherpod = &other; + DBT *thispod = this; + memcpy(thispod, otherpod, sizeof *thispod); +} + +Dbt& Dbt::operator = (const Dbt & other) +{ + if (this != &other) + { + using namespace std; + const DBT *otherpod = &other; + DBT *thispod = this; + memcpy(thispod, otherpod, sizeof *thispod); + } + return *this; +} + +Dbt::~Dbt() +{ +} + +void * Dbt::get_data() const +{ + return this->data; +} + +void Dbt::set_data(void *value) +{ + this->data = value; +} + +u_int32_t Dbt::get_size() const +{ + return this->size; +} + +void Dbt::set_size(u_int32_t value) +{ + this->size = value; +} + +//---------------------------------------------------------------------------- +void db_internal::raise_error(int dberr, const char * where) +{ + if (!where) where = "<unknown>"; + + const char * dberrmsg = db_strerror(dberr); + if (!dberrmsg || !*dberrmsg) dberrmsg = "<unknown DB error>"; + + rtl::OString msg = where; + msg += ": "; + msg += dberrmsg; + + throw DbException(msg); +} + +//---------------------------------------------------------------------------- +} // namespace ecomp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/misc/dp_dependencies.cxx b/desktop/source/deployment/misc/dp_dependencies.cxx new file mode 100644 index 000000000000..375138d86532 --- /dev/null +++ b/desktop/source/deployment/misc/dp_dependencies.cxx @@ -0,0 +1,176 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "sal/config.h" + +#include "com/sun/star/uno/Reference.hxx" +#include "com/sun/star/uno/Sequence.hxx" +#include "com/sun/star/xml/dom/XElement.hpp" +#include "com/sun/star/xml/dom/XNode.hpp" +#include "com/sun/star/xml/dom/XNodeList.hpp" +#include "rtl/bootstrap.hxx" +#include "rtl/string.h" +#include "rtl/ustring.h" +#include "rtl/ustring.hxx" +#include "sal/types.h" +#include "tools/string.hxx" + +#include "deployment.hrc" +#include "dp_resource.h" + +#include "dp_dependencies.hxx" +#include "dp_descriptioninfoset.hxx" +#include "dp_version.hxx" + +namespace { + +namespace css = ::com::sun::star; + +static char const xmlNamespace[] = + "http://openoffice.org/extensions/description/2006"; + +bool +lcl_versionIsNot(dp_misc::Order i_eOrder, ::rtl::OUString const& i_rVersion) +{ + ::rtl::OUString aVersion( + RTL_CONSTASCII_USTRINGPARAM( + "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("version") + ":Version:OOOPackageVersion}")); + ::rtl::Bootstrap::expandMacros(aVersion); + return ::dp_misc::compareVersions(aVersion, i_rVersion) != i_eOrder; +} + +bool satisfiesMinimalVersion(::rtl::OUString const& i_rVersion) +{ + return lcl_versionIsNot(dp_misc::LESS, i_rVersion); +} + +bool satisfiesMaximalVersion(::rtl::OUString const& i_rVersion) +{ + return lcl_versionIsNot(dp_misc::GREATER, i_rVersion); +} + +} + +namespace dp_misc { + +namespace Dependencies { + +css::uno::Sequence< css::uno::Reference< css::xml::dom::XElement > > +check(::dp_misc::DescriptionInfoset const & infoset) { + css::uno::Reference< css::xml::dom::XNodeList > deps( + infoset.getDependencies()); + ::sal_Int32 n = deps->getLength(); + css::uno::Sequence< css::uno::Reference< css::xml::dom::XElement > > + unsatisfied(n); + ::sal_Int32 unsat = 0; + for (::sal_Int32 i = 0; i < n; ++i) { + static rtl::OUString const minimalVersion( + RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org-minimal-version")); + css::uno::Reference< css::xml::dom::XElement > e( + deps->item(i), css::uno::UNO_QUERY_THROW); + bool sat = false; + if (e->getNamespaceURI().equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM(xmlNamespace)) + && (e->getTagName() == minimalVersion)) + { + sat = satisfiesMinimalVersion( + e->getAttribute( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("value")))); + } else if (e->getNamespaceURI().equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM(xmlNamespace)) + && e->getTagName().equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( + "OpenOffice.org-maximal-version"))) + { + sat = satisfiesMaximalVersion( + e->getAttribute( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("value")))); + } else if (e->hasAttributeNS( + ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM(xmlNamespace)), + minimalVersion)) + { + sat = satisfiesMinimalVersion( + e->getAttributeNS( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(xmlNamespace)), + minimalVersion)); + } + if (!sat) { + unsatisfied[unsat++] = e; + } + } + unsatisfied.realloc(unsat); + return unsatisfied; +} + +::rtl::OUString getErrorText( css::uno::Reference< css::xml::dom::XElement > const & dependency ) +{ + ::rtl::OUString sReason; + ::rtl::OUString sValue; + ::rtl::OUString sVersion(RTL_CONSTASCII_USTRINGPARAM("%VERSION")); + + if ( dependency->getNamespaceURI().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( xmlNamespace ) ) + && dependency->getTagName().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "OpenOffice.org-minimal-version" ) ) ) + { + sValue = dependency->getAttribute( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "value" ) ) ); + sReason = ::rtl::OUString( ::String(::dp_misc::getResId(RID_DEPLYOMENT_DEPENDENCIES_MIN)) ); + } + else if ( dependency->getNamespaceURI().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( xmlNamespace ) ) + && dependency->getTagName().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "OpenOffice.org-maximal-version" ) ) ) + { + sValue = dependency->getAttribute( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("value") ) ); + sReason = ::rtl::OUString( ::String(::dp_misc::getResId(RID_DEPLYOMENT_DEPENDENCIES_MAX)) ); + } + else if ( dependency->hasAttributeNS( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( xmlNamespace ) ), + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "OpenOffice.org-minimal-version" )))) + { + sValue = dependency->getAttributeNS( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( xmlNamespace ) ), + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "OpenOffice.org-minimal-version" ) ) ); + sReason = ::rtl::OUString( ::String(::dp_misc::getResId(RID_DEPLYOMENT_DEPENDENCIES_MIN)) ); + } + else + return ::rtl::OUString( ::String(::dp_misc::getResId(RID_DEPLYOMENT_DEPENDENCIES_UNKNOWN)) ); + + if ( sValue.getLength() == 0 ) + sValue = ::rtl::OUString( ::String(::dp_misc::getResId(RID_DEPLYOMENT_DEPENDENCIES_UNKNOWN)) ); + + sal_Int32 nPos = sReason.indexOf( sVersion ); + if ( nPos >= 0 ) + sReason = sReason.replaceAt( nPos, sVersion.getLength(), sValue ); + return sReason; +} + +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/misc/dp_descriptioninfoset.cxx b/desktop/source/deployment/misc/dp_descriptioninfoset.cxx new file mode 100644 index 000000000000..90592c645c93 --- /dev/null +++ b/desktop/source/deployment/misc/dp_descriptioninfoset.cxx @@ -0,0 +1,867 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_descriptioninfoset.hxx" + +#include "dp_resource.h" +#include "sal/config.h" + +#include "comphelper/sequence.hxx" +#include "comphelper/makesequence.hxx" +#include "comphelper/processfactory.hxx" +#include "boost/optional.hpp" +#include "com/sun/star/beans/Optional.hpp" +#include "com/sun/star/lang/XMultiComponentFactory.hpp" +#include "com/sun/star/lang/Locale.hpp" +#include "com/sun/star/uno/Reference.hxx" +#include "com/sun/star/uno/RuntimeException.hpp" +#include "com/sun/star/uno/Sequence.hxx" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/uno/XInterface.hpp" +#include "com/sun/star/xml/dom/DOMException.hpp" +#include "com/sun/star/xml/dom/XNode.hpp" +#include "com/sun/star/xml/dom/XNodeList.hpp" +#include "com/sun/star/xml/dom/XDocumentBuilder.hpp" +#include "com/sun/star/xml/xpath/XXPathAPI.hpp" +#include "com/sun/star/ucb/InteractiveAugmentedIOException.hpp" +#include "cppuhelper/implbase1.hxx" +#include "cppuhelper/implbase2.hxx" +#include "cppuhelper/weak.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "rtl/ustring.h" +#include "rtl/ustring.hxx" +#include "sal/types.h" +#include "ucbhelper/content.hxx" + +namespace { + +namespace css = ::com::sun::star; +using css::uno::Reference; +using ::rtl::OUString; + +class EmptyNodeList: public ::cppu::WeakImplHelper1< css::xml::dom::XNodeList > +{ +public: + EmptyNodeList(); + + virtual ~EmptyNodeList(); + + virtual ::sal_Int32 SAL_CALL getLength() throw (css::uno::RuntimeException); + + virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL + item(::sal_Int32 index) throw (css::uno::RuntimeException); + +private: + EmptyNodeList(EmptyNodeList &); // not defined + void operator =(EmptyNodeList &); // not defined +}; + +EmptyNodeList::EmptyNodeList() {} + +EmptyNodeList::~EmptyNodeList() {} + +::sal_Int32 EmptyNodeList::getLength() throw (css::uno::RuntimeException) { + return 0; +} + +css::uno::Reference< css::xml::dom::XNode > EmptyNodeList::item(::sal_Int32) + throw (css::uno::RuntimeException) +{ + throw css::uno::RuntimeException( + ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "bad EmptyNodeList com.sun.star.xml.dom.XNodeList.item call")), + static_cast< ::cppu::OWeakObject * >(this)); +} + +::rtl::OUString getNodeValue( + css::uno::Reference< css::xml::dom::XNode > const & node) +{ + OSL_ASSERT(node.is()); + try { + return node->getNodeValue(); + } catch (css::xml::dom::DOMException & e) { + throw css::uno::RuntimeException( + (::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.xml.dom.DOMException: ")) + + e.Message), + css::uno::Reference< css::uno::XInterface >()); + } +} + +/**The class uses the UCB to access the description.xml file in an + extension. The UCB must have been initialized already. It also + requires that the extension has already be unzipped to a particular + location. + */ +class ExtensionDescription +{ +public: + /**throws an exception if the description.xml is not + available, cannot be read, does not contain the expected data, + or any other error occurred. Therefore it shoult only be used with + new extensions. + + Throws com::sun::star::uno::RuntimeException, + com::sun::star::deployment::DeploymentException, + dp_registry::backend::bundle::NoDescriptionException. + */ + ExtensionDescription( + const css::uno::Reference<css::uno::XComponentContext>& xContext, + const ::rtl::OUString& installDir, + const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv); + + ~ExtensionDescription(); + + css::uno::Reference<css::xml::dom::XNode> getRootElement() const + { + return m_xRoot; + } + + ::rtl::OUString getExtensionRootUrl() const + { + return m_sExtensionRootUrl; + } + + +private: + css::uno::Reference<css::xml::dom::XNode> m_xRoot; + ::rtl::OUString m_sExtensionRootUrl; +}; + +class NoDescriptionException +{ +}; + +class FileDoesNotExistFilter + : public ::cppu::WeakImplHelper2< css::ucb::XCommandEnvironment, + css::task::XInteractionHandler > + +{ + //css::uno::Reference<css::task::XInteractionHandler> m_xHandler; + bool m_bExist; + css::uno::Reference< css::ucb::XCommandEnvironment > m_xCommandEnv; + +public: + virtual ~FileDoesNotExistFilter(); + FileDoesNotExistFilter( + const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv); + + bool exist(); + // XCommandEnvironment + virtual css::uno::Reference<css::task::XInteractionHandler > SAL_CALL + getInteractionHandler() throw (css::uno::RuntimeException); + virtual css::uno::Reference<css::ucb::XProgressHandler > + SAL_CALL getProgressHandler() throw (css::uno::RuntimeException); + + // XInteractionHandler + virtual void SAL_CALL handle( + css::uno::Reference<css::task::XInteractionRequest > const & xRequest ) + throw (css::uno::RuntimeException); +}; + +ExtensionDescription::ExtensionDescription( + const Reference<css::uno::XComponentContext>& xContext, + const OUString& installDir, + const Reference< css::ucb::XCommandEnvironment >& xCmdEnv) +{ + try { + m_sExtensionRootUrl = installDir; + //may throw ::com::sun::star::ucb::ContentCreationException + //If there is no description.xml then ucb will start an interaction which + //brings up a dialog.We want to prevent this. Therefore we wrap the xCmdEnv + //and filter the respective exception out. + OUString sDescriptionUri(installDir + OUSTR("/description.xml")); + Reference<css::ucb::XCommandEnvironment> xFilter = + static_cast<css::ucb::XCommandEnvironment*>( + new FileDoesNotExistFilter(xCmdEnv)); + ::ucbhelper::Content descContent(sDescriptionUri, xFilter); + + //throws an com::sun::star::uno::Exception if the file is not available + Reference<css::io::XInputStream> xIn; + try + { //throws com.sun.star.ucb.InteractiveAugmentedIOException + xIn = descContent.openStream(); + } + catch (css::uno::Exception& ) + { + if ( ! static_cast<FileDoesNotExistFilter*>(xFilter.get())->exist()) + throw NoDescriptionException(); + throw; + } + if (!xIn.is()) + { + throw css::uno::Exception( + OUSTR("Could not get XInputStream for description.xml of extension ") + + sDescriptionUri, 0); + } + + //get root node of description.xml + Reference<css::xml::dom::XDocumentBuilder> xDocBuilder( + xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.xml.dom.DocumentBuilder"), + xContext ), css::uno::UNO_QUERY); + if (!xDocBuilder.is()) + throw css::uno::Exception(OUSTR(" Could not create service com.sun.star.xml.dom.DocumentBuilder"), 0); + + if (xDocBuilder->isNamespaceAware() == sal_False) + { + throw css::uno::Exception( + OUSTR("Service com.sun.star.xml.dom.DocumentBuilder is not namespace aware."), 0); + } + + Reference<css::xml::dom::XDocument> xDoc = xDocBuilder->parse(xIn); + if (!xDoc.is()) + { + throw css::uno::Exception(sDescriptionUri + OUSTR(" contains data which cannot be parsed. "), 0); + } + + //check for proper root element and namespace + Reference<css::xml::dom::XElement> xRoot = xDoc->getDocumentElement(); + if (!xRoot.is()) + { + throw css::uno::Exception( + sDescriptionUri + OUSTR(" contains no root element."), 0); + } + + if ( ! xRoot->getTagName().equals(OUSTR("description"))) + { + throw css::uno::Exception( + sDescriptionUri + OUSTR(" does not contain the root element <description>."), 0); + } + + m_xRoot = Reference<css::xml::dom::XNode>( + xRoot, css::uno::UNO_QUERY_THROW); + OUString nsDescription = xRoot->getNamespaceURI(); + + //check if this namespace is supported + if ( ! nsDescription.equals(OUSTR("http://openoffice.org/extensions/description/2006"))) + { + throw css::uno::Exception(sDescriptionUri + OUSTR(" contains a root element with an unsupported namespace. "), 0); + } + } catch (css::uno::RuntimeException &) { + throw; + } catch (css::deployment::DeploymentException &) { + throw; + } catch (css::uno::Exception & e) { + css::uno::Any a(cppu::getCaughtException()); + throw css::deployment::DeploymentException( + e.Message, Reference< css::uno::XInterface >(), a); + } +} + +ExtensionDescription::~ExtensionDescription() +{ +} + +//====================================================================== +FileDoesNotExistFilter::FileDoesNotExistFilter( + const Reference< css::ucb::XCommandEnvironment >& xCmdEnv): + m_bExist(true), m_xCommandEnv(xCmdEnv) +{} + +FileDoesNotExistFilter::~FileDoesNotExistFilter() +{ +}; + +bool FileDoesNotExistFilter::exist() +{ + return m_bExist; +} + // XCommandEnvironment +Reference<css::task::XInteractionHandler > + FileDoesNotExistFilter::getInteractionHandler() throw (css::uno::RuntimeException) +{ + return static_cast<css::task::XInteractionHandler*>(this); +} + +Reference<css::ucb::XProgressHandler > + FileDoesNotExistFilter::getProgressHandler() throw (css::uno::RuntimeException) +{ + return m_xCommandEnv.is() + ? m_xCommandEnv->getProgressHandler() + : Reference<css::ucb::XProgressHandler>(); +} + +// XInteractionHandler +//If the interaction was caused by a non-existing file which is specified in the ctor +//of FileDoesNotExistFilter, then we do nothing +void FileDoesNotExistFilter::handle( + Reference<css::task::XInteractionRequest > const & xRequest ) + throw (css::uno::RuntimeException) +{ + css::uno::Any request( xRequest->getRequest() ); + + css::ucb::InteractiveAugmentedIOException ioexc; + if ((request>>= ioexc) && ioexc.Code == css::ucb::IOErrorCode_NOT_EXISTING ) + { + m_bExist = false; + return; + } + Reference<css::task::XInteractionHandler> xInteraction; + if (m_xCommandEnv.is()) { + xInteraction = m_xCommandEnv->getInteractionHandler(); + } + if (xInteraction.is()) { + xInteraction->handle(xRequest); + } +} + +} + +namespace dp_misc { + +DescriptionInfoset getDescriptionInfoset(OUString const & sExtensionFolderURL) +{ + Reference< css::xml::dom::XNode > root; + Reference<css::uno::XComponentContext> context = + comphelper_getProcessComponentContext(); + OSL_ASSERT(context.is()); + try { + root = + ExtensionDescription( + context, sExtensionFolderURL, + Reference< css::ucb::XCommandEnvironment >()). + getRootElement(); + } catch (NoDescriptionException &) { + } catch (css::deployment::DeploymentException & e) { + throw css::uno::RuntimeException( + (OUString( + RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.deployment.DeploymentException: ")) + + e.Message), 0); + } + return DescriptionInfoset(context, root); +} + +DescriptionInfoset::DescriptionInfoset( + css::uno::Reference< css::uno::XComponentContext > const & context, + css::uno::Reference< css::xml::dom::XNode > const & element): + m_element(element) +{ + css::uno::Reference< css::lang::XMultiComponentFactory > manager( + context->getServiceManager(), css::uno::UNO_QUERY_THROW); + if (m_element.is()) { + m_xpath = css::uno::Reference< css::xml::xpath::XXPathAPI >( + manager->createInstanceWithContext( + ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.xml.xpath.XPathAPI")), + context), + css::uno::UNO_QUERY_THROW); + m_xpath->registerNS( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("desc")), + element->getNamespaceURI()); + m_xpath->registerNS( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("xlink")), + ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("http://www.w3.org/1999/xlink"))); + } +} + +DescriptionInfoset::~DescriptionInfoset() {} + +::boost::optional< ::rtl::OUString > DescriptionInfoset::getIdentifier() const { + return getOptionalValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("desc:identifier/@value"))); +} + +::rtl::OUString DescriptionInfoset::getNodeValueFromExpression(::rtl::OUString const & expression) const +{ + css::uno::Reference< css::xml::dom::XNode > n; + if (m_element.is()) { + try { + n = m_xpath->selectSingleNode(m_element, expression); + } catch (css::xml::xpath::XPathException &) { + // ignore + } + } + return n.is() ? getNodeValue(n) : ::rtl::OUString(); +} + + +::rtl::OUString DescriptionInfoset::getVersion() const +{ + return getNodeValueFromExpression( ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("desc:version/@value"))); +} + +css::uno::Sequence< ::rtl::OUString > DescriptionInfoset::getSupportedPlaforms() const +{ + //When there is no description.xml then we assume that we support all platforms + if (! m_element.is()) + { + return comphelper::makeSequence( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("all"))); + } + + //Check if the <platform> element was provided. If not the default is "all" platforms + css::uno::Reference< css::xml::dom::XNode > nodePlatform( + m_xpath->selectSingleNode(m_element, ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("desc:platform")))); + if (!nodePlatform.is()) + { + return comphelper::makeSequence( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("all"))); + } + + //There is a platform element. + const ::rtl::OUString value = getNodeValueFromExpression(::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("desc:platform/@value"))); + //parse the string, it can contained multiple strings separated by commas + ::std::vector< ::rtl::OUString> vec; + sal_Int32 nIndex = 0; + do + { + ::rtl::OUString aToken = value.getToken( 0, ',', nIndex ); + aToken = aToken.trim(); + if (aToken.getLength()) + vec.push_back(aToken); + + } + while (nIndex >= 0); + + return comphelper::containerToSequence(vec); +} + +css::uno::Reference< css::xml::dom::XNodeList > +DescriptionInfoset::getDependencies() const { + if (m_element.is()) { + try { + return m_xpath->selectNodeList(m_element, ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("desc:dependencies/*"))); + } catch (css::xml::xpath::XPathException &) { + // ignore + } + } + return new EmptyNodeList; +} + +css::uno::Sequence< ::rtl::OUString > +DescriptionInfoset::getUpdateInformationUrls() const { + return getUrls( + ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "desc:update-information/desc:src/@xlink:href"))); +} + +css::uno::Sequence< ::rtl::OUString > +DescriptionInfoset::getUpdateDownloadUrls() const +{ + return getUrls( + ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "desc:update-download/desc:src/@xlink:href"))); +} + +::rtl::OUString DescriptionInfoset::getIconURL( sal_Bool bHighContrast ) const +{ + css::uno::Sequence< ::rtl::OUString > aStrList = getUrls( ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( "desc:icon/desc:default/@xlink:href"))); + css::uno::Sequence< ::rtl::OUString > aStrListHC = getUrls( ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( "desc:icon/desc:high-contrast/@xlink:href"))); + + if ( bHighContrast && aStrListHC.hasElements() && aStrListHC[0].getLength() ) + return aStrListHC[0]; + + if ( aStrList.hasElements() && aStrList[0].getLength() ) + return aStrList[0]; + + return ::rtl::OUString(); +} + +::boost::optional< ::rtl::OUString > DescriptionInfoset::getLocalizedUpdateWebsiteURL() + const +{ + bool bParentExists = false; + const ::rtl::OUString sURL (getLocalizedHREFAttrFromChild(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "/desc:description/desc:update-website")), &bParentExists )); + + if (sURL.getLength() > 0) + return ::boost::optional< ::rtl::OUString >(sURL); + else + return bParentExists ? ::boost::optional< ::rtl::OUString >(::rtl::OUString()) : + ::boost::optional< ::rtl::OUString >(); +} + +::boost::optional< ::rtl::OUString > DescriptionInfoset::getOptionalValue( + ::rtl::OUString const & expression) const +{ + css::uno::Reference< css::xml::dom::XNode > n; + if (m_element.is()) { + try { + n = m_xpath->selectSingleNode(m_element, expression); + } catch (css::xml::xpath::XPathException &) { + // ignore + } + } + return n.is() + ? ::boost::optional< ::rtl::OUString >(getNodeValue(n)) + : ::boost::optional< ::rtl::OUString >(); +} + +css::uno::Sequence< ::rtl::OUString > DescriptionInfoset::getUrls( + ::rtl::OUString const & expression) const +{ + css::uno::Reference< css::xml::dom::XNodeList > ns; + if (m_element.is()) { + try { + ns = m_xpath->selectNodeList(m_element, expression); + } catch (css::xml::xpath::XPathException &) { + // ignore + } + } + css::uno::Sequence< ::rtl::OUString > urls(ns.is() ? ns->getLength() : 0); + for (::sal_Int32 i = 0; i < urls.getLength(); ++i) { + urls[i] = getNodeValue(ns->item(i)); + } + return urls; +} + +::std::pair< ::rtl::OUString, ::rtl::OUString > DescriptionInfoset::getLocalizedPublisherNameAndURL() const +{ + css::uno::Reference< css::xml::dom::XNode > node = + getLocalizedChild(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("desc:publisher"))); + + ::rtl::OUString sPublisherName; + ::rtl::OUString sURL; + if (node.is()) + { + const ::rtl::OUString exp1(RTL_CONSTASCII_USTRINGPARAM("text()")); + css::uno::Reference< css::xml::dom::XNode > xPathName; + try { + xPathName = m_xpath->selectSingleNode(node, exp1); + } catch (css::xml::xpath::XPathException &) { + // ignore + } + OSL_ASSERT(xPathName.is()); + if (xPathName.is()) + sPublisherName = xPathName->getNodeValue(); + + const ::rtl::OUString exp2(RTL_CONSTASCII_USTRINGPARAM("@xlink:href")); + css::uno::Reference< css::xml::dom::XNode > xURL; + try { + xURL = m_xpath->selectSingleNode(node, exp2); + } catch (css::xml::xpath::XPathException &) { + // ignore + } + OSL_ASSERT(xURL.is()); + if (xURL.is()) + sURL = xURL->getNodeValue(); + } + return ::std::make_pair(sPublisherName, sURL); +} + +::rtl::OUString DescriptionInfoset::getLocalizedReleaseNotesURL() const +{ + return getLocalizedHREFAttrFromChild(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "/desc:description/desc:release-notes")), NULL); +} + +::rtl::OUString DescriptionInfoset::getLocalizedDisplayName() const +{ + css::uno::Reference< css::xml::dom::XNode > node = + getLocalizedChild(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("desc:display-name"))); + if (node.is()) + { + const ::rtl::OUString exp(RTL_CONSTASCII_USTRINGPARAM("text()")); + css::uno::Reference< css::xml::dom::XNode > xtext; + try { + xtext = m_xpath->selectSingleNode(node, exp); + } catch (css::xml::xpath::XPathException &) { + // ignore + } + if (xtext.is()) + return xtext->getNodeValue(); + } + return ::rtl::OUString(); +} + +::rtl::OUString DescriptionInfoset::getLocalizedLicenseURL() const +{ + return getLocalizedHREFAttrFromChild(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "/desc:description/desc:registration/desc:simple-license")), NULL); + +} + +::boost::optional<SimpleLicenseAttributes> +DescriptionInfoset::getSimpleLicenseAttributes() const +{ + //Check if the node exist + css::uno::Reference< css::xml::dom::XNode > n; + if (m_element.is()) { + try { + n = m_xpath->selectSingleNode(m_element, + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "/desc:description/desc:registration/desc:simple-license/@accept-by"))); + } catch (css::xml::xpath::XPathException &) { + // ignore + } + if (n.is()) + { + SimpleLicenseAttributes attributes; + attributes.acceptBy = + getNodeValueFromExpression(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "/desc:description/desc:registration/desc:simple-license/@accept-by"))); + + ::boost::optional< ::rtl::OUString > suppressOnUpdate = getOptionalValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "/desc:description/desc:registration/desc:simple-license/@suppress-on-update"))); + if (suppressOnUpdate) + attributes.suppressOnUpdate = (*suppressOnUpdate).trim().equalsIgnoreAsciiCase( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("true"))); + else + attributes.suppressOnUpdate = false; + + ::boost::optional< ::rtl::OUString > suppressIfRequired = getOptionalValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "/desc:description/desc:registration/desc:simple-license/@suppress-if-required"))); + if (suppressIfRequired) + attributes.suppressIfRequired = (*suppressIfRequired).trim().equalsIgnoreAsciiCase( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("true"))); + else + attributes.suppressIfRequired = false; + + return ::boost::optional<SimpleLicenseAttributes>(attributes); + } + } + return ::boost::optional<SimpleLicenseAttributes>(); +} + +::rtl::OUString DescriptionInfoset::getLocalizedDescriptionURL() const +{ + return getLocalizedHREFAttrFromChild(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "/desc:description/desc:extension-description")), NULL); +} + +css::uno::Reference< css::xml::dom::XNode > +DescriptionInfoset::getLocalizedChild( const ::rtl::OUString & sParent) const +{ + if ( ! m_element.is() || !sParent.getLength()) + return css::uno::Reference< css::xml::dom::XNode > (); + + css::uno::Reference< css::xml::dom::XNode > xParent; + try { + xParent = m_xpath->selectSingleNode(m_element, sParent); + } catch (css::xml::xpath::XPathException &) { + // ignore + } + css::uno::Reference<css::xml::dom::XNode> nodeMatch; + if (xParent.is()) + { + const ::rtl::OUString sLocale = getOfficeLocaleString(); + nodeMatch = matchFullLocale(xParent, sLocale); + + //office: en-DE, en, en-DE-altmark + if (! nodeMatch.is()) + { + const css::lang::Locale officeLocale = getOfficeLocale(); + nodeMatch = matchCountryAndLanguage(xParent, officeLocale); + if ( ! nodeMatch.is()) + { + nodeMatch = matchLanguage(xParent, officeLocale); + if (! nodeMatch.is()) + nodeMatch = getChildWithDefaultLocale(xParent); + } + } + } + + return nodeMatch; +} + +css::uno::Reference<css::xml::dom::XNode> +DescriptionInfoset::matchFullLocale(css::uno::Reference< css::xml::dom::XNode > + const & xParent, ::rtl::OUString const & sLocale) const +{ + OSL_ASSERT(xParent.is()); + const ::rtl::OUString exp1( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*[@lang=\"")) + + sLocale + + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("\"]"))); + try { + return m_xpath->selectSingleNode(xParent, exp1); + } catch (css::xml::xpath::XPathException &) { + // ignore + return 0; + } +} + +css::uno::Reference<css::xml::dom::XNode> +DescriptionInfoset::matchCountryAndLanguage( + css::uno::Reference< css::xml::dom::XNode > const & xParent, css::lang::Locale const & officeLocale) const +{ + OSL_ASSERT(xParent.is()); + css::uno::Reference<css::xml::dom::XNode> nodeMatch; + + if (officeLocale.Country.getLength()) + { + const ::rtl::OUString sLangCountry(officeLocale.Language + + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("-")) + + officeLocale.Country); + //first try exact match for lang-country + const ::rtl::OUString exp1( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*[@lang=\"")) + + sLangCountry + + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("\"]"))); + try { + nodeMatch = m_xpath->selectSingleNode(xParent, exp1); + } catch (css::xml::xpath::XPathException &) { + // ignore + } + + //try to match in strings that also have a variant, for example en-US matches in + //en-US-montana + if (!nodeMatch.is()) + { + const ::rtl::OUString exp2( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*[starts-with(@lang,\"")) + + sLangCountry + + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("-\")]"))); + try { + nodeMatch = m_xpath->selectSingleNode(xParent, exp2); + } catch (css::xml::xpath::XPathException &) { + // ignore + } + } + } + + return nodeMatch; +} + + +css::uno::Reference<css::xml::dom::XNode> +DescriptionInfoset::matchLanguage( + css::uno::Reference< css::xml::dom::XNode > const & xParent, css::lang::Locale const & officeLocale) const +{ + OSL_ASSERT(xParent.is()); + css::uno::Reference<css::xml::dom::XNode> nodeMatch; + + //first try exact match for lang + const ::rtl::OUString exp1( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*[@lang=\"")) + + officeLocale.Language + + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("\"]"))); + try { + nodeMatch = m_xpath->selectSingleNode(xParent, exp1); + } catch (css::xml::xpath::XPathException &) { + // ignore + } + + //try to match in strings that also have a country and/orvariant, for example en matches in + //en-US-montana, en-US, en-montana + if (!nodeMatch.is()) + { + const ::rtl::OUString exp2( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*[starts-with(@lang,\"")) + + officeLocale.Language + + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("-\")]"))); + try { + nodeMatch = m_xpath->selectSingleNode(xParent, exp2); + } catch (css::xml::xpath::XPathException &) { + // ignore + } + } + return nodeMatch; +} + +css::uno::Reference<css::xml::dom::XNode> +DescriptionInfoset::getChildWithDefaultLocale(css::uno::Reference< css::xml::dom::XNode > + const & xParent) const +{ + OSL_ASSERT(xParent.is()); + if (xParent->getNodeName().equals(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("simple-license")))) + { + css::uno::Reference<css::xml::dom::XNode> nodeDefault; + try { + nodeDefault = m_xpath->selectSingleNode(xParent, ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("@default-license-id"))); + } catch (css::xml::xpath::XPathException &) { + // ignore + } + if (nodeDefault.is()) + { + //The old way + const ::rtl::OUString exp1( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("desc:license-text[@license-id = \"")) + + nodeDefault->getNodeValue() + + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("\"]"))); + try { + return m_xpath->selectSingleNode(xParent, exp1); + } catch (css::xml::xpath::XPathException &) { + // ignore + } + } + } + + const ::rtl::OUString exp2(RTL_CONSTASCII_USTRINGPARAM("*[1]")); + try { + return m_xpath->selectSingleNode(xParent, exp2); + } catch (css::xml::xpath::XPathException &) { + // ignore + return 0; + } +} + +::rtl::OUString DescriptionInfoset::getLocalizedHREFAttrFromChild( + ::rtl::OUString const & sXPathParent, bool * out_bParentExists) + const +{ + css::uno::Reference< css::xml::dom::XNode > node = + getLocalizedChild(sXPathParent); + + ::rtl::OUString sURL; + if (node.is()) + { + if (out_bParentExists) + *out_bParentExists = true; + const ::rtl::OUString exp(RTL_CONSTASCII_USTRINGPARAM("@xlink:href")); + css::uno::Reference< css::xml::dom::XNode > xURL; + try { + xURL = m_xpath->selectSingleNode(node, exp); + } catch (css::xml::xpath::XPathException &) { + // ignore + } + OSL_ASSERT(xURL.is()); + if (xURL.is()) + sURL = xURL->getNodeValue(); + } + else + { + if (out_bParentExists) + *out_bParentExists = false; + } + return sURL; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/misc/dp_identifier.cxx b/desktop/source/deployment/misc/dp_identifier.cxx new file mode 100644 index 000000000000..b24ccd7def52 --- /dev/null +++ b/desktop/source/deployment/misc/dp_identifier.cxx @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "sal/config.h" + +#include "boost/optional.hpp" +#include "com/sun/star/beans/Optional.hpp" +#include "com/sun/star/deployment/XPackage.hpp" +#include "com/sun/star/uno/Reference.hxx" +#include "osl/diagnose.h" +#include "rtl/string.h" +#include "rtl/ustrbuf.hxx" +#include "rtl/ustring.hxx" + +#include "dp_identifier.hxx" + +namespace { + namespace css = ::com::sun::star; +} + +namespace dp_misc { + +::rtl::OUString generateIdentifier( + ::boost::optional< ::rtl::OUString > const & optional, + ::rtl::OUString const & fileName) +{ + return optional ? *optional : generateLegacyIdentifier(fileName); +} + +::rtl::OUString getIdentifier( + css::uno::Reference< css::deployment::XPackage > const & package) +{ + OSL_ASSERT(package.is()); + css::beans::Optional< ::rtl::OUString > id(package->getIdentifier()); + return id.IsPresent + ? id.Value : generateLegacyIdentifier(package->getName()); +} + +::rtl::OUString generateLegacyIdentifier(::rtl::OUString const & fileName) { + rtl::OUStringBuffer b; + b.appendAscii(RTL_CONSTASCII_STRINGPARAM("org.openoffice.legacy.")); + b.append(fileName); + return b.makeStringAndClear(); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/misc/dp_interact.cxx b/desktop/source/deployment/misc/dp_interact.cxx new file mode 100644 index 000000000000..c42ccd249cb7 --- /dev/null +++ b/desktop/source/deployment/misc/dp_interact.cxx @@ -0,0 +1,187 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_interact.h" +#include "cppuhelper/exc_hlp.hxx" +#include "cppuhelper/implbase1.hxx" +#include "com/sun/star/task/XInteractionAbort.hpp" + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using ::rtl::OUString; + +namespace dp_misc { +namespace { + +//============================================================================== +class InteractionContinuationImpl : public ::cppu::OWeakObject, + public task::XInteractionContinuation +{ + const Type m_type; + bool * m_pselect; + +public: + inline InteractionContinuationImpl( Type const & type, bool * pselect ) + : m_type( type ), + m_pselect( pselect ) + { OSL_ASSERT( + ::getCppuType( + static_cast< Reference<task::XInteractionContinuation> + const *>(0) ).isAssignableFrom(m_type) ); } + + // XInterface + virtual void SAL_CALL acquire() throw (); + virtual void SAL_CALL release() throw (); + virtual Any SAL_CALL queryInterface( Type const & type ) + throw (RuntimeException); + + // XInteractionContinuation + virtual void SAL_CALL select() throw (RuntimeException); +}; + +// XInterface +//______________________________________________________________________________ +void InteractionContinuationImpl::acquire() throw () +{ + OWeakObject::acquire(); +} + +//______________________________________________________________________________ +void InteractionContinuationImpl::release() throw () +{ + OWeakObject::release(); +} + +//______________________________________________________________________________ +Any InteractionContinuationImpl::queryInterface( Type const & type ) + throw (RuntimeException) +{ + if (type.isAssignableFrom( m_type )) { + Reference<task::XInteractionContinuation> xThis(this); + return Any( &xThis, type ); + } + else + return OWeakObject::queryInterface(type); +} + +// XInteractionContinuation +//______________________________________________________________________________ +void InteractionContinuationImpl::select() throw (RuntimeException) +{ + *m_pselect = true; +} + +//============================================================================== +class InteractionRequest : + public ::cppu::WeakImplHelper1<task::XInteractionRequest> +{ + Any m_request; + Sequence< Reference<task::XInteractionContinuation> > m_conts; + +public: + inline InteractionRequest( + Any const & request, + Sequence< Reference<task::XInteractionContinuation> > const & conts ) + : m_request( request ), + m_conts( conts ) + {} + + // XInteractionRequest + virtual Any SAL_CALL getRequest() + throw (RuntimeException); + virtual Sequence< Reference<task::XInteractionContinuation> > + SAL_CALL getContinuations() throw (RuntimeException); +}; + +// XInteractionRequest +//______________________________________________________________________________ +Any InteractionRequest::getRequest() throw (RuntimeException) +{ + return m_request; +} + +//______________________________________________________________________________ +Sequence< Reference< task::XInteractionContinuation > > +InteractionRequest::getContinuations() throw (RuntimeException) +{ + return m_conts; +} + +} // anon namespace + +//============================================================================== +bool interactContinuation( Any const & request, + Type const & continuation, + Reference<XCommandEnvironment> const & xCmdEnv, + bool * pcont, bool * pabort ) +{ + OSL_ASSERT( + task::XInteractionContinuation::static_type().isAssignableFrom( + continuation ) ); + if (xCmdEnv.is()) { + Reference<task::XInteractionHandler> xInteractionHandler( + xCmdEnv->getInteractionHandler() ); + if (xInteractionHandler.is()) { + bool cont = false; + bool abort = false; + Sequence< Reference<task::XInteractionContinuation> > conts( 2 ); + conts[ 0 ] = new InteractionContinuationImpl( + continuation, &cont ); + conts[ 1 ] = new InteractionContinuationImpl( + task::XInteractionAbort::static_type(), &abort ); + xInteractionHandler->handle( + new InteractionRequest( request, conts ) ); + if (cont || abort) { + if (pcont != 0) + *pcont = cont; + if (pabort != 0) + *pabort = abort; + return true; + } + } + } + return false; +} + +// XAbortChannel +//______________________________________________________________________________ +void AbortChannel::sendAbort() throw (RuntimeException) +{ + m_aborted = true; + if (m_xNext.is()) + m_xNext->sendAbort(); +} + +} // dp_misc + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/misc/dp_misc.cxx b/desktop/source/deployment/misc/dp_misc.cxx new file mode 100644 index 000000000000..ba7952364663 --- /dev/null +++ b/desktop/source/deployment/misc/dp_misc.cxx @@ -0,0 +1,632 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + + +#include "dp_misc.h" +#include "dp_version.hxx" +#include "dp_interact.h" +#include "rtl/uri.hxx" +#include "rtl/digest.h" +#include "rtl/random.h" +#include "rtl/bootstrap.hxx" +#include "unotools/bootstrap.hxx" +#include "osl/file.hxx" +#include "osl/pipe.hxx" +#include "osl/security.hxx" +#include "osl/thread.hxx" +#include "osl/mutex.hxx" +#include "com/sun/star/ucb/CommandAbortedException.hpp" +#include "com/sun/star/task/XInteractionHandler.hpp" +#include "com/sun/star/bridge/UnoUrlResolver.hpp" +#include "com/sun/star/bridge/XUnoUrlResolver.hpp" +#include "com/sun/star/deployment/ExtensionManager.hpp" +#include "com/sun/star/task/XRestartManager.hpp" +#include "boost/scoped_array.hpp" +#include "boost/shared_ptr.hpp" +#include <comphelper/processfactory.hxx> + +#ifdef WNT +#define UNICODE +#define _UNICODE +#define WIN32_LEAN_AND_MEAN +#include <Windows.h> +#endif + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using ::rtl::OUString; +using ::rtl::OString; + + +#define SOFFICE1 "soffice.exe" +#define SOFFICE2 "soffice.bin" +#define SBASE "sbase.exe" +#define SCALC "scalc.exe" +#define SDRAW "sdraw.exe" +#define SIMPRESS "simpress.exe" +#define SWRITER "swriter.exe" + +namespace dp_misc { +namespace { + +struct UnoRc : public rtl::StaticWithInit< + const boost::shared_ptr<rtl::Bootstrap>, UnoRc> { + const boost::shared_ptr<rtl::Bootstrap> operator () () { + OUString unorc( RTL_CONSTASCII_USTRINGPARAM( + "$OOO_BASE_DIR/program/" SAL_CONFIGFILE("uno")) ); + ::rtl::Bootstrap::expandMacros( unorc ); + ::boost::shared_ptr< ::rtl::Bootstrap > ret( + new ::rtl::Bootstrap( unorc ) ); + OSL_ASSERT( ret->getHandle() != 0 ); + return ret; + } +}; + +struct OfficePipeId : public rtl::StaticWithInit<const OUString, OfficePipeId> { + const OUString operator () (); +}; + +const OUString OfficePipeId::operator () () +{ + OUString userPath; + ::utl::Bootstrap::PathStatus aLocateResult = + ::utl::Bootstrap::locateUserInstallation( userPath ); + if (!(aLocateResult == ::utl::Bootstrap::PATH_EXISTS || + aLocateResult == ::utl::Bootstrap::PATH_VALID)) + { + throw Exception(OUSTR("Extension Manager: Could not obtain path for UserInstallation."), 0); + } + + rtlDigest digest = rtl_digest_create( rtl_Digest_AlgorithmMD5 ); + if (digest <= 0) { + throw RuntimeException( + OUSTR("cannot get digest rtl_Digest_AlgorithmMD5!"), 0 ); + } + + sal_uInt8 const * data = + reinterpret_cast<sal_uInt8 const *>(userPath.getStr()); + sal_Size size = (userPath.getLength() * sizeof (sal_Unicode)); + sal_uInt32 md5_key_len = rtl_digest_queryLength( digest ); + ::boost::scoped_array<sal_uInt8> md5_buf( new sal_uInt8 [ md5_key_len ] ); + + rtl_digest_init( digest, data, static_cast<sal_uInt32>(size) ); + rtl_digest_update( digest, data, static_cast<sal_uInt32>(size) ); + rtl_digest_get( digest, md5_buf.get(), md5_key_len ); + rtl_digest_destroy( digest ); + + // create hex-value string from the MD5 value to keep + // the string size minimal + ::rtl::OUStringBuffer buf; + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("SingleOfficeIPC_") ); + for ( sal_uInt32 i = 0; i < md5_key_len; ++i ) { + buf.append( static_cast<sal_Int32>(md5_buf[ i ]), 0x10 ); + } + return buf.makeStringAndClear(); +} + +bool existsOfficePipe() +{ + OUString const & pipeId = OfficePipeId::get(); + if (pipeId.getLength() == 0) + return false; + ::osl::Security sec; + ::osl::Pipe pipe( pipeId, osl_Pipe_OPEN, sec ); + return pipe.is(); +} + + +//Returns true if the Folder was more recently modified then +//the lastsynchronized file. That is the repository needs to +//be synchronized. +bool compareExtensionFolderWithLastSynchronizedFile( + OUString const & folderURL, OUString const & fileURL) +{ + bool bNeedsSync = false; + ::osl::DirectoryItem itemExtFolder; + ::osl::File::RC err1 = + ::osl::DirectoryItem::get(folderURL, itemExtFolder); + //If it does not exist, then there is nothing to be done + if (err1 == ::osl::File::E_NOENT) + { + return false; + } + else if (err1 != ::osl::File::E_None) + { + OSL_ENSURE(0, "Cannot access extension folder"); + return true; //sync just in case + } + + //If last synchronized does not exist, then OOo is started for the first time + ::osl::DirectoryItem itemFile; + ::osl::File::RC err2 = ::osl::DirectoryItem::get(fileURL, itemFile); + if (err2 == ::osl::File::E_NOENT) + { + return true; + + } + else if (err2 != ::osl::File::E_None) + { + OSL_ENSURE(0, "Cannot access file lastsynchronized"); + return true; //sync just in case + } + + //compare the modification time of the extension folder and the last + //modified file + ::osl::FileStatus statFolder(FileStatusMask_ModifyTime); + ::osl::FileStatus statFile(FileStatusMask_ModifyTime); + if (itemExtFolder.getFileStatus(statFolder) == ::osl::File::E_None) + { + if (itemFile.getFileStatus(statFile) == ::osl::File::E_None) + { + TimeValue timeFolder = statFolder.getModifyTime(); + TimeValue timeFile = statFile.getModifyTime(); + + if (timeFile.Seconds < timeFolder.Seconds) + bNeedsSync = true; + } + else + { + OSL_ASSERT(0); + bNeedsSync = true; + } + } + else + { + OSL_ASSERT(0); + bNeedsSync = true; + } + return bNeedsSync; +} + +bool needToSyncRepostitory(OUString const & name) +{ + OUString folder; + OUString file; + if (name.equals(OUString(RTL_CONSTASCII_USTRINGPARAM("bundled")))) + { + folder = OUString( + RTL_CONSTASCII_USTRINGPARAM("$BUNDLED_EXTENSIONS")); + file = OUString ( + RTL_CONSTASCII_USTRINGPARAM( + "$BUNDLED_EXTENSIONS_USER/lastsynchronized")); + } + else if (name.equals(OUString(RTL_CONSTASCII_USTRINGPARAM("shared")))) + { + folder = OUString( + RTL_CONSTASCII_USTRINGPARAM( + "$UNO_SHARED_PACKAGES_CACHE/uno_packages")); + file = OUString ( + RTL_CONSTASCII_USTRINGPARAM( + "$SHARED_EXTENSIONS_USER/lastsynchronized")); + } + else + { + OSL_ASSERT(0); + return true; + } + ::rtl::Bootstrap::expandMacros(folder); + ::rtl::Bootstrap::expandMacros(file); + return compareExtensionFolderWithLastSynchronizedFile( + folder, file); +} + + +} // anon namespace + +//============================================================================== + +namespace { +inline OUString encodeForRcFile( OUString const & str ) +{ + // escape $\{} (=> rtl bootstrap files) + ::rtl::OUStringBuffer buf; + sal_Int32 pos = 0; + const sal_Int32 len = str.getLength(); + for ( ; pos < len; ++pos ) { + sal_Unicode c = str[ pos ]; + switch (c) { + case '$': + case '\\': + case '{': + case '}': + buf.append( static_cast<sal_Unicode>('\\') ); + break; + } + buf.append( c ); + } + return buf.makeStringAndClear(); +} +} + +//============================================================================== +OUString makeURL( OUString const & baseURL, OUString const & relPath_ ) +{ + ::rtl::OUStringBuffer buf; + if (baseURL.getLength() > 1 && baseURL[ baseURL.getLength() - 1 ] == '/') + buf.append( baseURL.copy( 0, baseURL.getLength() - 1 ) ); + else + buf.append( baseURL ); + OUString relPath(relPath_); + if (relPath.getLength() > 0 && relPath[ 0 ] == '/') + relPath = relPath.copy( 1 ); + if (relPath.getLength() > 0) + { + buf.append( static_cast<sal_Unicode>('/') ); + if (baseURL.matchAsciiL( + RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.expand:") )) { + // encode for macro expansion: relPath is supposed to have no + // macros, so encode $, {} \ (bootstrap mimic) + relPath = encodeForRcFile(relPath); + + // encode once more for vnd.sun.star.expand schema: + // vnd.sun.star.expand:$UNO_... + // will expand to file-url + relPath = ::rtl::Uri::encode( relPath, rtl_UriCharClassUric, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ); + } + buf.append( relPath ); + } + return buf.makeStringAndClear(); +} + +OUString makeURLAppendSysPathSegment( OUString const & baseURL, OUString const & relPath_ ) +{ + OUString segment = relPath_; + OSL_ASSERT(segment.indexOf(static_cast<sal_Unicode>('/')) == -1); + + ::rtl::Uri::encode( + segment, rtl_UriCharClassPchar, rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8); + return makeURL(baseURL, segment); +} + + + +//============================================================================== +OUString expandUnoRcTerm( OUString const & term_ ) +{ + OUString term(term_); + UnoRc::get()->expandMacrosFrom( term ); + return term; +} + +OUString makeRcTerm( OUString const & url ) +{ + OSL_ASSERT( url.matchAsciiL( RTL_CONSTASCII_STRINGPARAM( + "vnd.sun.star.expand:") ) ); + if (url.matchAsciiL( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.expand:") )) { + // cut protocol: + OUString rcterm( url.copy( sizeof ("vnd.sun.star.expand:") - 1 ) ); + // decode uric class chars: + rcterm = ::rtl::Uri::decode( + rcterm, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 ); + return rcterm; + } + else + return url; +} + +//============================================================================== +OUString expandUnoRcUrl( OUString const & url ) +{ + if (url.matchAsciiL( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.expand:") )) { + // cut protocol: + OUString rcurl( url.copy( sizeof ("vnd.sun.star.expand:") - 1 ) ); + // decode uric class chars: + rcurl = ::rtl::Uri::decode( + rcurl, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 ); + // expand macro string: + UnoRc::get()->expandMacrosFrom( rcurl ); + return rcurl; + } + else { + return url; + } +} + +//============================================================================== +bool office_is_running() +{ + //We need to check if we run within the office process. Then we must not use the pipe, because + //this could cause a deadlock. This is actually a workaround for i82778 + OUString sFile; + oslProcessError err = osl_getExecutableFile(& sFile.pData); + bool ret = false; + if (osl_Process_E_None == err) + { + sFile = sFile.copy(sFile.lastIndexOf('/') + 1); + if ( +#if defined UNIX + sFile.equals(OUString(RTL_CONSTASCII_USTRINGPARAM(SOFFICE2))) +#elif defined WNT || defined OS2 + //osl_getExecutableFile should deliver "soffice.bin" on windows + //even if swriter.exe, scalc.exe etc. was started. This is a bug + //in osl_getExecutableFile + sFile.equals(OUString(RTL_CONSTASCII_USTRINGPARAM(SOFFICE1))) + || sFile.equals(OUString(RTL_CONSTASCII_USTRINGPARAM(SOFFICE2))) + || sFile.equals(OUString(RTL_CONSTASCII_USTRINGPARAM(SBASE))) + || sFile.equals(OUString(RTL_CONSTASCII_USTRINGPARAM(SCALC))) + || sFile.equals(OUString(RTL_CONSTASCII_USTRINGPARAM(SDRAW))) + || sFile.equals(OUString(RTL_CONSTASCII_USTRINGPARAM(SIMPRESS))) + || sFile.equals(OUString(RTL_CONSTASCII_USTRINGPARAM(SWRITER))) +#else +#error "Unsupported platform" +#endif + + ) + ret = true; + else + ret = existsOfficePipe(); + } + else + { + OSL_ENSURE(0, "NOT osl_Process_E_None "); + //if osl_getExecutable file than we take the risk of creating a pipe + ret = existsOfficePipe(); + } + return ret; +} + +//============================================================================== +oslProcess raiseProcess( + OUString const & appURL, Sequence<OUString> const & args ) +{ + ::osl::Security sec; + oslProcess hProcess = 0; + oslProcessError rc = osl_executeProcess( + appURL.pData, + reinterpret_cast<rtl_uString **>( + const_cast<OUString *>(args.getConstArray()) ), + args.getLength(), + osl_Process_DETACHED, + sec.getHandle(), + 0, // => current working dir + 0, 0, // => no env vars + &hProcess ); + + switch (rc) { + case osl_Process_E_None: + break; + case osl_Process_E_NotFound: + throw RuntimeException( OUSTR("image not found!"), 0 ); + case osl_Process_E_TimedOut: + throw RuntimeException( OUSTR("timout occurred!"), 0 ); + case osl_Process_E_NoPermission: + throw RuntimeException( OUSTR("permission denied!"), 0 ); + case osl_Process_E_Unknown: + throw RuntimeException( OUSTR("unknown error!"), 0 ); + case osl_Process_E_InvalidError: + default: + throw RuntimeException( OUSTR("unmapped error!"), 0 ); + } + + return hProcess; +} + +//============================================================================== +OUString generateRandomPipeId() +{ + // compute some good pipe id: + static rtlRandomPool s_hPool = rtl_random_createPool(); + if (s_hPool == 0) + throw RuntimeException( OUSTR("cannot create random pool!?"), 0 ); + sal_uInt8 bytes[ 32 ]; + if (rtl_random_getBytes( + s_hPool, bytes, ARLEN(bytes) ) != rtl_Random_E_None) { + throw RuntimeException( OUSTR("random pool error!?"), 0 ); + } + ::rtl::OUStringBuffer buf; + for ( sal_uInt32 i = 0; i < ARLEN(bytes); ++i ) { + buf.append( static_cast<sal_Int32>(bytes[ i ]), 0x10 ); + } + return buf.makeStringAndClear(); +} + +//============================================================================== +Reference<XInterface> resolveUnoURL( + OUString const & connectString, + Reference<XComponentContext> const & xLocalContext, + AbortChannel * abortChannel ) +{ + Reference<bridge::XUnoUrlResolver> xUnoUrlResolver( + bridge::UnoUrlResolver::create( xLocalContext ) ); + + for (;;) + { + if (abortChannel != 0 && abortChannel->isAborted()) { + throw ucb::CommandAbortedException( + OUSTR("abort!"), Reference<XInterface>() ); + } + try { + return xUnoUrlResolver->resolve( connectString ); + } + catch (connection::NoConnectException &) { + TimeValue tv = { 0 /* secs */, 500000000 /* nanosecs */ }; + ::osl::Thread::wait( tv ); + } + } +} + +#ifdef WNT +void writeConsoleWithStream(::rtl::OUString const & sText, HANDLE stream) +{ + DWORD nWrittenChars = 0; + WriteFile(stream, sText.getStr(), + sText.getLength() * 2, &nWrittenChars, NULL); +} +#else +void writeConsoleWithStream(::rtl::OUString const & sText, FILE * stream) +{ + OString s = OUStringToOString(sText, osl_getThreadTextEncoding()); + fprintf(stream, "%s", s.getStr()); + fflush(stream); +} +#endif + +#ifdef WNT +void writeConsoleWithStream(::rtl::OString const & sText, HANDLE stream) +{ + writeConsoleWithStream(OStringToOUString( + sText, RTL_TEXTENCODING_UTF8), stream); +} +#else +void writeConsoleWithStream(::rtl::OString const & sText, FILE * stream) +{ + fprintf(stream, "%s", sText.getStr()); + fflush(stream); +} +#endif + +void writeConsole(::rtl::OUString const & sText) +{ +#ifdef WNT + writeConsoleWithStream(sText, GetStdHandle(STD_OUTPUT_HANDLE)); +#else + writeConsoleWithStream(sText, stdout); +#endif +} + +void writeConsole(::rtl::OString const & sText) +{ +#ifdef WNT + writeConsoleWithStream(sText, GetStdHandle(STD_OUTPUT_HANDLE)); +#else + writeConsoleWithStream(sText, stdout); +#endif +} + +void writeConsoleError(::rtl::OUString const & sText) +{ +#ifdef WNT + writeConsoleWithStream(sText, GetStdHandle(STD_ERROR_HANDLE)); +#else + writeConsoleWithStream(sText, stderr); +#endif +} + + +void writeConsoleError(::rtl::OString const & sText) +{ +#ifdef WNT + writeConsoleWithStream(sText, GetStdHandle(STD_ERROR_HANDLE)); +#else + writeConsoleWithStream(sText, stderr); +#endif +} + + + +OUString readConsole() +{ +#ifdef WNT + sal_Unicode aBuffer[1024]; + DWORD dwRead = 0; + //unopkg.com feeds unopkg.exe with wchar_t|s + if (ReadFile( GetStdHandle(STD_INPUT_HANDLE), &aBuffer, sizeof(aBuffer), &dwRead, NULL ) ) + { + OSL_ASSERT((dwRead % 2) == 0); + OUString value( aBuffer, dwRead / 2); + return value.trim(); + } +#else + char buf[1024]; + rtl_zeroMemory(buf, 1024); + // read one char less so that the last char in buf is always zero + if (fgets(buf, 1024, stdin) != NULL) + { + OUString value = ::rtl::OStringToOUString(::rtl::OString(buf), osl_getThreadTextEncoding()); + return value.trim(); + } +#endif + return OUString(); +} + +void TRACE(::rtl::OUString const & sText) +{ + (void) sText; +#if OSL_DEBUG_LEVEL > 1 + writeConsole(sText); +#endif +} + +void TRACE(::rtl::OString const & sText) +{ + (void) sText; +#if OSL_DEBUG_LEVEL > 1 + writeConsole(sText); +#endif +} + +void syncRepositories(Reference<ucb::XCommandEnvironment> const & xCmdEnv) +{ + OUString sDisable; + ::rtl::Bootstrap::get( OUSTR( "DISABLE_EXTENSION_SYNCHRONIZATION" ), sDisable, OUString() ); + if (sDisable.getLength() > 0) + return; + + Reference<deployment::XExtensionManager> xExtensionManager; + //synchronize shared before bundled otherewise there are + //more revoke and registration calls. + sal_Bool bModified = false; + if (needToSyncRepostitory(OUString(RTL_CONSTASCII_USTRINGPARAM("shared"))) + || needToSyncRepostitory(OUString(RTL_CONSTASCII_USTRINGPARAM("bundled")))) + { + xExtensionManager = + deployment::ExtensionManager::get( + comphelper_getProcessComponentContext()); + + if (xExtensionManager.is()) + { + bModified = xExtensionManager->synchronize( + Reference<task::XAbortChannel>(), xCmdEnv); + } + } + + if (bModified) + { + Reference<task::XRestartManager> restarter( + comphelper_getProcessComponentContext()->getValueByName( + OUSTR( "/singletons/com.sun.star.task.OfficeRestartManager") ), UNO_QUERY ); + if (restarter.is()) + { + OSL_TRACE( "Request restart for modified extensions manager" ); + restarter->requestRestart(xCmdEnv.is() == sal_True ? xCmdEnv->getInteractionHandler() : + Reference<task::XInteractionHandler>()); + } + } +} + + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/misc/dp_misc.hrc b/desktop/source/deployment/misc/dp_misc.hrc new file mode 100644 index 000000000000..55fabac5c5b5 --- /dev/null +++ b/desktop/source/deployment/misc/dp_misc.hrc @@ -0,0 +1,33 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_MISC_HRC +#define INCLUDED_DP_MISC_HRC + +#include "deployment.hrc" + +#endif diff --git a/desktop/source/deployment/misc/dp_misc.src b/desktop/source/deployment/misc/dp_misc.src new file mode 100644 index 000000000000..0d341122af16 --- /dev/null +++ b/desktop/source/deployment/misc/dp_misc.src @@ -0,0 +1,40 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "dp_misc.hrc" + +String RID_DEPLYOMENT_DEPENDENCIES_UNKNOWN { + Text[en-US] = "Unknown"; +}; + +String RID_DEPLYOMENT_DEPENDENCIES_MIN { + Text[en-US] = "Extensions requires at least OpenOffice.org %VERSION"; +}; + +String RID_DEPLYOMENT_DEPENDENCIES_MAX { + Text[en-US] = "Extension doesn't support versions greater than: OpenOffice.org %VERSION"; +}; diff --git a/desktop/source/deployment/misc/dp_platform.cxx b/desktop/source/deployment/misc/dp_platform.cxx new file mode 100644 index 000000000000..459e7da4b5f0 --- /dev/null +++ b/desktop/source/deployment/misc/dp_platform.cxx @@ -0,0 +1,247 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_misc.h" +#include "dp_platform.hxx" +#include "rtl/ustring.hxx" +#include "rtl/ustrbuf.hxx" +#include "rtl/instance.hxx" +#include "rtl/bootstrap.hxx" + +#define PLATFORM_ALL "all" +#define PLATFORM_WIN_X86 "windows_x86" +#define PLATFORM_LINUX_X86 "linux_x86" +#define PLATFORM_LINUX_X86_64 "linux_x86_64" +#define PLATFORM_KFREEBSD_X86 "kfreebsd_x86" +#define PLATFORM_KFREEBSD_X86_64 "kfreebsd_x86_64" +#define PLATFORM_LINUX_SPARC "linux_sparc" +#define PLATFORM_LINUX_POWERPC "linux_powerpc" +#define PLATFORM_LINUX_POWERPC64 "linux_powerpc64" +#define PLATFORM_LINUX_ARM_EABI "linux_arm_eabi" +#define PLATFORM_LINUX_ARM_OABI "linux_arm_oabi" +#define PLATFORM_LINUX_MIPS_EL "linux_mips_el" +#define PLATFORM_LINUX_MIPS_EB "linux_mips_eb" +#define PLATFORM_LINUX_IA64 "linux_ia64" +#define PLATFORM_LINUX_M68K "linux_m68k" +#define PLATFORM_LINUX_S390 "linux_s390" +#define PLATFORM_LINUX_S390x "linux_s390x" +#define PLATFORM_LINUX_HPPA "linux_hppa" +#define PLATFORM_LINUX_ALPHA "linux_alpha" + + + +#define PLATFORM_SOLARIS_SPARC "solaris_sparc" +#define PLATFORM_SOLARIS_SPARC64 "solaris_sparc64" +#define PLATFORM_SOLARIS_X86 "solaris_x86" +#define PLATFORM_FREEBSD_X86 "freebsd_x86" +#define PLATFORM_FREEBSD_X86_64 "freebsd_x86_64" +#define PLATFORM_NETBSD_X86 "netbsd_x86" +#define PLATFORM_NETBSD_X86_64 "netbsd_x86_64" +#define PLATFORM_MACOSX_X86 "macosx_x86" +#define PLATFORM_MACOSX_PPC "macosx_powerpc" +#define PLATFORM_OS2_X86 "os2_x86" +#define PLATFORM_OPENBSD_X86 "openbsd_x86" +#define PLATFORM_OPENBSD_X86_64 "openbsd_x86_64" + + +#define PLATFORM_AIX_POWERPC "aix_powerpc" + + + + + + + +#define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) +using ::rtl::OUString; +namespace css = ::com::sun::star; + +namespace dp_misc +{ +namespace +{ + struct StrOperatingSystem : + public rtl::StaticWithInit<const OUString, StrOperatingSystem> { + const OUString operator () () { + OUString os( RTL_CONSTASCII_USTRINGPARAM("$_OS") ); + ::rtl::Bootstrap::expandMacros( os ); + return os; + } + }; + + struct StrCPU : + public rtl::StaticWithInit<const OUString, StrCPU> { + const OUString operator () () { + OUString arch( RTL_CONSTASCII_USTRINGPARAM("$_ARCH") ); + ::rtl::Bootstrap::expandMacros( arch ); + return arch; + } + }; + + + struct StrPlatform : public rtl::StaticWithInit< + const OUString, StrPlatform> { + const OUString operator () () { + ::rtl::OUStringBuffer buf; + buf.append( StrOperatingSystem::get() ); + buf.append( static_cast<sal_Unicode>('_') ); + buf.append( StrCPU::get() ); + return buf.makeStringAndClear(); + } + }; + + bool checkOSandCPU(OUString const & os, OUString const & cpu) + { + return os.equals(StrOperatingSystem::get()) + && cpu.equals(StrCPU::get()); + } + + bool isValidPlatform(OUString const & token ) + { + bool ret = false; + if (token.equals(OUSTR(PLATFORM_ALL))) + ret = true; + else if (token.equals(OUSTR(PLATFORM_WIN_X86))) + ret = checkOSandCPU(OUSTR("Windows"), OUSTR("x86")); + else if (token.equals(OUSTR(PLATFORM_LINUX_X86))) + ret = checkOSandCPU(OUSTR("Linux"), OUSTR("x86")); + else if (token.equals(OUSTR(PLATFORM_LINUX_X86_64))) + ret = checkOSandCPU(OUSTR("Linux"), OUSTR("X86_64")); + else if (token.equals(OUSTR(PLATFORM_KFREEBSD_X86))) + ret = checkOSandCPU(OUSTR("kFreeBSD"), OUSTR("x86")); + else if (token.equals(OUSTR(PLATFORM_KFREEBSD_X86_64))) + ret = checkOSandCPU(OUSTR("kFreeBSD"), OUSTR("X86_64")); + else if (token.equals(OUSTR(PLATFORM_LINUX_SPARC))) + ret = checkOSandCPU(OUSTR("Linux"), OUSTR("SPARC")); + else if (token.equals(OUSTR(PLATFORM_LINUX_POWERPC))) + ret = checkOSandCPU(OUSTR("Linux"), OUSTR("PowerPC")); + else if (token.equals(OUSTR(PLATFORM_LINUX_POWERPC64))) + ret = checkOSandCPU(OUSTR("Linux"), OUSTR("PowerPC_64")); + else if (token.equals(OUSTR(PLATFORM_LINUX_ARM_EABI))) + ret = checkOSandCPU(OUSTR("Linux"), OUSTR("ARM_EABI")); + else if (token.equals(OUSTR(PLATFORM_LINUX_ARM_OABI))) + ret = checkOSandCPU(OUSTR("Linux"), OUSTR("ARM_OABI")); + else if (token.equals(OUSTR(PLATFORM_LINUX_MIPS_EL))) + ret = checkOSandCPU(OUSTR("Linux"), OUSTR("MIPS_EL")); + else if (token.equals(OUSTR(PLATFORM_LINUX_MIPS_EB))) + ret = checkOSandCPU(OUSTR("Linux"), OUSTR("MIPS_EB")); + else if (token.equals(OUSTR(PLATFORM_LINUX_IA64))) + ret = checkOSandCPU(OUSTR("Linux"), OUSTR("IA64")); + else if (token.equals(OUSTR(PLATFORM_LINUX_M68K))) + ret = checkOSandCPU(OUSTR("Linux"), OUSTR("M68K")); + else if (token.equals(OUSTR(PLATFORM_LINUX_S390))) + ret = checkOSandCPU(OUSTR("Linux"), OUSTR("S390")); + else if (token.equals(OUSTR(PLATFORM_LINUX_S390x))) + ret = checkOSandCPU(OUSTR("Linux"), OUSTR("S390x")); + else if (token.equals(OUSTR(PLATFORM_LINUX_HPPA))) + ret = checkOSandCPU(OUSTR("Linux"), OUSTR("HPPA")); + else if (token.equals(OUSTR(PLATFORM_LINUX_ALPHA))) + ret = checkOSandCPU(OUSTR("Linux"), OUSTR("ALPHA")); + else if (token.equals(OUSTR(PLATFORM_SOLARIS_SPARC))) + ret = checkOSandCPU(OUSTR("Solaris"), OUSTR("SPARC")); + else if (token.equals(OUSTR(PLATFORM_SOLARIS_SPARC64))) + ret = checkOSandCPU(OUSTR("Solaris"), OUSTR("SPARC64")); + else if (token.equals(OUSTR(PLATFORM_SOLARIS_X86))) + ret = checkOSandCPU(OUSTR("Solaris"), OUSTR("x86")); + else if (token.equals(OUSTR(PLATFORM_FREEBSD_X86))) + ret = checkOSandCPU(OUSTR("FreeBSD"), OUSTR("x86")); + else if (token.equals(OUSTR(PLATFORM_FREEBSD_X86_64))) + ret = checkOSandCPU(OUSTR("FreeBSD"), OUSTR("X86_64")); + else if (token.equals(OUSTR(PLATFORM_NETBSD_X86))) + ret = checkOSandCPU(OUSTR("NetBSD"), OUSTR("x86")); + else if (token.equals(OUSTR(PLATFORM_NETBSD_X86_64))) + ret = checkOSandCPU(OUSTR("NetBSD"), OUSTR("X86_64")); + else if (token.equals(OUSTR(PLATFORM_MACOSX_X86))) + ret = checkOSandCPU(OUSTR("MacOSX"), OUSTR("x86")); + else if (token.equals(OUSTR(PLATFORM_MACOSX_PPC))) + ret = checkOSandCPU(OUSTR("MacOSX"), OUSTR("PowerPC")); + else if (token.equals(OUSTR(PLATFORM_OS2_X86))) + ret = checkOSandCPU(OUSTR("OS2"), OUSTR("x86")); + else if (token.equals(OUSTR(PLATFORM_AIX_POWERPC))) + ret = checkOSandCPU(OUSTR("AIX"), OUSTR("PowerPC")); + else if (token.equals(OUSTR(PLATFORM_OPENBSD_X86))) + ret = checkOSandCPU(OUSTR("OpenBSD"), OUSTR("x86")); + else if (token.equals(OUSTR(PLATFORM_OPENBSD_X86_64))) + ret = checkOSandCPU(OUSTR("OpenBSD"), OUSTR("X86_64")); + else + { + OSL_ENSURE(0, "Extension Manager: The extension supports an unknown platform. " + "Check the platform element in the description.xml"); + ret = false; + } + return ret; + } + +} // anon namespace +//============================================================================= + +OUString const & getPlatformString() +{ + return StrPlatform::get(); +} + +bool platform_fits( OUString const & platform_string ) +{ + sal_Int32 index = 0; + for (;;) + { + const OUString token( + platform_string.getToken( 0, ',', index ).trim() ); + // check if this platform: + if (token.equalsIgnoreAsciiCase( StrPlatform::get() ) || + (token.indexOf( '_' ) < 0 && /* check OS part only */ + token.equalsIgnoreAsciiCase( StrOperatingSystem::get() ))) + { + return true; + } + if (index < 0) + break; + } + return false; +} + +bool hasValidPlatform( css::uno::Sequence<OUString> const & platformStrings) +{ + bool ret = false; + for (sal_Int32 i = 0; i < platformStrings.getLength(); i++) + { + if (isValidPlatform(platformStrings[i])) + { + ret = true; + break; + } + } + return ret; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/misc/dp_resource.cxx b/desktop/source/deployment/misc/dp_resource.cxx new file mode 100644 index 000000000000..ddf50090e99b --- /dev/null +++ b/desktop/source/deployment/misc/dp_resource.cxx @@ -0,0 +1,235 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_misc.h" +#include "dp_resource.h" +#include "osl/module.hxx" +#include "osl/mutex.hxx" +#include "rtl/ustring.h" +#include "cppuhelper/implbase1.hxx" +#include "unotools/configmgr.hxx" + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using ::rtl::OUString; + +namespace dp_misc { +namespace { + +struct OfficeLocale : + public rtl::StaticWithInit<const OUString, OfficeLocale> { + const OUString operator () () { + OUString slang; + if (! (::utl::ConfigManager::GetDirectConfigProperty( + ::utl::ConfigManager::LOCALE ) >>= slang)) + throw RuntimeException( OUSTR("Cannot determine language!"), 0 ); + //fallback, the locale is currently only set when the user starts the + //office for the first time. + if (slang.getLength() == 0) + slang = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("en-US")); + return slang; + } +}; + +struct DeploymentResMgr : public rtl::StaticWithInit< + ResMgr *, DeploymentResMgr> { + ResMgr * operator () () { + return ResMgr::CreateResMgr( "deployment", getOfficeLocale() ); + } +}; + +osl::Mutex s_mutex; + +} // anon namespace + +//============================================================================== +ResId getResId( USHORT id ) +{ + const osl::MutexGuard guard( s_mutex ); + return ResId( id, *DeploymentResMgr::get() ); +} + +//============================================================================== +String getResourceString( USHORT id ) +{ + const osl::MutexGuard guard( s_mutex ); + String ret( ResId( id, *DeploymentResMgr::get() ) ); + if (ret.SearchAscii( "%PRODUCTNAME" ) != STRING_NOTFOUND) { + static String s_brandName; + if (s_brandName.Len() == 0) { + OUString brandName( + ::utl::ConfigManager::GetDirectConfigProperty( + ::utl::ConfigManager::PRODUCTNAME ).get<OUString>() ); + s_brandName = brandName; + } + ret.SearchAndReplaceAllAscii( "%PRODUCTNAME", s_brandName ); + } + return ret; +} + +//throws an Exception on failure +//primary subtag 2 or three letters(A-Z, a-z), i or x +void checkPrimarySubtag(::rtl::OUString const & tag) +{ + sal_Int32 len = tag.getLength(); + sal_Unicode const * arLang = tag.getStr(); + if (len < 1 || len > 3) + throw Exception(OUSTR("Invalid language string."), 0); + + if (len == 1 + && (arLang[0] != 'i' && arLang[0] != 'x')) + throw Exception(OUSTR("Invalid language string."), 0); + + if (len == 2 || len == 3) + { + for (sal_Int32 i = 0; i < len; i++) + { + if ( !((arLang[i] >= 'A' && arLang[i] <= 'Z') + || (arLang[i] >= 'a' && arLang[i] <= 'z'))) + { + throw Exception(OUSTR("Invalid language string."), 0); + } + } + } +} + +//throws an Exception on failure +//second subtag 2 letter country code or 3-8 letter other code(A-Z, a-z, 0-9) +void checkSecondSubtag(::rtl::OUString const & tag, bool & bIsCountry) +{ + sal_Int32 len = tag.getLength(); + sal_Unicode const * arLang = tag.getStr(); + if (len < 2 || len > 8) + throw Exception(OUSTR("Invalid language string."), 0); + //country code + bIsCountry = false; + if (len == 2) + { + for (sal_Int32 i = 0; i < 2; i++) + { + if (!( (arLang[i] >= 'A' && arLang[i] <= 'Z') + || (arLang[i] >= 'a' && arLang[i] <= 'z'))) + { + throw Exception(OUSTR("Invalid language string."), 0); + } + } + bIsCountry = true; + } + + if (len > 2) + { + for (sal_Int32 i = 0; i < len; i++) + { + if (!( (arLang[i] >= 'A' && arLang[i] <= 'Z') + || (arLang[i] >= 'a' && arLang[i] <= 'z') + || (arLang[i] >= '0' && arLang[i] <= '9') )) + { + throw Exception(OUSTR("Invalid language string."), 0); + } + } + } +} + +void checkThirdSubtag(::rtl::OUString const & tag) +{ + sal_Int32 len = tag.getLength(); + sal_Unicode const * arLang = tag.getStr(); + if (len < 1 || len > 8) + throw Exception(OUSTR("Invalid language string."), 0); + + for (sal_Int32 i = 0; i < len; i++) + { + if (!( (arLang[i] >= 'A' && arLang[i] <= 'Z') + || (arLang[i] >= 'a' && arLang[i] <= 'z') + || (arLang[i] >= '0' && arLang[i] <= '9') )) + { + throw Exception(OUSTR("Invalid language string."), 0); + } + } +} + +//============================================================================= + +//We parse the string acording to RFC 3066 +//We only use the primary sub-tag and two subtags. That is lang-country-variant +//We do some simple tests if the string is correct. Actually this should do a +//validating parser +//We may have the case that there is no country tag, for example en-welsh +::com::sun::star::lang::Locale toLocale( ::rtl::OUString const & slang ) +{ + OUString _sLang = slang.trim(); + ::com::sun::star::lang::Locale locale; + sal_Int32 nIndex = 0; + OUString lang = _sLang.getToken( 0, '-', nIndex ); + checkPrimarySubtag(lang); + locale.Language = lang; + OUString country = _sLang.getToken( 0, '-', nIndex ); + if (country.getLength() > 0) + { + bool bIsCountry = false; + checkSecondSubtag(country, bIsCountry); + if (bIsCountry) + { + locale.Country = country; + } + else + { + locale.Variant = country; + } + } + if (locale.Variant.getLength() == 0) + { + OUString variant = _sLang.getToken( 0, '-', nIndex ); + if (variant.getLength() > 0) + { + checkThirdSubtag(variant); + locale.Variant = variant; + } + } + + return locale; +} + +//============================================================================== +lang::Locale getOfficeLocale() +{ + return toLocale(OfficeLocale::get()); +} + +::rtl::OUString getOfficeLocaleString() +{ + return OfficeLocale::get(); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/misc/dp_ucb.cxx b/desktop/source/deployment/misc/dp_ucb.cxx new file mode 100644 index 000000000000..fa3896aab8c4 --- /dev/null +++ b/desktop/source/deployment/misc/dp_ucb.cxx @@ -0,0 +1,323 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_misc.hrc" +#include "dp_misc.h" +#include "dp_ucb.h" +#include "rtl/uri.hxx" +#include "rtl/ustrbuf.hxx" +#include "ucbhelper/content.hxx" +#include "xmlscript/xml_helper.hxx" +#include "com/sun/star/io/XInputStream.hpp" +#include "com/sun/star/ucb/CommandFailedException.hpp" +#include "com/sun/star/ucb/ContentInfo.hpp" +#include "com/sun/star/ucb/ContentInfoAttribute.hpp" + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using ::rtl::OUString; + +namespace dp_misc +{ + +const OUString StrTitle::operator () () +{ + return OUSTR("Title"); +} + +//============================================================================== +bool create_ucb_content( + ::ucbhelper::Content * ret_ucbContent, OUString const & url, + Reference<XCommandEnvironment> const & xCmdEnv, + bool throw_exc ) +{ + try { + // Existense check... + // content ctor/isFolder() will throw exception in case the resource + // does not exist. + + // dilemma: no chance to use the given iahandler here, because it would + // raise no such file dialogs, else no interaction for + // passwords, ...? xxx todo + ::ucbhelper::Content ucbContent( + url, Reference<XCommandEnvironment>() ); + + ucbContent.isFolder(); + + if (ret_ucbContent != 0) + { + ucbContent.setCommandEnvironment( xCmdEnv ); + *ret_ucbContent = ucbContent; + } + return true; + } + catch (RuntimeException &) { + throw; + } + catch (Exception &) { + if (throw_exc) + throw; + } + return false; +} + +//============================================================================== +bool create_folder( + ::ucbhelper::Content * ret_ucb_content, OUString const & url_, + Reference<XCommandEnvironment> const & xCmdEnv, bool throw_exc ) +{ + ::ucbhelper::Content ucb_content; + if (create_ucb_content( + &ucb_content, url_, xCmdEnv, false /* no throw */ )) + { + if (ucb_content.isFolder()) { + if (ret_ucb_content != 0) + *ret_ucb_content = ucb_content; + return true; + } + } + + OUString url( url_ ); + // xxx todo: find parent + sal_Int32 slash = url.lastIndexOf( '/' ); + if (slash < 0) { + // fallback: + url = expandUnoRcUrl( url ); + slash = url.lastIndexOf( '/' ); + } + if (slash < 0) { + // invalid: has to be at least "auth:/..." + if (throw_exc) + throw ContentCreationException( + OUSTR("Cannot create folder (invalid path): ") + url, + Reference<XInterface>(), ContentCreationError_UNKNOWN ); + return false; + } + ::ucbhelper::Content parentContent; + if (! create_folder( + &parentContent, url.copy( 0, slash ), xCmdEnv, throw_exc )) + return false; + const Any title( ::rtl::Uri::decode( url.copy( slash + 1 ), + rtl_UriDecodeWithCharset, + RTL_TEXTENCODING_UTF8 ) ); + const Sequence<ContentInfo> infos( + parentContent.queryCreatableContentsInfo() ); + for ( sal_Int32 pos = 0; pos < infos.getLength(); ++pos ) + { + // look KIND_FOLDER: + ContentInfo const & info = infos[ pos ]; + if ((info.Attributes & ContentInfoAttribute::KIND_FOLDER) != 0) + { + // make sure the only required bootstrap property is "Title": + Sequence<beans::Property> const & rProps = info.Properties; + if (rProps.getLength() != 1 || + !rProps[ 0 ].Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("Title") )) + continue; + + try { + if (parentContent.insertNewContent( + info.Type, + Sequence<OUString>( &StrTitle::get(), 1 ), + Sequence<Any>( &title, 1 ), + ucb_content )) { + if (ret_ucb_content != 0) + *ret_ucb_content = ucb_content; + return true; + } + } + catch (RuntimeException &) { + throw; + } + catch (CommandFailedException &) { + // Interaction Handler already handled the error + // that has occurred... + } + catch (Exception &) { + if (throw_exc) + throw; + return false; + } + } + } + if (throw_exc) + throw ContentCreationException( + OUSTR("Cannot create folder: ") + url, + Reference<XInterface>(), ContentCreationError_UNKNOWN ); + return false; +} + +//============================================================================== +bool erase_path( OUString const & url, + Reference<XCommandEnvironment> const & xCmdEnv, + bool throw_exc ) +{ + ::ucbhelper::Content ucb_content; + if (create_ucb_content( &ucb_content, url, xCmdEnv, false /* no throw */ )) + { + try { + ucb_content.executeCommand( + OUSTR("delete"), Any( true /* delete physically */ ) ); + } + catch (RuntimeException &) { + throw; + } + catch (Exception &) { + if (throw_exc) + throw; + return false; + } + } + return true; +} + +//============================================================================== +::rtl::ByteSequence readFile( ::ucbhelper::Content & ucb_content ) +{ + ::rtl::ByteSequence bytes; + Reference<io::XOutputStream> xStream( + ::xmlscript::createOutputStream( &bytes ) ); + if (! ucb_content.openStream( xStream )) + throw RuntimeException( + OUSTR( + "::ucbhelper::Content::openStream( XOutputStream ) failed!"), + 0 ); + return bytes; +} + +//============================================================================== +bool readLine( OUString * res, OUString const & startingWith, + ::ucbhelper::Content & ucb_content, rtl_TextEncoding textenc ) +{ + // read whole file: + ::rtl::ByteSequence bytes( readFile( ucb_content ) ); + OUString file( reinterpret_cast<sal_Char const *>(bytes.getConstArray()), + bytes.getLength(), textenc ); + sal_Int32 pos = 0; + for (;;) + { + if (file.match( startingWith, pos )) + { + ::rtl::OUStringBuffer buf; + sal_Int32 start = pos; + pos += startingWith.getLength(); + for (;;) + { + pos = file.indexOf( LF, pos ); + if (pos < 0) { // EOF + buf.append( file.copy( start ) ); + } + else + { + if (pos > 0 && file[ pos - 1 ] == CR) + { + // consume extra CR + buf.append( file.copy( start, pos - start - 1 ) ); + ++pos; + } + else + buf.append( file.copy( start, pos - start ) ); + ++pos; // consume LF + // check next line: + if (pos < file.getLength() && + (file[ pos ] == ' ' || file[ pos ] == '\t')) + { + buf.append( static_cast<sal_Unicode>(' ') ); + ++pos; + start = pos; + continue; + } + } + break; + } + *res = buf.makeStringAndClear(); + return true; + } + // next line: + sal_Int32 next_lf = file.indexOf( LF, pos ); + if (next_lf < 0) // EOF + break; + pos = next_lf + 1; + } + return false; +} + +bool readProperties( ::std::list< ::std::pair< ::rtl::OUString, ::rtl::OUString> > & out_result, + ::ucbhelper::Content & ucb_content ) +{ + // read whole file: + ::rtl::ByteSequence bytes( readFile( ucb_content ) ); + OUString file( reinterpret_cast<sal_Char const *>(bytes.getConstArray()), + bytes.getLength(), RTL_TEXTENCODING_UTF8); + sal_Int32 pos = 0; + + for (;;) + { + + ::rtl::OUStringBuffer buf; + sal_Int32 start = pos; + + bool bEOF = false; + pos = file.indexOf( LF, pos ); + if (pos < 0) { // EOF + buf.append( file.copy( start ) ); + bEOF = true; + } + else + { + if (pos > 0 && file[ pos - 1 ] == CR) + // consume extra CR + buf.append( file.copy( start, pos - start - 1 ) ); + else + buf.append( file.copy( start, pos - start ) ); + pos++; + } + OUString aLine = buf.makeStringAndClear(); + + sal_Int32 posEqual = aLine.indexOf('='); + if (posEqual > 0 && (posEqual + 1) < aLine.getLength()) + { + OUString name = aLine.copy(0, posEqual); + OUString value = aLine.copy(posEqual + 1); + out_result.push_back(::std::make_pair(name, value)); + } + + if (bEOF) + break; + } + return false; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/misc/dp_update.cxx b/desktop/source/deployment/misc/dp_update.cxx new file mode 100644 index 000000000000..5455dbd3d9e6 --- /dev/null +++ b/desktop/source/deployment/misc/dp_update.cxx @@ -0,0 +1,441 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + + +#include "dp_update.hxx" +#include "dp_version.hxx" +#include "dp_identifier.hxx" +#include "dp_descriptioninfoset.hxx" + +#include "rtl/bootstrap.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using ::rtl::OUString; +using ::rtl::OString; + + +namespace dp_misc { +namespace { + +int determineHighestVersion( + ::rtl::OUString const & userVersion, + ::rtl::OUString const & sharedVersion, + ::rtl::OUString const & bundledVersion, + ::rtl::OUString const & onlineVersion) +{ + int index = 0; + OUString greatest = userVersion; + if (dp_misc::compareVersions(sharedVersion, greatest) == dp_misc::GREATER) + { + index = 1; + greatest = sharedVersion; + } + if (dp_misc::compareVersions(bundledVersion, greatest) == dp_misc::GREATER) + { + index = 2; + greatest = bundledVersion; + } + if (dp_misc::compareVersions(onlineVersion, greatest) == dp_misc::GREATER) + { + index = 3; + } + return index; +} + +Sequence< Reference< xml::dom::XElement > > +getUpdateInformation( Reference<deployment::XUpdateInformationProvider > const & updateInformation, + Sequence< OUString > const & urls, + OUString const & identifier, + uno::Any & out_error) +{ + try { + return updateInformation->getUpdateInformation(urls, identifier); + } catch (uno::RuntimeException &) { + throw; + } catch (ucb::CommandFailedException & e) { + out_error = e.Reason; + } catch (ucb::CommandAbortedException &) { + } catch (uno::Exception & e) { + out_error = uno::makeAny(e); + } + return + Sequence<Reference< xml::dom::XElement > >(); +} + +void getOwnUpdateInfos( + Reference<uno::XComponentContext> const & xContext, + Reference<deployment::XUpdateInformationProvider > const & updateInformation, + UpdateInfoMap& inout_map, std::vector<std::pair<Reference<deployment::XPackage>, uno::Any> > & out_errors, + bool & out_allFound) +{ + bool allHaveOwnUpdateInformation = true; + for (UpdateInfoMap::iterator i = inout_map.begin(); i != inout_map.end(); ++i) + { + OSL_ASSERT(i->second.extension.is()); + Sequence<OUString> urls(i->second.extension->getUpdateInformationURLs()); + if (urls.getLength()) + { + const OUString id = dp_misc::getIdentifier(i->second.extension); + uno::Any anyError; + //It is unclear from the idl if there can be a null reference returned. + //However all valid information should be the same + Sequence<Reference< xml::dom::XElement > > + infos(getUpdateInformation(updateInformation, urls, id, anyError)); + if (anyError.hasValue()) + out_errors.push_back(std::make_pair(i->second.extension, anyError)); + + for (sal_Int32 j = 0; j < infos.getLength(); ++j) + { + dp_misc::DescriptionInfoset infoset( + xContext, + Reference< xml::dom::XNode >(infos[j], UNO_QUERY_THROW)); + if (!infoset.hasDescription()) + continue; + boost::optional< OUString > id2(infoset.getIdentifier()); + if (!id2) + continue; + OSL_ASSERT(*id2 == id); + if (*id2 == id) + { + i->second.version = infoset.getVersion(); + i->second.info = Reference< xml::dom::XNode >( + infos[j], UNO_QUERY_THROW); + } + break; + } + } + else + { + allHaveOwnUpdateInformation &= false; + } + } + out_allFound = allHaveOwnUpdateInformation; +} + +void getDefaultUpdateInfos( + Reference<uno::XComponentContext> const & xContext, + Reference<deployment::XUpdateInformationProvider > const & updateInformation, + UpdateInfoMap& inout_map, + std::vector<std::pair<Reference<deployment::XPackage>, uno::Any> > & out_errors) +{ + const rtl::OUString sDefaultURL(dp_misc::getExtensionDefaultUpdateURL()); + OSL_ASSERT(sDefaultURL.getLength()); + + Any anyError; + Sequence< Reference< xml::dom::XElement > > + infos( + getUpdateInformation( + updateInformation, + Sequence< OUString >(&sDefaultURL, 1), OUString(), anyError)); + if (anyError.hasValue()) + out_errors.push_back(std::make_pair(Reference<deployment::XPackage>(), anyError)); + for (sal_Int32 i = 0; i < infos.getLength(); ++i) + { + Reference< xml::dom::XNode > node(infos[i], UNO_QUERY_THROW); + dp_misc::DescriptionInfoset infoset(xContext, node); + boost::optional< OUString > id(infoset.getIdentifier()); + if (!id) { + continue; + } + UpdateInfoMap::iterator j = inout_map.find(*id); + if (j != inout_map.end()) + { + //skip those extension which provide its own update urls + if (j->second.extension->getUpdateInformationURLs().getLength()) + continue; + OUString v(infoset.getVersion()); + //look for the highest version in the online repository + if (dp_misc::compareVersions(v, j->second.version) == + dp_misc::GREATER) + { + j->second.version = v; + j->second.info = node; + } + } + } +} + +bool containsBundledOnly(Sequence<Reference<deployment::XPackage> > const & sameIdExtensions) +{ + OSL_ASSERT(sameIdExtensions.getLength() == 3); + return !sameIdExtensions[0].is() && !sameIdExtensions[1].is() && sameIdExtensions[2].is(); +} + +/** Returns true if the list of extensions are bundled extensions and there are no + other extensions with the same identifier in the shared or user repository. + If extensionList is NULL, then it is checked if there are only bundled extensions. +*/ +bool onlyBundledExtensions( + Reference<deployment::XExtensionManager> const & xExtMgr, + std::vector< Reference<deployment::XPackage > > const * extensionList) +{ + OSL_ASSERT(xExtMgr.is()); + bool onlyBundled = true; + if (extensionList) + { + typedef std::vector<Reference<deployment::XPackage > >::const_iterator CIT; + for (CIT i(extensionList->begin()), aEnd(extensionList->end()); onlyBundled && i != aEnd; ++i) + { + Sequence<Reference<deployment::XPackage> > seqExt = xExtMgr->getExtensionsWithSameIdentifier( + dp_misc::getIdentifier(*i), (*i)->getName(), Reference<ucb::XCommandEnvironment>()); + + onlyBundled = containsBundledOnly(seqExt); + } + } + else + { + const uno::Sequence< uno::Sequence< Reference<deployment::XPackage > > > seqAllExt = + xExtMgr->getAllExtensions(Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>()); + + for (int pos(0), nLen(seqAllExt.getLength()); onlyBundled && pos != nLen; ++pos) + { + onlyBundled = containsBundledOnly(seqAllExt[pos]); + } + } + return onlyBundled; +} + +} // anon namespace + + +OUString getExtensionDefaultUpdateURL() +{ + ::rtl::OUString sUrl( + RTL_CONSTASCII_USTRINGPARAM( + "${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE("version") + ":Version:ExtensionUpdateURL}")); + ::rtl::Bootstrap::expandMacros(sUrl); + return sUrl; +} + +/* returns the index of the greatest version, starting with 0 + + */ +UPDATE_SOURCE isUpdateUserExtension( + bool bReadOnlyShared, + ::rtl::OUString const & userVersion, + ::rtl::OUString const & sharedVersion, + ::rtl::OUString const & bundledVersion, + ::rtl::OUString const & onlineVersion) +{ + UPDATE_SOURCE retVal = UPDATE_SOURCE_NONE; + if (bReadOnlyShared) + { + if (userVersion.getLength()) + { + int index = determineHighestVersion( + userVersion, sharedVersion, bundledVersion, onlineVersion); + if (index == 1) + retVal = UPDATE_SOURCE_SHARED; + else if (index == 2) + retVal = UPDATE_SOURCE_BUNDLED; + else if (index == 3) + retVal = UPDATE_SOURCE_ONLINE; + } + else if (sharedVersion.getLength()) + { + int index = determineHighestVersion( + OUString(), sharedVersion, bundledVersion, onlineVersion); + if (index == 2) + retVal = UPDATE_SOURCE_BUNDLED; + else if (index == 3) + retVal = UPDATE_SOURCE_ONLINE; + + } + //No update for bundled extensions, they are updated only by the setup + //else if (bundledVersion.getLength()) + //{ + // int index = determineHighestVersion( + // OUString(), OUString(), bundledVersion, onlineVersion); + // if (index == 3) + // retVal = UPDATE_SOURCE_ONLINE; + //} + } + else + { + if (userVersion.getLength()) + { + int index = determineHighestVersion( + userVersion, sharedVersion, bundledVersion, onlineVersion); + if (index == 1) + retVal = UPDATE_SOURCE_SHARED; + else if (index == 2) + retVal = UPDATE_SOURCE_BUNDLED; + else if (index == 3) + retVal = UPDATE_SOURCE_ONLINE; + } + } + + return retVal; +} + +UPDATE_SOURCE isUpdateSharedExtension( + bool bReadOnlyShared, + ::rtl::OUString const & sharedVersion, + ::rtl::OUString const & bundledVersion, + ::rtl::OUString const & onlineVersion) +{ + if (bReadOnlyShared) + return UPDATE_SOURCE_NONE; + UPDATE_SOURCE retVal = UPDATE_SOURCE_NONE; + + if (sharedVersion.getLength()) + { + int index = determineHighestVersion( + OUString(), sharedVersion, bundledVersion, onlineVersion); + if (index == 2) + retVal = UPDATE_SOURCE_BUNDLED; + else if (index == 3) + retVal = UPDATE_SOURCE_ONLINE; + } + //No update for bundled extensions, they are updated only by the setup + //else if (bundledVersion.getLength()) + //{ + // int index = determineHighestVersion( + // OUString(), OUString(), bundledVersion, onlineVersion); + // if (index == 3) + // retVal = UPDATE_SOURCE_ONLINE; + //} + return retVal; +} + +Reference<deployment::XPackage> +getExtensionWithHighestVersion( + Sequence<Reference<deployment::XPackage> > const & seqExt) +{ + if (seqExt.getLength() == 0) + return Reference<deployment::XPackage>(); + + Reference<deployment::XPackage> greatest; + sal_Int32 len = seqExt.getLength(); + + for (sal_Int32 i = 0; i < len; i++) + { + if (!greatest.is()) + { + greatest = seqExt[i]; + continue; + } + Reference<deployment::XPackage> const & current = seqExt[i]; + //greatest has a value + if (! current.is()) + continue; + + if (dp_misc::compareVersions(current->getVersion(), greatest->getVersion()) == dp_misc::GREATER) + greatest = current; + } + return greatest; +} + +UpdateInfo::UpdateInfo( Reference< deployment::XPackage> const & ext): +extension(ext) +{ +} + + + +UpdateInfoMap getOnlineUpdateInfos( + Reference<uno::XComponentContext> const &xContext, + Reference<deployment::XExtensionManager> const & xExtMgr, + Reference<deployment::XUpdateInformationProvider > const & updateInformation, + std::vector<Reference<deployment::XPackage > > const * extensionList, + std::vector<std::pair< Reference<deployment::XPackage>, uno::Any> > & out_errors) +{ + OSL_ASSERT(xExtMgr.is()); + UpdateInfoMap infoMap; + if (!xExtMgr.is() || onlyBundledExtensions(xExtMgr, extensionList)) + return infoMap; + + if (!extensionList) + { + const uno::Sequence< uno::Sequence< Reference<deployment::XPackage > > > seqAllExt = xExtMgr->getAllExtensions( + Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>()); + + //fill the UpdateInfoMap. key = extension identifier, value = UpdateInfo + for (int pos = seqAllExt.getLength(); pos --; ) + { + uno::Sequence<Reference<deployment::XPackage> > const & seqExt = seqAllExt[pos]; + + Reference<deployment::XPackage> extension = getExtensionWithHighestVersion(seqExt); + OSL_ASSERT(extension.is()); + + std::pair<UpdateInfoMap::iterator, bool> insertRet = infoMap.insert( + UpdateInfoMap::value_type( + dp_misc::getIdentifier(extension), UpdateInfo(extension))); + OSL_ASSERT(insertRet.second == true); + (void)insertRet; + } + } + else + { + typedef std::vector<Reference<deployment::XPackage > >::const_iterator CIT; + for (CIT i = extensionList->begin(); i != extensionList->end(); ++i) + { + OSL_ASSERT(i->is()); + std::pair<UpdateInfoMap::iterator, bool> insertRet = infoMap.insert( + UpdateInfoMap::value_type( + dp_misc::getIdentifier(*i), UpdateInfo(*i))); + OSL_ASSERT(insertRet.second == true); + (void)insertRet; + } + } + + //Now find the update information for the extensions which provide their own + //URLs to update information. + bool allInfosObtained = false; + getOwnUpdateInfos(xContext, updateInformation, infoMap, out_errors, allInfosObtained); + + if (!allInfosObtained) + getDefaultUpdateInfos(xContext, updateInformation, infoMap, out_errors); + return infoMap; +} +OUString getHighestVersion( + ::rtl::OUString const & userVersion, + ::rtl::OUString const & sharedVersion, + ::rtl::OUString const & bundledVersion, + ::rtl::OUString const & onlineVersion) +{ + int index = determineHighestVersion(userVersion, sharedVersion, bundledVersion, onlineVersion); + switch (index) + { + case 0: return userVersion; + case 1: return sharedVersion; + case 2: return bundledVersion; + case 3: return onlineVersion; + default: OSL_ASSERT(0); + } + + return OUString(); +} +} //namespace dp_misc + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/misc/dp_version.cxx b/desktop/source/deployment/misc/dp_version.cxx new file mode 100644 index 000000000000..5c563b7dafb7 --- /dev/null +++ b/desktop/source/deployment/misc/dp_version.cxx @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "sal/config.h" + +#include "com/sun/star/deployment/XPackage.hpp" +#include "rtl/ustring.hxx" + +#include "dp_version.hxx" + +namespace { + +namespace css = ::com::sun::star; + +::rtl::OUString getElement(::rtl::OUString const & version, ::sal_Int32 * index) +{ + while (*index < version.getLength() && version[*index] == '0') { + ++*index; + } + return version.getToken(0, '.', *index); +} + +} + +namespace dp_misc { + +::dp_misc::Order compareVersions( + ::rtl::OUString const & version1, ::rtl::OUString const & version2) +{ + for (::sal_Int32 i1 = 0, i2 = 0; i1 >= 0 || i2 >= 0;) { + ::rtl::OUString e1(getElement(version1, &i1)); + ::rtl::OUString e2(getElement(version2, &i2)); + if (e1.getLength() < e2.getLength()) { + return ::dp_misc::LESS; + } else if (e1.getLength() > e2.getLength()) { + return ::dp_misc::GREATER; + } else if (e1 < e2) { + return ::dp_misc::LESS; + } else if (e1 > e2) { + return ::dp_misc::GREATER; + } + } + return ::dp_misc::EQUAL; +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/misc/makefile.mk b/desktop/source/deployment/misc/makefile.mk new file mode 100644 index 000000000000..3e4bd68cb4c0 --- /dev/null +++ b/desktop/source/deployment/misc/makefile.mk @@ -0,0 +1,95 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/.. + +PRJNAME = desktop +TARGET = deployment_misc +USE_DEFFILE = TRUE +ENABLE_EXCEPTIONS = TRUE +VISIBILITY_HIDDEN=TRUE + +.IF "$(GUI)"=="OS2" +TARGET = deplmisc +.ENDIF + +.INCLUDE : settings.mk + +# Reduction of exported symbols: +CDEFS += -DDESKTOP_DEPLOYMENTMISC_DLLIMPLEMENTATION + +.IF "$(SYSTEM_DB)" == "YES" +CFLAGS+=-DSYSTEM_DB -I$(DB_INCLUDES) +.ENDIF + +SRS1NAME = $(TARGET) +SRC1FILES = \ + dp_misc.src + +.IF "$(GUI)"=="OS2" +SHL1TARGET = $(TARGET) +.ELSE +SHL1TARGET = deploymentmisc$(DLLPOSTFIX) +.ENDIF +SHL1OBJS = \ + $(SLO)$/dp_misc.obj \ + $(SLO)$/dp_resource.obj \ + $(SLO)$/dp_identifier.obj \ + $(SLO)$/dp_interact.obj \ + $(SLO)$/dp_ucb.obj \ + $(SLO)$/db.obj \ + $(SLO)$/dp_version.obj \ + $(SLO)$/dp_descriptioninfoset.obj \ + $(SLO)$/dp_dependencies.obj \ + $(SLO)$/dp_platform.obj \ + $(SLO)$/dp_update.obj + +SHL1STDLIBS = \ + $(BERKELEYLIB) \ + $(CPPUHELPERLIB) \ + $(CPPULIB) \ + $(SALLIB) \ + $(TOOLSLIB) \ + $(UCBHELPERLIB) \ + $(UNOTOOLSLIB) \ + $(XMLSCRIPTLIB) \ + $(COMPHELPERLIB) +.IF "$(GUI)"=="OS2" +SHL1IMPLIB = ideploymentmisc$(DLLPOSTFIX) +LIB1TARGET = $(SLB)$/_deplmisc.lib +LIB1OBJFILES = $(SHL1OBJS) +DEFLIB1NAME = _deplmisc +.ELSE +SHL1IMPLIB = i$(SHL1TARGET) +.ENDIF +DEF1NAME = $(SHL1TARGET) + +SLOFILES = $(SHL1OBJS) + +.INCLUDE : ..$/target.pmk +.INCLUDE : target.mk + diff --git a/desktop/source/deployment/registry/component/dp_compbackenddb.cxx b/desktop/source/deployment/registry/component/dp_compbackenddb.cxx new file mode 100644 index 000000000000..7de93a00cd86 --- /dev/null +++ b/desktop/source/deployment/registry/component/dp_compbackenddb.cxx @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "rtl/string.h" +#include "rtl/bootstrap.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/xml/dom/XDocumentBuilder.hpp" +#include "com/sun/star/xml/xpath/XXPathAPI.hpp" +#include "dp_misc.h" + +#include "dp_compbackenddb.hxx" + + +namespace css = ::com::sun::star; +using namespace ::com::sun::star::uno; +using ::rtl::OUString; + +#define EXTENSION_REG_NS "http://openoffice.org/extensionmanager/component-registry/2010" +#define NS_PREFIX "comp" +#define ROOT_ELEMENT_NAME "component-backend-db" +#define KEY_ELEMENT_NAME "component" + +namespace dp_registry { +namespace backend { +namespace component { + +ComponentBackendDb::ComponentBackendDb( + Reference<XComponentContext> const & xContext, + ::rtl::OUString const & url):BackendDb(xContext, url) +{ + +} + +OUString ComponentBackendDb::getDbNSName() +{ + return OUSTR(EXTENSION_REG_NS); +} + +OUString ComponentBackendDb::getNSPrefix() +{ + return OUSTR(NS_PREFIX); +} + +OUString ComponentBackendDb::getRootElementName() +{ + return OUSTR(ROOT_ELEMENT_NAME); +} + +OUString ComponentBackendDb::getKeyElementName() +{ + return OUSTR(KEY_ELEMENT_NAME); +} + +void ComponentBackendDb::addEntry(::rtl::OUString const & url, Data const & data) +{ + try{ + Reference<css::xml::dom::XNode> componentNode = writeKeyElement(url); + writeSimpleElement(OUSTR("java-type-library"), + OUString::valueOf((sal_Bool) data.javaTypeLibrary), + componentNode); + + writeSimpleList( + data.implementationNames, + OUSTR("implementation-names"), + OUSTR("name"), + componentNode); + + writeVectorOfPair( + data.singletons, + OUSTR("singletons"), + OUSTR("item"), + OUSTR("key"), + OUSTR("value"), + componentNode); + + save(); + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to write data entry in backend db: ") + + m_urlDb, 0, exc); + } +} + +ComponentBackendDb::Data ComponentBackendDb::getEntry(::rtl::OUString const & url) +{ + try + { + ComponentBackendDb::Data retData; + Reference<css::xml::dom::XNode> aNode = getKeyElement(url); + if (aNode.is()) + { + bool bJava = readSimpleElement(OUSTR("java-type-library"), aNode) + .equals(OUSTR("true")) ? true : false; + retData.javaTypeLibrary = bJava; + + retData.implementationNames = + readList( + aNode, + OUSTR("implementation-names"), + OUSTR("name")); + + retData.singletons = + readVectorOfPair( + aNode, + OUSTR("singletons"), + OUSTR("item"), + OUSTR("key"), + OUSTR("value")); + } + return retData; + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to read data entry in backend db: ") + + m_urlDb, 0, exc); + } +} + + +} // namespace bundle +} // namespace backend +} // namespace dp_registry + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/component/dp_compbackenddb.hxx b/desktop/source/deployment/registry/component/dp_compbackenddb.hxx new file mode 100644 index 000000000000..2e0e39eea29c --- /dev/null +++ b/desktop/source/deployment/registry/component/dp_compbackenddb.hxx @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_COMPBACKENDDB_HXX +#define INCLUDED_DP_COMPBACKENDDB_HXX + +#include "rtl/ustring.hxx" +#include "rtl/string.hxx" +#include <vector> +#include <list> +#include "dp_backenddb.hxx" + +namespace css = ::com::sun::star; + +namespace com { namespace sun { namespace star { + namespace uno { + class XComponentContext; + } + namespace xml { namespace dom { + class XDocument; + class XNode; + }} + namespace xml { namespace xpath { + class XXPathAPI; + }} +}}} + +namespace dp_registry { +namespace backend { +namespace component { + +/* The XML file stores the extensions which are currently registered. + They will be removed when they are revoked. + The format looks like this: + +<?xml version="1.0"?> +<component-backend-db xmlns="http://openoffice.org/extensionmanager/component-registry/2010"> + <component url="vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/uno_packages/5CD5.tmp_/leaves1.oxt/extensionoptions.jar"> + <name>FileName</name> + <java-type-library>true</java-type-library> + <implementation-names> + <name>com.sun.star.comp.extensionoptions.OptionsEventHandler$_OptionsEventHandler</name> + ... + </implementation-names> + <singletons> + <item> + <key>com.sun.star.java.theJavaVirtualMachine</key> + <value>com.sun.star.java.JavaVirtualMachine</value> + </item> + ... + </singletons> + </component> + + <component ...> + ... +</component-backend-db> + */ +class ComponentBackendDb: public dp_registry::backend::BackendDb +{ +protected: + virtual ::rtl::OUString getDbNSName(); + virtual ::rtl::OUString getNSPrefix(); + virtual ::rtl::OUString getRootElementName(); + virtual ::rtl::OUString getKeyElementName(); + +public: + struct Data + { + Data(): javaTypeLibrary(false) {}; + + ::std::list< ::rtl::OUString> implementationNames; + /* every singleton has a key and a value + */ + ::std::vector< ::std::pair< ::rtl::OUString, ::rtl::OUString> >singletons; + bool javaTypeLibrary; + }; + +public: + + ComponentBackendDb( css::uno::Reference<css::uno::XComponentContext> const & xContext, + ::rtl::OUString const & url); + + void addEntry(::rtl::OUString const & url, Data const & data); + + Data getEntry(::rtl::OUString const & url); + + +}; + + + +} +} +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/component/dp_component.cxx b/desktop/source/deployment/registry/component/dp_component.cxx new file mode 100644 index 000000000000..1cda30d69297 --- /dev/null +++ b/desktop/source/deployment/registry/component/dp_component.cxx @@ -0,0 +1,1584 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_component.hrc" +#include "dp_backend.h" +#include "dp_platform.hxx" +#include "dp_ucb.h" +#include "rtl/string.hxx" +#include "rtl/strbuf.hxx" +#include "rtl/ustrbuf.hxx" +#include "rtl/uri.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "ucbhelper/content.hxx" +#include "comphelper/anytostring.hxx" +#include "comphelper/servicedecl.hxx" +#include "comphelper/sequence.hxx" +#include "xmlscript/xml_helper.hxx" +#include "svl/inettype.hxx" +#include "com/sun/star/lang/WrappedTargetRuntimeException.hpp" +#include "com/sun/star/container/XNameContainer.hpp" +#include "com/sun/star/container/XHierarchicalNameAccess.hpp" +#include "com/sun/star/container/XSet.hpp" +#include "com/sun/star/registry/XSimpleRegistry.hpp" +#include "com/sun/star/registry/XImplementationRegistration.hpp" +#include "com/sun/star/loader/XImplementationLoader.hpp" +#include "com/sun/star/io/XInputStream.hpp" +#include "com/sun/star/ucb/NameClash.hpp" +#include "com/sun/star/util/XMacroExpander.hpp" +#include <list> +#include <hash_map> +#include <vector> +#include <memory> +#include <algorithm> +#include "dp_compbackenddb.hxx" + +using namespace ::dp_misc; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using ::rtl::OUString; + +namespace dp_registry { +namespace backend { +namespace component { +namespace { + +typedef ::std::list<OUString> t_stringlist; +typedef ::std::vector< ::std::pair<OUString, OUString> > t_stringpairvec; + +#define IMPLEMENTATION_NAME "com.sun.star.comp.deployment.component.PackageRegistryBackend" + +/** return a vector of bootstrap variables which have been provided + as command arguments. +*/ +::std::vector<OUString> getCmdBootstrapVariables() +{ + ::std::vector<OUString> ret; + sal_uInt32 count = osl_getCommandArgCount(); + for (sal_uInt32 i = 0; i < count; i++) + { + OUString arg; + osl_getCommandArg(i, &arg.pData); + if (arg.matchAsciiL("-env:", 5)) + ret.push_back(arg); + } + return ret; +} + +bool jarManifestHeaderPresent( + OUString const & url, OUString const & name, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + ::rtl::OUStringBuffer buf; + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.zip://") ); + buf.append( + ::rtl::Uri::encode( + url, rtl_UriCharClassRegName, rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ) ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("/META-INF/MANIFEST.MF") ); + ::ucbhelper::Content manifestContent; + OUString line; + return + create_ucb_content( + &manifestContent, buf.makeStringAndClear(), xCmdEnv, + false /* no throw */ ) + && readLine( &line, name, manifestContent, RTL_TEXTENCODING_ASCII_US ); +} + +//============================================================================== +class BackendImpl : public ::dp_registry::backend::PackageRegistryBackend +{ + class ComponentPackageImpl : public ::dp_registry::backend::Package + { + BackendImpl * getMyBackend() const; + + const OUString m_loader; + ComponentBackendDb::Data m_registeredComponentsDb; + + enum reg { + REG_UNINIT, REG_VOID, REG_REGISTERED, REG_NOT_REGISTERED, REG_MAYBE_REGISTERED + } m_registered; + + Reference<loader::XImplementationLoader> getComponentInfo( + t_stringlist * pImplNames, t_stringpairvec * pSingletons, + Reference<XComponentContext> const & xContext ); + + virtual void SAL_CALL disposing(); + + // Package + virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_( + ::osl::ResettableMutexGuard & guard, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + virtual void processPackage_( + ::osl::ResettableMutexGuard & guard, + bool registerPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + + const Reference<registry::XSimpleRegistry> getRDB() const; + + //Provides the read-only registry (e.g. not the one based on the duplicated + //rdb files + const Reference<registry::XSimpleRegistry> getRDB_RO() const; + + public: + ComponentPackageImpl( + ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + OUString const & loader, bool bRemoved, + OUString const & identifier); + }; + friend class ComponentPackageImpl; + + class TypelibraryPackageImpl : public ::dp_registry::backend::Package + { + BackendImpl * getMyBackend() const; + + const bool m_jarFile; + Reference<container::XHierarchicalNameAccess> m_xTDprov; + + virtual void SAL_CALL disposing(); + + // Package + virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_( + ::osl::ResettableMutexGuard & guard, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + virtual void processPackage_( + ::osl::ResettableMutexGuard & guard, + bool registerPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + + public: + TypelibraryPackageImpl( + ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + bool jarFile, bool bRemoved, + OUString const & identifier); + }; + friend class TypelibraryPackageImpl; + + t_stringlist m_jar_typelibs; + t_stringlist m_rdb_typelibs; + t_stringlist & getTypelibs( bool jar ) { + return jar ? m_jar_typelibs : m_rdb_typelibs; + } + + bool m_unorc_inited; + bool m_unorc_modified; + bool bSwitchedRdbFiles; + + typedef ::std::hash_map< OUString, Reference<XInterface>, + ::rtl::OUStringHash > t_string2object; + t_string2object m_backendObjects; + + // PackageRegistryBackend + virtual Reference<deployment::XPackage> bindPackage_( + OUString const & url, OUString const & mediaType, + sal_Bool bRemoved, OUString const & identifier, + Reference<XCommandEnvironment> const & xCmdEnv ); + + virtual void SAL_CALL disposing(); + + const Reference<deployment::XPackageTypeInfo> m_xDynComponentTypeInfo; + const Reference<deployment::XPackageTypeInfo> m_xJavaComponentTypeInfo; + const Reference<deployment::XPackageTypeInfo> m_xPythonComponentTypeInfo; + const Reference<deployment::XPackageTypeInfo> m_xRDBTypelibTypeInfo; + const Reference<deployment::XPackageTypeInfo> m_xJavaTypelibTypeInfo; + Sequence< Reference<deployment::XPackageTypeInfo> > m_typeInfos; + + OUString m_commonRDB; + OUString m_nativeRDB; + + //URLs of the read-only rdbs (e.g. not the ones of the duplicated files) + OUString m_commonRDB_RO; + OUString m_nativeRDB_RO; + + std::auto_ptr<ComponentBackendDb> m_backendDb; + + void addDataToDb(OUString const & url, ComponentBackendDb::Data const & data); + void deleteDataFromDb(OUString const & url); + ComponentBackendDb::Data readDataFromDb(OUString const & url); + + + //These rdbs are for writing new service entries. The rdb files are copies + //which are created when services are added or removed. + Reference<registry::XSimpleRegistry> m_xCommonRDB; + Reference<registry::XSimpleRegistry> m_xNativeRDB; + + //These rdbs are created on the read-only rdbs which are already used + //by UNO since the startup of the current session. + Reference<registry::XSimpleRegistry> m_xCommonRDB_RO; + Reference<registry::XSimpleRegistry> m_xNativeRDB_RO; + + + void unorc_verify_init( Reference<XCommandEnvironment> const & xCmdEnv ); + void unorc_flush( Reference<XCommandEnvironment> const & xCmdEnv ); + + Reference<XInterface> getObject( OUString const & id ); + Reference<XInterface> insertObject( + OUString const & id, Reference<XInterface> const & xObject ); + void releaseObject( OUString const & id ); + + bool addToUnoRc( bool jarFile, OUString const & url, + Reference<XCommandEnvironment> const & xCmdEnv ); + bool removeFromUnoRc( bool jarFile, OUString const & url, + Reference<XCommandEnvironment> const & xCmdEnv ); + bool hasInUnoRc( bool jarFile, OUString const & url ); + + + +public: + BackendImpl( Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ); + + // XPackageRegistry + virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL + getSupportedPackageTypes() throw (RuntimeException); + + using PackageRegistryBackend::disposing; + + //Will be called from ComponentPackageImpl + void initServiceRdbFiles(); + + //Creates the READ ONLY registries (m_xCommonRDB_RO,m_xNativeRDB_RO) + void initServiceRdbFiles_RO(); +}; + +//______________________________________________________________________________ + +BackendImpl::ComponentPackageImpl::ComponentPackageImpl( + ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + OUString const & loader, bool bRemoved, + OUString const & identifier) + : Package( myBackend, url, name, name /* display-name */, + xPackageType, bRemoved, identifier), + m_loader( loader ), + m_registered( REG_UNINIT ) +{ + if (bRemoved) + { + m_registeredComponentsDb = getMyBackend()->readDataFromDb(url); + } +} + + +const Reference<registry::XSimpleRegistry> +BackendImpl::ComponentPackageImpl::getRDB() const +{ + BackendImpl * that = getMyBackend(); + + //Late "initialization" of the services rdb files + //This is to prevent problems when running several + //instances of OOo with root rights in parallel. This + //would otherwise cause problems when copying the rdbs. + //See http://qa.openoffice.org/issues/show_bug.cgi?id=99257 + { + const ::osl::MutexGuard guard( getMutex() ); + if (!that->bSwitchedRdbFiles) + { + that->bSwitchedRdbFiles = true; + that->initServiceRdbFiles(); + } + } + if (m_loader.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("com.sun.star.loader.SharedLibrary") )) + return that->m_xNativeRDB; + else + return that->m_xCommonRDB; +} + +//Returns the read only RDB. +const Reference<registry::XSimpleRegistry> +BackendImpl::ComponentPackageImpl::getRDB_RO() const +{ + BackendImpl * that = getMyBackend(); + + if (m_loader.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("com.sun.star.loader.SharedLibrary") )) + return that->m_xNativeRDB_RO; + else + return that->m_xCommonRDB_RO; +} + +BackendImpl * BackendImpl::ComponentPackageImpl::getMyBackend() const +{ + BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get()); + if (NULL == pBackend) + { + //Throws a DisposedException + check(); + //We should never get here... + throw RuntimeException( + OUSTR("Failed to get the BackendImpl"), + static_cast<OWeakObject*>(const_cast<ComponentPackageImpl *>(this))); + } + return pBackend; +} + + +//______________________________________________________________________________ +void BackendImpl::ComponentPackageImpl::disposing() +{ +// m_xRemoteContext.clear(); + Package::disposing(); +} + +//______________________________________________________________________________ +void BackendImpl::TypelibraryPackageImpl::disposing() +{ + m_xTDprov.clear(); + Package::disposing(); +} + +//______________________________________________________________________________ +void BackendImpl::disposing() +{ + try { + m_backendObjects = t_string2object(); + if (m_xNativeRDB.is()) { + m_xNativeRDB->close(); + m_xNativeRDB.clear(); + } + if (m_xCommonRDB.is()) { + m_xCommonRDB->close(); + m_xCommonRDB.clear(); + } + unorc_flush( Reference<XCommandEnvironment>() ); + + PackageRegistryBackend::disposing(); + } + catch (RuntimeException &) { + throw; + } + catch (Exception &) { + Any exc( ::cppu::getCaughtException() ); + throw lang::WrappedTargetRuntimeException( + OUSTR("caught unexpected exception while disposing..."), + static_cast<OWeakObject *>(this), exc ); + } +} + + +void BackendImpl::initServiceRdbFiles() +{ + const Reference<XCommandEnvironment> xCmdEnv; + + ::ucbhelper::Content cacheDir( getCachePath(), xCmdEnv ); + ::ucbhelper::Content oldRDB; + // switch common rdb: + if (m_commonRDB_RO.getLength() > 0) + { + create_ucb_content( + &oldRDB, makeURL( getCachePath(), m_commonRDB_RO), + xCmdEnv, false /* no throw */ ); + } + m_commonRDB = m_commonRDB_RO.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("common.rdb") ) + ? OUSTR("common_.rdb") : OUSTR("common.rdb"); + if (oldRDB.get().is()) + { + if (! cacheDir.transferContent( + oldRDB, ::ucbhelper::InsertOperation_COPY, + m_commonRDB, NameClash::OVERWRITE )) + { + + throw RuntimeException( + OUSTR("UCB transferContent() failed!"), 0 ); + } + oldRDB = ::ucbhelper::Content(); + } + // switch native rdb: + if (m_nativeRDB_RO.getLength() > 0) + { + create_ucb_content( + &oldRDB, makeURL(getCachePath(), m_nativeRDB_RO), + xCmdEnv, false /* no throw */ ); + } + const OUString plt_rdb( getPlatformString() + OUSTR(".rdb") ); + const OUString plt_rdb_( getPlatformString() + OUSTR("_.rdb") ); + m_nativeRDB = m_nativeRDB_RO.equals( plt_rdb ) ? plt_rdb_ : plt_rdb; + if (oldRDB.get().is()) + { + if (! cacheDir.transferContent( + oldRDB, ::ucbhelper::InsertOperation_COPY, + m_nativeRDB, NameClash::OVERWRITE )) + throw RuntimeException( + OUSTR("UCB transferContent() failed!"), 0 ); + } + + // UNO is bootstrapped, flush for next process start: + m_unorc_modified = true; + unorc_flush( Reference<XCommandEnvironment>() ); + + + // common rdb for java, native rdb for shared lib components + if (m_commonRDB.getLength() > 0) { + m_xCommonRDB.set( + m_xComponentContext->getServiceManager() + ->createInstanceWithContext( + OUSTR("com.sun.star.registry.SimpleRegistry"), + m_xComponentContext ), UNO_QUERY_THROW ); + m_xCommonRDB->open( + makeURL( expandUnoRcUrl(getCachePath()), m_commonRDB ), +// m_readOnly, !m_readOnly ); + false, true); + } + if (m_nativeRDB.getLength() > 0) { + m_xNativeRDB.set( + m_xComponentContext->getServiceManager() + ->createInstanceWithContext( + OUSTR("com.sun.star.registry.SimpleRegistry"), + m_xComponentContext ), UNO_QUERY_THROW ); + m_xNativeRDB->open( + makeURL( expandUnoRcUrl(getCachePath()), m_nativeRDB ), +// m_readOnly, !m_readOnly ); + false, true); + } +} + +void BackendImpl::initServiceRdbFiles_RO() +{ + const Reference<XCommandEnvironment> xCmdEnv; + + // common rdb for java, native rdb for shared lib components + if (m_commonRDB_RO.getLength() > 0) + { + m_xCommonRDB_RO.set( + m_xComponentContext->getServiceManager() + ->createInstanceWithContext( + OUSTR("com.sun.star.registry.SimpleRegistry"), + m_xComponentContext), UNO_QUERY_THROW); + m_xCommonRDB_RO->open( + makeURL(expandUnoRcUrl(getCachePath()), m_commonRDB_RO), + sal_True, //read-only + sal_True); // create data source if necessary + } + if (m_nativeRDB_RO.getLength() > 0) + { + m_xNativeRDB_RO.set( + m_xComponentContext->getServiceManager() + ->createInstanceWithContext( + OUSTR("com.sun.star.registry.SimpleRegistry"), + m_xComponentContext), UNO_QUERY_THROW); + m_xNativeRDB_RO->open( + makeURL(expandUnoRcUrl(getCachePath()), m_nativeRDB_RO), + sal_True, //read-only + sal_True); // create data source if necessary + } +} + +//______________________________________________________________________________ +BackendImpl::BackendImpl( + Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ) + : PackageRegistryBackend( args, xComponentContext ), + m_unorc_inited( false ), + m_unorc_modified( false ), + bSwitchedRdbFiles(false), + m_xDynComponentTypeInfo( new Package::TypeInfo( + OUSTR("application/" + "vnd.sun.star.uno-component;" + "type=native;platform=") + + getPlatformString(), + OUSTR("*" SAL_DLLEXTENSION), + getResourceString(RID_STR_DYN_COMPONENT), + RID_IMG_COMPONENT) ), + m_xJavaComponentTypeInfo( new Package::TypeInfo( + OUSTR("application/" + "vnd.sun.star.uno-component;" + "type=Java"), + OUSTR("*.jar"), + getResourceString(RID_STR_JAVA_COMPONENT), + RID_IMG_JAVA_COMPONENT) ), + m_xPythonComponentTypeInfo( new Package::TypeInfo( + OUSTR("application/" + "vnd.sun.star.uno-component;" + "type=Python"), + OUSTR("*.py"), + getResourceString( + RID_STR_PYTHON_COMPONENT), + RID_IMG_COMPONENT ) ), + m_xRDBTypelibTypeInfo( new Package::TypeInfo( + OUSTR("application/" + "vnd.sun.star.uno-typelibrary;" + "type=RDB"), + OUSTR("*.rdb"), + getResourceString(RID_STR_RDB_TYPELIB), + RID_IMG_TYPELIB ) ), + m_xJavaTypelibTypeInfo( new Package::TypeInfo( + OUSTR("application/" + "vnd.sun.star.uno-typelibrary;" + "type=Java"), + OUSTR("*.jar"), + getResourceString(RID_STR_JAVA_TYPELIB), + RID_IMG_JAVA_TYPELIB ) ), + m_typeInfos( 5 ) +{ + m_typeInfos[ 0 ] = m_xDynComponentTypeInfo; + m_typeInfos[ 1 ] = m_xJavaComponentTypeInfo; + m_typeInfos[ 2 ] = m_xPythonComponentTypeInfo; + m_typeInfos[ 3 ] = m_xRDBTypelibTypeInfo; + m_typeInfos[ 4 ] = m_xJavaTypelibTypeInfo; + + const Reference<XCommandEnvironment> xCmdEnv; + + if (transientMode()) + { + // in-mem rdbs: + // common rdb for java, native rdb for shared lib components + m_xCommonRDB.set( + xComponentContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.registry.SimpleRegistry"), + xComponentContext ), UNO_QUERY_THROW ); + m_xCommonRDB->open( OUString() /* in-mem */, + false /* ! read-only */, true /* create */ ); + m_xNativeRDB.set( + xComponentContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.registry.SimpleRegistry"), + xComponentContext ), UNO_QUERY_THROW ); + m_xNativeRDB->open( OUString() /* in-mem */, + false /* ! read-only */, true /* create */ ); + } + else + { + //do this before initServiceRdbFiles_RO, because it determines + //m_commonRDB and m_nativeRDB + unorc_verify_init( xCmdEnv ); + + initServiceRdbFiles_RO(); + + OUString dbFile = makeURL(getCachePath(), OUSTR("backenddb.xml")); + m_backendDb.reset( + new ComponentBackendDb(getComponentContext(), dbFile)); + } +} + +void BackendImpl::addDataToDb( + OUString const & url, ComponentBackendDb::Data const & data) +{ + if (m_backendDb.get()) + m_backendDb->addEntry(url, data); +} + +void BackendImpl::deleteDataFromDb(OUString const & url) +{ + if (m_backendDb.get()) + m_backendDb->removeEntry(url); +} + +ComponentBackendDb::Data BackendImpl::readDataFromDb(OUString const & url) +{ + ComponentBackendDb::Data data; + if (m_backendDb.get()) + data = m_backendDb->getEntry(url); + return data; +} + +// XPackageRegistry +//______________________________________________________________________________ +Sequence< Reference<deployment::XPackageTypeInfo> > +BackendImpl::getSupportedPackageTypes() throw (RuntimeException) +{ + return m_typeInfos; +} + +// PackageRegistryBackend +//______________________________________________________________________________ +Reference<deployment::XPackage> BackendImpl::bindPackage_( + OUString const & url, OUString const & mediaType_, + sal_Bool bRemoved, OUString const & identifier, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + OUString mediaType(mediaType_); + if (mediaType.getLength() == 0 || + mediaType.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( + "application/vnd.sun.star.uno-component") ) || + mediaType.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( + "application/vnd.sun.star.uno-typelibrary") )) + { + // detect exact media-type: + ::ucbhelper::Content ucbContent; + if (create_ucb_content( &ucbContent, url, xCmdEnv )) { + const OUString title( ucbContent.getPropertyValue( + StrTitle::get() ).get<OUString>() ); + if (title.endsWithIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM(SAL_DLLEXTENSION) )) + { + mediaType = OUSTR("application/vnd.sun.star.uno-component;" + "type=native;platform=") + + getPlatformString(); + } + else if (title.endsWithIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM(".jar") )) + { + if (jarManifestHeaderPresent( + url, OUSTR("RegistrationClassName"), xCmdEnv )) + mediaType = OUSTR( + "application/vnd.sun.star.uno-component;type=Java"); + if (mediaType.getLength() == 0) + mediaType = OUSTR( + "application/vnd.sun.star.uno-typelibrary;type=Java"); + } + else if (title.endsWithIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM(".py") )) + mediaType = + OUSTR("application/vnd.sun.star.uno-component;type=Python"); + else if (title.endsWithIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM(".rdb") )) + mediaType = + OUSTR("application/vnd.sun.star.uno-typelibrary;type=RDB"); + } + if (mediaType.getLength() == 0) + throw lang::IllegalArgumentException( + StrCannotDetectMediaType::get() + url, + static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) ); + } + + String type, subType; + INetContentTypeParameterList params; + if (INetContentTypes::parse( mediaType, type, subType, ¶ms )) + { + if (type.EqualsIgnoreCaseAscii("application")) + { + OUString name; + if (!bRemoved) + { + ::ucbhelper::Content ucbContent( url, xCmdEnv ); + name = ucbContent.getPropertyValue( + StrTitle::get() ).get<OUString>(); + } + + if (subType.EqualsIgnoreCaseAscii("vnd.sun.star.uno-component")) + { + // xxx todo: probe and evaluate component xml description + + INetContentTypeParameter const * param = params.find( + ByteString("platform") ); + if (param == 0 || platform_fits( param->m_sValue )) { + param = params.find( ByteString("type") ); + if (param != 0) + { + String const & value = param->m_sValue; + if (value.EqualsIgnoreCaseAscii("native")) { + return new BackendImpl::ComponentPackageImpl( + this, url, name, m_xDynComponentTypeInfo, + OUSTR("com.sun.star.loader.SharedLibrary"), + bRemoved, identifier); + } + if (value.EqualsIgnoreCaseAscii("Java")) { + return new BackendImpl::ComponentPackageImpl( + this, url, name, m_xJavaComponentTypeInfo, + OUSTR("com.sun.star.loader.Java2"), + bRemoved, identifier); + } + if (value.EqualsIgnoreCaseAscii("Python")) { + return new BackendImpl::ComponentPackageImpl( + this, url, name, m_xPythonComponentTypeInfo, + OUSTR("com.sun.star.loader.Python"), + bRemoved, identifier); + } + } + } + } + else if (subType.EqualsIgnoreCaseAscii( + "vnd.sun.star.uno-typelibrary")) + { + INetContentTypeParameter const * param = params.find( + ByteString("type") ); + if (param != 0) { + String const & value = param->m_sValue; + if (value.EqualsIgnoreCaseAscii("RDB")) + { + return new BackendImpl::TypelibraryPackageImpl( + this, url, name, m_xRDBTypelibTypeInfo, + false /* rdb */, bRemoved, identifier); + } + if (value.EqualsIgnoreCaseAscii("Java")) { + return new BackendImpl::TypelibraryPackageImpl( + this, url, name, m_xJavaTypelibTypeInfo, + true /* jar */, bRemoved, identifier); + } + } + } + } + } + throw lang::IllegalArgumentException( + StrUnsupportedMediaType::get() + mediaType, + static_cast<OWeakObject *>(this), + static_cast<sal_Int16>(-1) ); +} + +//############################################################################## + +//______________________________________________________________________________ +void BackendImpl::unorc_verify_init( + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + if (transientMode()) + return; + const ::osl::MutexGuard guard( getMutex() ); + if (! m_unorc_inited) + { + // common rc: + ::ucbhelper::Content ucb_content; + if (create_ucb_content( + &ucb_content, + makeURL( getCachePath(), OUSTR("unorc") ), + xCmdEnv, false /* no throw */ )) + { + OUString line; + if (readLine( &line, OUSTR("UNO_JAVA_CLASSPATH="), ucb_content, + RTL_TEXTENCODING_UTF8 )) + { + sal_Int32 index = sizeof ("UNO_JAVA_CLASSPATH=") - 1; + do { + OUString token( line.getToken( 0, ' ', index ).trim() ); + if (token.getLength() > 0) + { + if (create_ucb_content( + 0, expandUnoRcTerm(token), xCmdEnv, + false /* no throw */ )) + { + //The jar file may not exist anymore if a shared or bundled + //extension was removed, but it can still be in the unorc + //After running XExtensionManager::synchronize, the unorc is + //cleaned up + m_jar_typelibs.push_back( token ); + } + } + } + while (index >= 0); + } + if (readLine( &line, OUSTR("UNO_TYPES="), ucb_content, + RTL_TEXTENCODING_UTF8 )) { + sal_Int32 index = sizeof ("UNO_TYPES=") - 1; + do { + OUString token( line.getToken( 0, ' ', index ).trim() ); + if (token.getLength() > 0) + { + if (token[ 0 ] == '?') + token = token.copy( 1 ); + if (create_ucb_content( + 0, expandUnoRcTerm(token), xCmdEnv, + false /* no throw */ )) + { + //The RDB file may not exist anymore if a shared or bundled + //extension was removed, but it can still be in the unorc. + //After running XExtensionManager::synchronize, the unorc is + //cleaned up + m_rdb_typelibs.push_back( token ); + } + } + } + while (index >= 0); + } + if (readLine( &line, OUSTR("UNO_SERVICES="), ucb_content, + RTL_TEXTENCODING_UTF8 )) { + sal_Int32 start = sizeof ("UNO_SERVICES=?$ORIGIN/") - 1; + sal_Int32 sep = line.indexOf( ' ', start ); + OSL_ASSERT( sep > 0 ); + m_commonRDB_RO = line.copy( start, sep - start ); + } + + // native rc: + if (create_ucb_content( + &ucb_content, + makeURL( getCachePath(), getPlatformString() + OUSTR("rc")), + xCmdEnv, false /* no throw */ )) { + if (readLine( &line, OUSTR("UNO_SERVICES="), ucb_content, + RTL_TEXTENCODING_UTF8 )) { + m_nativeRDB_RO = line.copy( + sizeof ("UNO_SERVICES=?$ORIGIN/") - 1 ); + } + } + } + m_unorc_modified = false; + m_unorc_inited = true; + } +} + +//______________________________________________________________________________ +void BackendImpl::unorc_flush( Reference<XCommandEnvironment> const & xCmdEnv ) +{ + if (transientMode()) + return; + if (!m_unorc_inited || !m_unorc_modified) + return; + + ::rtl::OStringBuffer buf; + + buf.append(RTL_CONSTASCII_STRINGPARAM("ORIGIN=")); + OUString sOrigin = dp_misc::makeRcTerm(m_cachePath); + ::rtl::OString osOrigin = ::rtl::OUStringToOString(sOrigin, RTL_TEXTENCODING_UTF8); + buf.append(osOrigin); + buf.append(LF); + + if (! m_jar_typelibs.empty()) + { + t_stringlist::const_iterator iPos( m_jar_typelibs.begin() ); + t_stringlist::const_iterator const iEnd( m_jar_typelibs.end() ); + buf.append( RTL_CONSTASCII_STRINGPARAM("UNO_JAVA_CLASSPATH=") ); + while (iPos != iEnd) { + // encoded ASCII file-urls: + const ::rtl::OString item( + ::rtl::OUStringToOString( *iPos, RTL_TEXTENCODING_ASCII_US ) ); + buf.append( item ); + ++iPos; + if (iPos != iEnd) + buf.append( ' ' ); + } + buf.append(LF); + } + if (! m_rdb_typelibs.empty()) + { + t_stringlist::const_iterator iPos( m_rdb_typelibs.begin() ); + t_stringlist::const_iterator const iEnd( m_rdb_typelibs.end() ); + buf.append( RTL_CONSTASCII_STRINGPARAM("UNO_TYPES=") ); + while (iPos != iEnd) { + buf.append( '?' ); + // encoded ASCII file-urls: + const ::rtl::OString item( + ::rtl::OUStringToOString( *iPos, RTL_TEXTENCODING_ASCII_US ) ); + buf.append( item ); + ++iPos; + if (iPos != iEnd) + buf.append( ' ' ); + } + buf.append(LF); + } + + // If we duplicated the common or native rdb then we must use those urls + //otherwise we use those of the original files. That is, m_commonRDB_RO and + //m_nativeRDB_RO; + OUString sCommonRDB(m_commonRDB.getLength() > 0 ? m_commonRDB : m_commonRDB_RO); + OUString sNativeRDB(m_nativeRDB.getLength() > 0 ? m_nativeRDB : m_nativeRDB_RO); + + if (sCommonRDB.getLength() > 0 || sNativeRDB.getLength() > 0) + { + buf.append( RTL_CONSTASCII_STRINGPARAM("UNO_SERVICES=?$ORIGIN/") ); + buf.append( ::rtl::OUStringToOString( + sCommonRDB, RTL_TEXTENCODING_ASCII_US ) ); + if (sNativeRDB.getLength() > 0) + { + buf.append( RTL_CONSTASCII_STRINGPARAM( + " ${$ORIGIN/${_OS}_${_ARCH}rc:UNO_SERVICES}") ); + buf.append(LF); + + // write native rc: + ::rtl::OStringBuffer buf2; + buf2.append(RTL_CONSTASCII_STRINGPARAM("ORIGIN=")); + buf2.append(osOrigin); + buf2.append(LF); + buf2.append( RTL_CONSTASCII_STRINGPARAM("UNO_SERVICES=?$ORIGIN/") ); + buf2.append( ::rtl::OUStringToOString( + sNativeRDB, RTL_TEXTENCODING_ASCII_US ) ); + buf2.append(LF); + + const Reference<io::XInputStream> xData( + ::xmlscript::createInputStream( + ::rtl::ByteSequence( + reinterpret_cast<sal_Int8 const *>(buf2.getStr()), + buf2.getLength() ) ) ); + ::ucbhelper::Content ucb_content( + makeURL( getCachePath(), getPlatformString() + OUSTR("rc") ), + xCmdEnv ); + ucb_content.writeStream( xData, true /* replace existing */ ); + } + } + + // write unorc: + const Reference<io::XInputStream> xData( + ::xmlscript::createInputStream( + ::rtl::ByteSequence( + reinterpret_cast<sal_Int8 const *>(buf.getStr()), + buf.getLength() ) ) ); + ::ucbhelper::Content ucb_content( + makeURL( getCachePath(), OUSTR("unorc") ), xCmdEnv ); + ucb_content.writeStream( xData, true /* replace existing */ ); + + m_unorc_modified = false; +} + +//______________________________________________________________________________ +bool BackendImpl::addToUnoRc( bool jarFile, OUString const & url_, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + const OUString rcterm( dp_misc::makeRcTerm(url_) ); + const ::osl::MutexGuard guard( getMutex() ); + unorc_verify_init( xCmdEnv ); + t_stringlist & rSet = getTypelibs(jarFile); + if (::std::find( rSet.begin(), rSet.end(), rcterm ) == rSet.end()) { + rSet.push_front( rcterm ); // prepend to list, thus overriding + // write immediately: + m_unorc_modified = true; + unorc_flush( xCmdEnv ); + return true; + } + else + return false; +} + +//______________________________________________________________________________ +bool BackendImpl::removeFromUnoRc( + bool jarFile, OUString const & url_, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + const OUString rcterm( dp_misc::makeRcTerm(url_) ); + const ::osl::MutexGuard guard( getMutex() ); + unorc_verify_init( xCmdEnv ); + getTypelibs(jarFile).remove( rcterm ); + // write immediately: + m_unorc_modified = true; + unorc_flush( xCmdEnv ); + return true; +} + +//______________________________________________________________________________ +bool BackendImpl::hasInUnoRc( + bool jarFile, OUString const & url_ ) +{ + const OUString rcterm( dp_misc::makeRcTerm(url_) ); + const ::osl::MutexGuard guard( getMutex() ); + t_stringlist const & rSet = getTypelibs(jarFile); + return ::std::find( rSet.begin(), rSet.end(), rcterm ) != rSet.end(); +} + +//______________________________________________________________________________ +void BackendImpl::releaseObject( OUString const & id ) +{ + const ::osl::MutexGuard guard( getMutex() ); + if ( m_backendObjects.erase( id ) != 1 ) + { + OSL_ASSERT( false ); + } +} + +//______________________________________________________________________________ +Reference<XInterface> BackendImpl::getObject( OUString const & id ) +{ + const ::osl::MutexGuard guard( getMutex() ); + const t_string2object::const_iterator iFind( m_backendObjects.find( id ) ); + if (iFind == m_backendObjects.end()) + return Reference<XInterface>(); + else + return iFind->second; +} + +//______________________________________________________________________________ +Reference<XInterface> BackendImpl::insertObject( + OUString const & id, Reference<XInterface> const & xObject ) +{ + const ::osl::MutexGuard guard( getMutex() ); + const ::std::pair<t_string2object::iterator, bool> insertion( + m_backendObjects.insert( t_string2object::value_type( + id, xObject ) ) ); + return insertion.first->second; +} + +//------------------------------------------------------------------------------ +Reference<XComponentContext> raise_uno_process( + Reference<XComponentContext> const & xContext, + ::rtl::Reference<AbortChannel> const & abortChannel ) +{ + OSL_ASSERT( xContext.is() ); + + ::rtl::OUString url( + Reference<util::XMacroExpander>( + xContext->getValueByName( + OUSTR("/singletons/com.sun.star.util.theMacroExpander") ), + UNO_QUERY_THROW )-> + expandMacros( OUSTR("$URE_BIN_DIR/uno") ) ); + + ::rtl::OUStringBuffer buf; + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("uno:pipe,name=") ); + OUString pipeId( generateRandomPipeId() ); + buf.append( pipeId ); + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM(";urp;uno.ComponentContext") ); + const OUString connectStr( buf.makeStringAndClear() ); + + // raise core UNO process to register/run a component, + // javavm service uses unorc next to executable to retrieve deployed + // jar typelibs + + ::std::vector<OUString> args; +#if OSL_DEBUG_LEVEL <= 1 + args.push_back( OUSTR("--quiet") ); +#endif + args.push_back( OUSTR("--singleaccept") ); + args.push_back( OUSTR("-u") ); + args.push_back( connectStr ); + // don't inherit from unorc: + args.push_back( OUSTR("-env:INIFILENAME=") ); + + //now add the bootstrap variables which were supplied on the command line + ::std::vector<OUString> bootvars = getCmdBootstrapVariables(); + args.insert(args.end(), bootvars.begin(), bootvars.end()); + + oslProcess hProcess = raiseProcess( + url, comphelper::containerToSequence(args) ); + try { + return Reference<XComponentContext>( + resolveUnoURL( connectStr, xContext, abortChannel.get() ), + UNO_QUERY_THROW ); + } + catch (...) { + // try to terminate process: + if ( osl_terminateProcess( hProcess ) != osl_Process_E_None ) + { + OSL_ASSERT( false ); + } + throw; + } +} + +//------------------------------------------------------------------------------ +Reference<loader::XImplementationLoader> +BackendImpl::ComponentPackageImpl::getComponentInfo( + t_stringlist * pImplNames, t_stringpairvec * pSingletons, + Reference<XComponentContext> const & xContext ) +{ + const Reference<loader::XImplementationLoader> xLoader( + xContext->getServiceManager()->createInstanceWithContext( + m_loader, xContext ), UNO_QUERY ); + if (! xLoader.is()) + return Reference<loader::XImplementationLoader>(); + + // HACK: highly dependent on stoc/source/servicemanager + // and stoc/source/implreg implementation which rely on the same + // services.rdb format! + + const Reference<registry::XSimpleRegistry> xMemReg( + xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.registry.SimpleRegistry"), xContext ), + UNO_QUERY_THROW ); + xMemReg->open( OUString() /* in mem */, false, true ); + xLoader->writeRegistryInfo( xMemReg->getRootKey(), OUString(), getURL() ); + + const Sequence< Reference<registry::XRegistryKey> > keys( + xMemReg->getRootKey()->openKeys() ); + for ( sal_Int32 pos = keys.getLength(); pos--; ) + { + Reference<registry::XRegistryKey> const & xImplKey = keys[ pos ]; + const OUString implName( + xImplKey->getKeyName().copy( 1 /*leading slash*/ ) ); + + // check for singletons: + const Reference<registry::XRegistryKey> xSingletonKey( + xImplKey->openKey( OUSTR("UNO/SINGLETONS") ) ); + if (xSingletonKey.is() && xSingletonKey->isValid()) + { + const Sequence< Reference<registry::XRegistryKey> > singletonKeys( + xSingletonKey->openKeys() ); + for ( sal_Int32 i = singletonKeys.getLength(); i--; ) + { + Reference<registry::XRegistryKey> const & xSingleton = + singletonKeys[ i ]; + pSingletons->push_back( + ::std::pair<OUString, OUString>( + xSingleton->getKeyName().copy( + implName.getLength() + + sizeof ("//UNO/SINGLETONS/") - 1 ), + xSingleton->getStringValue() ) ); + } + } + else + { + pImplNames->push_back( implName ); + } + } + + return xLoader; +} + +// Package +//______________________________________________________________________________ +beans::Optional< beans::Ambiguous<sal_Bool> > +BackendImpl::ComponentPackageImpl::isRegistered_( + ::osl::ResettableMutexGuard &, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & ) +{ + if (m_registered == REG_UNINIT) + { + m_registered = REG_NOT_REGISTERED; + bool bAmbiguousComponentName = false; + const Reference<registry::XSimpleRegistry> xRDB( getRDB_RO() ); + if (xRDB.is()) + { + // lookup rdb for location URL: + const Reference<registry::XRegistryKey> xRootKey( + xRDB->getRootKey() ); + const Reference<registry::XRegistryKey> xImplKey( + xRootKey->openKey( OUSTR("IMPLEMENTATIONS") ) ); + Sequence<OUString> implNames; + if (xImplKey.is() && xImplKey->isValid()) + implNames = xImplKey->getKeyNames(); + OUString const * pImplNames = implNames.getConstArray(); + sal_Int32 pos = implNames.getLength(); + for ( ; pos--; ) + { + checkAborted( abortChannel ); + const OUString key( + pImplNames[ pos ] + OUSTR("/UNO/LOCATION") ); + const Reference<registry::XRegistryKey> xKey( + xRootKey->openKey(key) ); + if (xKey.is() && xKey->isValid()) + { + const OUString location( xKey->getAsciiValue() ); + if (location.equalsIgnoreAsciiCase( getURL() )) + { + break; + } + else + { + //try to match only the file name + OUString thisUrl(getURL()); + OUString thisFileName(thisUrl.copy(thisUrl.lastIndexOf('/'))); + + OUString locationFileName(location.copy(location.lastIndexOf('/'))); + if (locationFileName.equalsIgnoreAsciiCase(thisFileName)) + bAmbiguousComponentName = true; + } + } + } + if (pos >= 0) + m_registered = REG_REGISTERED; + else if (bAmbiguousComponentName) + m_registered = REG_MAYBE_REGISTERED; + } + } + + //Different extensions can use the same service implementations. Then the extensions + //which was installed last will overwrite the one from the other extension. That is + //the registry will contain the path (the location) of the library or jar of the + //second extension. In this case isRegistered called for the lib of the first extension + //would return "not registered". That would mean that during uninstallation + //XPackage::registerPackage is not called, because it just was not registered. This is, + //however, necessary for jar files. Registering and unregistering update + //uno_packages/cache/registry/com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc + //Therefore, we will return always "is ambiguous" if the path of this component cannot + //be found in the registry and if there is another path and both have the same file name (but + //the rest of the path is different). + //If the caller cannot precisely determine that this package was registered, then it must + //call registerPackage. + sal_Bool bAmbiguous = m_registered == REG_VOID // REG_VOID == we are in the progress of unregistration + || m_registered == REG_MAYBE_REGISTERED; + return beans::Optional< beans::Ambiguous<sal_Bool> >( + true /* IsPresent */, + beans::Ambiguous<sal_Bool>( + m_registered == REG_REGISTERED, bAmbiguous) ); +} + +//______________________________________________________________________________ +void BackendImpl::ComponentPackageImpl::processPackage_( + ::osl::ResettableMutexGuard &, + bool doRegisterPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + BackendImpl * that = getMyBackend(); + + + const bool java = m_loader.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("com.sun.star.loader.Java2") ); + const OUString url( getURL() ); + bool isJavaTypelib; + if (m_bRemoved) + isJavaTypelib = m_registeredComponentsDb.javaTypeLibrary; + else + isJavaTypelib = java && + !jarManifestHeaderPresent( url, OUSTR("UNO-Type-Path"), xCmdEnv ); + + ComponentBackendDb::Data data; + data.javaTypeLibrary = isJavaTypelib; + if (doRegisterPackage) + { + Reference <uno::XComponentContext> context(that->getComponentContext()); + if (! startup) + { + context.set( + that->getObject( url ), UNO_QUERY ); + + if (! context.is()) { + context.set( + that->insertObject( url, raise_uno_process( + that->getComponentContext(), + abortChannel ) ), + UNO_QUERY_THROW ); + } + } + + const Reference<registry::XSimpleRegistry> xServicesRDB( getRDB() ); + const Reference<registry::XImplementationRegistration> xImplReg( + context->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.registry.ImplementationRegistration"), + context ), UNO_QUERY_THROW ); + + xImplReg->registerImplementation( m_loader, url, xServicesRDB ); + //only write to unorc if registration was successful. + //It may fail if there is no suitable java. + if (isJavaTypelib) + { + that->addToUnoRc( java, url, xCmdEnv ); + data.javaTypeLibrary = true; + } + + t_stringlist implNames; + t_stringpairvec singletons; + const Reference<loader::XImplementationLoader> xLoader( + getComponentInfo( &implNames, &singletons, context ) ); + data.implementationNames = implNames; + data.singletons = singletons; + + if (!startup) + { + // factories live insertion: + const Reference<container::XSet> xSet( + that->getComponentContext()->getServiceManager(), UNO_QUERY_THROW ); + for ( t_stringlist::const_iterator iPos( implNames.begin() ); + iPos != implNames.end(); ++iPos ) + { + checkAborted( abortChannel ); + OUString const & implName = *iPos; + // activate factory: + const Reference<XInterface> xFactory( + xLoader->activate( + implName, OUString(), url, + xServicesRDB->getRootKey()->openKey( + OUSTR("/IMPLEMENTATIONS/") + implName ) ) ); + try { + xSet->insert( Any(xFactory) ); + } // ignore if factory has already been inserted: + catch (container::ElementExistException &) { + OSL_ENSURE( 0, "### factory already registered?" ); + } + } + + if (! singletons.empty()) + { + // singletons live insertion: + const Reference<container::XNameContainer> xRootContext( + that->getComponentContext()->getValueByName( + OUSTR("_root") ), UNO_QUERY ); + if (xRootContext.is()) + { + for ( t_stringpairvec::const_iterator iPos( + singletons.begin() ); + iPos != singletons.end(); ++iPos ) + { + ::std::pair<OUString, OUString> const & sp = *iPos; + const OUString name( OUSTR("/singletons/") + sp.first ); + // assure no arguments: + try { + xRootContext->removeByName( name + OUSTR("/arguments")); + } catch (container::NoSuchElementException &) {} + // used service: + try { + xRootContext->insertByName( + name + OUSTR("/service"), Any(sp.second) ); + } catch (container::ElementExistException &) { + xRootContext->replaceByName( + name + OUSTR("/service"), Any(sp.second) ); + } + // singleton entry: + try { + xRootContext->insertByName( name, Any() ); + } catch (container::ElementExistException & exc) { + (void) exc; // avoid warnings + OSL_ENSURE( + 0, OUStringToOString( + exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); + xRootContext->replaceByName( name, Any() ); + } + } + } + } + } + + m_registered = REG_REGISTERED; + getMyBackend()->addDataToDb(url, data); + } + else // revokePackage() + { + // set to VOID during revocation process: + m_registered = REG_VOID; + + //get the remote context. If it does not exist then use the local one + Reference<XComponentContext> xContext( + that->getObject( url ), UNO_QUERY ); + bool bRemoteContext = false; + if (!xContext.is()) + xContext = that->getComponentContext(); + else + bRemoteContext = true; + + t_stringlist implNames; + t_stringpairvec singletons; + if (m_bRemoved) + { + implNames = m_registeredComponentsDb.implementationNames; + singletons = m_registeredComponentsDb.singletons; + } + else + { + getComponentInfo( &implNames, &singletons, xContext ); + } + + if (!startup) + { + // factories live removal: + const Reference<container::XSet> xSet( + that->getComponentContext()->getServiceManager(), UNO_QUERY_THROW ); + for ( t_stringlist::const_iterator iPos( implNames.begin() ); + iPos != implNames.end(); ++iPos ) + { + OUString const & implName = *iPos; + try { + xSet->remove( Any(implName) ); + } // ignore if factory has not been live deployed: + catch (container::NoSuchElementException &) { + } + } + + if (! singletons.empty()) + { + // singletons live removal: + const Reference<container::XNameContainer> xRootContext( + that->getComponentContext()->getValueByName( + OUSTR("_root") ), UNO_QUERY ); + if (xRootContext.is()) + { + for ( t_stringpairvec::const_iterator iPos( + singletons.begin() ); + iPos != singletons.end(); ++iPos ) + { + ::std::pair<OUString, OUString> const & sp = *iPos; + const OUString name( OUSTR("/singletons/") + sp.first ); + // arguments: + try { + xRootContext->removeByName( name + OUSTR("/arguments")); + } + catch (container::NoSuchElementException &) {} + // used service: + try { + xRootContext->removeByName( name + OUSTR("/service") ); + } + catch (container::NoSuchElementException &) {} + // singleton entry: + try { + xRootContext->removeByName( name ); + } + catch (container::NoSuchElementException & exc) { + (void) exc; // avoid warnings + OSL_ENSURE( + 0, OUStringToOString( + exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); + } + } + } + } + } + + const Reference<registry::XSimpleRegistry> xServicesRDB( getRDB() ); + const Reference<registry::XImplementationRegistration> xImplReg( + xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.registry.ImplementationRegistration"), + xContext ), UNO_QUERY_THROW ); + xImplReg->revokeImplementation( url, xServicesRDB ); + + if (isJavaTypelib) + that->removeFromUnoRc( java, url, xCmdEnv ); + + if (bRemoteContext) + that->releaseObject( url ); + + m_registered = REG_NOT_REGISTERED; + getMyBackend()->deleteDataFromDb(url); + } +} + +//############################################################################## +BackendImpl::TypelibraryPackageImpl::TypelibraryPackageImpl( + ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + bool jarFile, bool bRemoved, OUString const & identifier) + : Package( myBackend, url, name, name /* display-name */, + xPackageType, bRemoved, identifier), + m_jarFile( jarFile ) +{ +} + +// Package +BackendImpl * BackendImpl::TypelibraryPackageImpl::getMyBackend() const +{ + BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get()); + if (NULL == pBackend) + { + //May throw a DisposedException + check(); + //We should never get here... + throw RuntimeException( + OUSTR("Failed to get the BackendImpl"), + static_cast<OWeakObject*>(const_cast<TypelibraryPackageImpl *>(this))); + } + return pBackend; +} +//______________________________________________________________________________ +beans::Optional< beans::Ambiguous<sal_Bool> > +BackendImpl::TypelibraryPackageImpl::isRegistered_( + ::osl::ResettableMutexGuard &, + ::rtl::Reference<AbortChannel> const &, + Reference<XCommandEnvironment> const & ) +{ + BackendImpl * that = getMyBackend(); + return beans::Optional< beans::Ambiguous<sal_Bool> >( + true /* IsPresent */, + beans::Ambiguous<sal_Bool>( + that->hasInUnoRc( m_jarFile, getURL() ), + false /* IsAmbiguous */ ) ); +} + +//______________________________________________________________________________ +void BackendImpl::TypelibraryPackageImpl::processPackage_( + ::osl::ResettableMutexGuard &, + bool doRegisterPackage, + bool /*startup*/, + ::rtl::Reference<AbortChannel> const &, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + BackendImpl * that = getMyBackend(); + const OUString url( getURL() ); + + if (doRegisterPackage) + { + // live insertion: + if (m_jarFile) { + // xxx todo add to classpath at runtime: ??? + //SB: It is probably not worth it to add the live inserted type + // library JAR to the UnoClassLoader in the soffice process. Any + // live inserted component JAR that might reference this type + // library JAR runs in its own uno process, so there is probably no + // Java code in the soffice process that would see any UNO types + // introduced by this type library JAR. + } + else // RDB: + { + Reference<XComponentContext> const & xContext = + that->getComponentContext(); + if (! m_xTDprov.is()) + { + m_xTDprov.set( that->getObject( url ), UNO_QUERY ); + if (! m_xTDprov.is()) + { + const Reference<registry::XSimpleRegistry> xReg( + xContext->getServiceManager() + ->createInstanceWithContext( + OUSTR("com.sun.star.registry.SimpleRegistry"), + xContext ), UNO_QUERY_THROW ); + xReg->open( expandUnoRcUrl(url), + true /* read-only */, false /* ! create */ ); + const Any arg(xReg); + Reference<container::XHierarchicalNameAccess> xTDprov( + xContext->getServiceManager() + ->createInstanceWithArgumentsAndContext( + OUSTR("com.sun.star.comp.stoc." + "RegistryTypeDescriptionProvider"), + Sequence<Any>( &arg, 1 ), xContext ), UNO_QUERY ); + OSL_ASSERT( xTDprov.is() ); + if (xTDprov.is()) + m_xTDprov.set( that->insertObject( url, xTDprov ), + UNO_QUERY_THROW ); + } + } + if (m_xTDprov.is()) { + Reference<container::XSet> xSet( + xContext->getValueByName( + OUSTR("/singletons/com.sun.star." + "reflection.theTypeDescriptionManager") ), + UNO_QUERY_THROW ); + xSet->insert( Any(m_xTDprov) ); + } + } + + that->addToUnoRc( m_jarFile, url, xCmdEnv ); + } + else // revokePackage() + { + that->removeFromUnoRc( m_jarFile, url, xCmdEnv ); + + // revoking types at runtime, possible, sensible? + if (!m_xTDprov.is()) + m_xTDprov.set( that->getObject( url ), UNO_QUERY ); + if (m_xTDprov.is()) { + // remove live: + const Reference<container::XSet> xSet( + that->getComponentContext()->getValueByName( + OUSTR("/singletons/com.sun.star." + "reflection.theTypeDescriptionManager") ), + UNO_QUERY_THROW ); + xSet->remove( Any(m_xTDprov) ); + + that->releaseObject( url ); + m_xTDprov.clear(); + } + } +} + +} // anon namespace + +namespace sdecl = comphelper::service_decl; +sdecl::class_<BackendImpl, sdecl::with_args<true> > serviceBI; +extern sdecl::ServiceDecl const serviceDecl( + serviceBI, + IMPLEMENTATION_NAME, + BACKEND_SERVICE_NAME ); + +} // namespace component +} // namespace backend +} // namespace dp_registry + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/component/dp_component.hrc b/desktop/source/deployment/registry/component/dp_component.hrc new file mode 100644 index 000000000000..53085a48d185 --- /dev/null +++ b/desktop/source/deployment/registry/component/dp_component.hrc @@ -0,0 +1,39 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_COMPONENT_HRC +#define INCLUDED_DP_COMPONENT_HRC + +#include "deployment.hrc" + +#define RID_STR_DYN_COMPONENT (RID_DEPLOYMENT_COMPONENT_START+10) +#define RID_STR_JAVA_COMPONENT (RID_DEPLOYMENT_COMPONENT_START+11) +#define RID_STR_PYTHON_COMPONENT (RID_DEPLOYMENT_COMPONENT_START+12) +#define RID_STR_RDB_TYPELIB (RID_DEPLOYMENT_COMPONENT_START+20) +#define RID_STR_JAVA_TYPELIB (RID_DEPLOYMENT_COMPONENT_START+21) + +#endif diff --git a/desktop/source/deployment/registry/component/dp_component.src b/desktop/source/deployment/registry/component/dp_component.src new file mode 100644 index 000000000000..36f2a1cc4a5c --- /dev/null +++ b/desktop/source/deployment/registry/component/dp_component.src @@ -0,0 +1,54 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "dp_component.hrc" + +String RID_STR_DYN_COMPONENT +{ + Text [ en-US ] = "UNO Dynamic Library Component"; +}; + +String RID_STR_JAVA_COMPONENT +{ + Text [ en-US ] = "UNO Java Component"; +}; + +String RID_STR_PYTHON_COMPONENT +{ + Text [ en-US ] = "UNO Python Component"; +}; + +String RID_STR_RDB_TYPELIB +{ + Text [ en-US ] = "UNO RDB Type Library"; +}; + +String RID_STR_JAVA_TYPELIB +{ + Text [ en-US ] = "UNO Java Type Library"; +}; + diff --git a/desktop/source/deployment/registry/component/makefile.mk b/desktop/source/deployment/registry/component/makefile.mk new file mode 100644 index 000000000000..b7ee5c203cd5 --- /dev/null +++ b/desktop/source/deployment/registry/component/makefile.mk @@ -0,0 +1,48 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/..$/.. + +PRJNAME = desktop +TARGET = deployment_registry_component +ENABLE_EXCEPTIONS = TRUE + +.INCLUDE : settings.mk + +SRS1NAME = $(TARGET) +SRC1FILES = \ + dp_component.src + +INCPRE += ..$/..$/inc + +SLOFILES = \ + $(SLO)$/dp_component.obj \ + $(SLO)$/dp_compbackenddb.obj + +.INCLUDE : ..$/..$/target.pmk +.INCLUDE : target.mk + diff --git a/desktop/source/deployment/registry/configuration/dp_configuration.cxx b/desktop/source/deployment/registry/configuration/dp_configuration.cxx new file mode 100644 index 000000000000..d6d373a79e01 --- /dev/null +++ b/desktop/source/deployment/registry/configuration/dp_configuration.cxx @@ -0,0 +1,774 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +//TODO: Large parts of this file were copied from dp_component.cxx; those parts +// should be consolidated. + +#include "dp_configuration.hrc" +#include "dp_backend.h" +#include "dp_persmap.h" +#include "dp_ucb.h" +#include "rtl/string.hxx" +#include "rtl/ustrbuf.hxx" +#include "rtl/uri.hxx" +#include "rtl/memory.h" +#include "osl/file.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "ucbhelper/content.hxx" +#include "comphelper/anytostring.hxx" +#include "comphelper/servicedecl.hxx" +#include "xmlscript/xml_helper.hxx" +#include "svl/inettype.hxx" +#include "com/sun/star/configuration/Update.hpp" +#include "com/sun/star/ucb/NameClash.hpp" +#include "com/sun/star/io/XActiveDataSink.hpp" +#include "com/sun/star/lang/WrappedTargetRuntimeException.hpp" +#include "com/sun/star/util/XRefreshable.hpp" +#include <list> +#include <memory> + +#include "dp_configurationbackenddb.hxx" + +using namespace ::dp_misc; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using ::rtl::OUString; + +namespace dp_registry { +namespace backend { +namespace configuration { +namespace { + +typedef ::std::list<OUString> t_stringlist; + +//============================================================================== +class BackendImpl : public ::dp_registry::backend::PackageRegistryBackend +{ + class PackageImpl : public ::dp_registry::backend::Package + { + BackendImpl * getMyBackend() const ; + + const bool m_isSchema; + + // Package + virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_( + ::osl::ResettableMutexGuard & guard, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + virtual void processPackage_( + ::osl::ResettableMutexGuard & guard, + bool registerPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + + public: + inline PackageImpl( + ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + bool isSchema, bool bRemoved, OUString const & identifier) + : Package( myBackend, url, name, name /* display-name */, + xPackageType, bRemoved, identifier), + m_isSchema( isSchema ) + {} + }; + friend class PackageImpl; + + t_stringlist m_xcs_files; + t_stringlist m_xcu_files; + t_stringlist & getFiles( bool xcs ) { + return xcs ? m_xcs_files : m_xcu_files; + } + + bool m_configmgrini_inited; + bool m_configmgrini_modified; + std::auto_ptr<ConfigurationBackendDb> m_backendDb; + + // PackageRegistryBackend + virtual Reference<deployment::XPackage> bindPackage_( + OUString const & url, OUString const & mediaType, sal_Bool bRemoved, + OUString const & identifier, + Reference<XCommandEnvironment> const & xCmdEnv ); + + ::std::auto_ptr<PersistentMap> m_registeredPackages; + // for backwards compatibility + + virtual void SAL_CALL disposing(); + + const Reference<deployment::XPackageTypeInfo> m_xConfDataTypeInfo; + const Reference<deployment::XPackageTypeInfo> m_xConfSchemaTypeInfo; + Sequence< Reference<deployment::XPackageTypeInfo> > m_typeInfos; + + void configmgrini_verify_init( + Reference<XCommandEnvironment> const & xCmdEnv ); + void configmgrini_flush( Reference<XCommandEnvironment> const & xCmdEnv ); + + bool addToConfigmgrIni( bool isSchema, OUString const & url, + Reference<XCommandEnvironment> const & xCmdEnv ); + bool removeFromConfigmgrIni( bool isSchema, OUString const & url, + Reference<XCommandEnvironment> const & xCmdEnv ); + + void addDataToDb(OUString const & url, ConfigurationBackendDb::Data const & data); + ::boost::optional<ConfigurationBackendDb::Data> readDataFromDb(OUString const & url); + OUString deleteDataFromDb(OUString const & url); + +public: + BackendImpl( Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ); + + // XPackageRegistry + virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL + getSupportedPackageTypes() throw (RuntimeException); + + using PackageRegistryBackend::disposing; +}; + +//______________________________________________________________________________ +void BackendImpl::disposing() +{ + try { + configmgrini_flush( Reference<XCommandEnvironment>() ); + + PackageRegistryBackend::disposing(); + } + catch (RuntimeException &) { + throw; + } + catch (Exception &) { + Any exc( ::cppu::getCaughtException() ); + throw lang::WrappedTargetRuntimeException( + OUSTR("caught unexpected exception while disposing..."), + static_cast<OWeakObject *>(this), exc ); + } +} + +//______________________________________________________________________________ +BackendImpl::BackendImpl( + Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ) + : PackageRegistryBackend( args, xComponentContext ), + m_configmgrini_inited( false ), + m_configmgrini_modified( false ), + m_xConfDataTypeInfo( new Package::TypeInfo( + OUSTR("application/" + "vnd.sun.star.configuration-data"), + OUSTR("*.xcu"), + getResourceString(RID_STR_CONF_DATA), + RID_IMG_CONF_XML ) ), + m_xConfSchemaTypeInfo( new Package::TypeInfo( + OUSTR("application/" + "vnd.sun.star.configuration-schema"), + OUSTR("*.xcs"), + getResourceString(RID_STR_CONF_SCHEMA), + RID_IMG_CONF_XML ) ), + m_typeInfos( 2 ) +{ + m_typeInfos[ 0 ] = m_xConfDataTypeInfo; + m_typeInfos[ 1 ] = m_xConfSchemaTypeInfo; + + const Reference<XCommandEnvironment> xCmdEnv; + + if (transientMode()) + { + //TODO + } + else + { + OUString dbFile = makeURL(getCachePath(), OUSTR("backenddb.xml")); + m_backendDb.reset( + new ConfigurationBackendDb(getComponentContext(), dbFile)); + //clean up data folders which are no longer used. + //This must not be done in the same process where the help files + //are still registers. Only after revoking and restarting OOo the folders + //can be removed. This works now, because the extension manager is a singleton + //and the backends are only create once per process. + ::std::list<OUString> folders = m_backendDb->getAllDataUrls(); + deleteUnusedFolders(OUString(), folders); + + + configmgrini_verify_init( xCmdEnv ); + m_registeredPackages.reset( + new PersistentMap( + makeURL( getCachePath(), OUSTR("registered_packages.db") ), + false ) ); + } +} + +void BackendImpl::addDataToDb( + OUString const & url, ConfigurationBackendDb::Data const & data) +{ + if (m_backendDb.get()) + m_backendDb->addEntry(url, data); +} + +::boost::optional<ConfigurationBackendDb::Data> BackendImpl::readDataFromDb( + OUString const & url) +{ + ::boost::optional<ConfigurationBackendDb::Data> data; + if (m_backendDb.get()) + data = m_backendDb->getEntry(url); + return data; +} + +OUString BackendImpl::deleteDataFromDb(OUString const & url) +{ + OUString url2(url); + if (m_backendDb.get()) { + boost::optional< ConfigurationBackendDb::Data > data( + m_backendDb->getEntry(url)); + if (data) { + url2 = expandUnoRcTerm(data->iniEntry); + } + m_backendDb->removeEntry(url); + } + return url2; +} + +// XPackageRegistry +//______________________________________________________________________________ +Sequence< Reference<deployment::XPackageTypeInfo> > +BackendImpl::getSupportedPackageTypes() throw (RuntimeException) +{ + return m_typeInfos; +} + +// PackageRegistryBackend +//______________________________________________________________________________ +Reference<deployment::XPackage> BackendImpl::bindPackage_( + OUString const & url, OUString const & mediaType_, + sal_Bool bRemoved, OUString const & identifier, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + OUString mediaType( mediaType_ ); + if (mediaType.getLength() == 0) + { + // detect media-type: + ::ucbhelper::Content ucbContent; + if (create_ucb_content( &ucbContent, url, xCmdEnv )) + { + const OUString title( ucbContent.getPropertyValue( + StrTitle::get() ).get<OUString>() ); + if (title.endsWithIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM(".xcu") )) { + mediaType = OUSTR("application/" + "vnd.sun.star.configuration-data"); + } + if (title.endsWithIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM(".xcs") )) { + mediaType = OUSTR("application/" + "vnd.sun.star.configuration-schema"); + } + } + if (mediaType.getLength() == 0) + throw lang::IllegalArgumentException( + StrCannotDetectMediaType::get() + url, + static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) ); + } + + String type, subType; + INetContentTypeParameterList params; + if (INetContentTypes::parse( mediaType, type, subType, ¶ms )) + { + if (type.EqualsIgnoreCaseAscii("application")) + { + OUString name; + if (!bRemoved) + { + ::ucbhelper::Content ucbContent( url, xCmdEnv ); + name = ucbContent.getPropertyValue( + StrTitle::get() ).get<OUString>(); + } + + ::ucbhelper::Content ucbContent( url, xCmdEnv ); + if (subType.EqualsIgnoreCaseAscii( + "vnd.sun.star.configuration-data")) + { + return new PackageImpl( + this, url, name, m_xConfDataTypeInfo, false /* data file */, + bRemoved, identifier); + } + else if (subType.EqualsIgnoreCaseAscii( + "vnd.sun.star.configuration-schema")) { + return new PackageImpl( + this, url, name, m_xConfSchemaTypeInfo, true /* schema file */, + bRemoved, identifier); + } + } + } + throw lang::IllegalArgumentException( + StrUnsupportedMediaType::get() + mediaType, + static_cast<OWeakObject *>(this), + static_cast<sal_Int16>(-1) ); +} + +//############################################################################## + +//______________________________________________________________________________ +void BackendImpl::configmgrini_verify_init( + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + if (transientMode()) + return; + const ::osl::MutexGuard guard( getMutex() ); + if (! m_configmgrini_inited) + { + // common rc: + ::ucbhelper::Content ucb_content; + if (create_ucb_content( + &ucb_content, + makeURL( getCachePath(), OUSTR("configmgr.ini") ), + xCmdEnv, false /* no throw */ )) + { + OUString line; + if (readLine( &line, OUSTR("SCHEMA="), ucb_content, + RTL_TEXTENCODING_UTF8 )) + { + sal_Int32 index = sizeof ("SCHEMA=") - 1; + do { + OUString token( line.getToken( 0, ' ', index ).trim() ); + if (token.getLength() > 0) { + //The file may not exist anymore if a shared or bundled + //extension was removed, but it can still be in the configmgrini. + //After running XExtensionManager::synchronize, the configmgrini is + //cleaned up + m_xcs_files.push_back( token ); + } + } + while (index >= 0); + } + if (readLine( &line, OUSTR("DATA="), ucb_content, + RTL_TEXTENCODING_UTF8 )) { + sal_Int32 index = sizeof ("DATA=") - 1; + do { + OUString token( line.getToken( 0, ' ', index ).trim() ); + if (token.getLength() > 0) + { + if (token[ 0 ] == '?') + token = token.copy( 1 ); + //The file may not exist anymore if a shared or bundled + //extension was removed, but it can still be in the configmgrini. + //After running XExtensionManager::synchronize, the configmgrini is + //cleaned up + m_xcu_files.push_back( token ); + } + } + while (index >= 0); + } + } + m_configmgrini_modified = false; + m_configmgrini_inited = true; + } +} + +//______________________________________________________________________________ +void BackendImpl::configmgrini_flush( + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + if (transientMode()) + return; + if (!m_configmgrini_inited || !m_configmgrini_modified) + return; + + ::rtl::OStringBuffer buf; + if (! m_xcs_files.empty()) + { + t_stringlist::const_iterator iPos( m_xcs_files.begin() ); + t_stringlist::const_iterator const iEnd( m_xcs_files.end() ); + buf.append( RTL_CONSTASCII_STRINGPARAM("SCHEMA=") ); + while (iPos != iEnd) { + // encoded ASCII file-urls: + const ::rtl::OString item( + ::rtl::OUStringToOString( *iPos, RTL_TEXTENCODING_ASCII_US ) ); + buf.append( item ); + ++iPos; + if (iPos != iEnd) + buf.append( ' ' ); + } + buf.append(LF); + } + if (! m_xcu_files.empty()) + { + t_stringlist::const_iterator iPos( m_xcu_files.begin() ); + t_stringlist::const_iterator const iEnd( m_xcu_files.end() ); + buf.append( RTL_CONSTASCII_STRINGPARAM("DATA=") ); + while (iPos != iEnd) { + // encoded ASCII file-urls: + const ::rtl::OString item( + ::rtl::OUStringToOString( *iPos, RTL_TEXTENCODING_ASCII_US ) ); + buf.append( item ); + ++iPos; + if (iPos != iEnd) + buf.append( ' ' ); + } + buf.append(LF); + } + + // write configmgr.ini: + const Reference<io::XInputStream> xData( + ::xmlscript::createInputStream( + ::rtl::ByteSequence( + reinterpret_cast<sal_Int8 const *>(buf.getStr()), + buf.getLength() ) ) ); + ::ucbhelper::Content ucb_content( + makeURL( getCachePath(), OUSTR("configmgr.ini") ), xCmdEnv ); + ucb_content.writeStream( xData, true /* replace existing */ ); + + m_configmgrini_modified = false; +} + +//______________________________________________________________________________ +bool BackendImpl::addToConfigmgrIni( bool isSchema, OUString const & url_, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + const OUString rcterm( dp_misc::makeRcTerm(url_) ); + const ::osl::MutexGuard guard( getMutex() ); + configmgrini_verify_init( xCmdEnv ); + t_stringlist & rSet = getFiles(isSchema); + if (::std::find( rSet.begin(), rSet.end(), rcterm ) == rSet.end()) { + rSet.push_front( rcterm ); // prepend to list, thus overriding + // write immediately: + m_configmgrini_modified = true; + configmgrini_flush( xCmdEnv ); + return true; + } + else + return false; +} + +//______________________________________________________________________________ +bool BackendImpl::removeFromConfigmgrIni( + bool isSchema, OUString const & url_, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + const OUString rcterm( dp_misc::makeRcTerm(url_) ); + const ::osl::MutexGuard guard( getMutex() ); + configmgrini_verify_init( xCmdEnv ); + t_stringlist & rSet = getFiles(isSchema); + t_stringlist::iterator i(std::find(rSet.begin(), rSet.end(), rcterm)); + if (i == rSet.end() && !isSchema) + { + //in case the xcu contained %origin% then the configmr.ini contains the + //url to the file in the user installation (e.g. $BUNDLED_EXTENSIONS_USER) + //However, m_url (getURL()) contains the URL for the file in the actual + //extension installatation. + ::boost::optional<ConfigurationBackendDb::Data> data = readDataFromDb(url_); + if (data) + i = std::find(rSet.begin(), rSet.end(), data->iniEntry); + } + if (i == rSet.end()) { + return false; + } + rSet.erase(i); + // write immediately: + m_configmgrini_modified = true; + configmgrini_flush( xCmdEnv ); + return true; +} + +//############################################################################## + +// Package +//______________________________________________________________________________ +BackendImpl * BackendImpl::PackageImpl::getMyBackend() const +{ + BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get()); + if (NULL == pBackend) + { + //May throw a DisposedException + check(); + //We should never get here... + throw RuntimeException( + OUSTR("Failed to get the BackendImpl"), + static_cast<OWeakObject*>(const_cast<PackageImpl *>(this))); + } + return pBackend; +} + +beans::Optional< beans::Ambiguous<sal_Bool> > +BackendImpl::PackageImpl::isRegistered_( + ::osl::ResettableMutexGuard &, + ::rtl::Reference<AbortChannel> const &, + Reference<XCommandEnvironment> const & ) +{ + BackendImpl * that = getMyBackend(); + const rtl::OUString url(getURL()); + + bool bReg = false; + if (that->readDataFromDb(getURL())) + bReg = true; + if (!bReg) + //fallback for user extension registered in berkeley DB + bReg = that->m_registeredPackages->has( + rtl::OUStringToOString( url, RTL_TEXTENCODING_UTF8 )); + + return beans::Optional< beans::Ambiguous<sal_Bool> >( + true, beans::Ambiguous<sal_Bool>( bReg, false ) ); +} + +//------------------------------------------------------------------------------ +OUString encodeForXml( OUString const & text ) +{ + // encode conforming xml: + sal_Int32 len = text.getLength(); + ::rtl::OUStringBuffer buf; + for ( sal_Int32 pos = 0; pos < len; ++pos ) + { + sal_Unicode c = text[ pos ]; + switch (c) { + case '<': + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("<") ); + break; + case '>': + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(">") ); + break; + case '&': + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("&") ); + break; + case '\'': + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("'") ); + break; + case '\"': + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(""") ); + break; + default: + buf.append( c ); + break; + } + } + return buf.makeStringAndClear(); +} + +//______________________________________________________________________________ +OUString replaceOrigin( + OUString const & url, OUString const & destFolder, Reference< XCommandEnvironment > const & xCmdEnv, bool & out_replaced) +{ + // looking for %origin%: + ::ucbhelper::Content ucb_content( url, xCmdEnv ); + ::rtl::ByteSequence bytes( readFile( ucb_content ) ); + ::rtl::ByteSequence filtered( bytes.getLength() * 2, + ::rtl::BYTESEQ_NODEFAULT ); + bool use_filtered = false; + ::rtl::OString origin; + sal_Char const * pBytes = reinterpret_cast<sal_Char const *>( + bytes.getConstArray()); + sal_Size nBytes = bytes.getLength(); + sal_Int32 write_pos = 0; + while (nBytes > 0) + { + sal_Int32 index = rtl_str_indexOfChar_WithLength( pBytes, nBytes, '%' ); + if (index < 0) { + if (! use_filtered) // opt + break; + index = nBytes; + } + + if ((write_pos + index) > filtered.getLength()) + filtered.realloc( (filtered.getLength() + index) * 2 ); + rtl_copyMemory( filtered.getArray() + write_pos, pBytes, index ); + write_pos += index; + pBytes += index; + nBytes -= index; + if (nBytes == 0) + break; + + // consume %: + ++pBytes; + --nBytes; + sal_Char const * pAdd = "%"; + sal_Int32 nAdd = 1; + if (nBytes > 1 && pBytes[ 0 ] == '%') + { + // %% => % + ++pBytes; + --nBytes; + use_filtered = true; + } + else if (rtl_str_shortenedCompare_WithLength( + pBytes, nBytes, + RTL_CONSTASCII_STRINGPARAM("origin%"), + sizeof ("origin%") - 1 ) == 0) + { + if (origin.getLength() == 0) { + // encode only once + origin = ::rtl::OUStringToOString( + encodeForXml( url.copy( 0, url.lastIndexOf( '/' ) ) ), + // xxx todo: encode always for UTF-8? => lookup doc-header? + RTL_TEXTENCODING_UTF8 ); + } + pAdd = origin.getStr(); + nAdd = origin.getLength(); + pBytes += (sizeof ("origin%") - 1); + nBytes -= (sizeof ("origin%") - 1); + use_filtered = true; + } + if ((write_pos + nAdd) > filtered.getLength()) + filtered.realloc( (filtered.getLength() + nAdd) * 2 ); + rtl_copyMemory( filtered.getArray() + write_pos, pAdd, nAdd ); + write_pos += nAdd; + } + if (!use_filtered) + return url; + if (write_pos < filtered.getLength()) + filtered.realloc( write_pos ); + rtl::OUString newUrl(url); + if (destFolder.getLength()) + { + //get the file name of the xcu and add it to the url of the temporary folder + sal_Int32 i = url.lastIndexOf('/'); + newUrl = destFolder + url.copy(i); + } + + ucbhelper::Content(newUrl, xCmdEnv).writeStream( + xmlscript::createInputStream(filtered), true); + out_replaced = true; + return newUrl; +} + +//______________________________________________________________________________ +void BackendImpl::PackageImpl::processPackage_( + ::osl::ResettableMutexGuard &, + bool doRegisterPackage, + bool startup, + ::rtl::Reference<AbortChannel> const &, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + BackendImpl * that = getMyBackend(); + OUString url( getURL() ); + + if (doRegisterPackage) + { + ConfigurationBackendDb::Data data; + if (!m_isSchema) + { + const OUString sModFolder = that->createFolder(OUString(), xCmdEnv); + bool out_replaced = false; + url = replaceOrigin(url, sModFolder, xCmdEnv, out_replaced); + if (out_replaced) + data.dataUrl = sModFolder; + else + deleteTempFolder(sModFolder); + } + //No need for live-deployment for bundled extension, because OOo + //restarts after installation + if (that->m_eContext != CONTEXT_BUNDLED + && !startup) + { + if (m_isSchema) + { + com::sun::star::configuration::Update::get( + that->m_xComponentContext)->insertExtensionXcsFile( + that->m_eContext == CONTEXT_SHARED, expandUnoRcUrl(url)); + } + else + { + com::sun::star::configuration::Update::get( + that->m_xComponentContext)->insertExtensionXcuFile( + that->m_eContext == CONTEXT_SHARED, expandUnoRcUrl(url)); + } + } + that->addToConfigmgrIni( m_isSchema, url, xCmdEnv ); + data.iniEntry = dp_misc::makeRcTerm(url); + that->addDataToDb(getURL(), data); + } + else // revoke + { + if (!that->removeFromConfigmgrIni(m_isSchema, url, xCmdEnv)) { + t_string2string_map entries( + that->m_registeredPackages->getEntries()); + for (t_string2string_map::iterator i(entries.begin()); + i != entries.end(); ++i) + { + //If the xcu file was installed before the configmgr was chaned + //to use the configmgr.ini, one needed to rebuild to whole directory + //structur containing the xcu, xcs files from all extensions. Now, + //we just add all other xcu/xcs files to the configmgr.ini instead of + //rebuilding the directory structure. + rtl::OUString url2( + rtl::OStringToOUString(i->first, RTL_TEXTENCODING_UTF8)); + if (url2 != url) { + bool schema = i->second.equalsIgnoreAsciiCase( + "vnd.sun.star.configuration-schema"); + OUString url_replaced(url2); + ConfigurationBackendDb::Data data; + if (!schema) + { + const OUString sModFolder = that->createFolder(OUString(), xCmdEnv); + bool out_replaced = false; + url_replaced = replaceOrigin( + url2, sModFolder, xCmdEnv, out_replaced); + if (out_replaced) + data.dataUrl = sModFolder; + else + deleteTempFolder(sModFolder); + } + that->addToConfigmgrIni(schema, url_replaced, xCmdEnv); + data.iniEntry = dp_misc::makeRcTerm(url_replaced); + that->addDataToDb(url2, data); + } + that->m_registeredPackages->erase(i->first); + } + try + { + ::ucbhelper::Content( + makeURL( that->getCachePath(), OUSTR("registry") ), + xCmdEnv ).executeCommand( + OUSTR("delete"), Any( true /* delete physically */ ) ); + } + catch(Exception&) + { + OSL_ASSERT(0); + } + } + url = that->deleteDataFromDb(url); + if (!m_isSchema) { + com::sun::star::configuration::Update::get( + that->m_xComponentContext)->removeExtensionXcuFile( + expandUnoRcUrl(url)); + } + } +} + +} // anon namespace + +namespace sdecl = comphelper::service_decl; +sdecl::class_<BackendImpl, sdecl::with_args<true> > serviceBI; +extern sdecl::ServiceDecl const serviceDecl( + serviceBI, + "com.sun.star.comp.deployment.configuration.PackageRegistryBackend", + BACKEND_SERVICE_NAME ); + +} // namespace configuration +} // namespace backend +} // namespace dp_registry + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/configuration/dp_configuration.hrc b/desktop/source/deployment/registry/configuration/dp_configuration.hrc new file mode 100644 index 000000000000..01e1905228b3 --- /dev/null +++ b/desktop/source/deployment/registry/configuration/dp_configuration.hrc @@ -0,0 +1,36 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_CONFIGURATION_HRC +#define INCLUDED_DP_CONFIGURATION_HRC + +#include "deployment.hrc" + +#define RID_STR_CONF_SCHEMA (RID_DEPLOYMENT_CONF_START+10) +#define RID_STR_CONF_DATA (RID_DEPLOYMENT_CONF_START+11) + +#endif diff --git a/desktop/source/deployment/registry/configuration/dp_configuration.src b/desktop/source/deployment/registry/configuration/dp_configuration.src new file mode 100644 index 000000000000..7ff749b18459 --- /dev/null +++ b/desktop/source/deployment/registry/configuration/dp_configuration.src @@ -0,0 +1,39 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "dp_configuration.hrc" + +String RID_STR_CONF_SCHEMA +{ + Text [ en-US ] = "Configuration Schema"; +}; + +String RID_STR_CONF_DATA +{ + Text [ en-US ] = "Configuration Data"; +}; + diff --git a/desktop/source/deployment/registry/configuration/dp_configurationbackenddb.cxx b/desktop/source/deployment/registry/configuration/dp_configurationbackenddb.cxx new file mode 100644 index 000000000000..5a433cbb03a5 --- /dev/null +++ b/desktop/source/deployment/registry/configuration/dp_configurationbackenddb.cxx @@ -0,0 +1,178 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "rtl/string.h" +#include "rtl/bootstrap.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/xml/dom/XDocumentBuilder.hpp" +#include "com/sun/star/xml/xpath/XXPathAPI.hpp" +#include "dp_misc.h" + +#include "dp_configurationbackenddb.hxx" + + +namespace css = ::com::sun::star; +using namespace ::com::sun::star::uno; +using ::rtl::OUString; + +#define EXTENSION_REG_NS "http://openoffice.org/extensionmanager/configuration-registry/2010" +#define NS_PREFIX "conf" +#define ROOT_ELEMENT_NAME "configuration-backend-db" +#define KEY_ELEMENT_NAME "configuration" + +namespace dp_registry { +namespace backend { +namespace configuration { + +ConfigurationBackendDb::ConfigurationBackendDb( + Reference<XComponentContext> const & xContext, + ::rtl::OUString const & url):BackendDb(xContext, url) +{ + +} + +OUString ConfigurationBackendDb::getDbNSName() +{ + return OUSTR(EXTENSION_REG_NS); +} + +OUString ConfigurationBackendDb::getNSPrefix() +{ + return OUSTR(NS_PREFIX); +} + +OUString ConfigurationBackendDb::getRootElementName() +{ + return OUSTR(ROOT_ELEMENT_NAME); +} + +OUString ConfigurationBackendDb::getKeyElementName() +{ + return OUSTR(KEY_ELEMENT_NAME); +} + + +void ConfigurationBackendDb::addEntry(::rtl::OUString const & url, Data const & data) +{ + try{ + Reference<css::xml::dom::XNode> helpNode + = writeKeyElement(url); + + writeSimpleElement(OUSTR("data-url"), data.dataUrl, helpNode); + writeSimpleElement(OUSTR("ini-entry"), data.iniEntry, helpNode); + save(); + } + catch (css::deployment::DeploymentException& ) + { + throw; + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to write data entry in configuration backend db: ") + + m_urlDb, 0, exc); + } +} + + +::boost::optional<ConfigurationBackendDb::Data> +ConfigurationBackendDb::getEntry(::rtl::OUString const & url) +{ + try + { + ConfigurationBackendDb::Data retData; + Reference<css::xml::dom::XNode> aNode = getKeyElement(url); + if (aNode.is()) + { + retData.dataUrl = readSimpleElement(OUSTR("data-url"), aNode); + retData.iniEntry = readSimpleElement(OUSTR("ini-entry"), aNode); + } + else + { + return ::boost::optional<Data>(); + } + return ::boost::optional<Data>(retData); + } + catch (css::deployment::DeploymentException& ) + { + throw; + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to read data entry in configuration backend db: ") + + m_urlDb, 0, exc); + } +} + +::std::list<OUString> ConfigurationBackendDb::getAllDataUrls() +{ + try + { + ::std::list<OUString> listRet; + Reference<css::xml::dom::XDocument> doc = getDocument(); + Reference<css::xml::dom::XNode> root = doc->getFirstChild(); + + Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI(); + const OUString sPrefix = getNSPrefix(); + OUString sExpression( + sPrefix + OUSTR(":configuration/") + sPrefix + OUSTR(":data-url/text()")); + Reference<css::xml::dom::XNodeList> nodes = + xpathApi->selectNodeList(root, sExpression); + if (nodes.is()) + { + sal_Int32 length = nodes->getLength(); + for (sal_Int32 i = 0; i < length; i++) + listRet.push_back(nodes->item(i)->getNodeValue()); + } + return listRet; + } + catch (css::deployment::DeploymentException& ) + { + throw; + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to read data entry in configuration backend db: ") + + m_urlDb, 0, exc); + } +} + +} // namespace configuration +} // namespace backend +} // namespace dp_registry + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/configuration/dp_configurationbackenddb.hxx b/desktop/source/deployment/registry/configuration/dp_configurationbackenddb.hxx new file mode 100644 index 000000000000..00a5515b3780 --- /dev/null +++ b/desktop/source/deployment/registry/configuration/dp_configurationbackenddb.hxx @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_CONFIGURATIONBACKENDDB_HXX +#define INCLUDED_DP_CONFIGURATIONBACKENDDB_HXX + +#include "rtl/ustring.hxx" +#include "rtl/string.hxx" +#include <list> +#include "boost/optional.hpp" +#include "dp_backenddb.hxx" + +namespace css = ::com::sun::star; + +namespace com { namespace sun { namespace star { + namespace uno { + class XComponentContext; + } +}}} + +namespace dp_registry { +namespace backend { +namespace configuration { + +/* The XML file stores the extensions which are currently registered. + They will be removed when they are revoked. + */ +class ConfigurationBackendDb: public dp_registry::backend::BackendDb +{ +protected: + virtual ::rtl::OUString getDbNSName(); + + virtual ::rtl::OUString getNSPrefix(); + + virtual ::rtl::OUString getRootElementName(); + + virtual ::rtl::OUString getKeyElementName(); + +public: + struct Data + { + /* the URL to the folder containing the xcu or xcs files which contained + %origin% + */ + ::rtl::OUString dataUrl; + /* the URL of the xcu or xcs file which is written in to the configmgr.ini + */ + ::rtl::OUString iniEntry; + }; + +public: + + ConfigurationBackendDb( css::uno::Reference<css::uno::XComponentContext> const & xContext, + ::rtl::OUString const & url); + + void addEntry(::rtl::OUString const & url, Data const & data); + + ::boost::optional<Data> getEntry(::rtl::OUString const & url); + ::std::list< ::rtl::OUString> getAllDataUrls(); +}; + + + +} +} +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/configuration/makefile.mk b/desktop/source/deployment/registry/configuration/makefile.mk new file mode 100644 index 000000000000..9bcbd50d4230 --- /dev/null +++ b/desktop/source/deployment/registry/configuration/makefile.mk @@ -0,0 +1,52 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/..$/.. + +PRJNAME = desktop +TARGET = deployment_registry_configuration +ENABLE_EXCEPTIONS = TRUE + +INCPRE += ..$/..$/inc + +.INCLUDE : settings.mk + +.IF "$(SYSTEM_DB)" == "YES" +CFLAGS+=-DSYSTEM_DB -I$(DB_INCLUDES) +.ENDIF + +SRS1NAME = $(TARGET) +SRC1FILES = \ + dp_configuration.src + +SLOFILES = \ + $(SLO)$/dp_configuration.obj \ + $(SLO)$/dp_configurationbackenddb.obj + +.INCLUDE : ..$/..$/target.pmk +.INCLUDE : target.mk + diff --git a/desktop/source/deployment/registry/dp_backend.cxx b/desktop/source/deployment/registry/dp_backend.cxx new file mode 100644 index 000000000000..3550f6291744 --- /dev/null +++ b/desktop/source/deployment/registry/dp_backend.cxx @@ -0,0 +1,819 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_backend.h" +#include "dp_ucb.h" +#include "rtl/uri.hxx" +#include "rtl/bootstrap.hxx" +#include "osl/file.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "comphelper/servicedecl.hxx" +#include "comphelper/unwrapargs.hxx" +#include "ucbhelper/content.hxx" +#include "com/sun/star/lang/WrappedTargetRuntimeException.hpp" +#include "com/sun/star/deployment/InvalidRemovedParameterException.hpp" +#include "com/sun/star/ucb/InteractiveAugmentedIOException.hpp" +#include "com/sun/star/ucb/IOErrorCode.hpp" +#include "com/sun/star/beans/StringPair.hpp" +#include "com/sun/star/sdbc/XResultSet.hpp" +#include "com/sun/star/sdbc/XRow.hpp" + + +using namespace ::dp_misc; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using ::rtl::OUString; + +namespace dp_registry { +namespace backend { + +//______________________________________________________________________________ +PackageRegistryBackend::~PackageRegistryBackend() +{ +} + +//______________________________________________________________________________ +void PackageRegistryBackend::disposing( lang::EventObject const & event ) + throw (RuntimeException) +{ + Reference<deployment::XPackage> xPackage( + event.Source, UNO_QUERY_THROW ); + OUString url( xPackage->getURL() ); + ::osl::MutexGuard guard( getMutex() ); + if ( m_bound.erase( url ) != 1 ) + { + OSL_ASSERT( false ); + } +} + +//______________________________________________________________________________ +PackageRegistryBackend::PackageRegistryBackend( + Sequence<Any> const & args, + Reference<XComponentContext> const & xContext ) + : t_BackendBase( getMutex() ), + m_xComponentContext( xContext ), + m_eContext( CONTEXT_UNKNOWN ), + m_readOnly( false ) +{ + boost::optional<OUString> cachePath; + boost::optional<bool> readOnly; + comphelper::unwrapArgs( args, m_context, cachePath, readOnly ); + if (cachePath) + m_cachePath = *cachePath; + if (readOnly) + m_readOnly = *readOnly; + + if (m_context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("user") )) + m_eContext = CONTEXT_USER; + else if (m_context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("shared") )) + m_eContext = CONTEXT_SHARED; + else if (m_context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("bundled") )) + m_eContext = CONTEXT_BUNDLED; + else if (m_context.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("tmp") )) + m_eContext = CONTEXT_TMP; + else if (m_context.matchIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.tdoc:/") )) + m_eContext = CONTEXT_DOCUMENT; + else + m_eContext = CONTEXT_UNKNOWN; +} + +//______________________________________________________________________________ +void PackageRegistryBackend::check() +{ + ::osl::MutexGuard guard( getMutex() ); + if (rBHelper.bInDispose || rBHelper.bDisposed) { + throw lang::DisposedException( + OUSTR("PackageRegistryBackend instance has already been disposed!"), + static_cast<OWeakObject *>(this) ); + } +} + +//______________________________________________________________________________ +void PackageRegistryBackend::disposing() +{ + try { + for ( t_string2ref::const_iterator i = m_bound.begin(); i != m_bound.end(); ++i) + i->second->removeEventListener(this); + m_bound.clear(); + m_xComponentContext.clear(); + WeakComponentImplHelperBase::disposing(); + } + catch (RuntimeException &) { + throw; + } + catch (Exception &) { + Any exc( ::cppu::getCaughtException() ); + throw lang::WrappedTargetRuntimeException( + OUSTR("caught unexpected exception while disposing!"), + static_cast<OWeakObject *>(this), exc ); + } +} + +// XPackageRegistry +//______________________________________________________________________________ +Reference<deployment::XPackage> PackageRegistryBackend::bindPackage( + OUString const & url, OUString const & mediaType, sal_Bool bRemoved, + OUString const & identifier, Reference<XCommandEnvironment> const & xCmdEnv ) + throw (deployment::DeploymentException, + deployment::InvalidRemovedParameterException, + ucb::CommandFailedException, + lang::IllegalArgumentException, RuntimeException) +{ + ::osl::ResettableMutexGuard guard( getMutex() ); + check(); + + t_string2ref::const_iterator const iFind( m_bound.find( url ) ); + if (iFind != m_bound.end()) + { + Reference<deployment::XPackage> xPackage( iFind->second ); + if (xPackage.is()) + { + if (mediaType.getLength() && + mediaType != xPackage->getPackageType()->getMediaType()) + throw lang::IllegalArgumentException + (OUSTR("XPackageRegistry::bindPackage: media type does not match"), + static_cast<OWeakObject*>(this), 1); + if (xPackage->isRemoved() != bRemoved) + throw deployment::InvalidRemovedParameterException( + OUSTR("XPackageRegistry::bindPackage: bRemoved parameter does not match"), + static_cast<OWeakObject*>(this), xPackage->isRemoved(), xPackage); + return xPackage; + } + } + + guard.clear(); + + Reference<deployment::XPackage> xNewPackage; + try { + xNewPackage = bindPackage_( url, mediaType, bRemoved, + identifier, xCmdEnv ); + } + catch (RuntimeException &) { + throw; + } + catch (lang::IllegalArgumentException &) { + throw; + } + catch (CommandFailedException &) { + throw; + } + catch (deployment::DeploymentException &) { + throw; + } + catch (Exception &) { + Any exc( ::cppu::getCaughtException() ); + throw deployment::DeploymentException( + OUSTR("Error binding package: ") + url, + static_cast<OWeakObject *>(this), exc ); + } + + guard.reset(); + + ::std::pair< t_string2ref::iterator, bool > insertion( + m_bound.insert( t_string2ref::value_type( url, xNewPackage ) ) ); + if (insertion.second) + { // first insertion + OSL_ASSERT( Reference<XInterface>(insertion.first->second) + == xNewPackage ); + } + else + { // found existing entry + Reference<deployment::XPackage> xPackage( insertion.first->second ); + if (xPackage.is()) + return xPackage; + insertion.first->second = xNewPackage; + } + + guard.clear(); + xNewPackage->addEventListener( this ); // listen for disposing events + return xNewPackage; +} + +OUString PackageRegistryBackend::createFolder( + OUString const & relUrl, + Reference<ucb::XCommandEnvironment> const & xCmdEnv) +{ + OUString sDataFolder = makeURL(getCachePath(), relUrl); + //make sure the folder exist + ucbhelper::Content dataContent; + ::dp_misc::create_folder(&dataContent, sDataFolder, xCmdEnv); + + OUString sDataFolderURL = dp_misc::expandUnoRcUrl(sDataFolder); + + OUString tempEntry; + if (::osl::File::createTempFile( + &sDataFolderURL, 0, &tempEntry ) != ::osl::File::E_None) + throw RuntimeException( + OUSTR("::osl::File::createTempFile() failed!"), 0 ); + tempEntry = tempEntry.copy( tempEntry.lastIndexOf( '/' ) + 1 ); + OUString destFolder= makeURL(sDataFolder, tempEntry) + OUSTR("_"); + ::ucbhelper::Content destFolderContent; + dp_misc::create_folder( &destFolderContent, destFolder, xCmdEnv ); + + return destFolder; +} + +void PackageRegistryBackend::deleteTempFolder( + OUString const & folderUrl) +{ + OSL_ASSERT(folderUrl.getLength() + && folderUrl[folderUrl.getLength() - 1] == '_'); + if (folderUrl.getLength() + && folderUrl[folderUrl.getLength() - 1] == '_') + { + const OUString tempFile = folderUrl.copy(0, folderUrl.getLength() - 1); + erase_path( folderUrl, Reference<XCommandEnvironment>(), + false /* no throw: ignore errors */ ); + erase_path( tempFile, Reference<XCommandEnvironment>(), + false /* no throw: ignore errors */ ); + } +} + +void PackageRegistryBackend::deleteUnusedFolders( + OUString const & relUrl, + ::std::list< OUString> const & usedFolders) +{ + try + { + const OUString sDataFolder = makeURL(getCachePath(), relUrl); + ::ucbhelper::Content tempFolder( + sDataFolder, Reference<ucb::XCommandEnvironment>()); + Reference<sdbc::XResultSet> xResultSet( + tempFolder.createCursor( + Sequence<OUString>( &StrTitle::get(), 1 ), + ::ucbhelper::INCLUDE_DOCUMENTS_ONLY ) ); + // get all temp directories: + ::std::vector<OUString> tempEntries; + + const char tmp[] = ".tmp"; + + while (xResultSet->next()) + { + OUString title( + Reference<sdbc::XRow>( + xResultSet, UNO_QUERY_THROW )->getString( + 1 /* Title */ ) ); + + if (title.endsWithAsciiL(RTL_CONSTASCII_STRINGPARAM(tmp))) + tempEntries.push_back( + makeURLAppendSysPathSegment(sDataFolder, title)); + } + + for ( ::std::size_t pos = 0; pos < tempEntries.size(); ++pos ) + { + //usedFolders contains the urls to the folders which have + //a trailing underscore + const OUString tempFolderName = tempEntries[ pos ] + OUSTR("_"); + + if (::std::find( usedFolders.begin(), usedFolders.end(), tempFolderName ) == + usedFolders.end()) + { + deleteTempFolder(tempFolderName); + } + } + } + catch (ucb::InteractiveAugmentedIOException& e) + { + //In case the folder containing all the data folder does not + //exist yet, we ignore the exception + if (e.Code != ucb::IOErrorCode_NOT_EXISTING) + throw e; + } + +} + +//############################################################################## + +//______________________________________________________________________________ +Package::~Package() +{ +} + +//______________________________________________________________________________ +Package::Package( ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, + OUString const & rName, + OUString const & displayName, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + bool bRemoved, + OUString const & identifier) + : t_PackageBase( getMutex() ), + m_myBackend( myBackend ), + m_url( url ), + m_name( rName ), + m_displayName( displayName ), + m_xPackageType( xPackageType ), + m_bRemoved(bRemoved), + m_identifier(identifier) +{ + if (m_bRemoved) + { + //We use the last segment of the URL + OSL_ASSERT(m_name.getLength() == 0); + OUString name = m_url; + rtl::Bootstrap::expandMacros(name); + sal_Int32 index = name.lastIndexOf('/'); + if (index != -1 && index < name.getLength()) + m_name = name.copy(index + 1); + } +} + +//______________________________________________________________________________ +void Package::disposing() +{ + m_myBackend.clear(); + WeakComponentImplHelperBase::disposing(); +} + +//______________________________________________________________________________ +void Package::check() const +{ + ::osl::MutexGuard guard( getMutex() ); + if (rBHelper.bInDispose || rBHelper.bDisposed) { + throw lang::DisposedException( + OUSTR("Package instance has already been disposed!"), + static_cast<OWeakObject *>(const_cast<Package *>(this))); + } +} + +// XComponent +//______________________________________________________________________________ +void Package::dispose() throw (RuntimeException) +{ + check(); + WeakComponentImplHelperBase::dispose(); +} + +//______________________________________________________________________________ +void Package::addEventListener( + Reference<lang::XEventListener> const & xListener ) throw (RuntimeException) +{ + check(); + WeakComponentImplHelperBase::addEventListener( xListener ); +} + +//______________________________________________________________________________ +void Package::removeEventListener( + Reference<lang::XEventListener> const & xListener ) throw (RuntimeException) +{ + check(); + WeakComponentImplHelperBase::removeEventListener( xListener ); +} + +// XModifyBroadcaster +//______________________________________________________________________________ +void Package::addModifyListener( + Reference<util::XModifyListener> const & xListener ) + throw (RuntimeException) +{ + check(); + rBHelper.addListener( ::getCppuType( &xListener ), xListener ); +} + +//______________________________________________________________________________ +void Package::removeModifyListener( + Reference<util::XModifyListener> const & xListener ) + throw (RuntimeException) +{ + check(); + rBHelper.removeListener( ::getCppuType( &xListener ), xListener ); +} + +//______________________________________________________________________________ +void Package::checkAborted( + ::rtl::Reference<AbortChannel> const & abortChannel ) +{ + if (abortChannel.is() && abortChannel->isAborted()) { + throw CommandAbortedException( + OUSTR("abort!"), static_cast<OWeakObject *>(this) ); + } +} + +// XPackage +//______________________________________________________________________________ +Reference<task::XAbortChannel> Package::createAbortChannel() + throw (RuntimeException) +{ + check(); + return new AbortChannel; +} + +//______________________________________________________________________________ +sal_Bool Package::isBundle() throw (RuntimeException) +{ + return false; // default +} + +//______________________________________________________________________________ +::sal_Int32 Package::checkPrerequisites( + const css::uno::Reference< css::task::XAbortChannel >&, + const css::uno::Reference< css::ucb::XCommandEnvironment >&, + sal_Bool) + throw (css::deployment::DeploymentException, + css::deployment::ExtensionRemovedException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::uno::RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + return 0; +} + +//______________________________________________________________________________ +::sal_Bool Package::checkDependencies( + const css::uno::Reference< css::ucb::XCommandEnvironment >& ) + throw (css::deployment::DeploymentException, + css::deployment::ExtensionRemovedException, + css::ucb::CommandFailedException, + css::uno::RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + return true; +} + + +//______________________________________________________________________________ +Sequence< Reference<deployment::XPackage> > Package::getBundle( + Reference<task::XAbortChannel> const &, + Reference<XCommandEnvironment> const & ) + throw (deployment::DeploymentException, + CommandFailedException, CommandAbortedException, + lang::IllegalArgumentException, RuntimeException) +{ + return Sequence< Reference<deployment::XPackage> >(); +} + +//______________________________________________________________________________ +OUString Package::getName() throw (RuntimeException) +{ + return m_name; +} + +beans::Optional<OUString> Package::getIdentifier() throw (RuntimeException) +{ + if (m_bRemoved) + return beans::Optional<OUString>(true, m_identifier); + + return beans::Optional<OUString>(); +} + +//______________________________________________________________________________ +OUString Package::getVersion() throw ( + deployment::ExtensionRemovedException, + RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + return OUString(); +} + +//______________________________________________________________________________ +OUString Package::getURL() throw (RuntimeException) +{ + return m_url; +} + +//______________________________________________________________________________ +OUString Package::getDisplayName() throw ( + deployment::ExtensionRemovedException, RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + return m_displayName; +} + +//______________________________________________________________________________ +OUString Package::getDescription() throw ( + deployment::ExtensionRemovedException,RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + return OUString(); +} + +//______________________________________________________________________________ +Sequence<OUString> Package::getUpdateInformationURLs() throw ( + deployment::ExtensionRemovedException, RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + return Sequence<OUString>(); +} + +//______________________________________________________________________________ +css::beans::StringPair Package::getPublisherInfo() throw ( + deployment::ExtensionRemovedException, RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + css::beans::StringPair aEmptyPair; + return aEmptyPair; +} + +//______________________________________________________________________________ +uno::Reference< css::graphic::XGraphic > Package::getIcon( sal_Bool /*bHighContrast*/ ) + throw (deployment::ExtensionRemovedException, RuntimeException ) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + + uno::Reference< css::graphic::XGraphic > aEmpty; + return aEmpty; +} + +//______________________________________________________________________________ +Reference<deployment::XPackageTypeInfo> Package::getPackageType() + throw (RuntimeException) +{ + return m_xPackageType; +} + +//______________________________________________________________________________ +void Package::exportTo( + OUString const & destFolderURL, OUString const & newTitle, + sal_Int32 nameClashAction, Reference<XCommandEnvironment> const & xCmdEnv ) + throw (deployment::ExtensionRemovedException, + CommandFailedException, CommandAbortedException, RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + + ::ucbhelper::Content destFolder( destFolderURL, xCmdEnv ); + ::ucbhelper::Content sourceContent( getURL(), xCmdEnv ); + if (! destFolder.transferContent( + sourceContent, ::ucbhelper::InsertOperation_COPY, + newTitle, nameClashAction )) + throw RuntimeException( OUSTR("UCB transferContent() failed!"), 0 ); +} + +//______________________________________________________________________________ +void Package::fireModified() +{ + ::cppu::OInterfaceContainerHelper * container = rBHelper.getContainer( + ::getCppuType( static_cast<Reference< + util::XModifyListener> const *>(0) ) ); + if (container != 0) { + Sequence< Reference<XInterface> > elements( + container->getElements() ); + lang::EventObject evt( static_cast<OWeakObject *>(this) ); + for ( sal_Int32 pos = 0; pos < elements.getLength(); ++pos ) + { + Reference<util::XModifyListener> xListener( + elements[ pos ], UNO_QUERY ); + if (xListener.is()) + xListener->modified( evt ); + } + } +} + +// XPackage +//______________________________________________________________________________ +beans::Optional< beans::Ambiguous<sal_Bool> > Package::isRegistered( + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ) + throw (deployment::DeploymentException, + CommandFailedException, CommandAbortedException, RuntimeException) +{ + try { + ::osl::ResettableMutexGuard guard( getMutex() ); + return isRegistered_( guard, + AbortChannel::get(xAbortChannel), + xCmdEnv ); + } + catch (RuntimeException &) { + throw; + } + catch (CommandFailedException &) { + throw; + } + catch (CommandAbortedException &) { + throw; + } + catch (deployment::DeploymentException &) { + throw; + } + catch (Exception &) { + Any exc( ::cppu::getCaughtException() ); + throw deployment::DeploymentException( + OUSTR("unexpected exception occurred!"), + static_cast<OWeakObject *>(this), exc ); + } +} + +//______________________________________________________________________________ +void Package::processPackage_impl( + bool doRegisterPackage, + bool startup, + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + check(); + bool action = false; + + try { + try { + ::osl::ResettableMutexGuard guard( getMutex() ); + beans::Optional< beans::Ambiguous<sal_Bool> > option( + isRegistered_( guard, AbortChannel::get(xAbortChannel), + xCmdEnv ) ); + action = (option.IsPresent && + (option.Value.IsAmbiguous || + (doRegisterPackage ? !option.Value.Value + : option.Value.Value))); + if (action) { + + OUString displayName = isRemoved() ? getName() : getDisplayName(); + ProgressLevel progress( + xCmdEnv, + (doRegisterPackage + ? PackageRegistryBackend::StrRegisteringPackage::get() + : PackageRegistryBackend::StrRevokingPackage::get()) + + displayName ); + processPackage_( guard, + doRegisterPackage, + startup, + AbortChannel::get(xAbortChannel), + xCmdEnv ); + } + } + catch (RuntimeException &) { + OSL_ENSURE( 0, "### unexpected RuntimeException!" ); + throw; + } + catch (CommandFailedException &) { + throw; + } + catch (CommandAbortedException &) { + throw; + } + catch (deployment::DeploymentException &) { + throw; + } + catch (Exception &) { + Any exc( ::cppu::getCaughtException() ); + throw deployment::DeploymentException( + (doRegisterPackage + ? getResourceString(RID_STR_ERROR_WHILE_REGISTERING) + : getResourceString(RID_STR_ERROR_WHILE_REVOKING)) + + getDisplayName(), static_cast<OWeakObject *>(this), exc ); + } + } + catch (...) { + if (action) + fireModified(); + throw; + } + if (action) + fireModified(); +} + +//______________________________________________________________________________ +void Package::registerPackage( + sal_Bool startup, + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ) + throw (deployment::DeploymentException, + deployment::ExtensionRemovedException, + CommandFailedException, CommandAbortedException, + lang::IllegalArgumentException, RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + processPackage_impl( true /* register */, startup, xAbortChannel, xCmdEnv ); +} + +//______________________________________________________________________________ +void Package::revokePackage( + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ) + throw (deployment::DeploymentException, + CommandFailedException, CommandAbortedException, + lang::IllegalArgumentException, RuntimeException) +{ + processPackage_impl( false /* revoke */, false, xAbortChannel, xCmdEnv ); + +} + +PackageRegistryBackend * Package::getMyBackend() const +{ + PackageRegistryBackend * pBackend = m_myBackend.get(); + if (NULL == pBackend) + { + //May throw a DisposedException + check(); + //We should never get here... + throw RuntimeException( + OUSTR("Failed to get the BackendImpl"), + static_cast<OWeakObject*>(const_cast<Package *>(this))); + } + return pBackend; +} +OUString Package::getRepositoryName() + throw (RuntimeException) +{ + PackageRegistryBackend * backEnd = getMyBackend(); + return backEnd->getContext(); +} + +beans::Optional< OUString > Package::getRegistrationDataURL() + throw (deployment::ExtensionRemovedException, + css::uno::RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + return beans::Optional<OUString>(); +} + +sal_Bool Package::isRemoved() + throw (RuntimeException) +{ + return m_bRemoved; +} + +//############################################################################## + +//______________________________________________________________________________ +Package::TypeInfo::~TypeInfo() +{ +} + +// XPackageTypeInfo +//______________________________________________________________________________ +OUString Package::TypeInfo::getMediaType() throw (RuntimeException) +{ + return m_mediaType; +} + +//______________________________________________________________________________ +OUString Package::TypeInfo::getDescription() + throw (deployment::ExtensionRemovedException, RuntimeException) +{ + return getShortDescription(); +} + +//______________________________________________________________________________ +OUString Package::TypeInfo::getShortDescription() + throw (deployment::ExtensionRemovedException, RuntimeException) +{ + return m_shortDescr; +} + +//______________________________________________________________________________ +OUString Package::TypeInfo::getFileFilter() throw (RuntimeException) +{ + return m_fileFilter; +} + +//______________________________________________________________________________ +/************************** + * Get Icon + * + * @param highContrast NOTE: disabled the returning of high contrast icons. + * This bool is a noop now. + * @param smallIcon Return the small version of the icon + */ +Any Package::TypeInfo::getIcon( sal_Bool /*highContrast*/, sal_Bool smallIcon ) + throw (RuntimeException) +{ + if (! smallIcon) + return Any(); + const sal_uInt16 nIconId = m_smallIcon; + return Any( &nIconId, getCppuType( static_cast<sal_uInt16 const *>(0) ) ); +} + +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/dp_backenddb.cxx b/desktop/source/deployment/registry/dp_backenddb.cxx new file mode 100644 index 000000000000..bafeb18a7192 --- /dev/null +++ b/desktop/source/deployment/registry/dp_backenddb.cxx @@ -0,0 +1,643 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "rtl/string.h" +#include "rtl/strbuf.hxx" +#include "rtl/bootstrap.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "osl/file.hxx" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/xml/dom/XDocumentBuilder.hpp" +#include "com/sun/star/xml/xpath/XXPathAPI.hpp" +#include "com/sun/star/io/XActiveDataSource.hpp" +#include "com/sun/star/io/XActiveDataControl.hpp" +#include "dp_ucb.h" +#include "dp_misc.h" +#include "ucbhelper/content.hxx" +#include "xmlscript/xml_helper.hxx" +#include "dp_backenddb.hxx" + + +namespace css = ::com::sun::star; +using namespace ::com::sun::star::uno; +using ::rtl::OUString; + + +namespace dp_registry { +namespace backend { + +BackendDb::BackendDb( + Reference<css::uno::XComponentContext> const & xContext, + ::rtl::OUString const & url): + m_xContext(xContext) +{ + m_urlDb = dp_misc::expandUnoRcUrl(url); +} + +void BackendDb::save() +{ + const Reference<css::io::XActiveDataSource> xDataSource(m_doc,css::uno::UNO_QUERY_THROW); + ::rtl::ByteSequence bytes; + xDataSource->setOutputStream(::xmlscript::createOutputStream(&bytes)); + const Reference<css::io::XActiveDataControl> xDataControl(m_doc,css::uno::UNO_QUERY_THROW); + xDataControl->start(); + + const Reference<css::io::XInputStream> xData( + ::xmlscript::createInputStream(bytes)); + ::ucbhelper::Content ucbDb(m_urlDb, 0); + ucbDb.writeStream(xData, true /*replace existing*/); +} + +css::uno::Reference<css::xml::dom::XDocument> BackendDb::getDocument() +{ + if (!m_doc.is()) + { + const Reference<css::xml::dom::XDocumentBuilder> xDocBuilder( + m_xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.xml.dom.DocumentBuilder"), + m_xContext ), css::uno::UNO_QUERY); + if (!xDocBuilder.is()) + throw css::uno::RuntimeException( + OUSTR(" Could not create service com.sun.star.xml.dom.DocumentBuilder"), 0); + + ::osl::DirectoryItem item; + ::osl::File::RC err = ::osl::DirectoryItem::get(m_urlDb, item); + if (err == ::osl::File::E_None) + { + m_doc = xDocBuilder->parseURI(m_urlDb); + } + else if (err == ::osl::File::E_NOENT) + { + //Create a new document and insert some basic stuff + m_doc = xDocBuilder->newDocument(); + const Reference<css::xml::dom::XElement> rootNode = + m_doc->createElementNS(getDbNSName(), getNSPrefix() + + OUSTR(":") + getRootElementName()); + + m_doc->appendChild(Reference<css::xml::dom::XNode>( + rootNode, UNO_QUERY_THROW)); + save(); + } + else + throw css::uno::RuntimeException( + OUSTR("Extension manager could not access database file:" ) + + m_urlDb, 0); + + if (!m_doc.is()) + throw css::uno::RuntimeException( + OUSTR("Extension manager could not get root node of data base file: ") + + m_urlDb, 0); + } + + return m_doc; +} + +Reference<css::xml::xpath::XXPathAPI> BackendDb::getXPathAPI() +{ + if (!m_xpathApi.is()) + { + m_xpathApi = Reference< css::xml::xpath::XXPathAPI >( + m_xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.xml.xpath.XPathAPI"), + m_xContext), css::uno::UNO_QUERY); + + if (!m_xpathApi.is()) + throw css::uno::RuntimeException( + OUSTR(" Could not create service com.sun.star.xml.xpath.XPathAPI"), 0); + + m_xpathApi->registerNS( + getNSPrefix(), getDbNSName()); + } + + return m_xpathApi; +} + +void BackendDb::removeElement(::rtl::OUString const & sXPathExpression) +{ + try + { + const Reference<css::xml::dom::XDocument> doc = getDocument(); + const Reference<css::xml::dom::XNode> root = doc->getFirstChild(); + const Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI(); + //find the extension element that is to be removed + const Reference<css::xml::dom::XNode> aNode = + xpathApi->selectSingleNode(root, sXPathExpression); + + if (aNode.is()) + { + root->removeChild(aNode); + save(); + } + +#if OSL_DEBUG_LEVEL > 0 + //There must not be any other entry with the same url + const Reference<css::xml::dom::XNode> nextNode = + xpathApi->selectSingleNode(root, sXPathExpression); + OSL_ASSERT(! nextNode.is()); +#endif + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to write data entry in backend db: ") + + m_urlDb, 0, exc); + } +} + +void BackendDb::removeEntry(::rtl::OUString const & url) +{ + const OUString sKeyElement = getKeyElementName(); + const OUString sPrefix = getNSPrefix(); + ::rtl::OUStringBuffer sExpression(500); + sExpression.append(sPrefix); + sExpression.appendAscii(":"); + sExpression.append(sKeyElement); + sExpression.append(OUSTR("[@url = \"")); + sExpression.append(url); + sExpression.appendAscii("\"]"); + + removeElement(sExpression.makeStringAndClear()); +} + +Reference<css::xml::dom::XNode> BackendDb::getKeyElement( + ::rtl::OUString const & url) +{ + try + { + const OUString sPrefix = getNSPrefix(); + const OUString sKeyElement = getKeyElementName(); + ::rtl::OUStringBuffer sExpression(500); + sExpression.append(sPrefix); + sExpression.appendAscii(":"); + sExpression.append(sKeyElement); + sExpression.append(OUSTR("[@url = \"")); + sExpression.append(url); + sExpression.appendAscii("\"]"); + + const Reference<css::xml::dom::XDocument> doc = getDocument(); + const Reference<css::xml::dom::XNode> root = doc->getFirstChild(); + const Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI(); + return xpathApi->selectSingleNode(root, sExpression.makeStringAndClear()); + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to read key element in backend db: ") + + m_urlDb, 0, exc); + } +} + +//Only writes the data if there is at least one entry +void BackendDb::writeVectorOfPair( + ::std::vector< ::std::pair< ::rtl::OUString, ::rtl::OUString > > const & vecPairs, + OUString const & sVectorTagName, + OUString const & sPairTagName, + OUString const & sFirstTagName, + OUString const & sSecondTagName, + css::uno::Reference<css::xml::dom::XNode> const & xParent) +{ + try{ + if (vecPairs.size() == 0) + return; + const OUString sNameSpace = getDbNSName(); + OSL_ASSERT(sNameSpace.getLength()); + const OUString sPrefix(getNSPrefix() + OUSTR(":")); + const Reference<css::xml::dom::XDocument> doc = getDocument(); + const Reference<css::xml::dom::XNode> root = doc->getFirstChild(); + + const Reference<css::xml::dom::XElement> vectorNode( + doc->createElementNS(sNameSpace, sPrefix + sVectorTagName)); + + xParent->appendChild( + Reference<css::xml::dom::XNode>( + vectorNode, css::uno::UNO_QUERY_THROW)); + typedef ::std::vector< ::std::pair< OUString, OUString > >::const_iterator CIT; + for (CIT i = vecPairs.begin(); i != vecPairs.end(); i++) + { + const Reference<css::xml::dom::XElement> pairNode( + doc->createElementNS(sNameSpace, sPrefix + sPairTagName)); + + vectorNode->appendChild( + Reference<css::xml::dom::XNode>( + pairNode, css::uno::UNO_QUERY_THROW)); + + const Reference<css::xml::dom::XElement> firstNode( + doc->createElementNS(sNameSpace, sPrefix + sFirstTagName)); + + pairNode->appendChild( + Reference<css::xml::dom::XNode>( + firstNode, css::uno::UNO_QUERY_THROW)); + + const Reference<css::xml::dom::XText> firstTextNode( + doc->createTextNode( i->first)); + + firstNode->appendChild( + Reference<css::xml::dom::XNode>( + firstTextNode, css::uno::UNO_QUERY_THROW)); + + const Reference<css::xml::dom::XElement> secondNode( + doc->createElementNS(sNameSpace, sPrefix + sSecondTagName)); + + pairNode->appendChild( + Reference<css::xml::dom::XNode>( + secondNode, css::uno::UNO_QUERY_THROW)); + + const Reference<css::xml::dom::XText> secondTextNode( + doc->createTextNode( i->second)); + + secondNode->appendChild( + Reference<css::xml::dom::XNode>( + secondTextNode, css::uno::UNO_QUERY_THROW)); + } + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to write data entry in backend db: ") + + m_urlDb, 0, exc); + } +} + +::std::vector< ::std::pair< OUString, OUString > > +BackendDb::readVectorOfPair( + Reference<css::xml::dom::XNode> const & parent, + OUString const & sListTagName, + OUString const & sPairTagName, + OUString const & sFirstTagName, + OUString const & sSecondTagName) +{ + try + { + OSL_ASSERT(parent.is()); + const OUString sPrefix(getNSPrefix() + OUSTR(":")); + const Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI(); + const OUString sExprPairs( + sPrefix + sListTagName + OUSTR("/") + sPrefix + sPairTagName); + const Reference<css::xml::dom::XNodeList> listPairs = + xpathApi->selectNodeList(parent, sExprPairs); + + ::std::vector< ::std::pair< OUString, OUString > > retVector; + sal_Int32 length = listPairs->getLength(); + for (sal_Int32 i = 0; i < length; i++) + { + const Reference<css::xml::dom::XNode> aPair = listPairs->item(i); + const OUString sExprFirst(sPrefix + sFirstTagName + OUSTR("/text()")); + const Reference<css::xml::dom::XNode> first = + xpathApi->selectSingleNode(aPair, sExprFirst); + + const OUString sExprSecond(sPrefix + sSecondTagName + OUSTR("/text()")); + const Reference<css::xml::dom::XNode> second = + xpathApi->selectSingleNode(aPair, sExprSecond); + OSL_ASSERT(first.is() && second.is()); + + retVector.push_back(::std::make_pair( + first->getNodeValue(), second->getNodeValue())); + } + return retVector; + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to read data entry in backend db: ") + + m_urlDb, 0, exc); + } +} + +//Only writes the data if there is at least one entry +void BackendDb::writeSimpleList( + ::std::list< ::rtl::OUString> const & list, + OUString const & sListTagName, + OUString const & sMemberTagName, + Reference<css::xml::dom::XNode> const & xParent) +{ + try + { + if (list.size() == 0) + return; + const OUString sNameSpace = getDbNSName(); + const OUString sPrefix(getNSPrefix() + OUSTR(":")); + const Reference<css::xml::dom::XDocument> doc = getDocument(); + + const Reference<css::xml::dom::XElement> listNode( + doc->createElementNS(sNameSpace, sPrefix + sListTagName)); + + xParent->appendChild( + Reference<css::xml::dom::XNode>( + listNode, css::uno::UNO_QUERY_THROW)); + + typedef ::std::list<OUString>::const_iterator ITC_ITEMS; + for (ITC_ITEMS i = list.begin(); i != list.end(); i++) + { + const Reference<css::xml::dom::XNode> memberNode( + doc->createElementNS(sNameSpace, sPrefix + sMemberTagName), css::uno::UNO_QUERY_THROW); + + listNode->appendChild(memberNode); + + const Reference<css::xml::dom::XNode> textNode( + doc->createTextNode( *i), css::uno::UNO_QUERY_THROW); + + memberNode->appendChild(textNode); + } + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to write data entry in backend db: ") + + m_urlDb, 0, exc); + } +} + +//Writes only the element if is has a value. +//The prefix is automatically added to the element name +void BackendDb::writeSimpleElement( + OUString const & sElementName, OUString const & value, + Reference<css::xml::dom::XNode> const & xParent) +{ + try + { + if (value.getLength() == 0) + return; + const OUString sPrefix = getNSPrefix(); + const Reference<css::xml::dom::XDocument> doc = getDocument(); + const OUString sNameSpace = getDbNSName(); + const Reference<css::xml::dom::XNode> dataNode( + doc->createElementNS(sNameSpace, sPrefix + OUSTR(":") + sElementName), + UNO_QUERY_THROW); + xParent->appendChild(dataNode); + + const Reference<css::xml::dom::XNode> dataValue( + doc->createTextNode(value), UNO_QUERY_THROW); + dataNode->appendChild(dataValue); + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to write data entry(writeSimpleElement) in backend db: ") + + m_urlDb, 0, exc); + } + +} + +/** The key elements have an url attribute and are always children of the root + element. +*/ +Reference<css::xml::dom::XNode> BackendDb::writeKeyElement( + ::rtl::OUString const & url) +{ + try + { + const OUString sNameSpace = getDbNSName(); + const OUString sPrefix = getNSPrefix(); + const OUString sElementName = getKeyElementName(); + const Reference<css::xml::dom::XDocument> doc = getDocument(); + const Reference<css::xml::dom::XNode> root = doc->getFirstChild(); + + //Check if there are an entry with the same url. This can be the case if the + //the status of an XPackage is ambiguous. In this case a call to activateExtension + //(dp_extensionmanager.cxx), will register the package again. See also + //Package::processPackage_impl in dp_backend.cxx. + //A package can become + //invalid after its successful registration, for example if a second extension with + //the same service is installed. + const OUString sExpression( + sPrefix + OUSTR(":") + sElementName + OUSTR("[@url = \"") + url + OUSTR("\"]")); + const Reference<css::xml::dom::XNode> existingNode = + getXPathAPI()->selectSingleNode(root, sExpression); + if (existingNode.is()) + { + OSL_ASSERT(0); + //replace the existing entry. + removeEntry(url); + } + + const Reference<css::xml::dom::XElement> keyElement( + doc->createElementNS(sNameSpace, sPrefix + OUSTR(":") + sElementName)); + + keyElement->setAttribute(OUSTR("url"), url); + + const Reference<css::xml::dom::XNode> keyNode( + keyElement, UNO_QUERY_THROW); + root->appendChild(keyNode); + return keyNode; + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to write key element in backend db: ") + + m_urlDb, 0, exc); + } +} + +OUString BackendDb::readSimpleElement( + OUString const & sElementName, Reference<css::xml::dom::XNode> const & xParent) +{ + try + { + const OUString sPrefix = getNSPrefix(); + const OUString sExpr(sPrefix + OUSTR(":") + sElementName + OUSTR("/text()")); + const Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI(); + const Reference<css::xml::dom::XNode> val = + xpathApi->selectSingleNode(xParent, sExpr); + if (val.is()) + return val->getNodeValue(); + return OUString(); + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to read data (readSimpleElement) in backend db: ") + + m_urlDb, 0, exc); + } +} + + +::std::list< OUString> BackendDb::readList( + Reference<css::xml::dom::XNode> const & parent, + OUString const & sListTagName, + OUString const & sMemberTagName) +{ + try + { + OSL_ASSERT(parent.is()); + const OUString sPrefix(getNSPrefix() + OUSTR(":")); + const Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI(); + const OUString sExprList( + sPrefix + sListTagName + OUSTR("/") + sPrefix + sMemberTagName + OUSTR("/text()")); + const Reference<css::xml::dom::XNodeList> list = + xpathApi->selectNodeList(parent, sExprList); + + ::std::list<OUString > retList; + sal_Int32 length = list->getLength(); + for (sal_Int32 i = 0; i < length; i++) + { + const Reference<css::xml::dom::XNode> member = list->item(i); + retList.push_back(member->getNodeValue()); + } + return retList; + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to read data entry in backend db: ") + + m_urlDb, 0, exc); + } +} + +::std::list<OUString> BackendDb::getOneChildFromAllEntries( + OUString const & name) +{ + try + { + ::std::list<OUString> listRet; + Reference<css::xml::dom::XDocument> doc = getDocument(); + Reference<css::xml::dom::XNode> root = doc->getFirstChild(); + + Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI(); + const OUString sPrefix = getNSPrefix(); + const OUString sKeyElement = getKeyElementName(); + ::rtl::OUStringBuffer buf(512); + buf.append(sPrefix); + buf.appendAscii(":"); + buf.append(sKeyElement); + buf.appendAscii("/"); + buf.append(sPrefix); + buf.appendAscii(":"); + buf.append(name); + buf.append(OUSTR("/text()")); + + Reference<css::xml::dom::XNodeList> nodes = + xpathApi->selectNodeList(root, buf.makeStringAndClear()); + if (nodes.is()) + { + sal_Int32 length = nodes->getLength(); + for (sal_Int32 i = 0; i < length; i++) + listRet.push_back(nodes->item(i)->getNodeValue()); + } + return listRet; + } + catch (css::deployment::DeploymentException& ) + { + throw; + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to read data entry in backend db: ") + + m_urlDb, 0, exc); + } +} + + +RegisteredDb::RegisteredDb( + Reference<XComponentContext> const & xContext, + ::rtl::OUString const & url):BackendDb(xContext, url) +{ +} + +void RegisteredDb::addEntry(::rtl::OUString const & url) +{ + try{ + + const OUString sNameSpace = getDbNSName(); + const OUString sPrefix = getNSPrefix(); + const OUString sEntry = getKeyElementName(); + + Reference<css::xml::dom::XDocument> doc = getDocument(); + Reference<css::xml::dom::XNode> root = doc->getFirstChild(); + +#if OSL_DEBUG_LEVEL > 0 + //There must not be yet an entry with the same url + OUString sExpression( + sPrefix + OUSTR(":") + sEntry + OUSTR("[@url = \"") + url + OUSTR("\"]")); + Reference<css::xml::dom::XNode> _extensionNode = + getXPathAPI()->selectSingleNode(root, sExpression); + OSL_ASSERT(! _extensionNode.is()); +#endif + Reference<css::xml::dom::XElement> helpElement( + doc->createElementNS(sNameSpace, sPrefix + OUSTR(":") + sEntry)); + + helpElement->setAttribute(OUSTR("url"), url); + + Reference<css::xml::dom::XNode> helpNode( + helpElement, UNO_QUERY_THROW); + root->appendChild(helpNode); + + save(); + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to write data entry in backend db: ") + + m_urlDb, 0, exc); + } +} + +bool RegisteredDb::getEntry(::rtl::OUString const & url) +{ + try + { + const OUString sPrefix = getNSPrefix(); + const OUString sEntry = getKeyElementName(); + const OUString sExpression( + sPrefix + OUSTR(":") + sEntry + OUSTR("[@url = \"") + url + OUSTR("\"]")); + Reference<css::xml::dom::XDocument> doc = getDocument(); + Reference<css::xml::dom::XNode> root = doc->getFirstChild(); + + Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI(); + Reference<css::xml::dom::XNode> aNode = + xpathApi->selectSingleNode(root, sExpression); + + return aNode.is(); + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to read data entry in backend db: ") + + m_urlDb, 0, exc); + } +} + +} // namespace backend +} // namespace dp_registry + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/dp_registry.cxx b/desktop/source/deployment/registry/dp_registry.cxx new file mode 100644 index 000000000000..bffdaeae1924 --- /dev/null +++ b/desktop/source/deployment/registry/dp_registry.cxx @@ -0,0 +1,560 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_registry.hrc" +#include "dp_misc.h" +#include "dp_resource.h" +#include "dp_interact.h" +#include "dp_ucb.h" +#include "osl/diagnose.h" +#include "rtl/ustrbuf.hxx" +#include "rtl/uri.hxx" +#include "cppuhelper/compbase2.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "comphelper/sequence.hxx" +#include "ucbhelper/content.hxx" +#include "com/sun/star/uno/DeploymentException.hpp" +#include "com/sun/star/lang/DisposedException.hpp" +#include "com/sun/star/lang/WrappedTargetRuntimeException.hpp" +#include "com/sun/star/lang/XServiceInfo.hpp" +#include "com/sun/star/lang/XSingleComponentFactory.hpp" +#include "com/sun/star/lang/XSingleServiceFactory.hpp" +#include "com/sun/star/util/XUpdatable.hpp" +#include "com/sun/star/container/XContentEnumerationAccess.hpp" +#include "com/sun/star/deployment/PackageRegistryBackend.hpp" +#include <hash_map> +#include <set> +#include <hash_set> +#include <memory> + +using namespace ::dp_misc; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using ::rtl::OUString; + + +namespace dp_registry { + +namespace backend { +namespace bundle { +Reference<deployment::XPackageRegistry> create( + Reference<deployment::XPackageRegistry> const & xRootRegistry, + OUString const & context, OUString const & cachePath, bool readOnly, + Reference<XComponentContext> const & xComponentContext ); +} +} + +namespace { + +typedef ::cppu::WeakComponentImplHelper2< + deployment::XPackageRegistry, util::XUpdatable > t_helper; + +//============================================================================== +class PackageRegistryImpl : private MutexHolder, public t_helper +{ + struct ci_string_hash { + ::std::size_t operator () ( OUString const & str ) const { + return str.toAsciiLowerCase().hashCode(); + } + }; + struct ci_string_equals { + bool operator () ( OUString const & str1, OUString const & str2 ) const{ + return str1.equalsIgnoreAsciiCase( str2 ); + } + }; + typedef ::std::hash_map< + OUString, Reference<deployment::XPackageRegistry>, + ci_string_hash, ci_string_equals > t_string2registry; + typedef ::std::hash_map< + OUString, OUString, + ci_string_hash, ci_string_equals > t_string2string; + typedef ::std::set< + Reference<deployment::XPackageRegistry> > t_registryset; + + t_string2registry m_mediaType2backend; + t_string2string m_filter2mediaType; + t_registryset m_ambiguousBackends; + t_registryset m_allBackends; + ::std::vector< Reference<deployment::XPackageTypeInfo> > m_typesInfos; + + void insertBackend( + Reference<deployment::XPackageRegistry> const & xBackend ); + +protected: + inline void check(); + virtual void SAL_CALL disposing(); + + virtual ~PackageRegistryImpl(); + PackageRegistryImpl() : t_helper( getMutex() ) {} + + +public: + static Reference<deployment::XPackageRegistry> create( + OUString const & context, + OUString const & cachePath, bool readOnly, + Reference<XComponentContext> const & xComponentContext ); + + // XUpdatable + virtual void SAL_CALL update() throw (RuntimeException); + + // XPackageRegistry + virtual Reference<deployment::XPackage> SAL_CALL bindPackage( + OUString const & url, OUString const & mediaType, sal_Bool bRemoved, + OUString const & identifier, Reference<XCommandEnvironment> const & xCmdEnv ) + throw (deployment::DeploymentException, + deployment::InvalidRemovedParameterException, + CommandFailedException, + lang::IllegalArgumentException, RuntimeException); + virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL + getSupportedPackageTypes() throw (RuntimeException); +}; + +//______________________________________________________________________________ +inline void PackageRegistryImpl::check() +{ + ::osl::MutexGuard guard( getMutex() ); + if (rBHelper.bInDispose || rBHelper.bDisposed) { + throw lang::DisposedException( + OUSTR("PackageRegistry instance has already been disposed!"), + static_cast<OWeakObject *>(this) ); + } +} + +//______________________________________________________________________________ +void PackageRegistryImpl::disposing() +{ + // dispose all backends: + t_registryset::const_iterator iPos( m_allBackends.begin() ); + t_registryset::const_iterator const iEnd( m_allBackends.end() ); + for ( ; iPos != iEnd; ++iPos ) { + try_dispose( *iPos ); + } + m_mediaType2backend = t_string2registry(); + m_ambiguousBackends = t_registryset(); + m_allBackends = t_registryset(); + + t_helper::disposing(); +} + +//______________________________________________________________________________ +PackageRegistryImpl::~PackageRegistryImpl() +{ +} + +//______________________________________________________________________________ +OUString normalizeMediaType( OUString const & mediaType ) +{ + ::rtl::OUStringBuffer buf; + sal_Int32 index = 0; + for (;;) { + buf.append( mediaType.getToken( 0, '/', index ).trim() ); + if (index < 0) + break; + buf.append( static_cast< sal_Unicode >('/') ); + } + return buf.makeStringAndClear(); +} + +//______________________________________________________________________________ + +void PackageRegistryImpl::insertBackend( + Reference<deployment::XPackageRegistry> const & xBackend ) +{ + m_allBackends.insert( xBackend ); + typedef ::std::hash_set<OUString, ::rtl::OUStringHash> t_stringset; + t_stringset ambiguousFilters; + + const Sequence< Reference<deployment::XPackageTypeInfo> > packageTypes( + xBackend->getSupportedPackageTypes() ); + for ( sal_Int32 pos = 0; pos < packageTypes.getLength(); ++pos ) + { + Reference<deployment::XPackageTypeInfo> const & xPackageType = + packageTypes[ pos ]; + m_typesInfos.push_back( xPackageType ); + + const OUString mediaType( normalizeMediaType( + xPackageType->getMediaType() ) ); + ::std::pair<t_string2registry::iterator, bool> mb_insertion( + m_mediaType2backend.insert( t_string2registry::value_type( + mediaType, xBackend ) ) ); + if (mb_insertion.second) + { + // add parameterless media-type, too: + sal_Int32 semi = mediaType.indexOf( ';' ); + if (semi >= 0) { + m_mediaType2backend.insert( + t_string2registry::value_type( + mediaType.copy( 0, semi ), xBackend ) ); + } + const OUString fileFilter( xPackageType->getFileFilter() ); + //The package backend shall also be called to determine the mediatype + //(XPackageRegistry.bindPackage) when the URL points to a directory. + const bool bExtension = mediaType.equals(OUSTR("application/vnd.sun.star.package-bundle")); + if (fileFilter.getLength() == 0 || + fileFilter.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("*.*") ) || + fileFilter.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("*") ) || + bExtension) + { + m_ambiguousBackends.insert( xBackend ); + } + else + { + sal_Int32 nIndex = 0; + do { + OUString token( fileFilter.getToken( 0, ';', nIndex ) ); + if (token.matchAsciiL( RTL_CONSTASCII_STRINGPARAM("*.") )) + token = token.copy( 1 ); + if (token.getLength() == 0) + continue; + // mark any further wildcards ambig: + bool ambig = (token.indexOf('*') >= 0 || + token.indexOf('?') >= 0); + if (! ambig) { + ::std::pair<t_string2string::iterator, bool> ins( + m_filter2mediaType.insert( + t_string2string::value_type( + token, mediaType ) ) ); + ambig = !ins.second; + if (ambig) { + // filter has already been in: add previously + // added backend to ambig set + const t_string2registry::const_iterator iFind( + m_mediaType2backend.find( + /* media-type of pr. added backend */ + ins.first->second ) ); + OSL_ASSERT( + iFind != m_mediaType2backend.end() ); + if (iFind != m_mediaType2backend.end()) + m_ambiguousBackends.insert( iFind->second ); + } + } + if (ambig) { + m_ambiguousBackends.insert( xBackend ); + // mark filter to be removed later from filters map: + ambiguousFilters.insert( token ); + } + } + while (nIndex >= 0); + } + } +#if OSL_DEBUG_LEVEL > 0 + else { + ::rtl::OUStringBuffer buf; + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM( + "more than one PackageRegistryBackend for " + "media-type=\"") ); + buf.append( mediaType ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\" => ") ); + buf.append( Reference<lang::XServiceInfo>( + xBackend, UNO_QUERY_THROW )-> + getImplementationName() ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\"!") ); + OSL_ENSURE( 0, ::rtl::OUStringToOString( + buf.makeStringAndClear(), + RTL_TEXTENCODING_UTF8 ) ); + } +#endif + } + + // cut out ambiguous filters: + t_stringset::const_iterator iPos( ambiguousFilters.begin() ); + const t_stringset::const_iterator iEnd( ambiguousFilters.end() ); + for ( ; iPos != iEnd; ++iPos ) { + m_filter2mediaType.erase( *iPos ); + } +} + +//______________________________________________________________________________ +Reference<deployment::XPackageRegistry> PackageRegistryImpl::create( + OUString const & context, + OUString const & cachePath, bool readOnly, + Reference<XComponentContext> const & xComponentContext ) +{ + PackageRegistryImpl * that = new PackageRegistryImpl; + Reference<deployment::XPackageRegistry> xRet(that); + + // auto-detect all registered package registries: + Reference<container::XEnumeration> xEnum( + Reference<container::XContentEnumerationAccess>( + xComponentContext->getServiceManager(), + UNO_QUERY_THROW )->createContentEnumeration( + OUSTR("com.sun.star.deployment.PackageRegistryBackend") ) ); + if (xEnum.is()) + { + while (xEnum->hasMoreElements()) + { + Any element( xEnum->nextElement() ); + Sequence<Any> registryArgs( + cachePath.getLength() == 0 ? 1 : 3 ); + registryArgs[ 0 ] <<= context; + if (cachePath.getLength() > 0) + { + Reference<lang::XServiceInfo> xServiceInfo( + element, UNO_QUERY_THROW ); + OUString registryCachePath( + makeURL( cachePath, + ::rtl::Uri::encode( + xServiceInfo->getImplementationName(), + rtl_UriCharClassPchar, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ) ) ); + registryArgs[ 1 ] <<= registryCachePath; + registryArgs[ 2 ] <<= readOnly; + if (! readOnly) + create_folder( 0, registryCachePath, + Reference<XCommandEnvironment>() ); + } + + Reference<deployment::XPackageRegistry> xBackend; + Reference<lang::XSingleComponentFactory> xFac( element, UNO_QUERY ); + if (xFac.is()) { + xBackend.set( + xFac->createInstanceWithArgumentsAndContext( + registryArgs, xComponentContext ), UNO_QUERY ); + } + else { + Reference<lang::XSingleServiceFactory> xSingleServiceFac( + element, UNO_QUERY_THROW ); + xBackend.set( + xSingleServiceFac->createInstanceWithArguments( + registryArgs ), UNO_QUERY ); + } + if (! xBackend.is()) { + throw DeploymentException( + OUSTR("cannot instantiate PackageRegistryBackend service: ") + + Reference<lang::XServiceInfo>( + element, UNO_QUERY_THROW )->getImplementationName(), + static_cast<OWeakObject *>(that) ); + } + + that->insertBackend( xBackend ); + } + } + + // Insert bundle back-end. + // Always register as last, because we want to add extensions also as folders + // and as a default we accept every folder, which was not recognized by the other + // backends. + Reference<deployment::XPackageRegistry> extensionBackend = + ::dp_registry::backend::bundle::create( + that, context, cachePath, readOnly, xComponentContext); + that->insertBackend(extensionBackend); + + Reference<lang::XServiceInfo> xServiceInfo( + extensionBackend, UNO_QUERY_THROW ); + + OSL_ASSERT(xServiceInfo.is()); + OUString registryCachePath( + makeURL( cachePath, + ::rtl::Uri::encode( + xServiceInfo->getImplementationName(), + rtl_UriCharClassPchar, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ) ) ); + create_folder( 0, registryCachePath, Reference<XCommandEnvironment>()); + + +#if OSL_DEBUG_LEVEL > 1 + // dump tables: + { + t_registryset allBackends; + dp_misc::TRACE("> [dp_registry.cxx] media-type detection:\n\n" ); + for ( t_string2string::const_iterator iPos( + that->m_filter2mediaType.begin() ); + iPos != that->m_filter2mediaType.end(); ++iPos ) + { + ::rtl::OUStringBuffer buf; + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("extension \"") ); + buf.append( iPos->first ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( + "\" maps to media-type \"") ); + buf.append( iPos->second ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( + "\" maps to backend ") ); + const Reference<deployment::XPackageRegistry> xBackend( + that->m_mediaType2backend.find( iPos->second )->second ); + allBackends.insert( xBackend ); + buf.append( Reference<lang::XServiceInfo>( + xBackend, UNO_QUERY_THROW ) + ->getImplementationName() ); + dp_misc::writeConsole( buf.makeStringAndClear() + OUSTR("\n")); + } + dp_misc::TRACE( "> [dp_registry.cxx] ambiguous backends:\n\n" ); + for ( t_registryset::const_iterator iPos( + that->m_ambiguousBackends.begin() ); + iPos != that->m_ambiguousBackends.end(); ++iPos ) + { + ::rtl::OUStringBuffer buf; + buf.append( + Reference<lang::XServiceInfo>( + *iPos, UNO_QUERY_THROW )->getImplementationName() ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(": ") ); + const Sequence< Reference<deployment::XPackageTypeInfo> > types( + (*iPos)->getSupportedPackageTypes() ); + for ( sal_Int32 pos = 0; pos < types.getLength(); ++pos ) { + Reference<deployment::XPackageTypeInfo> const & xInfo = + types[ pos ]; + buf.append( xInfo->getMediaType() ); + const OUString filter( xInfo->getFileFilter() ); + if (filter.getLength() > 0) { + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(" (") ); + buf.append( filter ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(")") ); + } + if (pos < (types.getLength() - 1)) + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(", ") ); + } + dp_misc::TRACE(buf.makeStringAndClear() + OUSTR("\n\n")); + } + allBackends.insert( that->m_ambiguousBackends.begin(), + that->m_ambiguousBackends.end() ); + OSL_ASSERT( allBackends == that->m_allBackends ); + } +#endif + + return xRet; +} + +// XUpdatable: broadcast to backends +//______________________________________________________________________________ +void PackageRegistryImpl::update() throw (RuntimeException) +{ + check(); + t_registryset::const_iterator iPos( m_allBackends.begin() ); + const t_registryset::const_iterator iEnd( m_allBackends.end() ); + for ( ; iPos != iEnd; ++iPos ) { + const Reference<util::XUpdatable> xUpdatable( *iPos, UNO_QUERY ); + if (xUpdatable.is()) + xUpdatable->update(); + } +} + +// XPackageRegistry +//______________________________________________________________________________ +Reference<deployment::XPackage> PackageRegistryImpl::bindPackage( + OUString const & url, OUString const & mediaType_, sal_Bool bRemoved, + OUString const & identifier, Reference<XCommandEnvironment> const & xCmdEnv ) + throw (deployment::DeploymentException, deployment::InvalidRemovedParameterException, + CommandFailedException, + lang::IllegalArgumentException, RuntimeException) +{ + check(); + OUString mediaType(mediaType_); + if (mediaType.getLength() == 0) + { + ::ucbhelper::Content ucbContent; + if (create_ucb_content( + &ucbContent, url, xCmdEnv, false /* no throw */ ) + && !ucbContent.isFolder()) + { + OUString title( ucbContent.getPropertyValue( + StrTitle::get() ).get<OUString>() ); + for (;;) + { + const t_string2string::const_iterator iFind( + m_filter2mediaType.find(title) ); + if (iFind != m_filter2mediaType.end()) { + mediaType = iFind->second; + break; + } + sal_Int32 point = title.indexOf( '.', 1 /* consume . */ ); + if (point < 0) + break; + title = title.copy(point); + } + } + } + if (mediaType.getLength() == 0) + { + // try ambiguous backends: + t_registryset::const_iterator iPos( m_ambiguousBackends.begin() ); + const t_registryset::const_iterator iEnd( m_ambiguousBackends.end() ); + for ( ; iPos != iEnd; ++iPos ) + { + try { + return (*iPos)->bindPackage( url, mediaType, bRemoved, + identifier, xCmdEnv ); + } + catch (lang::IllegalArgumentException &) { + } + } + throw lang::IllegalArgumentException( + getResourceString(RID_STR_CANNOT_DETECT_MEDIA_TYPE) + url, + static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) ); + } + else + { + // get backend by media-type: + t_string2registry::const_iterator iFind( + m_mediaType2backend.find( normalizeMediaType(mediaType) ) ); + if (iFind == m_mediaType2backend.end()) { + // xxx todo: more sophisticated media-type argument parsing... + sal_Int32 q = mediaType.indexOf( ';' ); + if (q >= 0) { + iFind = m_mediaType2backend.find( + normalizeMediaType( + // cut parameters: + mediaType.copy( 0, q ) ) ); + } + } + if (iFind == m_mediaType2backend.end()) { + throw lang::IllegalArgumentException( + getResourceString(RID_STR_UNSUPPORTED_MEDIA_TYPE) + mediaType, + static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) ); + } + return iFind->second->bindPackage( url, mediaType, bRemoved, + identifier, xCmdEnv ); + } +} + +//______________________________________________________________________________ +Sequence< Reference<deployment::XPackageTypeInfo> > +PackageRegistryImpl::getSupportedPackageTypes() throw (RuntimeException) +{ + return comphelper::containerToSequence(m_typesInfos); +} +} // anon namespace + +//============================================================================== +Reference<deployment::XPackageRegistry> SAL_CALL create( + OUString const & context, + OUString const & cachePath, bool readOnly, + Reference<XComponentContext> const & xComponentContext ) +{ + return PackageRegistryImpl::create( + context, cachePath, readOnly, xComponentContext ); +} + +} // namespace dp_registry + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/dp_registry.src b/desktop/source/deployment/registry/dp_registry.src new file mode 100644 index 000000000000..68a52621741f --- /dev/null +++ b/desktop/source/deployment/registry/dp_registry.src @@ -0,0 +1,59 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "dp_registry.hrc" + +String RID_STR_REGISTERING_PACKAGE +{ + Text [ en-US ] = "Enabling: "; +}; + +String RID_STR_REVOKING_PACKAGE +{ + Text [ en-US ] = "Disabling: "; +}; + +String RID_STR_CANNOT_DETECT_MEDIA_TYPE +{ + Text [ en-US ] = "Cannot detect media-type: "; +}; + +String RID_STR_UNSUPPORTED_MEDIA_TYPE +{ + Text [ en-US ] = "This media-type is not supported: "; +}; + +String RID_STR_ERROR_WHILE_REGISTERING +{ + Text [ en-US ] = "An error occurred while enabling: "; +}; + +String RID_STR_ERROR_WHILE_REVOKING +{ + Text [ en-US ] = "An error occurred while disabling: "; +}; + diff --git a/desktop/source/deployment/registry/executable/dp_executable.cxx b/desktop/source/deployment/registry/executable/dp_executable.cxx new file mode 100644 index 000000000000..1b05a3fae184 --- /dev/null +++ b/desktop/source/deployment/registry/executable/dp_executable.cxx @@ -0,0 +1,332 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_misc.h" +#include "dp_backend.h" +#include "dp_ucb.h" +#include "dp_interact.h" +#include "rtl/string.hxx" +#include "osl/file.hxx" +#include "ucbhelper/content.hxx" +#include "comphelper/servicedecl.hxx" +#include "svl/inettype.hxx" +#include "cppuhelper/implbase1.hxx" +#include "dp_executablebackenddb.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using namespace dp_misc; +using ::rtl::OUString; + +namespace dp_registry { +namespace backend { +namespace executable { +namespace { + +class BackendImpl : public ::dp_registry::backend::PackageRegistryBackend +{ + class ExecutablePackageImpl : public ::dp_registry::backend::Package + { + BackendImpl * getMyBackend() const; + + // Package + virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_( + ::osl::ResettableMutexGuard & guard, + ::rtl::Reference<dp_misc::AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + virtual void processPackage_( + ::osl::ResettableMutexGuard & guard, + bool registerPackage, + bool startup, + ::rtl::Reference<dp_misc::AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + + bool getFileAttributes(sal_uInt64& out_Attributes); + bool isUrlTargetInExtension(); + public: + inline ExecutablePackageImpl( + ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + bool bRemoved, OUString const & identifier) + : Package( myBackend, url, name, name /* display-name */, + xPackageType, bRemoved, identifier) + {} + }; + friend class ExecutablePackageImpl; + + typedef ::std::hash_map< OUString, Reference<XInterface>, + ::rtl::OUStringHash > t_string2object; + + // PackageRegistryBackend + virtual Reference<deployment::XPackage> bindPackage_( + OUString const & url, OUString const & mediaType, sal_Bool bRemoved, + OUString const & identifier, Reference<XCommandEnvironment> const & xCmdEnv ); + + void addDataToDb(OUString const & url); + bool isRegisteredInDb(OUString const & url); + void deleteDataFromDb(OUString const & url); + + Reference<deployment::XPackageTypeInfo> m_xExecutableTypeInfo; + std::auto_ptr<ExecutableBackendDb> m_backendDb; +public: + BackendImpl( Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ); + + // XPackageRegistry + virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL + getSupportedPackageTypes() throw (RuntimeException); + + using PackageRegistryBackend::disposing; +}; + + +BackendImpl::BackendImpl( + Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ) + : PackageRegistryBackend( args, xComponentContext ), + m_xExecutableTypeInfo(new Package::TypeInfo( + OUSTR("application/vnd.sun.star.executable"), + OUSTR(""), + OUSTR("Executable"), + RID_IMG_COMPONENT ) ) +{ + if (!transientMode()) + { + OUString dbFile = makeURL(getCachePath(), OUSTR("backenddb.xml")); + m_backendDb.reset( + new ExecutableBackendDb(getComponentContext(), dbFile)); + } +} + +void BackendImpl::addDataToDb(OUString const & url) +{ + if (m_backendDb.get()) + m_backendDb->addEntry(url); +} + +bool BackendImpl::isRegisteredInDb(OUString const & url) +{ + bool ret = false; + if (m_backendDb.get()) + ret = m_backendDb->getEntry(url); + return ret; +} + +void BackendImpl::deleteDataFromDb(OUString const & url) +{ + if (m_backendDb.get()) + m_backendDb->removeEntry(url); +} + +// XPackageRegistry +Sequence< Reference<deployment::XPackageTypeInfo> > +BackendImpl::getSupportedPackageTypes() throw (RuntimeException) +{ + return Sequence<Reference<deployment::XPackageTypeInfo> >( + & m_xExecutableTypeInfo, 1); +} + +// PackageRegistryBackend +Reference<deployment::XPackage> BackendImpl::bindPackage_( + OUString const & url, OUString const & mediaType, sal_Bool bRemoved, + OUString const & identifier, Reference<XCommandEnvironment> const & xCmdEnv ) +{ + if (mediaType.getLength() == 0) + { + throw lang::IllegalArgumentException( + StrCannotDetectMediaType::get() + url, + static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) ); + } + + String type, subType; + INetContentTypeParameterList params; + if (INetContentTypes::parse( mediaType, type, subType, ¶ms )) + { + if (type.EqualsIgnoreCaseAscii("application")) + { + OUString name; + if (!bRemoved) + { + ::ucbhelper::Content ucbContent( url, xCmdEnv ); + name = ucbContent.getPropertyValue( + dp_misc::StrTitle::get() ).get<OUString>(); + } + if (subType.EqualsIgnoreCaseAscii("vnd.sun.star.executable")) + { + return new BackendImpl::ExecutablePackageImpl( + this, url, name, m_xExecutableTypeInfo, bRemoved, + identifier); + } + } + } + return Reference<deployment::XPackage>(); +} + +//############################################################################## + + +// Package +BackendImpl * BackendImpl::ExecutablePackageImpl::getMyBackend() const +{ + BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get()); + if (NULL == pBackend) + { + //May throw a DisposedException + check(); + //We should never get here... + throw RuntimeException( + OUSTR("Failed to get the BackendImpl"), + static_cast<OWeakObject*>(const_cast<ExecutablePackageImpl *>(this))); + } + return pBackend; +} + +beans::Optional< beans::Ambiguous<sal_Bool> > +BackendImpl::ExecutablePackageImpl::isRegistered_( + ::osl::ResettableMutexGuard &, + ::rtl::Reference<dp_misc::AbortChannel> const &, + Reference<XCommandEnvironment> const & ) +{ + bool registered = getMyBackend()->isRegisteredInDb(getURL()); + return beans::Optional< beans::Ambiguous<sal_Bool> >( + sal_True /* IsPresent */, + beans::Ambiguous<sal_Bool>( + registered, sal_False /* IsAmbiguous */ ) ); +} + +void BackendImpl::ExecutablePackageImpl::processPackage_( + ::osl::ResettableMutexGuard &, + bool doRegisterPackage, + bool /*startup*/, + ::rtl::Reference<dp_misc::AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & /*xCmdEnv*/ ) +{ + checkAborted(abortChannel); + if (doRegisterPackage) + { + if (!isUrlTargetInExtension()) + { + OSL_ASSERT(0); + return; + } + sal_uInt64 attributes = 0; + //Setting the executable attribut does not affect executables on Windows + if (getFileAttributes(attributes)) + { + if(getMyBackend()->m_context.equals(OUSTR("user"))) + attributes |= osl_File_Attribute_OwnExe; + else if (getMyBackend()->m_context.equals(OUSTR("shared"))) + attributes |= (osl_File_Attribute_OwnExe | osl_File_Attribute_GrpExe + | osl_File_Attribute_OthExe); + else if (!getMyBackend()->m_context.equals(OUSTR("bundled"))) + //Bundled extension are required to be in the properly + //installed. That is an executable must have the right flags + OSL_ASSERT(0); + + //This won't have affect on Windows + osl::File::setAttributes( + dp_misc::expandUnoRcUrl(m_url), attributes); + } + getMyBackend()->addDataToDb(getURL()); + } + else + { + getMyBackend()->deleteDataFromDb(getURL()); + } +} + +//We currently cannot check if this XPackage represents a content of a particular extension +//But we can check if we are within $UNO_USER_PACKAGES_CACHE etc. +//Done for security reasons. For example an extension manifest could contain a path to +//an executable outside the extension. +bool BackendImpl::ExecutablePackageImpl::isUrlTargetInExtension() +{ + bool bSuccess = false; + OUString sExtensionDir; + if(getMyBackend()->m_context.equals(OUSTR("user"))) + sExtensionDir = dp_misc::expandUnoRcTerm(OUSTR("$UNO_USER_PACKAGES_CACHE")); + else if (getMyBackend()->m_context.equals(OUSTR("shared"))) + sExtensionDir = dp_misc::expandUnoRcTerm(OUSTR("$UNO_SHARED_PACKAGES_CACHE")); + else if (getMyBackend()->m_context.equals(OUSTR("bundled"))) + sExtensionDir = dp_misc::expandUnoRcTerm(OUSTR("$BUNDLED_EXTENSIONS")); + else + OSL_ASSERT(0); + //remove file ellipses + if (osl::File::E_None == osl::File::getAbsoluteFileURL(OUString(), sExtensionDir, sExtensionDir)) + { + OUString sFile; + if (osl::File::E_None == osl::File::getAbsoluteFileURL( + OUString(), dp_misc::expandUnoRcUrl(m_url), sFile)) + { + if (sal_True == sFile.match(sExtensionDir, 0)) + bSuccess = true; + } + } + return bSuccess; +} + +bool BackendImpl::ExecutablePackageImpl::getFileAttributes(sal_uInt64& out_Attributes) +{ + bool bSuccess = false; + const OUString url(dp_misc::expandUnoRcUrl(m_url)); + osl::DirectoryItem item; + if (osl::FileBase::E_None == osl::DirectoryItem::get(url, item)) + { + osl::FileStatus aStatus(osl_FileStatus_Mask_Attributes); + if( osl::FileBase::E_None == item.getFileStatus(aStatus)) + { + out_Attributes = aStatus.getAttributes(); + bSuccess = true; + } + } + return bSuccess; +} + +//############################################################################## + + +} // anon namespace + +namespace sdecl = comphelper::service_decl; +sdecl::class_<BackendImpl, sdecl::with_args<true> > serviceBI; +extern sdecl::ServiceDecl const serviceDecl( + serviceBI, + "com.sun.star.comp.deployment.executable.PackageRegistryBackend", + BACKEND_SERVICE_NAME ); + +} // namespace component +} // namespace backend +} // namespace dp_registry + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/executable/dp_executablebackenddb.cxx b/desktop/source/deployment/registry/executable/dp_executablebackenddb.cxx new file mode 100644 index 000000000000..0c65a9bf4d2c --- /dev/null +++ b/desktop/source/deployment/registry/executable/dp_executablebackenddb.cxx @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "rtl/string.h" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "dp_misc.h" +#include "dp_executablebackenddb.hxx" + + +namespace css = ::com::sun::star; +using namespace ::com::sun::star::uno; +using ::rtl::OUString; + +#define EXTENSION_REG_NS "http://openoffice.org/extensionmanager/executable-registry/2010" +#define NS_PREFIX "exe" +#define ROOT_ELEMENT_NAME "executable-backend-db" +#define ENTRY_NAME "executable" + +namespace dp_registry { +namespace backend { +namespace executable { + +ExecutableBackendDb::ExecutableBackendDb( + Reference<XComponentContext> const & xContext, + ::rtl::OUString const & url):RegisteredDb(xContext, url) +{ + +} + +OUString ExecutableBackendDb::getDbNSName() +{ + return OUSTR(EXTENSION_REG_NS); +} + +OUString ExecutableBackendDb::getNSPrefix() +{ + return OUSTR(NS_PREFIX); +} + +OUString ExecutableBackendDb::getRootElementName() +{ + return OUSTR(ROOT_ELEMENT_NAME); +} + +OUString ExecutableBackendDb::getKeyElementName() +{ + return OUSTR(ENTRY_NAME); +} + + +} // namespace executable +} // namespace backend +} // namespace dp_registry + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/executable/dp_executablebackenddb.hxx b/desktop/source/deployment/registry/executable/dp_executablebackenddb.hxx new file mode 100644 index 000000000000..1a5828015260 --- /dev/null +++ b/desktop/source/deployment/registry/executable/dp_executablebackenddb.hxx @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_EXECUTABLEBACKENDDB_HXX +#define INCLUDED_DP_EXECUTABLEBACKENDDB_HXX + +#include "rtl/ustring.hxx" +#include "dp_backenddb.hxx" + +namespace css = ::com::sun::star; + +namespace com { namespace sun { namespace star { + namespace uno { + class XComponentContext; + } +}}} + +namespace dp_registry { +namespace backend { +namespace executable { + +/* The XML file stores the extensions which are currently registered. + They will be removed when they are revoked. + The format looks like this: + +<?xml version="1.0"?> + */ +class ExecutableBackendDb: public dp_registry::backend::RegisteredDb +{ +protected: + virtual ::rtl::OUString getDbNSName(); + + virtual ::rtl::OUString getNSPrefix(); + + virtual ::rtl::OUString getRootElementName(); + + virtual ::rtl::OUString getKeyElementName(); + +public: + + ExecutableBackendDb( css::uno::Reference<css::uno::XComponentContext> const & xContext, + ::rtl::OUString const & url); + +}; + + + +} +} +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/executable/makefile.mk b/desktop/source/deployment/registry/executable/makefile.mk new file mode 100644 index 000000000000..81b2baa44e5d --- /dev/null +++ b/desktop/source/deployment/registry/executable/makefile.mk @@ -0,0 +1,44 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/..$/.. + +PRJNAME = desktop +TARGET = deployment_registry_executable +ENABLE_EXCEPTIONS = TRUE + +.INCLUDE : settings.mk + +INCPRE += ..$/..$/inc + +SLOFILES = \ + $(SLO)$/dp_executable.obj \ + $(SLO)$/dp_executablebackenddb.obj + +.INCLUDE : ..$/..$/target.pmk +.INCLUDE : target.mk + diff --git a/desktop/source/deployment/registry/help/dp_help.cxx b/desktop/source/deployment/registry/help/dp_help.cxx new file mode 100644 index 000000000000..d69e5698b7a4 --- /dev/null +++ b/desktop/source/deployment/registry/help/dp_help.cxx @@ -0,0 +1,656 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_help.hrc" +#include "dp_backend.h" +#include "dp_helpbackenddb.hxx" +#include "dp_ucb.h" +#include "rtl/uri.hxx" +#include "osl/file.hxx" +#include "rtl/bootstrap.hxx" +#include "ucbhelper/content.hxx" +#include "comphelper/servicedecl.hxx" +#include "svl/inettype.hxx" +#include "unotools/pathoptions.hxx" + +#include <l10ntools/compilehelp.hxx> +#include <com/sun/star/ucb/XSimpleFileAccess.hpp> +#include <com/sun/star/util/XMacroExpander.hpp> +#include <com/sun/star/uri/XUriReferenceFactory.hpp> +#include <com/sun/star/uri/XVndSunStarExpandUrl.hpp> +#include <com/sun/star/script/XInvocation.hpp> +#include "boost/optional.hpp" + +using namespace ::dp_misc; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using ::rtl::OUString; + +namespace dp_registry { +namespace backend { +namespace help { +namespace { + +//============================================================================== +class BackendImpl : public ::dp_registry::backend::PackageRegistryBackend +{ + class PackageImpl : public ::dp_registry::backend::Package + { + BackendImpl * getMyBackend() const; + +// HelpBackendDb::Data m_dbData; + + // Package + virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_( + ::osl::ResettableMutexGuard & guard, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + virtual void processPackage_( + ::osl::ResettableMutexGuard & guard, + bool registerPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + + bool extensionContainsCompiledHelp(); + public: + PackageImpl( + ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + bool bRemoved, OUString const & identifier); + + //XPackage + virtual css::beans::Optional< ::rtl::OUString > SAL_CALL getRegistrationDataURL() + throw (deployment::ExtensionRemovedException, css::uno::RuntimeException); + }; + friend class PackageImpl; + + // PackageRegistryBackend + virtual Reference<deployment::XPackage> bindPackage_( + OUString const & url, OUString const & mediaType, + sal_Bool bRemoved, OUString const & identifier, + Reference<XCommandEnvironment> const & xCmdEnv ); + + void implProcessHelp( Reference< deployment::XPackage > xPackage, bool doRegisterPackage, + bool compiledHelp, Reference<ucb::XCommandEnvironment> const & xCmdEnv); + void implCollectXhpFiles( const rtl::OUString& aDir, + std::vector< rtl::OUString >& o_rXhpFileVector ); + + void addDataToDb(OUString const & url, HelpBackendDb::Data const & data); + ::boost::optional<HelpBackendDb::Data> readDataFromDb(OUString const & url); + void deleteDataFromDb(OUString const & url); + + Reference< ucb::XSimpleFileAccess > getFileAccess( void ); + Reference< ucb::XSimpleFileAccess > m_xSFA; + + const Reference<deployment::XPackageTypeInfo> m_xHelpTypeInfo; + Sequence< Reference<deployment::XPackageTypeInfo> > m_typeInfos; + std::auto_ptr<HelpBackendDb> m_backendDb; + +public: + BackendImpl( Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ); + + // XPackageRegistry + virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL + getSupportedPackageTypes() throw (RuntimeException); +}; + +//______________________________________________________________________________ +BackendImpl::BackendImpl( + Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ) + : PackageRegistryBackend( args, xComponentContext ), + m_xHelpTypeInfo( new Package::TypeInfo( + OUSTR("application/vnd.sun.star.help"), + rtl::OUString(), + getResourceString(RID_STR_HELP), + RID_IMG_HELP ) ), + m_typeInfos( 1 ) +{ + m_typeInfos[ 0 ] = m_xHelpTypeInfo; + if (!transientMode()) + { + OUString dbFile = makeURL(getCachePath(), OUSTR("backenddb.xml")); + m_backendDb.reset( + new HelpBackendDb(getComponentContext(), dbFile)); + + //clean up data folders which are no longer used. + //This must not be done in the same process where the help files + //are still registers. Only after revoking and restarting OOo the folders + //can be removed. This works now, because the extension manager is a singleton + //and the backends are only create once per process. + ::std::list<OUString> folders = m_backendDb->getAllDataUrls(); + deleteUnusedFolders(OUString(), folders); + } +} + +// XPackageRegistry +//______________________________________________________________________________ +Sequence< Reference<deployment::XPackageTypeInfo> > +BackendImpl::getSupportedPackageTypes() throw (RuntimeException) +{ + return m_typeInfos; +} + +// PackageRegistryBackend +//______________________________________________________________________________ +Reference<deployment::XPackage> BackendImpl::bindPackage_( + OUString const & url, OUString const & mediaType_, + sal_Bool bRemoved, OUString const & identifier, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + // we don't support auto detection: + if (mediaType_.getLength() == 0) + throw lang::IllegalArgumentException( + StrCannotDetectMediaType::get() + url, + static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) ); + + String type, subType; + INetContentTypeParameterList params; + if (INetContentTypes::parse( mediaType_, type, subType, ¶ms )) + { + if (type.EqualsIgnoreCaseAscii("application")) + { + OUString name; + if (!bRemoved) + { + ::ucbhelper::Content ucbContent( url, xCmdEnv ); + name = ucbContent.getPropertyValue( + StrTitle::get() ).get<OUString>(); + } + + if (subType.EqualsIgnoreCaseAscii( + "vnd.sun.star.help")) + { + return new PackageImpl( + this, url, name, m_xHelpTypeInfo, bRemoved, + identifier); + } + } + } + throw lang::IllegalArgumentException( + StrUnsupportedMediaType::get() + mediaType_, + static_cast<OWeakObject *>(this), + static_cast<sal_Int16>(-1) ); +} + +void BackendImpl::addDataToDb( + OUString const & url, HelpBackendDb::Data const & data) +{ + if (m_backendDb.get()) + m_backendDb->addEntry(url, data); +} + +::boost::optional<HelpBackendDb::Data> BackendImpl::readDataFromDb( + OUString const & url) +{ + ::boost::optional<HelpBackendDb::Data> data; + if (m_backendDb.get()) + data = m_backendDb->getEntry(url); + return data; +} + +void BackendImpl::deleteDataFromDb(OUString const & url) +{ + if (m_backendDb.get()) + m_backendDb->removeEntry(url); +} + +//############################################################################## +BackendImpl::PackageImpl::PackageImpl( + ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + bool bRemoved, OUString const & identifier) + : Package( myBackend, url, name, name, xPackageType, bRemoved, + identifier) +{ +// if (bRemoved) +// { +// ::boost::optional<HelpBackendDb::Data> opt = +// getMyBackend()->readDataFromDb(url); +// if (opt) +// m_dbData = *opt; +// } +} + +// Package +BackendImpl * BackendImpl::PackageImpl::getMyBackend() const +{ + BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get()); + if (NULL == pBackend) + { + //May throw a DisposedException + check(); + //We should never get here... + throw RuntimeException( + OUSTR("Failed to get the BackendImpl"), + static_cast<OWeakObject*>(const_cast<PackageImpl *>(this))); + } + return pBackend; +} + +bool BackendImpl::PackageImpl::extensionContainsCompiledHelp() +{ + bool bCompiled = true; + rtl::OUString aExpandedHelpURL = dp_misc::expandUnoRcUrl(getURL()); + + ::osl::Directory helpFolder(aExpandedHelpURL); + if ( helpFolder.open() == ::osl::File::E_None) + { + //iterate over the contents of the help folder + //We assume that all folders withing the help folder contain language specific + //help files. If just one of them does not contain compiled help then this + //function returns false. + ::osl::DirectoryItem item; + ::osl::File::RC errorNext = ::osl::File::E_None; + while ((errorNext = helpFolder.getNextItem(item)) == ::osl::File::E_None) + { + //No find the language folders + ::osl::FileStatus stat(FileStatusMask_Type | FileStatusMask_FileName |FileStatusMask_FileURL); + if (item.getFileStatus(stat) == ::osl::File::E_None) + { + if (stat.getFileType() != ::osl::FileStatus::Directory) + continue; + + //look if there is the folder help.idxl in the language folder + OUString compUrl(stat.getFileURL() + OUSTR("/help.idxl")); + ::osl::Directory compiledFolder(compUrl); + if (compiledFolder.open() != ::osl::File::E_None) + { + bCompiled = false; + break; + } + } + else + { + //Error + OSL_ASSERT(0); + bCompiled = false; + break; + } + } + if (errorNext != ::osl::File::E_NOENT + && errorNext != ::osl::File::E_None) + { + //Error + OSL_ASSERT(0); + bCompiled = false; + } + } + return bCompiled; +} +//______________________________________________________________________________ +beans::Optional< beans::Ambiguous<sal_Bool> > +BackendImpl::PackageImpl::isRegistered_( + ::osl::ResettableMutexGuard &, + ::rtl::Reference<AbortChannel> const &, + Reference<XCommandEnvironment> const & ) +{ + BackendImpl * that = getMyBackend(); + + bool bReg = false; + if (that->readDataFromDb(getURL())) + bReg = true; + + return beans::Optional< beans::Ambiguous<sal_Bool> >( true, beans::Ambiguous<sal_Bool>( bReg, false ) ); +} + +//______________________________________________________________________________ +void BackendImpl::PackageImpl::processPackage_( + ::osl::ResettableMutexGuard &, + bool doRegisterPackage, + bool /* startup */, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + (void)doRegisterPackage; + (void)abortChannel; + (void)xCmdEnv; + + BackendImpl* that = getMyBackend(); + Reference< deployment::XPackage > xThisPackage( this ); + that->implProcessHelp( xThisPackage, doRegisterPackage, + extensionContainsCompiledHelp(), xCmdEnv); +} + +beans::Optional< OUString > BackendImpl::PackageImpl::getRegistrationDataURL() + throw (deployment::ExtensionRemovedException, + css::uno::RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + + ::boost::optional<HelpBackendDb::Data> data = + getMyBackend()->readDataFromDb(getURL()); + + if (data) + return beans::Optional<OUString>(true, data->dataUrl); + + return beans::Optional<OUString>(true, OUString()); +} + +//############################################################################## + +static rtl::OUString aSlash(RTL_CONSTASCII_USTRINGPARAM("/")); +static rtl::OUString aHelpStr(RTL_CONSTASCII_USTRINGPARAM("help")); + +void BackendImpl::implProcessHelp +( Reference< deployment::XPackage > xPackage, bool doRegisterPackage, bool compiledHelp, + Reference<ucb::XCommandEnvironment> const & xCmdEnv) +{ + OSL_ASSERT(xPackage.is()); + if (doRegisterPackage) + { + HelpBackendDb::Data data; + + if (compiledHelp) + { + data.dataUrl = xPackage->getURL(); + } + else + { + const OUString sHelpFolder = createFolder(OUString(), xCmdEnv); + data.dataUrl = sHelpFolder; + + Reference< ucb::XSimpleFileAccess > xSFA = getFileAccess(); + rtl::OUString aHelpURL = xPackage->getURL(); + rtl::OUString aExpandedHelpURL = dp_misc::expandUnoRcUrl( aHelpURL ); + rtl::OUString aName = xPackage->getName(); + if( !xSFA->isFolder( aExpandedHelpURL ) ) + { + rtl::OUString aErrStr = getResourceString( RID_STR_HELPPROCESSING_GENERAL_ERROR ); + aErrStr += rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "No help folder" )); + OWeakObject* oWeakThis = static_cast<OWeakObject *>(this); + throw deployment::DeploymentException( rtl::OUString(), oWeakThis, + makeAny( uno::Exception( aErrStr, oWeakThis ) ) ); + } + + Reference<XComponentContext> const & xContext = getComponentContext(); + Reference< script::XInvocation > xInvocation; + if( xContext.is() ) + { + try + { + xInvocation = Reference< script::XInvocation >( + xContext->getServiceManager()->createInstanceWithContext( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.help.HelpIndexer" )), xContext ) , UNO_QUERY ); + } + catch (Exception &) + { + // i98680: Survive missing lucene + } + } + + // Scan languages + Sequence< rtl::OUString > aLanguageFolderSeq = xSFA->getFolderContents( aExpandedHelpURL, true ); + sal_Int32 nLangCount = aLanguageFolderSeq.getLength(); + const rtl::OUString* pSeq = aLanguageFolderSeq.getConstArray(); + for( sal_Int32 iLang = 0 ; iLang < nLangCount ; ++iLang ) + { + rtl::OUString aLangURL = pSeq[iLang]; + if( xSFA->isFolder( aLangURL ) ) + { + std::vector< rtl::OUString > aXhpFileVector; + + // calculate jar file URL + sal_Int32 indexStartSegment = aLangURL.lastIndexOf('/'); + // for example "/en" + OUString langFolderURLSegment( + aLangURL.copy( + indexStartSegment + 1, aLangURL.getLength() - indexStartSegment - 1)); + + //create the folder in the "temporary folder" + ::ucbhelper::Content langFolderContent; + const OUString langFolderDest = makeURL(sHelpFolder, langFolderURLSegment); + const OUString langFolderDestExpanded = ::dp_misc::expandUnoRcUrl(langFolderDest); + ::dp_misc::create_folder( + &langFolderContent, + langFolderDest, xCmdEnv); + + rtl::OUString aJarFile( + makeURL(sHelpFolder, langFolderURLSegment + aSlash + aHelpStr + + OUSTR(".jar"))); + aJarFile = ::dp_misc::expandUnoRcUrl(aJarFile); + + rtl::OUString aEncodedJarFilePath = rtl::Uri::encode( + aJarFile, rtl_UriCharClassPchar, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ); + rtl::OUString aDestBasePath(RTL_CONSTASCII_USTRINGPARAM( "vnd.sun.star.pkg://" )); + aDestBasePath += aEncodedJarFilePath; + aDestBasePath += rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "/" )); + + sal_Int32 nLenLangFolderURL = aLangURL.getLength() + 1; + + Sequence< rtl::OUString > aSubLangSeq = xSFA->getFolderContents( aLangURL, true ); + sal_Int32 nSubLangCount = aSubLangSeq.getLength(); + const rtl::OUString* pSubLangSeq = aSubLangSeq.getConstArray(); + for( sal_Int32 iSubLang = 0 ; iSubLang < nSubLangCount ; ++iSubLang ) + { + rtl::OUString aSubFolderURL = pSubLangSeq[iSubLang]; + if( !xSFA->isFolder( aSubFolderURL ) ) + continue; + + implCollectXhpFiles( aSubFolderURL, aXhpFileVector ); + + // Copy to package (later: move?) + rtl::OUString aDestPath = aDestBasePath; + rtl::OUString aPureFolderName = aSubFolderURL.copy( nLenLangFolderURL ); + aDestPath += aPureFolderName; + xSFA->copy( aSubFolderURL, aDestPath ); + } + + // Call compiler + sal_Int32 nXhpFileCount = aXhpFileVector.size(); + rtl::OUString* pXhpFiles = new rtl::OUString[nXhpFileCount]; + for( sal_Int32 iXhp = 0 ; iXhp < nXhpFileCount ; ++iXhp ) + { + rtl::OUString aXhpFile = aXhpFileVector[iXhp]; + rtl::OUString aXhpRelFile = aXhpFile.copy( nLenLangFolderURL ); + pXhpFiles[iXhp] = aXhpRelFile; + } + + rtl::OUString aOfficeHelpPath( SvtPathOptions().GetHelpPath() ); + rtl::OUString aOfficeHelpPathFileURL; + ::osl::File::getFileURLFromSystemPath( aOfficeHelpPath, aOfficeHelpPathFileURL ); + + HelpProcessingErrorInfo aErrorInfo; + bool bSuccess = compileExtensionHelp( + aOfficeHelpPathFileURL, aHelpStr, aLangURL, + nXhpFileCount, pXhpFiles, + langFolderDestExpanded, aErrorInfo ); + + if( bSuccess && xInvocation.is() ) + { + Sequence<uno::Any> aParamsSeq( 6 ); + + aParamsSeq[0] = uno::makeAny( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "-lang" )) ); + + rtl::OUString aLang; + sal_Int32 nLastSlash = aLangURL.lastIndexOf( '/' ); + if( nLastSlash != -1 ) + aLang = aLangURL.copy( nLastSlash + 1 ); + else + aLang = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "en" )); + aParamsSeq[1] = uno::makeAny( aLang ); + + aParamsSeq[2] = uno::makeAny( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "-mod" )) ); + aParamsSeq[3] = uno::makeAny( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "help" )) ); + + aParamsSeq[4] = uno::makeAny( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "-zipdir" )) ); + rtl::OUString aSystemPath; + osl::FileBase::getSystemPathFromFileURL( + langFolderDestExpanded, aSystemPath ); + aParamsSeq[5] = uno::makeAny( aSystemPath ); + + Sequence< sal_Int16 > aOutParamIndex; + Sequence< uno::Any > aOutParam; + uno::Any aRet = xInvocation->invoke( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "createIndex" )), + aParamsSeq, aOutParamIndex, aOutParam ); + } + + if( !bSuccess ) + { + USHORT nErrStrId = 0; + switch( aErrorInfo.m_eErrorClass ) + { + case HELPPROCESSING_GENERAL_ERROR: + case HELPPROCESSING_INTERNAL_ERROR: nErrStrId = RID_STR_HELPPROCESSING_GENERAL_ERROR; break; + case HELPPROCESSING_XMLPARSING_ERROR: nErrStrId = RID_STR_HELPPROCESSING_XMLPARSING_ERROR; break; + default: ; + }; + + rtl::OUString aErrStr; + if( nErrStrId != 0 ) + { + aErrStr = getResourceString( nErrStrId ); + + // Remoce CR/LF + rtl::OUString aErrMsg( aErrorInfo.m_aErrorMsg ); + sal_Unicode nCR = 13, nLF = 10; + sal_Int32 nSearchCR = aErrMsg.indexOf( nCR ); + sal_Int32 nSearchLF = aErrMsg.indexOf( nLF ); + sal_Int32 nCopy; + if( nSearchCR != -1 || nSearchLF != -1 ) + { + if( nSearchCR == -1 ) + nCopy = nSearchLF; + else if( nSearchLF == -1 ) + nCopy = nSearchCR; + else + nCopy = ( nSearchCR < nSearchLF ) ? nSearchCR : nSearchLF; + + aErrMsg = aErrMsg.copy( 0, nCopy ); + } + aErrStr += aErrMsg; + if( nErrStrId == RID_STR_HELPPROCESSING_XMLPARSING_ERROR && aErrorInfo.m_aXMLParsingFile.getLength() ) + { + aErrStr += rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( " in " )); + + rtl::OUString aDecodedFile = rtl::Uri::decode( aErrorInfo.m_aXMLParsingFile, + rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 ); + aErrStr += aDecodedFile; + if( aErrorInfo.m_nXMLParsingLine != -1 ) + { + aErrStr += rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( ", line " )); + aErrStr += ::rtl::OUString::valueOf( aErrorInfo.m_nXMLParsingLine ); + } + } + } + + OWeakObject* oWeakThis = static_cast<OWeakObject *>(this); + throw deployment::DeploymentException( rtl::OUString(), oWeakThis, + makeAny( uno::Exception( aErrStr, oWeakThis ) ) ); + } + } + } + } + //Writing the data entry replaces writing the flag file. If we got to this + //point the registration was successful. + addDataToDb(xPackage->getURL(), data); + } //if (doRegisterPackage) + else + { + deleteDataFromDb(xPackage->getURL()); + } +} + +void BackendImpl::implCollectXhpFiles( const rtl::OUString& aDir, + std::vector< rtl::OUString >& o_rXhpFileVector ) +{ + Reference< ucb::XSimpleFileAccess > xSFA = getFileAccess(); + + // Scan xhp files recursively + Sequence< rtl::OUString > aSeq = xSFA->getFolderContents( aDir, true ); + sal_Int32 nCount = aSeq.getLength(); + const rtl::OUString* pSeq = aSeq.getConstArray(); + for( sal_Int32 i = 0 ; i < nCount ; ++i ) + { + rtl::OUString aURL = pSeq[i]; + if( xSFA->isFolder( aURL ) ) + { + implCollectXhpFiles( aURL, o_rXhpFileVector ); + } + else + { + sal_Int32 nLastDot = aURL.lastIndexOf( '.' ); + if( nLastDot != -1 ) + { + rtl::OUString aExt = aURL.copy( nLastDot + 1 ); + if( aExt.equalsIgnoreAsciiCase( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "xhp" )) ) ) + o_rXhpFileVector.push_back( aURL ); + } + } + } +} + +Reference< ucb::XSimpleFileAccess > BackendImpl::getFileAccess( void ) +{ + if( !m_xSFA.is() ) + { + Reference<XComponentContext> const & xContext = getComponentContext(); + if( xContext.is() ) + { + m_xSFA = Reference< ucb::XSimpleFileAccess >( + xContext->getServiceManager()->createInstanceWithContext( + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.ucb.SimpleFileAccess" )), + xContext ), UNO_QUERY ); + } + if( !m_xSFA.is() ) + { + throw RuntimeException( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "dp_registry::backend::help::BackendImpl::getFileAccess(), " + "could not instatiate SimpleFileAccess." )), + Reference< XInterface >() ); + } + } + return m_xSFA; +} + +} // anon namespace + +namespace sdecl = comphelper::service_decl; +sdecl::class_<BackendImpl, sdecl::with_args<true> > serviceBI; +extern sdecl::ServiceDecl const serviceDecl( + serviceBI, + "com.sun.star.comp.deployment.help.PackageRegistryBackend", + BACKEND_SERVICE_NAME ); + +} // namespace help +} // namespace backend +} // namespace dp_registry + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/help/dp_help.hrc b/desktop/source/deployment/registry/help/dp_help.hrc new file mode 100644 index 000000000000..c1e10547ccdd --- /dev/null +++ b/desktop/source/deployment/registry/help/dp_help.hrc @@ -0,0 +1,39 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_HELP_HRC +#define INCLUDED_DP_HELP_HRC + +#include "deployment.hrc" + +#define RID_STR_HELP (RID_DEPLOYMENT_HELP_START+2) + +#define RID_STR_HELPPROCESSING_GENERAL_ERROR (RID_DEPLOYMENT_HELP_START+3) +#define RID_STR_HELPPROCESSING_XMLPARSING_ERROR (RID_DEPLOYMENT_HELP_START+4) + + +#endif diff --git a/desktop/source/deployment/registry/help/dp_help.src b/desktop/source/deployment/registry/help/dp_help.src new file mode 100644 index 000000000000..6b6a3f9a6508 --- /dev/null +++ b/desktop/source/deployment/registry/help/dp_help.src @@ -0,0 +1,44 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "dp_help.hrc" + +String RID_STR_HELP +{ + Text [ en-US ] = "Help"; +}; + +String RID_STR_HELPPROCESSING_GENERAL_ERROR +{ + Text [ en-US ] = "The extension cannot be installed because:\n"; +}; + +String RID_STR_HELPPROCESSING_XMLPARSING_ERROR +{ + Text [ en-US ] = "The extension will not be installed because an error occurred in the Help files:\n"; +}; + diff --git a/desktop/source/deployment/registry/help/dp_helpbackenddb.cxx b/desktop/source/deployment/registry/help/dp_helpbackenddb.cxx new file mode 100644 index 000000000000..315b32867760 --- /dev/null +++ b/desktop/source/deployment/registry/help/dp_helpbackenddb.cxx @@ -0,0 +1,146 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "rtl/string.h" +#include "rtl/bootstrap.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/xml/dom/XDocumentBuilder.hpp" +#include "com/sun/star/xml/xpath/XXPathAPI.hpp" +#include "dp_misc.h" + +#include "dp_helpbackenddb.hxx" + + +namespace css = ::com::sun::star; +using namespace ::com::sun::star::uno; +using ::rtl::OUString; + +#define EXTENSION_REG_NS "http://openoffice.org/extensionmanager/help-registry/2010" +#define NS_PREFIX "help" +#define ROOT_ELEMENT_NAME "help-backend-db" +#define KEY_ELEMENT_NAME "help" + +namespace dp_registry { +namespace backend { +namespace help { + +HelpBackendDb::HelpBackendDb( + Reference<XComponentContext> const & xContext, + ::rtl::OUString const & url):BackendDb(xContext, url) +{ + +} + +OUString HelpBackendDb::getDbNSName() +{ + return OUSTR(EXTENSION_REG_NS); +} + +OUString HelpBackendDb::getNSPrefix() +{ + return OUSTR(NS_PREFIX); +} + +OUString HelpBackendDb::getRootElementName() +{ + return OUSTR(ROOT_ELEMENT_NAME); +} + +OUString HelpBackendDb::getKeyElementName() +{ + return OUSTR(KEY_ELEMENT_NAME); +} + + +void HelpBackendDb::addEntry(::rtl::OUString const & url, Data const & data) +{ + try{ + Reference<css::xml::dom::XNode> helpNode + = writeKeyElement(url); + + writeSimpleElement(OUSTR("data-url"), data.dataUrl, helpNode); + save(); + } + catch (css::deployment::DeploymentException& ) + { + throw; + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to write data entry in help backend db: ") + + m_urlDb, 0, exc); + } +} + + +::boost::optional<HelpBackendDb::Data> +HelpBackendDb::getEntry(::rtl::OUString const & url) +{ + try + { + HelpBackendDb::Data retData; + Reference<css::xml::dom::XNode> aNode = getKeyElement(url); + if (aNode.is()) + { + retData.dataUrl = readSimpleElement(OUSTR("data-url"), aNode); + } + else + { + return ::boost::optional<Data>(); + } + return ::boost::optional<Data>(retData); + } + catch (css::deployment::DeploymentException& ) + { + throw; + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to read data entry in help backend db: ") + + m_urlDb, 0, exc); + } +} + +::std::list<OUString> HelpBackendDb::getAllDataUrls() +{ + return getOneChildFromAllEntries(OUString(RTL_CONSTASCII_USTRINGPARAM("data-url"))); +} + +} // namespace help +} // namespace backend +} // namespace dp_registry + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/help/dp_helpbackenddb.hxx b/desktop/source/deployment/registry/help/dp_helpbackenddb.hxx new file mode 100644 index 000000000000..71001c9e7d92 --- /dev/null +++ b/desktop/source/deployment/registry/help/dp_helpbackenddb.hxx @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_HELPBACKENDDB_HXX +#define INCLUDED_DP_HELPBACKENDDB_HXX + +#include "rtl/ustring.hxx" +#include <list> +#include "boost/optional.hpp" +#include "dp_backenddb.hxx" + +namespace css = ::com::sun::star; + +namespace com { namespace sun { namespace star { + namespace uno { + class XComponentContext; + } +}}} + +namespace dp_registry { +namespace backend { +namespace help { + +/* The XML file stores the extensions which are currently registered. + They will be removed when they are revoked. + */ +class HelpBackendDb: public dp_registry::backend::BackendDb +{ +protected: + virtual ::rtl::OUString getDbNSName(); + + virtual ::rtl::OUString getNSPrefix(); + + virtual ::rtl::OUString getRootElementName(); + + virtual ::rtl::OUString getKeyElementName(); + +public: + struct Data + { + /* the URL to the folder containing the compiled help files, etc. + */ + ::rtl::OUString dataUrl; + + }; + +public: + + HelpBackendDb( css::uno::Reference<css::uno::XComponentContext> const & xContext, + ::rtl::OUString const & url); + + void addEntry(::rtl::OUString const & url, Data const & data); + + ::boost::optional<Data> getEntry(::rtl::OUString const & url); + ::std::list< ::rtl::OUString> getAllDataUrls(); + +}; + + + +} +} +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/help/makefile.mk b/desktop/source/deployment/registry/help/makefile.mk new file mode 100644 index 000000000000..d4934f71a46f --- /dev/null +++ b/desktop/source/deployment/registry/help/makefile.mk @@ -0,0 +1,52 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/..$/.. + +PRJNAME = desktop +TARGET = deployment_registry_help +ENABLE_EXCEPTIONS = TRUE + +INCPRE += ..$/..$/inc + +.INCLUDE : settings.mk + +.IF "$(SYSTEM_DB)" == "YES" +CFLAGS+=-DSYSTEM_DB -I$(DB_INCLUDES) +.ENDIF + +SRS1NAME = $(TARGET) +SRC1FILES = \ + dp_help.src + +SLOFILES = \ + $(SLO)$/dp_help.obj \ + $(SLO)$/dp_helpbackenddb.obj + +.INCLUDE : ..$/..$/target.pmk +.INCLUDE : target.mk + diff --git a/desktop/source/deployment/registry/inc/dp_backend.h b/desktop/source/deployment/registry/inc/dp_backend.h new file mode 100644 index 000000000000..4e97689e253f --- /dev/null +++ b/desktop/source/deployment/registry/inc/dp_backend.h @@ -0,0 +1,380 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_REGISTRY_H +#define INCLUDED_DP_REGISTRY_H + +#include "dp_misc.h" +#include "dp_resource.h" +#include "dp_interact.h" +#include "rtl/ref.hxx" +#include "cppuhelper/weakref.hxx" +#include "cppuhelper/implbase1.hxx" +#include "cppuhelper/compbase1.hxx" +#include "cppuhelper/compbase2.hxx" +#include "tools/inetmime.hxx" +#include "com/sun/star/lang/XEventListener.hpp" +#include "com/sun/star/deployment/XPackageRegistry.hpp" +#include "com/sun/star/deployment/XPackageManager.hpp" +#include "com/sun/star/deployment/InvalidRemovedParameterException.hpp" +#include <memory> +#include <hash_map> +#include <list> +#include "dp_registry.hrc" + +namespace dp_registry +{ +namespace backend +{ + +namespace css = ::com::sun::star; + +class PackageRegistryBackend; + +#define BACKEND_SERVICE_NAME "com.sun.star.deployment.PackageRegistryBackend" + +typedef ::cppu::WeakComponentImplHelper1< + css::deployment::XPackage > t_PackageBase; + +//============================================================================== +class Package : protected ::dp_misc::MutexHolder, public t_PackageBase +{ + PackageRegistryBackend * getMyBackend() const; + void processPackage_impl( + bool registerPackage, + bool startup, + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ); + +protected: + ::rtl::Reference<PackageRegistryBackend> m_myBackend; + const ::rtl::OUString m_url; + ::rtl::OUString m_name; + ::rtl::OUString m_displayName; + const css::uno::Reference<css::deployment::XPackageTypeInfo> m_xPackageType; + const bool m_bRemoved; + //Only set if m_bRemoved = true; + const ::rtl::OUString m_identifier; + + void check() const; + void fireModified(); + virtual void SAL_CALL disposing(); + + void checkAborted( + ::rtl::Reference< ::dp_misc::AbortChannel > const & abortChannel ); + + // @@@ to be implemented by specific backend: + virtual css::beans::Optional< css::beans::Ambiguous<sal_Bool> > + isRegistered_( + ::osl::ResettableMutexGuard & guard, + ::rtl::Reference< ::dp_misc::AbortChannel > const & abortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + = 0; + virtual void processPackage_( + ::osl::ResettableMutexGuard & guard, + bool registerPackage, + bool startup, + ::rtl::Reference< ::dp_misc::AbortChannel > const & abortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + = 0; + + virtual ~Package(); + Package( ::rtl::Reference<PackageRegistryBackend> const & myBackend, + ::rtl::OUString const & url, + ::rtl::OUString const & name, + ::rtl::OUString const & displayName, + css::uno::Reference<css::deployment::XPackageTypeInfo> const & + xPackageType, + bool bRemoved, + ::rtl::OUString const & identifier); + +public: + + class TypeInfo : + public ::cppu::WeakImplHelper1<css::deployment::XPackageTypeInfo> + { + const ::rtl::OUString m_mediaType; + const ::rtl::OUString m_fileFilter; + const ::rtl::OUString m_shortDescr; + const sal_uInt16 m_smallIcon; + public: + virtual ~TypeInfo(); + TypeInfo( ::rtl::OUString const & mediaType, + ::rtl::OUString const & fileFilter, + ::rtl::OUString const & shortDescr, + sal_uInt16 smallIcon) + : m_mediaType(mediaType), m_fileFilter(fileFilter), + m_shortDescr(shortDescr), + m_smallIcon(smallIcon) + {} + // XPackageTypeInfo + virtual ::rtl::OUString SAL_CALL getMediaType() + throw (css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getDescription() + throw (css::deployment::ExtensionRemovedException, + css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getShortDescription() + throw (css::deployment::ExtensionRemovedException, + css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getFileFilter() + throw (css::uno::RuntimeException); + virtual css::uno::Any SAL_CALL getIcon( sal_Bool highContrast, + sal_Bool smallIcon ) + throw (css::uno::RuntimeException); + }; + + // XComponent + virtual void SAL_CALL dispose() throw (css::uno::RuntimeException); + virtual void SAL_CALL addEventListener( + css::uno::Reference<css::lang::XEventListener> const & xListener ) + throw (css::uno::RuntimeException); + virtual void SAL_CALL removeEventListener( + css::uno::Reference<css::lang::XEventListener> const & xListener ) + throw (css::uno::RuntimeException); + + // XModifyBroadcaster + virtual void SAL_CALL addModifyListener( + css::uno::Reference<css::util::XModifyListener> const & xListener ) + throw (css::uno::RuntimeException); + virtual void SAL_CALL removeModifyListener( + css::uno::Reference<css::util::XModifyListener> const & xListener ) + throw (css::uno::RuntimeException); + + // XPackage + virtual css::uno::Reference<css::task::XAbortChannel> SAL_CALL + createAbortChannel() throw (css::uno::RuntimeException); + virtual css::beans::Optional< css::beans::Ambiguous<sal_Bool> > + SAL_CALL isRegistered( + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::uno::RuntimeException); + + virtual ::sal_Int32 SAL_CALL checkPrerequisites( + const css::uno::Reference< css::task::XAbortChannel >& xAbortChannel, + const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv, + sal_Bool noLicenseChecking) + throw (css::deployment::DeploymentException, + css::deployment::ExtensionRemovedException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::uno::RuntimeException); + + virtual ::sal_Bool SAL_CALL checkDependencies( + const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv ) + throw (css::deployment::DeploymentException, + css::deployment::ExtensionRemovedException, + css::ucb::CommandFailedException, + css::uno::RuntimeException); + + virtual void SAL_CALL registerPackage( + sal_Bool startup, + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::deployment::ExtensionRemovedException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::lang::IllegalArgumentException, css::uno::RuntimeException); + virtual void SAL_CALL revokePackage( + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::lang::IllegalArgumentException, + css::uno::RuntimeException); + virtual sal_Bool SAL_CALL isBundle() + throw (css::uno::RuntimeException); + virtual css::uno::Sequence< css::uno::Reference<css::deployment::XPackage> > + SAL_CALL getBundle( + css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::lang::IllegalArgumentException, + css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getName() + throw (css::uno::RuntimeException); + virtual css::beans::Optional< ::rtl::OUString > SAL_CALL getIdentifier() + throw (css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getVersion() + throw (css::deployment::ExtensionRemovedException, + css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getURL() + throw (css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getDisplayName() + throw (css::deployment::ExtensionRemovedException, + css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getDescription() + throw (css::deployment::ExtensionRemovedException, + css::uno::RuntimeException); + virtual css::uno::Sequence< ::rtl::OUString > SAL_CALL + getUpdateInformationURLs() + throw (css::deployment::ExtensionRemovedException, + css::uno::RuntimeException); + virtual css::beans::StringPair SAL_CALL getPublisherInfo() + throw (css::deployment::ExtensionRemovedException, + css::uno::RuntimeException); + virtual css::uno::Reference< css::graphic::XGraphic > SAL_CALL + getIcon( sal_Bool bHighContrast ) + throw (css::deployment::ExtensionRemovedException, + css::uno::RuntimeException); + virtual css::uno::Reference<css::deployment::XPackageTypeInfo> SAL_CALL + getPackageType() throw (css::uno::RuntimeException); + virtual void SAL_CALL exportTo( + ::rtl::OUString const & destFolderURL, + ::rtl::OUString const & newTitle, + sal_Int32 nameClashAction, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::ExtensionRemovedException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, css::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getRepositoryName() + throw (css::uno::RuntimeException); + virtual css::beans::Optional< ::rtl::OUString > SAL_CALL getRegistrationDataURL() + throw (css::deployment::ExtensionRemovedException, + css::uno::RuntimeException); + virtual sal_Bool SAL_CALL isRemoved() + throw (css::uno::RuntimeException); + +}; + +typedef ::cppu::WeakComponentImplHelper2< + css::lang::XEventListener, + css::deployment::XPackageRegistry > t_BackendBase; + +//============================================================================== +class PackageRegistryBackend + : protected ::dp_misc::MutexHolder, public t_BackendBase +{ + //The map held originally WeakReferences. The map entries are removed in the disposing + //function, which is called when the XPackages are destructed or they are + //explicitely disposed. The latter happens, for example, when a extension is + //removed (see dp_manager.cxx). However, because of how the help systems work, now + // XPackageManager::getDeployedPackages is called often. This results in a lot + //of bindPackage calls which are costly. Therefore we keep hard references in + //the map now. + typedef ::std::hash_map< + ::rtl::OUString, css::uno::Reference<css::deployment::XPackage>, + ::rtl::OUStringHash > t_string2ref; + t_string2ref m_bound; + +protected: + ::rtl::OUString m_cachePath; + css::uno::Reference<css::uno::XComponentContext> m_xComponentContext; + + ::rtl::OUString m_context; + // currently only for library containers: + enum context { + CONTEXT_UNKNOWN, + CONTEXT_USER, CONTEXT_SHARED,CONTEXT_BUNDLED, CONTEXT_TMP, + CONTEXT_DOCUMENT + } m_eContext; + bool m_readOnly; + + struct StrCannotDetectMediaType : public ::dp_misc::StaticResourceString< + StrCannotDetectMediaType, RID_STR_CANNOT_DETECT_MEDIA_TYPE> {}; + struct StrUnsupportedMediaType : public ::dp_misc::StaticResourceString< + StrUnsupportedMediaType, RID_STR_UNSUPPORTED_MEDIA_TYPE> {}; + + // @@@ to be implemented by specific backend: + virtual css::uno::Reference<css::deployment::XPackage> bindPackage_( + ::rtl::OUString const & url, ::rtl::OUString const & mediaType, + sal_Bool bRemoved, ::rtl::OUString const & identifier, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + = 0; + + void check(); + virtual void SAL_CALL disposing(); + + virtual ~PackageRegistryBackend(); + PackageRegistryBackend( + css::uno::Sequence<css::uno::Any> const & args, + css::uno::Reference<css::uno::XComponentContext> const & xContext ); + + /* creates a folder with a unique name. + If url is empty then it is created in the the backend folder, otherwise + at a location relative to that folder specified by url. + */ + ::rtl::OUString createFolder( + ::rtl::OUString const & relUrl, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv); + /* deletes folders and files. + + All folder all files which end with ".tmp" or ".tmp_" and which are + not used are deleted. + */ + void deleteUnusedFolders( + ::rtl::OUString const & relUrl, + ::std::list< ::rtl::OUString> const & usedFolders); + /* deletes one folder with a "temporary" name and the corresponding + tmp file, which was used to derive the folder name. + */ + static void deleteTempFolder( + ::rtl::OUString const & folderUrl); + + +public: + struct StrRegisteringPackage : public ::dp_misc::StaticResourceString< + StrRegisteringPackage, RID_STR_REGISTERING_PACKAGE> {}; + struct StrRevokingPackage : public ::dp_misc::StaticResourceString< + StrRevokingPackage, RID_STR_REVOKING_PACKAGE> {}; + + inline css::uno::Reference<css::uno::XComponentContext> const & + getComponentContext() const { return m_xComponentContext; } + + inline ::rtl::OUString const & getCachePath() const { return m_cachePath; } + inline bool transientMode() const { return m_cachePath.getLength() == 0; } + + inline ::rtl::OUString getContext() const {return m_context; } + + // XEventListener + virtual void SAL_CALL disposing( css::lang::EventObject const & evt ) + throw (css::uno::RuntimeException); + + // XPackageRegistry + virtual css::uno::Reference<css::deployment::XPackage> SAL_CALL bindPackage( + ::rtl::OUString const & url, ::rtl::OUString const & mediaType, + sal_Bool bRemoved, ::rtl::OUString const & identifier, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv ) + throw (css::deployment::DeploymentException, + css::deployment::InvalidRemovedParameterException, + css::ucb::CommandFailedException, + css::lang::IllegalArgumentException, css::uno::RuntimeException); +}; + +} +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/inc/dp_backenddb.hxx b/desktop/source/deployment/registry/inc/dp_backenddb.hxx new file mode 100644 index 000000000000..e06538595cb7 --- /dev/null +++ b/desktop/source/deployment/registry/inc/dp_backenddb.hxx @@ -0,0 +1,169 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_BACKENDDB_HXX +#define INCLUDED_DP_BACKENDDB_HXX + +#include "rtl/ustring.hxx" +#include <list> +#include <vector> + +namespace css = ::com::sun::star; + +namespace com { namespace sun { namespace star { + namespace uno { + class XComponentContext; + } + namespace xml { namespace dom { + class XDocument; + class XNode; + }} + namespace xml { namespace xpath { + class XXPathAPI; + }} +}}} + +namespace dp_registry { +namespace backend { + +class BackendDb +{ +private: + + css::uno::Reference<css::xml::dom::XDocument> m_doc; + css::uno::Reference<css::xml::xpath::XXPathAPI> m_xpathApi; + + BackendDb(BackendDb const &); + BackendDb & operator = (BackendDb const &); + +protected: + const css::uno::Reference<css::uno::XComponentContext> m_xContext; + ::rtl::OUString m_urlDb; + +protected: + + /* caller must make sure that only one thread accesses the function + */ + css::uno::Reference<css::xml::dom::XDocument> getDocument(); + + /* the namespace prefix is "reg" (without quotes) + */ + css::uno::Reference<css::xml::xpath::XXPathAPI> getXPathAPI(); + void save(); + void removeElement(::rtl::OUString const & sXPathExpression); + + css::uno::Reference<css::xml::dom::XNode> getKeyElement( + ::rtl::OUString const & url); + + void writeSimpleList( + ::std::list< ::rtl::OUString> const & list, + ::rtl::OUString const & sListTagName, + ::rtl::OUString const & sMemberTagName, + css::uno::Reference<css::xml::dom::XNode> const & xParent); + + void writeVectorOfPair( + ::std::vector< ::std::pair< ::rtl::OUString, ::rtl::OUString > > const & vecPairs, + ::rtl::OUString const & sVectorTagName, + ::rtl::OUString const & sPairTagName, + ::rtl::OUString const & sFirstTagName, + ::rtl::OUString const & sSecondTagName, + css::uno::Reference<css::xml::dom::XNode> const & xParent); + + void writeSimpleElement( + ::rtl::OUString const & sElementName, ::rtl::OUString const & value, + css::uno::Reference<css::xml::dom::XNode> const & xParent); + + css::uno::Reference<css::xml::dom::XNode> writeKeyElement( + ::rtl::OUString const & url); + + ::rtl::OUString readSimpleElement( + ::rtl::OUString const & sElementName, + css::uno::Reference<css::xml::dom::XNode> const & xParent); + + ::std::vector< ::std::pair< ::rtl::OUString, ::rtl::OUString > > + readVectorOfPair( + css::uno::Reference<css::xml::dom::XNode> const & parent, + ::rtl::OUString const & sListTagName, + ::rtl::OUString const & sPairTagName, + ::rtl::OUString const & sFirstTagName, + ::rtl::OUString const & sSecondTagName); + + ::std::list< ::rtl::OUString> readList( + css::uno::Reference<css::xml::dom::XNode> const & parent, + ::rtl::OUString const & sListTagName, + ::rtl::OUString const & sMemberTagName); + + /* returns the values of one particulary child element of all key elements. + */ + ::std::list< ::rtl::OUString> getOneChildFromAllEntries( + ::rtl::OUString const & sElementName); + + + /* returns the namespace which is to be written as xmlns attribute + into the root element. + */ + virtual ::rtl::OUString getDbNSName()=0; + /* return the namespace prefix which is to be registered with the XPath API. + + The prefix can then be used in XPath expressions. + */ + virtual ::rtl::OUString getNSPrefix()=0; + /* returns the name of the root element without any namespace prefix. + */ + virtual ::rtl::OUString getRootElementName()=0; + /* returns the name of xml element for each entry + */ + virtual ::rtl::OUString getKeyElementName()=0; + +public: + BackendDb(css::uno::Reference<css::uno::XComponentContext> const & xContext, + ::rtl::OUString const & url); + virtual ~BackendDb() {}; + + void removeEntry(::rtl::OUString const & url); +}; + +class RegisteredDb: public BackendDb +{ + +public: + RegisteredDb( css::uno::Reference<css::uno::XComponentContext> const & xContext, + ::rtl::OUString const & url); + virtual ~RegisteredDb() {}; + + + virtual void addEntry(::rtl::OUString const & url); + virtual bool getEntry(::rtl::OUString const & url); + +}; + +} +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/inc/dp_registry.hrc b/desktop/source/deployment/registry/inc/dp_registry.hrc new file mode 100644 index 000000000000..4a3b1d0b1a4a --- /dev/null +++ b/desktop/source/deployment/registry/inc/dp_registry.hrc @@ -0,0 +1,40 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_REGISTRY_HRC +#define INCLUDED_DP_REGISTRY_HRC + +#include "deployment.hrc" + +#define RID_STR_CANNOT_DETECT_MEDIA_TYPE (RID_DEPLOYMENT_REGISTRY_START+0) +#define RID_STR_UNSUPPORTED_MEDIA_TYPE (RID_DEPLOYMENT_REGISTRY_START+1) +#define RID_STR_ERROR_WHILE_REGISTERING (RID_DEPLOYMENT_REGISTRY_START+2) +#define RID_STR_ERROR_WHILE_REVOKING (RID_DEPLOYMENT_REGISTRY_START+3) +#define RID_STR_REGISTERING_PACKAGE (RID_DEPLOYMENT_REGISTRY_START+4) +#define RID_STR_REVOKING_PACKAGE (RID_DEPLOYMENT_REGISTRY_START+5) + +#endif diff --git a/desktop/source/deployment/registry/makefile.mk b/desktop/source/deployment/registry/makefile.mk new file mode 100644 index 000000000000..e45cec272ca7 --- /dev/null +++ b/desktop/source/deployment/registry/makefile.mk @@ -0,0 +1,49 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/.. + +PRJNAME = desktop +TARGET = deployment_registry +ENABLE_EXCEPTIONS = TRUE + +.INCLUDE : settings.mk + +SRS1NAME = $(TARGET) +SRC1FILES = \ + dp_registry.src + +INCPRE += inc + +SLOFILES = \ + $(SLO)$/dp_backend.obj \ + $(SLO)$/dp_registry.obj \ + $(SLO)$/dp_backenddb.obj + +.INCLUDE : ..$/target.pmk +.INCLUDE : target.mk + diff --git a/desktop/source/deployment/registry/package/dp_extbackenddb.cxx b/desktop/source/deployment/registry/package/dp_extbackenddb.cxx new file mode 100644 index 000000000000..29df20956ea0 --- /dev/null +++ b/desktop/source/deployment/registry/package/dp_extbackenddb.cxx @@ -0,0 +1,136 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "rtl/bootstrap.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/xml/dom/XDocumentBuilder.hpp" +#include "com/sun/star/xml/xpath/XXPathAPI.hpp" +#include "dp_misc.h" + +#include "dp_extbackenddb.hxx" + + +namespace css = ::com::sun::star; +using namespace ::com::sun::star::uno; +using ::rtl::OUString; + +#define EXTENSION_REG_NS "http://openoffice.org/extensionmanager/extension-registry/2010" +#define NS_PREFIX "ext" +#define ROOT_ELEMENT_NAME "extension-backend-db" +#define KEY_ELEMENT_NAME "extension" + +namespace dp_registry { +namespace backend { +namespace bundle { + +ExtensionBackendDb::ExtensionBackendDb( + Reference<XComponentContext> const & xContext, + ::rtl::OUString const & url):BackendDb(xContext, url) +{ + +} + +OUString ExtensionBackendDb::getDbNSName() +{ + return OUSTR(EXTENSION_REG_NS); +} + +OUString ExtensionBackendDb::getNSPrefix() +{ + return OUSTR(NS_PREFIX); +} + +OUString ExtensionBackendDb::getRootElementName() +{ + return OUSTR(ROOT_ELEMENT_NAME); +} + +OUString ExtensionBackendDb::getKeyElementName() +{ + return OUSTR(KEY_ELEMENT_NAME); +} + +void ExtensionBackendDb::addEntry(::rtl::OUString const & url, Data const & data) +{ + try{ + Reference<css::xml::dom::XNode> extensionNodeNode = writeKeyElement(url); + writeVectorOfPair( + data.items, + OUSTR("extension-items"), + OUSTR("item"), + OUSTR("url"), + OUSTR("media-type"), + extensionNodeNode); + save(); + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to write data entry in backend db: ") + + m_urlDb, 0, exc); + } +} + +ExtensionBackendDb::Data ExtensionBackendDb::getEntry(::rtl::OUString const & url) +{ + try + { + ExtensionBackendDb::Data retData; + Reference<css::xml::dom::XNode> aNode = getKeyElement(url); + + if (aNode.is()) + { + retData.items = + readVectorOfPair( + aNode, + OUSTR("extension-items"), + OUSTR("item"), + OUSTR("url"), + OUSTR("media-type")); + } + return retData; + } + catch(css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Extension Manager: failed to read data entry in backend db: ") + + m_urlDb, 0, exc); + } +} + +} // namespace bundle +} // namespace backend +} // namespace dp_registry + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/package/dp_extbackenddb.hxx b/desktop/source/deployment/registry/package/dp_extbackenddb.hxx new file mode 100644 index 000000000000..e94c846887c3 --- /dev/null +++ b/desktop/source/deployment/registry/package/dp_extbackenddb.hxx @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_EXTBACKENDDB_HXX +#define INCLUDED_DP_EXTBACKENDDB_HXX + +#include <utility> +#include <vector> + +#include "rtl/ustring.hxx" + +#include "dp_backenddb.hxx" + +namespace css = ::com::sun::star; + +namespace com { namespace sun { namespace star { + namespace uno { + class XComponentContext; + } + namespace xml { namespace dom { + class XDocument; + class XNode; + }} + namespace xml { namespace xpath { + class XXPathAPI; + }} +}}} + +namespace dp_registry { +namespace backend { +namespace bundle { + +/* The XML file stores the extensions which are currently registered. + They will be removed when they are revoked. + */ +class ExtensionBackendDb: public dp_registry::backend::BackendDb +{ +protected: + virtual ::rtl::OUString getDbNSName(); + virtual ::rtl::OUString getNSPrefix(); + virtual ::rtl::OUString getRootElementName(); + virtual ::rtl::OUString getKeyElementName(); + +public: + struct Data + { + /* every element consists of a pair of the url to the item (jar,rdb, etc) + and the media type + */ + ::std::vector< ::std::pair< ::rtl::OUString, ::rtl::OUString> > items; + typedef ::std::vector< + ::std::pair< ::rtl::OUString, ::rtl::OUString> >::const_iterator ITC_ITEMS; + }; + +public: + ExtensionBackendDb( css::uno::Reference<css::uno::XComponentContext> const & xContext, + ::rtl::OUString const & url); + + void addEntry(::rtl::OUString const & url, Data const & data); + + Data getEntry(::rtl::OUString const & url); + +}; + +} +} +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/package/dp_package.cxx b/desktop/source/deployment/registry/package/dp_package.cxx new file mode 100644 index 000000000000..0c89b4a62739 --- /dev/null +++ b/desktop/source/deployment/registry/package/dp_package.cxx @@ -0,0 +1,1650 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_package.hrc" +#include "dp_backend.h" +#include "dp_ucb.h" +#include "dp_interact.h" +#include "dp_dependencies.hxx" +#include "dp_platform.hxx" +#include "dp_descriptioninfoset.hxx" +#include "dp_identifier.hxx" +#include "rtl/uri.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "cppuhelper/implbase1.hxx" +#include "ucbhelper/content.hxx" +#include "svl/inettype.hxx" +#include "comphelper/anytostring.hxx" +#include "comphelper/makesequence.hxx" +#include "comphelper/sequence.hxx" +#include "com/sun/star/lang/WrappedTargetException.hpp" +#include "com/sun/star/lang/XServiceInfo.hpp" +#include "com/sun/star/beans/UnknownPropertyException.hpp" +#include "com/sun/star/graphic/XGraphic.hpp" +#include "com/sun/star/graphic/XGraphicProvider.hpp" +#include "com/sun/star/io/XOutputStream.hpp" +#include "com/sun/star/io/XInputStream.hpp" +#include "com/sun/star/task/InteractionClassification.hpp" +#include "com/sun/star/task/XInteractionApprove.hpp" +#include "com/sun/star/ucb/XInteractionReplaceExistingData.hpp" +#include "com/sun/star/ucb/NameClashResolveRequest.hpp" +#include "com/sun/star/ucb/XContentAccess.hpp" +#include "com/sun/star/ucb/NameClash.hpp" +#include "com/sun/star/ucb/UnsupportedCommandException.hpp" +#include "com/sun/star/sdbc/XResultSet.hpp" +#include "com/sun/star/sdbc/XRow.hpp" +#include "com/sun/star/packages/manifest/XManifestReader.hpp" +#include "com/sun/star/packages/manifest/XManifestWriter.hpp" +#include "com/sun/star/deployment/DependencyException.hpp" +#include "com/sun/star/deployment/LicenseException.hpp" +#include "com/sun/star/deployment/PlatformException.hpp" +#include "com/sun/star/deployment/Prerequisites.hpp" +#include "com/sun/star/xml/dom/XDocumentBuilder.hpp" +#include "com/sun/star/xml/xpath/XXPathAPI.hpp" +#include "com/sun/star/deployment/XPackageManager.hpp" +#include "boost/optional.hpp" +#include <vector> +#include <stdio.h> + +#include "dp_extbackenddb.hxx" +using namespace ::dp_misc; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace css = ::com::sun::star; + +using ::rtl::OUString; + +namespace dp_registry { +namespace backend { +namespace bundle { +namespace { + +typedef cppu::ImplInheritanceHelper1<PackageRegistryBackend, + lang::XServiceInfo> ImplBaseT; + +//============================================================================== +class BackendImpl : public ImplBaseT +{ + class PackageImpl : public ::dp_registry::backend::Package + { + BackendImpl * getMyBackend() const; + /** constains the old tooltip description for the Extension Manager GUI in OOo v.2.x + We keep it for backward compatibility. + */ + OUString m_oldDescription; + OUString m_url_expanded; + const bool m_legacyBundle; + Sequence< Reference<deployment::XPackage> > m_bundle; + Sequence< Reference<deployment::XPackage> > * m_pBundle; + + ExtensionBackendDb::Data m_dbData; + + Reference<deployment::XPackage> bindBundleItem( + OUString const & url, OUString const & mediaType, + sal_Bool bRemoved, //that is, useing data base information + OUString const & identifier, + Reference<ucb::XCommandEnvironment> const & xCmdEnv, + bool notifyDetectionError = true ); + + typedef ::std::vector< Reference<deployment::XPackage> > t_packagevec; + void scanBundle( + t_packagevec & bundle, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ); + void scanLegacyBundle( + t_packagevec & bundle, + OUString const & url, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv, + bool skip_registration = false ); + ::std::vector<Reference<deployment::XPackage> > getPackagesFromDb( + Reference<ucb::XCommandEnvironment> const & xCmdEnv); + bool checkPlatform( + Reference<ucb::XCommandEnvironment > const & environment); + + bool checkDependencies( + Reference<ucb::XCommandEnvironment > const & + environment, + DescriptionInfoset const & description); + // throws css::uno::RuntimeException, + // css::deployment::DeploymentException + + ::sal_Bool checkLicense( + Reference< ucb::XCommandEnvironment > const & xCmdEnv, + DescriptionInfoset const & description, bool bNoLicenseChecking) + throw (deployment::DeploymentException, + ucb::CommandFailedException, + ucb::CommandAbortedException, + RuntimeException); + // @throws DeploymentException + OUString getTextFromURL( + const Reference< ucb::XCommandEnvironment >& xCmdEnv, + const OUString& licenseUrl); + + DescriptionInfoset getDescriptionInfoset(); + + // Package + virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_( + ::osl::ResettableMutexGuard & guard, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ); + virtual void processPackage_( + ::osl::ResettableMutexGuard & guard, + bool registerPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ); + + virtual void SAL_CALL disposing(); + + + + public: + PackageImpl( + ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, + OUString const & name, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + bool legacyBundle, + bool bRemoved, + OUString const & identifier); + + // XPackage + virtual sal_Bool SAL_CALL isBundle() throw (RuntimeException); + + virtual Sequence< Reference<deployment::XPackage> > SAL_CALL getBundle( + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) + throw (deployment::DeploymentException, + ucb::CommandFailedException, + ucb::CommandAbortedException, + lang::IllegalArgumentException, RuntimeException); + virtual OUString SAL_CALL getDescription() + throw (deployment::ExtensionRemovedException, RuntimeException); + + virtual void SAL_CALL exportTo( + OUString const & destFolderURL, OUString const & newTitle, + sal_Int32 nameClashAction, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) + throw (deployment::ExtensionRemovedException, + ucb::CommandFailedException, + ucb::CommandAbortedException, + RuntimeException); + + virtual ::sal_Int32 SAL_CALL checkPrerequisites( + const Reference< task::XAbortChannel >& xAbortChannel, + const Reference< ucb::XCommandEnvironment >& xCmdEnv, + ::sal_Bool noLicenseChecking) + throw (deployment::ExtensionRemovedException, + deployment::DeploymentException, + ucb::CommandFailedException, + ucb::CommandAbortedException, + RuntimeException); + + virtual ::sal_Bool SAL_CALL checkDependencies( + const Reference< ucb::XCommandEnvironment >& xCmdEnv ) + throw (deployment::DeploymentException, + deployment::ExtensionRemovedException, + ucb::CommandFailedException, + RuntimeException); + + virtual beans::Optional<OUString> SAL_CALL getIdentifier() + throw (RuntimeException); + + virtual OUString SAL_CALL getVersion() + throw (deployment::ExtensionRemovedException, RuntimeException); + + virtual Sequence<OUString> SAL_CALL getUpdateInformationURLs() + throw (deployment::ExtensionRemovedException, RuntimeException); + + virtual beans::StringPair SAL_CALL getPublisherInfo() + throw (deployment::ExtensionRemovedException, RuntimeException); + + virtual OUString SAL_CALL getDisplayName() + throw (deployment::ExtensionRemovedException, RuntimeException); + + virtual Reference< graphic::XGraphic > SAL_CALL + getIcon( ::sal_Bool bHighContrast ) + throw (deployment::ExtensionRemovedException, + RuntimeException); + }; + friend class PackageImpl; + + Reference<deployment::XPackageRegistry> m_xRootRegistry; + const Reference<deployment::XPackageTypeInfo> m_xBundleTypeInfo; + const Reference<deployment::XPackageTypeInfo> m_xLegacyBundleTypeInfo; + Sequence< Reference<deployment::XPackageTypeInfo> > m_typeInfos; + + std::auto_ptr<ExtensionBackendDb> m_backendDb; + + void addDataToDb(OUString const & url, ExtensionBackendDb::Data const & data); + ExtensionBackendDb::Data readDataFromDb(OUString const & url); + void deleteDataFromDb(OUString const & url); + + // PackageRegistryBackend + virtual Reference<deployment::XPackage> bindPackage_( + OUString const & url, OUString const & mediaType, + sal_Bool bRemoved, OUString const & identifier, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ); + + virtual void SAL_CALL disposing(); + +public: + BackendImpl( + Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext, + Reference<deployment::XPackageRegistry> const & xRootRegistry ); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() throw (RuntimeException); + virtual sal_Bool SAL_CALL supportsService( OUString const& name ) + throw (RuntimeException); + virtual Sequence<OUString> SAL_CALL getSupportedServiceNames() + throw (RuntimeException); + + // XPackageRegistry + virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL + getSupportedPackageTypes() throw (RuntimeException); + + using ImplBaseT::disposing; +}; + +//Used to find a XPackage with a particular URL +class XPackage_eq : public std::unary_function<Reference<deployment::XPackage>, bool> +{ + OUString m_URL; +public: + explicit XPackage_eq(const OUString & s) : m_URL(s) {} + bool operator() (const Reference<deployment::XPackage> & p) const + { + return m_URL.equals(p->getURL()); + } +}; + +//______________________________________________________________________________ +BackendImpl::BackendImpl( + Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext, + Reference<deployment::XPackageRegistry> const & xRootRegistry ) + : ImplBaseT( args, xComponentContext ), + m_xRootRegistry( xRootRegistry ), + m_xBundleTypeInfo( new Package::TypeInfo( + OUSTR("application/vnd.sun.star.package-bundle"), + OUSTR("*.oxt;*.uno.pkg"), + getResourceString(RID_STR_PACKAGE_BUNDLE), + RID_IMG_DEF_PACKAGE_BUNDLE ) ), + m_xLegacyBundleTypeInfo( new Package::TypeInfo( + OUSTR("application/" + "vnd.sun.star.legacy-package-bundle"), + OUSTR("*.zip"), + m_xBundleTypeInfo->getShortDescription(), + RID_IMG_DEF_PACKAGE_BUNDLE ) ), + m_typeInfos(2) +{ + m_typeInfos[ 0 ] = m_xBundleTypeInfo; + m_typeInfos[ 1 ] = m_xLegacyBundleTypeInfo; + + if (!transientMode()) + { + OUString dbFile = makeURL(getCachePath(), getImplementationName()); + dbFile = makeURL(dbFile, OUSTR("backenddb.xml")); + m_backendDb.reset( + new ExtensionBackendDb(getComponentContext(), dbFile)); + } +} + +//______________________________________________________________________________ +void BackendImpl::disposing() +{ + m_xRootRegistry.clear(); + PackageRegistryBackend::disposing(); +} + +// XServiceInfo +OUString BackendImpl::getImplementationName() throw (RuntimeException) +{ + return OUSTR("com.sun.star.comp.deployment.bundle.PackageRegistryBackend"); +} + +sal_Bool BackendImpl::supportsService( OUString const& name ) + throw (RuntimeException) +{ + return getSupportedServiceNames()[0].equals(name); +} + +Sequence<OUString> BackendImpl::getSupportedServiceNames() + throw (RuntimeException) +{ + return comphelper::makeSequence( + OUString(RTL_CONSTASCII_USTRINGPARAM(BACKEND_SERVICE_NAME)) ); +} + +// XPackageRegistry +//______________________________________________________________________________ +Sequence< Reference<deployment::XPackageTypeInfo> > +BackendImpl::getSupportedPackageTypes() throw (RuntimeException) +{ + return m_typeInfos; +} + + + +// PackageRegistryBackend +//______________________________________________________________________________ +Reference<deployment::XPackage> BackendImpl::bindPackage_( + OUString const & url, OUString const & mediaType_, + sal_Bool bRemoved, OUString const & identifier, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) +{ + OUString mediaType( mediaType_ ); + if (mediaType.getLength() == 0) + { + // detect media-type: + ::ucbhelper::Content ucbContent; + if (create_ucb_content( &ucbContent, url, xCmdEnv )) + { + if (ucbContent.isFolder()) + { + //Every .oxt, uno.pkg file must contain a META-INF folder + ::ucbhelper::Content metaInfContent; + if (create_ucb_content( + &metaInfContent, makeURL( url, OUSTR("META-INF") ), + xCmdEnv, false /* no throw */ )) + { + mediaType = OUSTR("application/vnd.sun.star.package-bundle"); + } + //No support of legacy bundles, because every folder could be one. + } + else + { + const OUString title( ucbContent.getPropertyValue( + StrTitle::get() ).get<OUString>() ); + if (title.endsWithIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM(".oxt") ) || + title.endsWithIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM(".uno.pkg") )) + mediaType = OUSTR("application/vnd.sun.star.package-bundle"); + else if (title.endsWithIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM(".zip") )) + mediaType = + OUSTR("application/vnd.sun.star.legacy-package-bundle"); + } + } + if (mediaType.getLength() == 0) + throw lang::IllegalArgumentException( + StrCannotDetectMediaType::get() + url, + static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) ); + } + + String type, subType; + INetContentTypeParameterList params; + if (INetContentTypes::parse( mediaType, type, subType, ¶ms )) + { + if (type.EqualsIgnoreCaseAscii("application")) + { + + //In case a XPackage is created for a removed extension, we cannot + //obtain the name + OUString name; + if (!bRemoved) + { + ::ucbhelper::Content ucbContent( url, xCmdEnv ); + name = ucbContent.getPropertyValue( + StrTitle::get() ).get<OUString>(); + } + if (subType.EqualsIgnoreCaseAscii("vnd.sun.star.package-bundle")) { + return new PackageImpl( + this, url, name, m_xBundleTypeInfo, false, bRemoved, + identifier); + } + else if (subType.EqualsIgnoreCaseAscii( + "vnd.sun.star.legacy-package-bundle")) { + return new PackageImpl( + this, url, name, m_xLegacyBundleTypeInfo, true, bRemoved, + identifier); + } + } + } + throw lang::IllegalArgumentException( + StrUnsupportedMediaType::get() + mediaType, + static_cast<OWeakObject *>(this), + static_cast<sal_Int16>(-1) ); +} + +void BackendImpl::addDataToDb( + OUString const & url, ExtensionBackendDb::Data const & data) +{ + if (m_backendDb.get()) + m_backendDb->addEntry(url, data); +} + +ExtensionBackendDb::Data BackendImpl::readDataFromDb( + OUString const & url) +{ + ExtensionBackendDb::Data data; + if (m_backendDb.get()) + data = m_backendDb->getEntry(url); + return data; +} + +void BackendImpl::deleteDataFromDb(OUString const & url) +{ + if (m_backendDb.get()) + m_backendDb->removeEntry(url); +} + + +//############################################################################## + +BackendImpl::PackageImpl::PackageImpl( + ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, + OUString const & name, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + bool legacyBundle, bool bRemoved, OUString const & identifier) + : Package( myBackend, url, name, name /* display-name */, + xPackageType, bRemoved, identifier), + m_url_expanded( expandUnoRcUrl( url ) ), + m_legacyBundle( legacyBundle ), + m_pBundle( 0 ) +{ + if (bRemoved) + m_dbData = getMyBackend()->readDataFromDb(url); +} + +BackendImpl * BackendImpl::PackageImpl::getMyBackend() const +{ + BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get()); + if (NULL == pBackend) + { + //May throw a DisposedException + check(); + //We should never get here... + throw RuntimeException( + OUSTR("Failed to get the BackendImpl"), + static_cast<OWeakObject*>(const_cast<PackageImpl *>(this))); + } + return pBackend; +} +//______________________________________________________________________________ +void BackendImpl::PackageImpl::disposing() +{ + sal_Int32 len = m_bundle.getLength(); + Reference<deployment::XPackage> const * p = m_bundle.getConstArray(); + for ( sal_Int32 pos = 0; pos < len; ++pos ) + try_dispose( p[ pos ] ); + m_bundle.realloc( 0 ); + + Package::disposing(); +} + +// Package +//______________________________________________________________________________ +beans::Optional< beans::Ambiguous<sal_Bool> > +BackendImpl::PackageImpl::isRegistered_( + ::osl::ResettableMutexGuard &, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) +{ + //In case the object was created for a removed extension (m_bRemoved = true) + //but the extension is not registered, then bundle will be empty. Then + //the return value will be Optional<...>.IsPresent= false. Althoug this is + //not true, this does not matter. Then registerPackage or revokePackage + //would never be called for the items. But since the extension is removed + //and not registered anyway, this does not matter. + const Sequence< Reference<deployment::XPackage> > bundle( + getBundle( abortChannel.get(), xCmdEnv ) ); + + bool reg = false; + bool present = false; + bool ambig = false; + for ( sal_Int32 pos = bundle.getLength(); pos--; ) + { + Reference<deployment::XPackage> const & xPackage = bundle[ pos ]; + Reference<task::XAbortChannel> xSubAbortChannel( + xPackage->createAbortChannel() ); + AbortChannel::Chain chain( abortChannel, xSubAbortChannel ); + beans::Optional< beans::Ambiguous<sal_Bool> > option( + xPackage->isRegistered( xSubAbortChannel, xCmdEnv ) ); + + //present = true if at least one bundle item has this value. + //reg = true if all bundle items have an option value (option.IsPresent == 1) + //and all have value of true (option.Value.Value == true) + //If not, then the bundle has the status of not registered and ambiguous. + if (option.IsPresent) + { + beans::Ambiguous<sal_Bool> const & status = option.Value; + if (present) + { + //we never come here in the first iteration + if (reg != (status.Value != sal_False)) { + + ambig = true; + reg = false; + break; + } + } + else + { + //we always come here in the first iteration + reg = status.Value; + present = true; + } + } + } + return beans::Optional< beans::Ambiguous<sal_Bool> >( + present, beans::Ambiguous<sal_Bool>(reg, ambig) ); +} + +OUString BackendImpl::PackageImpl::getTextFromURL( + const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv, + const OUString& licenseUrl) +{ + try + { + ::ucbhelper::Content descContent(licenseUrl, xCmdEnv); + ::rtl::ByteSequence seq = dp_misc::readFile(descContent); + return OUString( reinterpret_cast<sal_Char const *>( + seq.getConstArray()), seq.getLength(), RTL_TEXTENCODING_UTF8); + } + catch (css::uno::Exception&) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + OUSTR("Could not read file ") + licenseUrl, 0, exc); + } + +} + +DescriptionInfoset BackendImpl::PackageImpl::getDescriptionInfoset() +{ + return dp_misc::getDescriptionInfoset(m_url_expanded); +} + +bool BackendImpl::PackageImpl::checkPlatform( + css::uno::Reference< css::ucb::XCommandEnvironment > const & environment) +{ + bool ret = false; + DescriptionInfoset info(getDescriptionInfoset()); + Sequence<OUString> platforms(info.getSupportedPlaforms()); + if (hasValidPlatform(platforms)) + { + ret = true; + } + else + { + ret = false; + rtl::OUString msg( + RTL_CONSTASCII_USTRINGPARAM("unsupported platform")); + Any e( + css::deployment::PlatformException( + msg, static_cast<OWeakObject *>(this), this)); + if (!interactContinuation( + e, cppu::UnoType< css::task::XInteractionApprove >::get(), + environment, NULL, NULL)) + { + throw css::deployment::DeploymentException( + msg, static_cast<OWeakObject *>(this), e); + } + } + return ret; +} + + +bool BackendImpl::PackageImpl::checkDependencies( + css::uno::Reference< css::ucb::XCommandEnvironment > const & environment, + DescriptionInfoset const & description) +{ + css::uno::Sequence< css::uno::Reference< css::xml::dom::XElement > > + unsatisfied(dp_misc::Dependencies::check(description)); + + if (unsatisfied.getLength() == 0) { + return true; + } else { + rtl::OUString msg( + RTL_CONSTASCII_USTRINGPARAM("unsatisfied dependencies")); + Any e( + css::deployment::DependencyException( + msg, static_cast<OWeakObject *>(this), unsatisfied)); + if (!interactContinuation( + e, cppu::UnoType< css::task::XInteractionApprove >::get(), + environment, NULL, NULL)) + { + throw css::deployment::DeploymentException( + msg, static_cast<OWeakObject *>(this), e); + } + return false; + } +} + +::sal_Bool BackendImpl::PackageImpl::checkLicense( + css::uno::Reference< css::ucb::XCommandEnvironment > const & xCmdEnv, + DescriptionInfoset const & info, bool alreadyInstalled) + throw (css::deployment::DeploymentException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::uno::RuntimeException) +{ + try + { + ::boost::optional<SimpleLicenseAttributes> simplLicAttr + = info.getSimpleLicenseAttributes(); + if (! simplLicAttr) + return true; + OUString sLic = info.getLocalizedLicenseURL(); + //If we do not get a localized licence then there is an error in the description.xml + //This should be handled by using a validating parser. Therefore we assume that no + //license is available. + if (sLic.getLength() == 0) + throw css::deployment::DeploymentException( + OUSTR("Could not obtain path to license. Possible error in description.xml"), 0, Any()); + OUString sHref = m_url_expanded + OUSTR("/") + sLic; + OUString sLicense = getTextFromURL(xCmdEnv, sHref); + ////determine who has to agree to the license + //check correct value for attribute + if ( ! (simplLicAttr->acceptBy.equals(OUSTR("user")) || simplLicAttr->acceptBy.equals(OUSTR("admin")))) + throw css::deployment::DeploymentException( + OUSTR("Could not obtain attribute simple-lincense@accept-by or it has no valid value"), 0, Any()); + + + //Only use interaction if there is no version of this extension already installed + //and the suppress-on-update flag is not set for the new extension + // alreadyInstalled | bSuppressOnUpdate | show license + //---------------------------------------- + // 0 | 0 | 1 + // 0 | 1 | 1 + // 1 | 0 | 1 + // 1 | 1 | 0 + + if ( !(alreadyInstalled && simplLicAttr->suppressOnUpdate)) + { + css::deployment::LicenseException licExc( + OUString(), 0, getDisplayName(), sLicense, + simplLicAttr->acceptBy); + bool approve = false; + bool abort = false; + if (! interactContinuation( + Any(licExc), task::XInteractionApprove::static_type(), xCmdEnv, &approve, &abort )) + throw css::deployment::DeploymentException( + OUSTR("Could not interact with user."), 0, Any()); + + if (approve == true) + return true; + else + return false; + //throw css::deployment::DeploymentException( + // OUSTR("Extension Manager: User declined the license."), + // static_cast<OWeakObject*>(this), + // Any( css::deployment::LicenseException(OUSTR("User declined the license."), 0, m_name, sLicense))); + } + return true; + } catch (css::ucb::CommandFailedException&) { + throw; + } catch (css::ucb::CommandAbortedException&) { + throw; + } catch (css::deployment::DeploymentException&) { + throw; + } catch (css::uno::RuntimeException&) { + throw; + } catch (css::uno::Exception&) { + Any anyExc = cppu::getCaughtException(); + throw css::deployment::DeploymentException(OUSTR("Unexpected exception"), 0, anyExc); + } +} + +::sal_Int32 BackendImpl::PackageImpl::checkPrerequisites( + const css::uno::Reference< css::task::XAbortChannel >&, + const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv, + sal_Bool alreadyInstalled) + throw (css::deployment::DeploymentException, + css::deployment::ExtensionRemovedException, + css::ucb::CommandFailedException, + css::ucb::CommandAbortedException, + css::uno::RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + DescriptionInfoset info = getDescriptionInfoset(); + if (!info.hasDescription()) + return 0; + + //always return LICENSE as long as the user did not accept the license + //so that XExtensonManager::checkPrerequisitesAndEnable will again + //check the license + if (!checkPlatform(xCmdEnv)) + return deployment::Prerequisites::PLATFORM | + deployment::Prerequisites::LICENSE; + else if(!checkDependencies(xCmdEnv, info)) + return deployment::Prerequisites::DEPENDENCIES | + deployment::Prerequisites::LICENSE; + else if(!checkLicense(xCmdEnv, info, alreadyInstalled)) + return deployment::Prerequisites::LICENSE; + else + return 0; +} + +::sal_Bool BackendImpl::PackageImpl::checkDependencies( + const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv ) + throw (deployment::DeploymentException, + deployment::ExtensionRemovedException, + ucb::CommandFailedException, + RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + DescriptionInfoset info = getDescriptionInfoset(); + if (!info.hasDescription()) + return sal_True; + + return checkDependencies(xCmdEnv, info); +} + +beans::Optional<OUString> BackendImpl::PackageImpl::getIdentifier() + throw (RuntimeException) +{ + OUString identifier; + if (m_bRemoved) + identifier = m_identifier; + else + identifier = dp_misc::generateIdentifier( + getDescriptionInfoset().getIdentifier(), m_name); + + return beans::Optional<OUString>( + true, identifier); +} + +OUString BackendImpl::PackageImpl::getVersion() + throw (deployment::ExtensionRemovedException, RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + return getDescriptionInfoset().getVersion(); +} + +Sequence<OUString> BackendImpl::PackageImpl::getUpdateInformationURLs() + throw (deployment::ExtensionRemovedException, RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + return getDescriptionInfoset().getUpdateInformationUrls(); +} + +beans::StringPair BackendImpl::PackageImpl::getPublisherInfo() + throw (deployment::ExtensionRemovedException, RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + ::std::pair< OUString, OUString > aInfo = getDescriptionInfoset().getLocalizedPublisherNameAndURL(); + beans::StringPair aStrPair( aInfo.first, aInfo.second ); + return aStrPair; +} + +//______________________________________________________________________________ +uno::Reference< graphic::XGraphic > BackendImpl::PackageImpl::getIcon( sal_Bool bHighContrast ) + throw (deployment::ExtensionRemovedException, RuntimeException ) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + + uno::Reference< graphic::XGraphic > xGraphic; + + OUString aIconURL = getDescriptionInfoset().getIconURL( bHighContrast ); + if ( aIconURL.getLength() ) + { + OUString aFullIconURL = m_url_expanded + OUSTR("/") + aIconURL; + + uno::Reference< XComponentContext > xContext( getMyBackend()->getComponentContext() ); + uno::Reference< graphic::XGraphicProvider > xGraphProvider( + xContext->getServiceManager()->createInstanceWithContext( OUSTR( "com.sun.star.graphic.GraphicProvider" ), xContext ), + uno::UNO_QUERY ); + + if ( xGraphProvider.is() ) + { + uno::Sequence< beans::PropertyValue > aMediaProps( 1 ); + aMediaProps[0].Name = OUSTR( "URL" ); + aMediaProps[0].Value <<= aFullIconURL; + + xGraphic = xGraphProvider->queryGraphic( aMediaProps ); + } + } + + return xGraphic; +} + +//______________________________________________________________________________ +void BackendImpl::PackageImpl::processPackage_( + ::osl::ResettableMutexGuard &, + bool doRegisterPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) +{ + const Sequence< Reference<deployment::XPackage> > bundle( + getBundle( abortChannel.get(), xCmdEnv ) ); + + if (doRegisterPackage) + { + ExtensionBackendDb::Data data; + const sal_Int32 len = bundle.getLength(); + for ( sal_Int32 pos = 0; pos < len; ++pos ) + { + checkAborted(abortChannel); + Reference<deployment::XPackage> const & xPackage = bundle[ pos ]; + Reference<task::XAbortChannel> xSubAbortChannel( + xPackage->createAbortChannel() ); + AbortChannel::Chain chain( abortChannel, xSubAbortChannel ); + try { + xPackage->registerPackage( startup, xSubAbortChannel, xCmdEnv ); + } + catch (Exception &) + { + //We even try a rollback if the user cancelled the action (CommandAbortedException) + //in order to prevent invalid database entries. + Any exc( ::cppu::getCaughtException() ); + // try to handle exception, notify: + bool approve = false, abort = false; + if (! interactContinuation( + Any( lang::WrappedTargetException( + OUSTR("bundle item registration error!"), + static_cast<OWeakObject *>(this), exc ) ), + task::XInteractionApprove::static_type(), xCmdEnv, + &approve, &abort )) { + OSL_ASSERT( !approve && !abort ); + if (m_legacyBundle) // default for legacy packages: ignore + continue; + // no selection at all, so rethrow; + // no C++ rethrow after getCaughtException(), + // see cppuhelper/exc_hlp.hxx: + ::cppu::throwException(exc); + } + if (approve && !abort) // ignore error, just continue + continue; + + { + ProgressLevel progress( + xCmdEnv, OUSTR("rollback...") ); + // try rollback + for ( ; pos--; ) + { + try { + bundle[ pos ]->revokePackage( + xSubAbortChannel, xCmdEnv ); + } + catch (Exception &) + { + OSL_ENSURE( 0, ::rtl::OUStringToOString( + ::comphelper::anyToString( + ::cppu::getCaughtException() ), + RTL_TEXTENCODING_UTF8 ).getStr() ); + // ignore any errors of rollback + } + } + progress.update( OUSTR("rollback finished.") ); + } + + deployment::DeploymentException dpExc; + if (exc >>= dpExc) { + throw ucb::CommandFailedException( + dpExc.Message, dpExc.Context, dpExc.Cause ); + } + else { + // rethrow CommandFailedException + ::cppu::throwException(exc); + } + } + data.items.push_back( + ::std::make_pair(xPackage->getURL(), + xPackage->getPackageType()->getMediaType())); + } + getMyBackend()->addDataToDb(getURL(), data); + } + else + { + // revoke in reverse order: + for ( sal_Int32 pos = bundle.getLength(); pos--; ) + { + checkAborted(abortChannel); + Reference<deployment::XPackage> const & xPackage = bundle[ pos ]; + Reference<task::XAbortChannel> xSubAbortChannel( + xPackage->createAbortChannel() ); + AbortChannel::Chain chain( abortChannel, xSubAbortChannel ); + try { + bundle[ pos ]->revokePackage( xSubAbortChannel, xCmdEnv ); + } + catch (RuntimeException &) { + throw; + } + catch (ucb::CommandAbortedException &) { + throw; + } + catch (Exception &) { + // CommandFailedException, DeploymentException: + Any exc( ::cppu::getCaughtException() ); + // try to handle exception, notify: + bool approve = false, abort = false; + if (! interactContinuation( + Any( lang::WrappedTargetException( + OUSTR("bundle item revocation error!"), + static_cast<OWeakObject *>(this), exc ) ), + task::XInteractionApprove::static_type(), xCmdEnv, + &approve, &abort )) { + OSL_ASSERT( !approve && !abort ); + if (m_legacyBundle) // default for legacy packages: ignore + continue; + // no selection at all, so rethrow + // no C++ rethrow after getCaughtException(), + // see cppuhelper/exc_hlp.hxx: + ::cppu::throwException(exc); + } + // ignore errors when revoking, although abort may have been + // selected + } + } + getMyBackend()->deleteDataFromDb(getURL()); + } +} + +//______________________________________________________________________________ +OUString BackendImpl::PackageImpl::getDescription() + throw (deployment::ExtensionRemovedException, RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + + const OUString sRelativeURL(getDescriptionInfoset().getLocalizedDescriptionURL()); + OUString sDescription; + if (sRelativeURL.getLength()) + { + OUString sURL = m_url_expanded + OUSTR("/") + sRelativeURL; + + try + { + sDescription = getTextFromURL( css::uno::Reference< css::ucb::XCommandEnvironment >(), sURL ); + } + catch ( css::deployment::DeploymentException& ) + { + OSL_ENSURE( 0, ::rtl::OUStringToOString( ::comphelper::anyToString( ::cppu::getCaughtException() ), RTL_TEXTENCODING_UTF8 ).getStr() ); + } + } + + if (sDescription.getLength()) + return sDescription; + return m_oldDescription; +} + +//______________________________________________________________________________ +void BackendImpl::PackageImpl::exportTo( + OUString const & destFolderURL, OUString const & newTitle, + sal_Int32 nameClashAction, Reference<ucb::XCommandEnvironment> const & xCmdEnv ) + throw (ucb::CommandFailedException, + deployment::ExtensionRemovedException, + ucb::CommandAbortedException, RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + + ::ucbhelper::Content sourceContent( m_url_expanded, xCmdEnv ); + OUString title(newTitle); + if (title.getLength() == 0) + sourceContent.getPropertyValue( StrTitle::get() ) >>= title; + OUString destURL( makeURL( destFolderURL, ::rtl::Uri::encode( + title, rtl_UriCharClassPchar, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ) ) ); + + if (nameClashAction == ucb::NameClash::ASK) + { + if (create_ucb_content( + 0, destURL, xCmdEnv, false /* no throw */ )) { + bool replace = false, abort = false; + if (! interactContinuation( + Any( ucb::NameClashResolveRequest( + OUSTR("file already exists: ") + title, + static_cast<OWeakObject *>(this), + task::InteractionClassification_QUERY, + destFolderURL, title, OUString() ) ), + ucb::XInteractionReplaceExistingData::static_type(), xCmdEnv, + &replace, &abort ) || !replace) { + return; + } + } + } + else if (nameClashAction != ucb::NameClash::OVERWRITE) { + throw ucb::CommandFailedException( + OUSTR("unsupported nameClashAction!"), + static_cast<OWeakObject *>(this), Any() ); + } + erase_path( destURL, xCmdEnv ); + + ::rtl::OUStringBuffer buf; + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.zip://") ); + buf.append( ::rtl::Uri::encode( destURL, + rtl_UriCharClassRegName, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ) ); + buf.append( static_cast<sal_Unicode>('/') ); + OUString destFolder( buf.makeStringAndClear() ); + + ::ucbhelper::Content destFolderContent( destFolder, xCmdEnv ); + { + // transfer every item of folder into zip: + Reference<sdbc::XResultSet> xResultSet( + sourceContent.createCursor( + Sequence<OUString>(), + ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS ) ); + ProgressLevel progress( xCmdEnv, OUString() ); + while (xResultSet->next()) + { + ::ucbhelper::Content subContent( + Reference<ucb::XContentAccess>( + xResultSet, UNO_QUERY_THROW )->queryContent(), xCmdEnv ); + if (! destFolderContent.transferContent( + subContent, ::ucbhelper::InsertOperation_COPY, + OUString(), ucb::NameClash::OVERWRITE )) + throw RuntimeException( OUSTR("UCB transferContent() failed!"), + static_cast<OWeakObject *>(this) ); + progress.update( Any() ); // animating progress bar + } + } + + // assure META-INF folder: + ::ucbhelper::Content metainfFolderContent; + create_folder( &metainfFolderContent, + makeURL( destFolderContent.getURL(), OUSTR("META-INF") ), + xCmdEnv ); + + if (m_legacyBundle) + { + // easy to migrate legacy bundles to new format: + // just export them once using a .oxt name! + // set detected media-types of any bundle item: + + // collect all manifest entries: + Sequence< Reference<deployment::XPackage> > bundle; + try { + bundle = getBundle( Reference<task::XAbortChannel>(), xCmdEnv ); + } + // xxx todo: think about exception specs: + catch (deployment::DeploymentException &) { + OSL_ENSURE( 0, ::rtl::OUStringToOString( + ::comphelper::anyToString( + ::cppu::getCaughtException() ), + RTL_TEXTENCODING_UTF8 ).getStr() ); + } + catch (lang::IllegalArgumentException & exc) { + (void) exc; + OSL_ENSURE( 0, ::rtl::OUStringToOString( + exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); + } + + ::std::vector< Sequence<beans::PropertyValue> > manifest; + manifest.reserve( bundle.getLength() ); + sal_Int32 baseURLlen = m_url_expanded.getLength(); + Reference<deployment::XPackage> const *pbundle = bundle.getConstArray(); + const OUString strMediaType = OUSTR("MediaType"); + const OUString strFullPath = OUSTR("FullPath"); + const OUString strIsFolder = OUSTR("IsFolder"); + for ( sal_Int32 pos = bundle.getLength(); pos--; ) + { + Reference<deployment::XPackage> const & xPackage = pbundle[ pos ]; + OUString url_( expandUnoRcUrl( xPackage->getURL() ) ); + OSL_ASSERT( url_.getLength() >= baseURLlen ); + OUString fullPath; + if (url_.getLength() > baseURLlen) + fullPath = url_.copy( baseURLlen + 1 ); + ::ucbhelper::Content ucbContent( url_, xCmdEnv ); + if (ucbContent.getPropertyValue(strIsFolder).get<bool>()) + fullPath += OUSTR("/"); + Sequence<beans::PropertyValue> attribs( 2 ); + beans::PropertyValue * pattribs = attribs.getArray(); + pattribs[ 0 ].Name = strFullPath; + pattribs[ 0 ].Value <<= fullPath; + pattribs[ 1 ].Name = strMediaType; + const Reference<deployment::XPackageTypeInfo> xPackageType( + xPackage->getPackageType() ); + OUString mediaType; + OSL_ASSERT( xPackageType.is() ); + if (xPackageType.is()) + mediaType = xPackageType->getMediaType(); + else + mediaType = OUSTR("unknown"); + pattribs[ 1 ].Value <<= mediaType; + manifest.push_back( attribs ); + } + + // write into pipe: + Reference<XComponentContext> xContext( + getMyBackend()->getComponentContext() ); + Reference<packages::manifest::XManifestWriter> xManifestWriter( + xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.packages.manifest.ManifestWriter"), + xContext ), UNO_QUERY_THROW ); + Reference<io::XOutputStream> xPipe( + xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.io.Pipe"), xContext ), UNO_QUERY_THROW ); + xManifestWriter->writeManifestSequence( + xPipe, comphelper::containerToSequence(manifest) ); + + // write buffered pipe data to content: + ::ucbhelper::Content manifestContent( + makeURL( metainfFolderContent.getURL(), OUSTR("manifest.xml") ), + xCmdEnv ); + manifestContent.writeStream( + Reference<io::XInputStream>( xPipe, UNO_QUERY_THROW ), + true /* replace existing */ ); + } + else + { + // overwrite manifest.xml: + ::ucbhelper::Content manifestContent; + if ( ! create_ucb_content( + &manifestContent, + makeURL( m_url_expanded, OUSTR("META-INF/manifest.xml") ), + xCmdEnv, false ) ) + { + OSL_ENSURE( 0, "### missing META-INF/manifest.xml file!" ); + return; + } + + if (! metainfFolderContent.transferContent( + manifestContent, ::ucbhelper::InsertOperation_COPY, + OUString(), ucb::NameClash::OVERWRITE )) + throw RuntimeException( OUSTR("UCB transferContent() failed!"), + static_cast<OWeakObject *>(this) ); + } + + // xxx todo: maybe obsolete in the future + try { + destFolderContent.executeCommand( OUSTR("flush"), Any() ); + } + catch (ucb::UnsupportedCommandException &) { + } +} + +//______________________________________________________________________________ +sal_Bool BackendImpl::PackageImpl::isBundle() throw (RuntimeException) +{ + return true; +} + +//______________________________________________________________________________ +Sequence< Reference<deployment::XPackage> > BackendImpl::PackageImpl::getBundle( + Reference<task::XAbortChannel> const & xAbortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) + throw (deployment::DeploymentException, + ucb::CommandFailedException, ucb::CommandAbortedException, + lang::IllegalArgumentException, RuntimeException) +{ + Sequence< Reference<deployment::XPackage> > * pBundle = m_pBundle; + if (pBundle == 0) + { + t_packagevec bundle; + if (m_bRemoved) + { + bundle = getPackagesFromDb(xCmdEnv); + } + else + { + try { + if (m_legacyBundle) + { + // .zip legacy packages allow script.xlb, dialog.xlb in bundle + // root folder: + OUString mediaType; + // probe for script.xlb: + if (create_ucb_content( + 0, makeURL( m_url_expanded, OUSTR("script.xlb") ), + xCmdEnv, false /* no throw */ )) { + mediaType = OUSTR("application/vnd.sun.star.basic-library"); + } + // probe for dialog.xlb: + else if (create_ucb_content( + 0, makeURL( m_url_expanded, OUSTR("dialog.xlb") ), + xCmdEnv, false /* no throw */ )) + mediaType = OUSTR("application/vnd.sun.star." + "dialog-library"); + + if (mediaType.getLength() > 0) { + const Reference<deployment::XPackage> xPackage( + bindBundleItem( getURL(), mediaType, false, OUString(), + xCmdEnv ) ); + if (xPackage.is()) + bundle.push_back( xPackage ); + // continue scanning: + } + scanLegacyBundle( bundle, getURL(), + AbortChannel::get(xAbortChannel), xCmdEnv ); + } + else + { + // .oxt: + scanBundle( bundle, AbortChannel::get(xAbortChannel), xCmdEnv ); + } + + } + catch (RuntimeException &) { + throw; + } + catch (ucb::CommandFailedException &) { + throw; + } + catch (ucb::CommandAbortedException &) { + throw; + } + catch (deployment::DeploymentException &) { + throw; + } + catch (Exception &) { + Any exc( ::cppu::getCaughtException() ); + throw deployment::DeploymentException( + OUSTR("error scanning bundle: ") + getURL(), + static_cast<OWeakObject *>(this), exc ); + } + } + + // sort: schema before config data, typelibs before components: + Sequence< Reference<deployment::XPackage> > ret( bundle.size() ); + Reference<deployment::XPackage> * pret = ret.getArray(); + sal_Int32 lower_end = 0; + sal_Int32 upper_end = ret.getLength(); + t_packagevec::const_iterator iPos( bundle.begin() ); + t_packagevec::const_iterator const iEnd( bundle.end() ); + for ( ; iPos != iEnd; ++iPos ) + { + const Reference<deployment::XPackageTypeInfo> xPackageType( + (*iPos)->getPackageType() ); + OSL_ASSERT( xPackageType.is() ); + if (xPackageType.is()) { + const OUString mediaType( xPackageType->getMediaType() ); + String type, subType; + INetContentTypeParameterList params; + if (INetContentTypes::parse( + mediaType, type, subType, ¶ms ) && + type.EqualsIgnoreCaseAscii("application") && + (subType.EqualsIgnoreCaseAscii( + "vnd.sun.star.uno-component") || + subType.EqualsIgnoreCaseAscii( + "vnd.sun.star.configuration-data"))) + { + --upper_end; + pret[ upper_end ] = *iPos; + continue; + } + } + pret[ lower_end ] = *iPos; + ++lower_end; + } + OSL_ASSERT( lower_end == upper_end ); + + const ::osl::MutexGuard guard( getMutex() ); + pBundle = m_pBundle; + if (pBundle == 0) { + m_bundle = ret; + pBundle = &m_bundle; + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + m_pBundle = pBundle; + } + } + else { + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + } + return *pBundle; +} + +inline bool isBundle_( OUString const & mediaType ) +{ + // xxx todo: additional parsing? + return mediaType.getLength() > 0 && + (mediaType.matchIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM( + "application/vnd.sun.star.package-bundle") ) || + mediaType.matchIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM( + "application/vnd.sun.star.legacy-package-bundle") )); +} + +//______________________________________________________________________________ +Reference<deployment::XPackage> BackendImpl::PackageImpl::bindBundleItem( + OUString const & url, OUString const & mediaType, + sal_Bool bRemoved, OUString const & identifier, + Reference<ucb::XCommandEnvironment> const & xCmdEnv, + bool notifyDetectionError ) +{ + // ignore any nested bundles: + if (isBundle_(mediaType)) + return Reference<deployment::XPackage>(); + + Reference<deployment::XPackage>xPackage; + try { + xPackage.set( getMyBackend()->m_xRootRegistry->bindPackage( + url, mediaType, bRemoved, identifier, xCmdEnv ) ); + OSL_ASSERT( xPackage.is() ); + } + catch (RuntimeException &) { + throw; + } + catch (ucb::CommandFailedException &) { + // ignore already handled error + } + catch (Exception &) { + const Any exc( ::cppu::getCaughtException() ); + if (notifyDetectionError || + !exc.isExtractableTo( + ::getCppuType( reinterpret_cast< + lang::IllegalArgumentException const *>(0) ) )) + { + interactContinuation( + Any( lang::WrappedTargetException( + OUSTR("bundle item error!"), + static_cast<OWeakObject *>(this), exc ) ), + task::XInteractionApprove::static_type(), xCmdEnv, 0, 0 ); + } + } + + if (xPackage.is()) { + const Reference<deployment::XPackageTypeInfo> xPackageType( + xPackage->getPackageType() ); + OSL_ASSERT( xPackageType.is() ); + // ignore any nested bundles: + if (xPackageType.is() && isBundle_( xPackageType->getMediaType() )) + xPackage.clear(); + } + return xPackage; +} + +//______________________________________________________________________________ +void BackendImpl::PackageImpl::scanBundle( + t_packagevec & bundle, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv ) +{ + OSL_ASSERT( !m_legacyBundle ); + + ::ucbhelper::Content manifestContent; + if (! create_ucb_content( + &manifestContent, + makeURL( m_url_expanded, OUSTR("META-INF/manifest.xml") ), + xCmdEnv, false /* no throw */ )) + { + OSL_ENSURE( 0, "### missing META-INF/manifest.xml file!" ); + return; + } + + + const lang::Locale officeLocale = getOfficeLocale(); + OUString descrFile; + lang::Locale descrFileLocale; + + const Reference<XComponentContext> xContext( + getMyBackend()->getComponentContext() ); + Reference<packages::manifest::XManifestReader> xManifestReader( + xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.packages.manifest.ManifestReader"), + xContext ), UNO_QUERY_THROW ); + const Sequence< Sequence<beans::PropertyValue> > manifestSeq( + xManifestReader->readManifestSequence( manifestContent.openStream() ) ); + const OUString packageRootURL( getURL() ); + for ( sal_Int32 pos = manifestSeq.getLength(); pos--; ) + { + OUString fullPath, mediaType; + Sequence<beans::PropertyValue> const & attribs = manifestSeq[ pos ]; + for ( sal_Int32 i = attribs.getLength(); i--; ) + { + if (fullPath.getLength() > 0 && mediaType.getLength() > 0) + break; + if (attribs[i].Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("FullPath") )) + attribs[i].Value >>= fullPath; + else if (attribs[i].Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("MediaType") )) + attribs[i].Value >>= mediaType; + } + + if (fullPath.getLength() == 0 || mediaType.getLength() == 0 || + mediaType.equalsAsciiL( // opt: exclude common text/xml + RTL_CONSTASCII_STRINGPARAM("text/xml") )) + continue; + + String type, subType; + INetContentTypeParameterList params; + if (! INetContentTypes::parse( mediaType, type, subType, ¶ms )) + continue; + + INetContentTypeParameter const * param = params.find( + ByteString("platform") ); + if (param != 0 && !platform_fits( param->m_sValue )) + continue; + const OUString url( makeURL( packageRootURL, fullPath ) ); + + // check for bundle description: + if (type.EqualsIgnoreCaseAscii("application") && + subType.EqualsIgnoreCaseAscii( + "vnd.sun.star.package-bundle-description")) + { + // check locale: + param = params.find( ByteString("locale") ); + if (param == 0) { + if (descrFile.getLength() == 0) + descrFile = url; + } + else { + // match best locale: + lang::Locale locale( toLocale(param->m_sValue) ); + if (locale.Language == officeLocale.Language) + { + if (descrFileLocale.Country == officeLocale.Country + && locale.Country != officeLocale.Country) + continue; + if (descrFileLocale.Variant == officeLocale.Variant + && locale.Variant != officeLocale.Variant) + continue; + descrFile = url; + descrFileLocale = locale; + } + } + continue; + } + + checkAborted( abortChannel ); + + //We make sure that we only create one XPackage for a particular URL. + //Sometime programmers insert the same URL several times in the manifest + //which may lead to DisposedExceptions. + if (bundle.end() == std::find_if(bundle.begin(), bundle.end(), XPackage_eq(url))) + { + const Reference<deployment::XPackage> xPackage( + bindBundleItem( url, mediaType, false, OUString(), xCmdEnv ) ); + if (xPackage.is()) + bundle.push_back( xPackage ); + } + else + { + fprintf(stderr, "manifest.xml contains a duplicate entry!\n"); + } + } + + if (descrFile.getLength() > 0) + { + ::ucbhelper::Content descrFileContent; + if (create_ucb_content( &descrFileContent, descrFile, + xCmdEnv, false /* no throw */ )) + { + // patch description: + ::rtl::ByteSequence bytes( readFile( descrFileContent ) ); + ::rtl::OUStringBuffer buf; + if ( bytes.getLength() ) + { + buf.append( OUString( reinterpret_cast<sal_Char const *>( + bytes.getConstArray() ), + bytes.getLength(), RTL_TEXTENCODING_UTF8 ) ); + } + else + { + buf.append( Package::getDescription() ); + } + m_oldDescription = buf.makeStringAndClear(); + } + } +} + +//______________________________________________________________________________ +void BackendImpl::PackageImpl::scanLegacyBundle( + t_packagevec & bundle, + OUString const & url, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<ucb::XCommandEnvironment> const & xCmdEnv, + bool skip_registration ) +{ + ::ucbhelper::Content ucbContent( url, xCmdEnv ); + + // check for platform pathes: + const OUString title( ucbContent.getPropertyValue( + StrTitle::get() ).get<OUString>() ); + if (title.endsWithIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM(".plt") ) && + !platform_fits( title.copy( 0, title.getLength() - 4 ) )) { + return; + } + if (title.endsWithIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM("skip_registration") )) + skip_registration = true; + + OUString ar [] = { StrTitle::get(), OUSTR("IsFolder") }; + Reference<sdbc::XResultSet> xResultSet( + ucbContent.createCursor( + Sequence<OUString>( ar, ARLEN(ar) ), + ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS ) ); + while (xResultSet->next()) + { + checkAborted( abortChannel ); + + const Reference<sdbc::XRow> xRow( xResultSet, UNO_QUERY_THROW ); + const OUString title_enc( ::rtl::Uri::encode( + xRow->getString( 1 /* Title */ ), + rtl_UriCharClassPchar, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ) ); + const OUString path( makeURL( url, title_enc ) ); + + OUString mediaType; + const Reference<deployment::XPackage> xPackage( + bindBundleItem( path, OUString() /* detect */, false, OUString(), + xCmdEnv, false /* ignore detection errors */ ) ); + if (xPackage.is()) { + const Reference<deployment::XPackageTypeInfo> xPackageType( + xPackage->getPackageType() ); + OSL_ASSERT( xPackageType.is() ); + if (xPackageType.is()) + mediaType = xPackageType->getMediaType(); + + if (skip_registration && + // xxx todo: additional parsing? + mediaType.matchIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM( + "application/vnd.sun.star.uno-component") )) + continue; + + bundle.push_back( xPackage ); + } + + if (mediaType.getLength() == 0 || + // script.xlb, dialog.xlb can be met everywhere: + mediaType.matchIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM( + "application/vnd.sun.star.basic-library") ) || + mediaType.matchIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM( + "application/vnd.sun.star.dialog-library") )) + { + if (xRow->getBoolean( 2 /* IsFolder */ )) { // recurse into folder: + scanLegacyBundle( + bundle, path, abortChannel, xCmdEnv, skip_registration ); + } + } + } +} + +OUString BackendImpl::PackageImpl::getDisplayName() + throw (deployment::ExtensionRemovedException, RuntimeException) +{ + if (m_bRemoved) + throw deployment::ExtensionRemovedException(); + + OUString sName = getDescriptionInfoset().getLocalizedDisplayName(); + if (sName.getLength() == 0) + return m_displayName; + else + return sName; +} + +::std::vector<Reference<deployment::XPackage> > +BackendImpl::PackageImpl::getPackagesFromDb( + Reference<ucb::XCommandEnvironment> const & xCmdEnv) +{ + ::std::vector<Reference<deployment::XPackage> > retVector; + + typedef ::std::vector< ::std::pair<OUString, OUString> >::const_iterator ITC; + for (ITC i = m_dbData.items.begin(); i != m_dbData.items.end(); i++) + { + Reference<deployment::XPackage> xExtension = + bindBundleItem(i->first, i->second, true, m_identifier, xCmdEnv); + OSL_ASSERT(xExtension.is()); + if (xExtension.is()) + retVector.push_back(xExtension); + } + + return retVector; +} + +} // anon namespace + +//============================================================================== +Reference<deployment::XPackageRegistry> create( + Reference<deployment::XPackageRegistry> const & xRootRegistry, + OUString const & context, OUString const & cachePath, bool readOnly, + Reference<XComponentContext> const & xComponentContext ) +{ + Sequence<Any> args( + cachePath.getLength() == 0 ? 1 : 3 ); + args[ 0 ] <<= context; + if (cachePath.getLength() > 0) { + args[ 1 ] <<= cachePath; + args[ 2 ] <<= readOnly; + } + return new BackendImpl( args, xComponentContext, xRootRegistry ); +} + +} // namespace bundle +} // namespace backend +} // namespace dp_registry + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/package/dp_package.hrc b/desktop/source/deployment/registry/package/dp_package.hrc new file mode 100644 index 000000000000..3a840b64f0b6 --- /dev/null +++ b/desktop/source/deployment/registry/package/dp_package.hrc @@ -0,0 +1,35 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_PACKAGE_HRC +#define INCLUDED_DP_PACKAGE_HRC + +#include "deployment.hrc" + +#define RID_STR_PACKAGE_BUNDLE (RID_DEPLOYMENT_BUNDLE_START+10) + +#endif diff --git a/desktop/source/deployment/registry/package/dp_package.src b/desktop/source/deployment/registry/package/dp_package.src new file mode 100644 index 000000000000..57307040bba4 --- /dev/null +++ b/desktop/source/deployment/registry/package/dp_package.src @@ -0,0 +1,34 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "dp_package.hrc" + +String RID_STR_PACKAGE_BUNDLE +{ + Text [ en-US ] = "Extension"; +}; + diff --git a/desktop/source/deployment/registry/package/makefile.mk b/desktop/source/deployment/registry/package/makefile.mk new file mode 100644 index 000000000000..203ce176d289 --- /dev/null +++ b/desktop/source/deployment/registry/package/makefile.mk @@ -0,0 +1,48 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/..$/.. + +PRJNAME = desktop +TARGET = deployment_registry_package +ENABLE_EXCEPTIONS = TRUE + +.INCLUDE : settings.mk + +SRS1NAME = $(TARGET) +SRC1FILES = \ + dp_package.src + +INCPRE += ..$/..$/inc + +SLOFILES = \ + $(SLO)$/dp_package.obj \ + $(SLO)$/dp_extbackenddb.obj + +.INCLUDE : ..$/..$/target.pmk +.INCLUDE : target.mk + diff --git a/desktop/source/deployment/registry/script/dp_lib_container.cxx b/desktop/source/deployment/registry/script/dp_lib_container.cxx new file mode 100644 index 000000000000..2bc2c07130a0 --- /dev/null +++ b/desktop/source/deployment/registry/script/dp_lib_container.cxx @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/ucb/XCommandEnvironment.hpp" + +#include "dp_script.hrc" +#include "dp_resource.h" +#include "dp_xml.h" +#include "dp_lib_container.h" + +#include "rtl/ustring.hxx" +#include "ucbhelper/content.hxx" +#include "xmlscript/xmllib_imexp.hxx" + + +using namespace ::dp_misc; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using ::rtl::OUString; + +namespace dp_registry { +namespace backend { +namespace script { + +namespace { +struct StrCannotDetermineLibName : public StaticResourceString< + StrCannotDetermineLibName, RID_STR_CANNOT_DETERMINE_LIBNAME> {}; +} + +//______________________________________________________________________________ +OUString LibraryContainer::get_libname( + OUString const & url, + Reference<XCommandEnvironment> const & xCmdEnv, + Reference<XComponentContext> const & xContext ) +{ + ::xmlscript::LibDescriptor import; + ::ucbhelper::Content ucb_content( url, xCmdEnv ); + xml_parse( ::xmlscript::importLibrary( import ), ucb_content, xContext ); + + if (import.aName.getLength() == 0) { + throw Exception( StrCannotDetermineLibName::get(), + Reference<XInterface>() ); + } + return import.aName; +} + +} +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/script/dp_lib_container.h b/desktop/source/deployment/registry/script/dp_lib_container.h new file mode 100644 index 000000000000..0cd5cb2cba90 --- /dev/null +++ b/desktop/source/deployment/registry/script/dp_lib_container.h @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_LIB_CONTAINER_H +#define INCLUDED_DP_LIB_CONTAINER_H + +#include <com/sun/star/uno/Reference.hxx> + +namespace com { namespace sun { namespace star { + namespace uno { + class XComponentContext; + } + namespace ucb { + class XCommandEnvironment; + } +}}} + +namespace rtl { + class OUString; +} + +namespace css = ::com::sun::star; + +namespace dp_registry { +namespace backend { +namespace script { + +//============================================================================== +class LibraryContainer +{ +public: + static ::rtl::OUString get_libname( + ::rtl::OUString const & url, + css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv, + css::uno::Reference<css::uno::XComponentContext> const & xContext ); +}; + +} +} +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/script/dp_script.cxx b/desktop/source/deployment/registry/script/dp_script.cxx new file mode 100644 index 000000000000..f760e98bbf7f --- /dev/null +++ b/desktop/source/deployment/registry/script/dp_script.cxx @@ -0,0 +1,474 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "dp_script.hrc" +#include "dp_lib_container.h" +#include "dp_backend.h" +#include "dp_ucb.h" +#include "rtl/uri.hxx" +#include "ucbhelper/content.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "cppuhelper/implbase1.hxx" +#include "comphelper/servicedecl.hxx" +#include "svl/inettype.hxx" +#include "com/sun/star/util/XUpdatable.hpp" +#include "com/sun/star/script/XLibraryContainer3.hpp" +#include <com/sun/star/util/XMacroExpander.hpp> +#include <com/sun/star/uri/XUriReferenceFactory.hpp> +#include <memory> +#include "dp_scriptbackenddb.hxx" + +using namespace ::dp_misc; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using ::rtl::OUString; +namespace css = ::com::sun::star; + +namespace dp_registry { +namespace backend { +namespace script { +namespace { + +typedef ::cppu::ImplInheritanceHelper1< + ::dp_registry::backend::PackageRegistryBackend, util::XUpdatable > t_helper; + +class BackendImpl : public t_helper +{ + class PackageImpl : public ::dp_registry::backend::Package + { + BackendImpl * getMyBackend() const; + + const OUString m_scriptURL; + const OUString m_dialogURL; + OUString m_dialogName; + + // Package + virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_( + ::osl::ResettableMutexGuard & guard, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + virtual void processPackage_( + ::osl::ResettableMutexGuard & guard, + bool registerPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + + public: + PackageImpl( + ::rtl::Reference<BackendImpl> const & myBackend, + OUString const & url, + Reference<XCommandEnvironment> const &xCmdEnv, + OUString const & scriptURL, OUString const & dialogURL, + bool bRemoved, OUString const & identifier); + }; + friend class PackageImpl; + + // PackageRegistryBackend + virtual Reference<deployment::XPackage> bindPackage_( + OUString const & url, OUString const & mediaType, + sal_Bool bRemoved, OUString const & identifier, + Reference<XCommandEnvironment> const & xCmdEnv ); + + void addDataToDb(OUString const & url); + void deleteDataFromDb(OUString const & url); + bool isRegisteredInDb(OUString const & url); + + const Reference<deployment::XPackageTypeInfo> m_xBasicLibTypeInfo; + const Reference<deployment::XPackageTypeInfo> m_xDialogLibTypeInfo; + Sequence< Reference<deployment::XPackageTypeInfo> > m_typeInfos; + std::auto_ptr<ScriptBackendDb> m_backendDb; +public: + BackendImpl( Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ); + + // XUpdatable + virtual void SAL_CALL update() throw (RuntimeException); + + // XPackageRegistry + virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL + getSupportedPackageTypes() throw (RuntimeException); +}; + +//______________________________________________________________________________ +BackendImpl::PackageImpl::PackageImpl( + ::rtl::Reference<BackendImpl> const & myBackend, + OUString const & url, + Reference<XCommandEnvironment> const &xCmdEnv, + OUString const & scriptURL, OUString const & dialogURL, bool bRemoved, + OUString const & identifier) + : Package( myBackend.get(), url, + OUString(), OUString(), // will be late-initialized + scriptURL.getLength() > 0 ? myBackend->m_xBasicLibTypeInfo + : myBackend->m_xDialogLibTypeInfo, bRemoved, identifier), + m_scriptURL( scriptURL ), + m_dialogURL( dialogURL ) +{ + // name, displayName: + if (dialogURL.getLength() > 0) { + m_dialogName = LibraryContainer::get_libname( + dialogURL, xCmdEnv, myBackend->getComponentContext() ); + } + if (scriptURL.getLength() > 0) { + m_name = LibraryContainer::get_libname( + scriptURL, xCmdEnv, myBackend->getComponentContext() ); + } + else + m_name = m_dialogName; + m_displayName = m_name; +} + +//______________________________________________________________________________ +BackendImpl::BackendImpl( + Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ) + : t_helper( args, xComponentContext ), + m_xBasicLibTypeInfo( new Package::TypeInfo( + OUSTR("application/" + "vnd.sun.star.basic-library"), + OUString() /* no file filter */, + getResourceString(RID_STR_BASIC_LIB), + RID_IMG_SCRIPTLIB) ), + m_xDialogLibTypeInfo( new Package::TypeInfo( + OUSTR("application/" + "vnd.sun.star.dialog-library"), + OUString() /* no file filter */, + getResourceString(RID_STR_DIALOG_LIB), + RID_IMG_DIALOGLIB) ), + m_typeInfos( 2 ) +{ + m_typeInfos[ 0 ] = m_xBasicLibTypeInfo; + m_typeInfos[ 1 ] = m_xDialogLibTypeInfo; + + OSL_ASSERT( ! transientMode() ); + + if (!transientMode()) + { + OUString dbFile = makeURL(getCachePath(), OUSTR("backenddb.xml")); + m_backendDb.reset( + new ScriptBackendDb(getComponentContext(), dbFile)); + } + +} +void BackendImpl::addDataToDb(OUString const & url) +{ + if (m_backendDb.get()) + m_backendDb->addEntry(url); +} + +bool BackendImpl::isRegisteredInDb(OUString const & url) +{ + bool registered = false; + if (m_backendDb.get()) + registered = m_backendDb->getEntry(url); + return registered; +} + +void BackendImpl::deleteDataFromDb(OUString const & url) +{ + if (m_backendDb.get()) + m_backendDb->removeEntry(url); +} + +// XUpdatable +//______________________________________________________________________________ +void BackendImpl::update() throw (RuntimeException) +{ + // Nothing to do here after fixing i70283!? +} + +// XPackageRegistry +//______________________________________________________________________________ +Sequence< Reference<deployment::XPackageTypeInfo> > +BackendImpl::getSupportedPackageTypes() throw (RuntimeException) +{ + return m_typeInfos; +} + +// PackageRegistryBackend +//______________________________________________________________________________ +Reference<deployment::XPackage> BackendImpl::bindPackage_( + OUString const & url, OUString const & mediaType_, + sal_Bool bRemoved, OUString const & identifier, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + OUString mediaType( mediaType_ ); + if (mediaType.getLength() == 0) + { + // detect media-type: + ::ucbhelper::Content ucbContent; + if (create_ucb_content( &ucbContent, url, xCmdEnv ) && + ucbContent.isFolder()) + { + // probe for script.xlb: + if (create_ucb_content( + 0, makeURL( url, OUSTR("script.xlb") ), + xCmdEnv, false /* no throw */ )) + mediaType = OUSTR("application/vnd.sun.star.basic-library"); + // probe for dialog.xlb: + else if (create_ucb_content( + 0, makeURL( url, OUSTR("dialog.xlb") ), + xCmdEnv, false /* no throw */ )) + mediaType = OUSTR("application/vnd.sun.star.dialog-library"); + } + if (mediaType.getLength() == 0) + throw lang::IllegalArgumentException( + StrCannotDetectMediaType::get() + url, + static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) ); + } + + String type, subType; + INetContentTypeParameterList params; + if (INetContentTypes::parse( mediaType, type, subType, ¶ms )) + { + if (type.EqualsIgnoreCaseAscii("application")) + { + OUString dialogURL( makeURL( url, OUSTR("dialog.xlb") ) ); + if (! create_ucb_content( + 0, dialogURL, xCmdEnv, false /* no throw */ )) { + dialogURL = OUString(); + } + + if (subType.EqualsIgnoreCaseAscii("vnd.sun.star.basic-library")) + { + OUString scriptURL( makeURL( url, OUSTR("script.xlb"))); + if (! create_ucb_content( + 0, scriptURL, xCmdEnv, false /* no throw */ )) { + scriptURL = OUString(); + } + + return new PackageImpl( + this, url, xCmdEnv, scriptURL, + dialogURL, bRemoved, identifier); + } + else if (subType.EqualsIgnoreCaseAscii( + "vnd.sun.star.dialog-library")) { + return new PackageImpl( + this, url, xCmdEnv, + OUString() /* no script lib */, + dialogURL, + bRemoved, identifier); + } + } + } + throw lang::IllegalArgumentException( + StrUnsupportedMediaType::get() + mediaType, + static_cast<OWeakObject *>(this), + static_cast<sal_Int16>(-1) ); +} + +//############################################################################## + +// Package +BackendImpl * BackendImpl::PackageImpl::getMyBackend() const +{ + BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get()); + if (NULL == pBackend) + { + //May throw a DisposedException + check(); + //We should never get here... + throw RuntimeException( + OUSTR("Failed to get the BackendImpl"), + static_cast<OWeakObject*>(const_cast<PackageImpl *>(this))); + } + return pBackend; +} + +beans::Optional< beans::Ambiguous<sal_Bool> > +BackendImpl::PackageImpl::isRegistered_( + ::osl::ResettableMutexGuard & /* guard */, + ::rtl::Reference<AbortChannel> const & /* abortChannel */, + Reference<XCommandEnvironment> const & /* xCmdEnv */ ) +{ + BackendImpl * that = getMyBackend(); + Reference< deployment::XPackage > xThisPackage( this ); + + bool registered = that->isRegisteredInDb(getURL()); + return beans::Optional< beans::Ambiguous<sal_Bool> >( + true /* IsPresent */, + beans::Ambiguous<sal_Bool>( registered, false /* IsAmbiguous */ ) ); +} + +void +lcl_maybeRemoveScript( + bool const bExists, + OUString const& rName, + OUString const& rScriptURL, + Reference<css::script::XLibraryContainer3> const& xScriptLibs) +{ + if (bExists && xScriptLibs.is() && xScriptLibs->hasByName(rName)) + { + const OUString sScriptUrl = xScriptLibs->getOriginalLibraryLinkURL(rName); + if (sScriptUrl.equals(rScriptURL)) + xScriptLibs->removeLibrary(rName); + } +} + +bool +lcl_maybeAddScript( + bool const bExists, + OUString const& rName, + OUString const& rScriptURL, + Reference<css::script::XLibraryContainer3> const& xScriptLibs) +{ + if (bExists && xScriptLibs.is()) + { + bool bCanAdd = true; + if (xScriptLibs->hasByName(rName)) + { + const OUString sOriginalUrl = xScriptLibs->getOriginalLibraryLinkURL(rName); + //We assume here that library names in extensions are unique, which may not be the case + //ToDo: If the script exist in another extension, then both extensions must have the + //same id + if (sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE")) + || sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE")) + || sOriginalUrl.match(OUSTR("vnd.sun.star.expand:$BUNDLED_EXTENSIONS"))) + { + xScriptLibs->removeLibrary(rName); + bCanAdd = true; + } + else + { + bCanAdd = false; + } + } + + if (bCanAdd) + { + xScriptLibs->createLibraryLink(rName, rScriptURL, false); + return xScriptLibs->hasByName(rName); + } + } + + return false; +} + +void BackendImpl::PackageImpl::processPackage_( + ::osl::ResettableMutexGuard & /* guard */, + bool doRegisterPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & /* abortChannel */, + Reference<XCommandEnvironment> const & /* xCmdEnv */ ) +{ + BackendImpl * that = getMyBackend(); + + Reference< deployment::XPackage > xThisPackage( this ); + Reference<XComponentContext> const & xComponentContext = that->getComponentContext(); + + bool bScript = (m_scriptURL.getLength() > 0); + Reference<css::script::XLibraryContainer3> xScriptLibs; + + bool bDialog = (m_dialogURL.getLength() > 0); + Reference<css::script::XLibraryContainer3> xDialogLibs; + + bool bRunning = office_is_running(); + if( bRunning ) + { + if( bScript ) + { + xScriptLibs.set( + xComponentContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.script.ApplicationScriptLibraryContainer"), + xComponentContext ), UNO_QUERY_THROW ); + } + + if( bDialog ) + { + xDialogLibs.set( + xComponentContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.script.ApplicationDialogLibraryContainer"), + xComponentContext ), UNO_QUERY_THROW ); + } + } + bool bRegistered = getMyBackend()->isRegisteredInDb(getURL()); + if( !doRegisterPackage ) + { + //We cannot just call removeLibrary(name) because this could remove a + //script which was added by an extension in a different repository. For + //example, extension foo is contained in the bundled repository and then + //the user adds it it to the user repository. The extension manager will + //then register the new script and revoke the script from the bundled + //extension. removeLibrary(name) would now remove the script from the + //user repository. That is, the script of the newly added user extension does + //not work anymore. Therefore we must check if the currently active + //script comes in fact from the currently processed extension. + + if (bRegistered) + { + //we also prevent and live deployment at startup + if (!isRemoved() && !startup) + { + lcl_maybeRemoveScript(bScript, m_name, m_scriptURL, xScriptLibs); + lcl_maybeRemoveScript(bDialog, m_dialogName, m_dialogURL, xDialogLibs); + } + getMyBackend()->deleteDataFromDb(getURL()); + return; + } + } + if (bRegistered) + return; // Already registered + + // Update LibraryContainer + bool bScriptSuccess = false; + bool bDialogSuccess = false; + if (!startup) + { + //If there is a bundled extension, and the user installes the same extension + //then the script from the bundled extension must be removed. If this does not work + //then live deployment does not work for scripts. + bScriptSuccess = lcl_maybeAddScript(bScript, m_name, m_scriptURL, xScriptLibs); + bDialogSuccess = lcl_maybeAddScript(bDialog, m_dialogName, m_dialogURL, xDialogLibs); + } + bool bSuccess = bScript || bDialog; // Something must have happened + if( bRunning && !startup) + if( (bScript && !bScriptSuccess) || (bDialog && !bDialogSuccess) ) + bSuccess = false; + + if (bSuccess) + getMyBackend()->addDataToDb(getURL()); +} + +} // anon namespace + +namespace sdecl = comphelper::service_decl; +sdecl::class_<BackendImpl, sdecl::with_args<true> > serviceBI; +extern sdecl::ServiceDecl const serviceDecl( + serviceBI, + "com.sun.star.comp.deployment.script.PackageRegistryBackend", + BACKEND_SERVICE_NAME ); + +} // namespace script +} // namespace backend +} // namespace dp_registry + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/script/dp_script.hrc b/desktop/source/deployment/registry/script/dp_script.hrc new file mode 100644 index 000000000000..8ddfa6f51ffc --- /dev/null +++ b/desktop/source/deployment/registry/script/dp_script.hrc @@ -0,0 +1,39 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_SCRIPT_HRC +#define INCLUDED_DP_SCRIPT_HRC + +#include "deployment.hrc" + +#define RID_STR_BASIC_LIB (RID_DEPLOYMENT_SCRIPT_START+10) +#define RID_STR_DIALOG_LIB (RID_DEPLOYMENT_SCRIPT_START+11) + +#define RID_STR_LIBNAME_ALREADY_EXISTS (RID_DEPLOYMENT_SCRIPT_START+15) +#define RID_STR_CANNOT_DETERMINE_LIBNAME (RID_DEPLOYMENT_SCRIPT_START+16) + +#endif diff --git a/desktop/source/deployment/registry/script/dp_script.src b/desktop/source/deployment/registry/script/dp_script.src new file mode 100644 index 000000000000..117f4eac945a --- /dev/null +++ b/desktop/source/deployment/registry/script/dp_script.src @@ -0,0 +1,49 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "dp_script.hrc" + +String RID_STR_BASIC_LIB +{ + Text [ en-US ] = "%PRODUCTNAME Basic Library"; +}; + +String RID_STR_DIALOG_LIB +{ + Text [ en-US ] = "Dialog Library"; +}; + +String RID_STR_CANNOT_DETERMINE_LIBNAME +{ + Text [ en-US ] = "The library name could not be determined."; +}; + +String RID_STR_LIBNAME_ALREADY_EXISTS +{ + Text [ en-US ] = "This library name already exists. Please choose a different name."; +}; + diff --git a/desktop/source/deployment/registry/script/dp_scriptbackenddb.cxx b/desktop/source/deployment/registry/script/dp_scriptbackenddb.cxx new file mode 100644 index 000000000000..8c6a4924212e --- /dev/null +++ b/desktop/source/deployment/registry/script/dp_scriptbackenddb.cxx @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" + +#include "rtl/string.h" +#include "cppuhelper/exc_hlp.hxx" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/xml/dom/XDocument.hpp" +#include "com/sun/star/xml/xpath/XXPathAPI.hpp" +#include "dp_misc.h" +#include "dp_scriptbackenddb.hxx" + + +namespace css = ::com::sun::star; +using namespace ::com::sun::star::uno; +using ::rtl::OUString; + +#define EXTENSION_REG_NS "http://openoffice.org/extensionmanager/script-registry/2010" +#define NS_PREFIX "script" +#define ROOT_ELEMENT_NAME "script-backend-db" +#define KEY_ELEMENT_NAME "script" + +namespace dp_registry { +namespace backend { +namespace script { + +ScriptBackendDb::ScriptBackendDb( + Reference<XComponentContext> const & xContext, + ::rtl::OUString const & url):RegisteredDb(xContext, url) +{ + +} + +OUString ScriptBackendDb::getDbNSName() +{ + return OUSTR(EXTENSION_REG_NS); +} + +OUString ScriptBackendDb::getNSPrefix() +{ + return OUSTR(NS_PREFIX); +} + +OUString ScriptBackendDb::getRootElementName() +{ + return OUSTR(ROOT_ELEMENT_NAME); +} + +OUString ScriptBackendDb::getKeyElementName() +{ + return OUSTR(KEY_ELEMENT_NAME); +} + + + +} // namespace executable +} // namespace backend +} // namespace dp_registry + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/script/dp_scriptbackenddb.hxx b/desktop/source/deployment/registry/script/dp_scriptbackenddb.hxx new file mode 100644 index 000000000000..58a749480113 --- /dev/null +++ b/desktop/source/deployment/registry/script/dp_scriptbackenddb.hxx @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_SCRIPTBACKENDDB_HXX +#define INCLUDED_DP_SCRIPTBACKENDDB_HXX + +#include "rtl/ustring.hxx" +#include "dp_backenddb.hxx" +#include "boost/optional.hpp" +namespace css = ::com::sun::star; + +namespace com { namespace sun { namespace star { + namespace uno { + class XComponentContext; + } +}}} + +namespace dp_registry { +namespace backend { +namespace script { + +/* The XML file stores the extensions which are currently registered. + They will be removed when they are revoked. + */ +class ScriptBackendDb: public dp_registry::backend::RegisteredDb +{ +protected: + virtual ::rtl::OUString getDbNSName(); + + virtual ::rtl::OUString getNSPrefix(); + + virtual ::rtl::OUString getRootElementName(); + + virtual ::rtl::OUString getKeyElementName(); + + +public: + + ScriptBackendDb( css::uno::Reference<css::uno::XComponentContext> const & xContext, + ::rtl::OUString const & url); +}; + + + +} +} +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/script/makefile.mk b/desktop/source/deployment/registry/script/makefile.mk new file mode 100644 index 000000000000..708def358021 --- /dev/null +++ b/desktop/source/deployment/registry/script/makefile.mk @@ -0,0 +1,49 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/..$/.. + +PRJNAME = desktop +TARGET = deployment_registry_script +ENABLE_EXCEPTIONS = TRUE + +.INCLUDE : settings.mk + +SRS1NAME = $(TARGET) +SRC1FILES = \ + dp_script.src + +INCPRE += ..$/..$/inc + +SLOFILES = \ + $(SLO)$/dp_script.obj \ + $(SLO)$/dp_lib_container.obj \ + $(SLO)$/dp_scriptbackenddb.obj + +.INCLUDE : ..$/..$/target.pmk +.INCLUDE : target.mk + diff --git a/desktop/source/deployment/registry/sfwk/dp_parceldesc.cxx b/desktop/source/deployment/registry/sfwk/dp_parceldesc.cxx new file mode 100644 index 000000000000..11835ddfa957 --- /dev/null +++ b/desktop/source/deployment/registry/sfwk/dp_parceldesc.cxx @@ -0,0 +1,132 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" +#include "dp_misc.h" +#include "dp_parceldesc.hxx" + + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +using ::rtl::OUString; + +namespace css = ::com::sun::star; +namespace dp_registry +{ +namespace backend +{ +namespace sfwk +{ + + +// XDocumentHandler +void SAL_CALL +ParcelDescDocHandler::startDocument() +throw ( xml::sax::SAXException, RuntimeException ) +{ + m_bIsParsed = false; +} + +void SAL_CALL +ParcelDescDocHandler::endDocument() +throw ( xml::sax::SAXException, RuntimeException ) +{ + m_bIsParsed = true; +} + +void SAL_CALL +ParcelDescDocHandler::characters( const OUString & ) + throw ( xml::sax::SAXException, RuntimeException ) +{ +} + +void SAL_CALL +ParcelDescDocHandler::ignorableWhitespace( const OUString & ) + throw ( xml::sax::SAXException, RuntimeException ) +{ +} + +void SAL_CALL +ParcelDescDocHandler::processingInstruction( + const OUString &, const OUString & ) + throw ( xml::sax::SAXException, RuntimeException ) +{ +} + +void SAL_CALL +ParcelDescDocHandler::setDocumentLocator( + const Reference< xml::sax::XLocator >& ) + throw ( xml::sax::SAXException, RuntimeException ) +{ +} + +void SAL_CALL +ParcelDescDocHandler::startElement( const OUString& aName, + const Reference< xml::sax::XAttributeList > & xAttribs ) + throw ( xml::sax::SAXException, + RuntimeException ) +{ + + dp_misc::TRACE(OUSTR("ParcelDescDocHandler::startElement() for ") + + aName + OUSTR("\n")); + if ( !skipIndex ) + { + if ( aName.equals( OUString(RTL_CONSTASCII_USTRINGPARAM( "parcel" )) ) ) + { + m_sLang = xAttribs->getValueByName( OUString(RTL_CONSTASCII_USTRINGPARAM( "language" )) ); + } + ++skipIndex; + } + else + { + dp_misc::TRACE(OUSTR("ParcelDescDocHandler::startElement() skipping for ") + + aName + OUSTR("\n")); + } + +} + +void SAL_CALL ParcelDescDocHandler::endElement( const OUString & aName ) + throw ( xml::sax::SAXException, RuntimeException ) +{ + if ( skipIndex ) + { + --skipIndex; + dp_misc::TRACE(OUSTR("ParcelDescDocHandler::endElement() skipping for ") + + aName + OUSTR("\n")); + } +} + + +} +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/sfwk/dp_parceldesc.hxx b/desktop/source/deployment/registry/sfwk/dp_parceldesc.hxx new file mode 100644 index 000000000000..83ffddda1aff --- /dev/null +++ b/desktop/source/deployment/registry/sfwk/dp_parceldesc.hxx @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <cppuhelper/implbase1.hxx> + +#include <com/sun/star/xml/sax/XAttributeList.hpp> +#include <com/sun/star/xml/sax/SAXException.hpp> +#include <com/sun/star/xml/sax/XDocumentHandler.hpp> +#include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp> +#include <com/sun/star/xml/sax/XParser.hpp> + +#include <com/sun/star/lang/NoSupportException.hpp> +#include <com/sun/star/lang/XMultiComponentFactory.hpp> +namespace css = ::com::sun::star; +namespace dp_registry +{ +namespace backend +{ +namespace sfwk +{ + +typedef ::cppu::WeakImplHelper1< css::xml::sax::XDocumentHandler > t_DocHandlerImpl; + +class ParcelDescDocHandler : public t_DocHandlerImpl +{ +private: + bool m_bIsParsed; + ::rtl::OUString m_sLang; + sal_Int32 skipIndex; +public: + ParcelDescDocHandler():m_bIsParsed( false ), skipIndex( 0 ){} + ::rtl::OUString getParcelLanguage() { return m_sLang; } + bool isParsed() { return m_bIsParsed; } + // XDocumentHandler + virtual void SAL_CALL startDocument() + throw ( css::xml::sax::SAXException, css::uno::RuntimeException ); + + virtual void SAL_CALL endDocument() + throw ( css::xml::sax::SAXException, css::uno::RuntimeException ); + + virtual void SAL_CALL startElement( const ::rtl::OUString& aName, + const css::uno::Reference< css::xml::sax::XAttributeList > & xAttribs ) + throw ( css::xml::sax::SAXException, + css::uno::RuntimeException ); + + virtual void SAL_CALL endElement( const ::rtl::OUString & aName ) + throw ( css::xml::sax::SAXException, css::uno::RuntimeException ); + + virtual void SAL_CALL characters( const ::rtl::OUString & aChars ) + throw ( css::xml::sax::SAXException, css::uno::RuntimeException ); + + virtual void SAL_CALL ignorableWhitespace( const ::rtl::OUString & aWhitespaces ) + throw ( css::xml::sax::SAXException, css::uno::RuntimeException ); + + virtual void SAL_CALL processingInstruction( + const ::rtl::OUString & aTarget, const ::rtl::OUString & aData ) + throw ( css::xml::sax::SAXException, css::uno::RuntimeException ); + + virtual void SAL_CALL setDocumentLocator( + const css::uno::Reference< css::xml::sax::XLocator >& xLocator ) + throw ( css::xml::sax::SAXException, css::uno::RuntimeException ); +}; +} +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/sfwk/dp_sfwk.cxx b/desktop/source/deployment/registry/sfwk/dp_sfwk.cxx new file mode 100644 index 000000000000..7904331ef11b --- /dev/null +++ b/desktop/source/deployment/registry/sfwk/dp_sfwk.cxx @@ -0,0 +1,410 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_desktop.hxx" +#include "dp_sfwk.hrc" +#include "dp_backend.h" +#include "dp_ucb.h" +#include "dp_parceldesc.hxx" +#include "rtl/uri.hxx" +#include "ucbhelper/content.hxx" +#include "cppuhelper/exc_hlp.hxx" +#include "comphelper/servicedecl.hxx" +#include "svl/inettype.hxx" +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/script/provider/XScriptProviderFactory.hpp> +#include <memory> + + +using namespace ::dp_misc; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::script; + +using ::rtl::OUString; +namespace css = ::com::sun::star; + +namespace dp_registry +{ +namespace backend +{ +namespace sfwk +{ + +//============================================================================== +class BackendImpl : public ::dp_registry::backend::PackageRegistryBackend +{ + class PackageImpl : public ::dp_registry::backend::Package + { + BackendImpl * getMyBackend() const; + + Reference< container::XNameContainer > m_xNameCntrPkgHandler; + OUString m_descr; + + void initPackageHandler(); + + // Package + virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_( + ::osl::ResettableMutexGuard & guard, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + virtual void processPackage_( + ::osl::ResettableMutexGuard & guard, + bool registerPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ); + + public: + PackageImpl( + ::rtl::Reference<BackendImpl> const & myBackend, + OUString const & url, OUString const & libType, bool bRemoved, + OUString const & identifier); + // XPackage + virtual OUString SAL_CALL getDescription() throw (RuntimeException); + }; + friend class PackageImpl; + + // PackageRegistryBackend + virtual Reference<deployment::XPackage> bindPackage_( + OUString const & url, OUString const & mediaType, + sal_Bool bRemoved, OUString const & identifier, + Reference<XCommandEnvironment> const & xCmdEnv ); + + const Reference<deployment::XPackageTypeInfo> m_xTypeInfo; + +public: + BackendImpl( + Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ); + + // XPackageRegistry + virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL + getSupportedPackageTypes() throw (RuntimeException); +}; + +BackendImpl * BackendImpl::PackageImpl::getMyBackend() const +{ + BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get()); + if (NULL == pBackend) + { + //May throw a DisposedException + check(); + //We should never get here... + throw RuntimeException( + OUSTR("Failed to get the BackendImpl"), + static_cast<OWeakObject*>(const_cast<PackageImpl *>(this))); + } + return pBackend; +} +//______________________________________________________________________________ +OUString BackendImpl::PackageImpl::getDescription() throw (RuntimeException) +{ + if (m_descr.getLength() == 0) + return Package::getDescription(); + else + return m_descr; +} + +//______________________________________________________________________________ +BackendImpl::PackageImpl::PackageImpl( + ::rtl::Reference<BackendImpl> const & myBackend, + OUString const & url, OUString const & libType, bool bRemoved, + OUString const & identifier) + : Package( myBackend.get(), url, OUString(), OUString(), + myBackend->m_xTypeInfo, bRemoved, identifier), + m_descr(libType) +{ + initPackageHandler(); + + sal_Int32 segmEnd = url.getLength(); + if (url.getLength() > 0 && url[ url.getLength() - 1 ] == '/') + --segmEnd; + sal_Int32 segmStart = (url.lastIndexOf( '/', segmEnd ) + 1); + if (segmStart < 0) + segmStart = 0; + // name and display name default the same: + m_displayName = ::rtl::Uri::decode( + url.copy( segmStart, segmEnd - segmStart ), + rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 ); + m_name = m_displayName; + + dp_misc::TRACE(OUSTR("PakageImpl displayName is ") + m_displayName); +} + +//______________________________________________________________________________ +BackendImpl::BackendImpl( + Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ) + : PackageRegistryBackend( args, xComponentContext ), + m_xTypeInfo( new Package::TypeInfo( + OUSTR("application/vnd.sun.star.framework-script"), + OUString() /* no file filter */, + OUSTR("Scripting Framework Script Library"), + RID_IMG_SCRIPTLIB ) ) +{ + if (! transientMode()) + { +/* + if (office_is_running()) + { + Reference<XComponentContext> xContext( getComponentContext() ); + m_xScriptLibs.set( + xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star." + "script.ApplicationScriptLibraryContainer"), + xContext ), UNO_QUERY_THROW ); + m_xDialogLibs.set( + xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star." + "script.ApplicationDialogLibraryContainer"), + xContext ), UNO_QUERY_THROW ); + } + else + { + OUString basic_path( + m_eContext == CONTEXT_USER + ? OUSTR("vnd.sun.star.expand:${$BRAND_BASE_DIR/program/" + SAL_CONFIGFILE("bootstrap") + ":UserInstallation}/user/basic") + : OUSTR("vnd.sun.star.expand:${$BRAND_BASE_DIR/program/" + SAL_CONFIGFILE("bootstrap") + ":BaseInstallation}/share/basic") ); + m_basic_script_libs.reset( + new LibraryContainer( + makeURL( basic_path, OUSTR("script.xlc") ), + getMutex(), + getComponentContext() ) ); + m_dialog_libs.reset( + new LibraryContainer( + makeURL( basic_path, OUSTR("dialog.xlc") ), + getMutex(), + getComponentContext() ) ); + } +*/ + } +} + +// XPackageRegistry +//______________________________________________________________________________ +Sequence< Reference<deployment::XPackageTypeInfo> > +BackendImpl::getSupportedPackageTypes() throw (RuntimeException) +{ + return Sequence< Reference<deployment::XPackageTypeInfo> >(&m_xTypeInfo, 1); +} + +// PackageRegistryBackend +//______________________________________________________________________________ +Reference<deployment::XPackage> BackendImpl::bindPackage_( + OUString const & url, OUString const & mediaType_, sal_Bool bRemoved, + OUString const & identifier, Reference<XCommandEnvironment> const & xCmdEnv ) +{ + OUString mediaType( mediaType_ ); + if (mediaType.getLength() == 0) + { + // detect media-type: + ::ucbhelper::Content ucbContent; + if (create_ucb_content( &ucbContent, url, xCmdEnv ) && + ucbContent.isFolder()) + { + // probe for parcel-descriptor.xml: + if (create_ucb_content( + 0, makeURL( url, OUSTR("parcel-descriptor.xml") ), + xCmdEnv, false /* no throw */ )) + { + mediaType = OUSTR("application/vnd.sun.star.framework-script"); + } + } + if (mediaType.getLength() == 0) + throw lang::IllegalArgumentException( + StrCannotDetectMediaType::get() + url, + static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) ); + } + + String type, subType; + INetContentTypeParameterList params; + if (INetContentTypes::parse( mediaType, type, subType, ¶ms )) + { + if (type.EqualsIgnoreCaseAscii("application")) + { + if (subType.EqualsIgnoreCaseAscii("vnd.sun.star.framework-script")) + { + OUString lang = OUString(RTL_CONSTASCII_USTRINGPARAM("Script")); + OUString sParcelDescURL = makeURL( + url, OUSTR("parcel-descriptor.xml") ); + + ::ucbhelper::Content ucb_content; + + if (create_ucb_content( &ucb_content, sParcelDescURL, + xCmdEnv, false /* no throw */ )) + { + ParcelDescDocHandler* pHandler = + new ParcelDescDocHandler(); + Reference< xml::sax::XDocumentHandler > + xDocHandler = pHandler; + + Reference<XComponentContext> + xContext( getComponentContext() ); + + Reference< xml::sax::XParser > xParser( + xContext->getServiceManager()->createInstanceWithContext( + OUSTR("com.sun.star.xml.sax.Parser"), xContext ), + UNO_QUERY_THROW ); + + xParser->setDocumentHandler( xDocHandler ); + xml::sax::InputSource source; + source.aInputStream = ucb_content.openStream(); + source.sSystemId = ucb_content.getURL(); + xParser->parseStream( source ); + + if ( pHandler->isParsed() ) + { + lang = pHandler->getParcelLanguage(); + } + } + + OUString sfwkLibType = getResourceString( RID_STR_SFWK_LIB ); + // replace %MACRONAME placeholder with language name + OUString MACRONAME( OUSTR("%MACROLANG" ) ); + sal_Int32 startOfReplace = sfwkLibType.indexOf( MACRONAME ); + sal_Int32 charsToReplace = MACRONAME.getLength(); + sfwkLibType = sfwkLibType.replaceAt( startOfReplace, charsToReplace, lang ); + dp_misc::TRACE("******************************\n"); + dp_misc::TRACE(OUSTR(" BackEnd detected lang = ") + lang + OUSTR("\n")); + dp_misc::TRACE(OUSTR(" for url ") + sParcelDescURL + OUSTR("\n") ); + dp_misc::TRACE("******************************\n"); + return new PackageImpl( this, url, sfwkLibType, bRemoved, identifier); + } + } + } + throw lang::IllegalArgumentException( + StrUnsupportedMediaType::get() + mediaType, + static_cast<OWeakObject *>(this), + static_cast<sal_Int16>(-1) ); +} + +//############################################################################## + +void BackendImpl::PackageImpl:: initPackageHandler() +{ + if (m_xNameCntrPkgHandler.is()) + return; + + BackendImpl * that = getMyBackend(); + Any aContext; + + if ( that->m_eContext == CONTEXT_USER ) + { + aContext <<= OUSTR("user"); + } + else if ( that->m_eContext == CONTEXT_SHARED ) + { + aContext <<= OUSTR("share"); + } + else if ( that->m_eContext == CONTEXT_BUNDLED ) + { + aContext <<= OUSTR("bundled"); + } + else + { + OSL_ASSERT( 0 ); + // NOT supported at the momemtn // TODO + } + + Reference< provider::XScriptProviderFactory > xFac( + that->getComponentContext()->getValueByName( + OUSTR( "/singletons/com.sun.star.script.provider.theMasterScriptProviderFactory") ), UNO_QUERY ); + + if ( xFac.is() ) + { + Reference< container::XNameContainer > xName( xFac->createScriptProvider( aContext ), UNO_QUERY ); + if ( xName.is() ) + { + m_xNameCntrPkgHandler.set( xName ); + } + } + // TODO what happens if above fails?? +} + +// Package +//______________________________________________________________________________ +beans::Optional< beans::Ambiguous<sal_Bool> > +BackendImpl::PackageImpl::isRegistered_( + ::osl::ResettableMutexGuard &, + ::rtl::Reference<AbortChannel> const &, + Reference<XCommandEnvironment> const & ) +{ + return beans::Optional< beans::Ambiguous<sal_Bool> >( + true /* IsPresent */, + beans::Ambiguous<sal_Bool>( + m_xNameCntrPkgHandler.is() && m_xNameCntrPkgHandler->hasByName( + m_url ), + false /* IsAmbiguous */ ) ); +} + +//______________________________________________________________________________ +void BackendImpl::PackageImpl::processPackage_( + ::osl::ResettableMutexGuard &, + bool doRegisterPackage, + bool /* startup */, + ::rtl::Reference<AbortChannel> const &, + Reference<XCommandEnvironment> const & ) +{ + if ( !m_xNameCntrPkgHandler.is() ) + { + dp_misc::TRACE("no package handler!!!!\n"); + throw RuntimeException( OUSTR("No package Handler " ), + Reference< XInterface >() ); + } + + if (doRegisterPackage) + { + // will throw if it fails + m_xNameCntrPkgHandler->insertByName( m_url, makeAny( Reference< XPackage >(this) ) ); + + } + else // revokePackage() + { + m_xNameCntrPkgHandler->removeByName( m_url ); + } +} + +namespace sdecl = comphelper::service_decl; +sdecl::class_<BackendImpl, sdecl::with_args<true> > serviceBI; +extern sdecl::ServiceDecl const serviceDecl( + serviceBI, + "com.sun.star.comp.deployment.sfwk.PackageRegistryBackend", + BACKEND_SERVICE_NAME ); + +} // namespace sfwk +} // namespace backend +} // namespace dp_registry + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/sfwk/dp_sfwk.hrc b/desktop/source/deployment/registry/sfwk/dp_sfwk.hrc new file mode 100644 index 000000000000..0eb619e839e3 --- /dev/null +++ b/desktop/source/deployment/registry/sfwk/dp_sfwk.hrc @@ -0,0 +1,35 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if ! defined INCLUDED_DP_SFWK_HRC +#define INCLUDED_DP_SFWK_HRC + +#include "deployment.hrc" + +#define RID_STR_SFWK_LIB (RID_DEPLOYMENT_SCRIPT_START+20) + +#endif diff --git a/desktop/source/deployment/registry/sfwk/dp_sfwk.src b/desktop/source/deployment/registry/sfwk/dp_sfwk.src new file mode 100644 index 000000000000..c8d37ce067ac --- /dev/null +++ b/desktop/source/deployment/registry/sfwk/dp_sfwk.src @@ -0,0 +1,35 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "dp_sfwk.hrc" + +String RID_STR_SFWK_LIB +{ + Text [ en-US ] = "%MACROLANG Library"; +}; + + diff --git a/desktop/source/deployment/registry/sfwk/makefile.mk b/desktop/source/deployment/registry/sfwk/makefile.mk new file mode 100644 index 000000000000..a052296d5c21 --- /dev/null +++ b/desktop/source/deployment/registry/sfwk/makefile.mk @@ -0,0 +1,48 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/..$/.. + +PRJNAME = desktop +TARGET = deployment_registry_sfwk +ENABLE_EXCEPTIONS = TRUE + +.INCLUDE : settings.mk +SRS1NAME = $(TARGET) + +SRC1FILES = \ + dp_sfwk.src + +INCPRE += ..$/..$/inc + +SLOFILES = \ + $(SLO)$/dp_parceldesc.obj \ + $(SLO)$/dp_sfwk.obj + +.INCLUDE : ..$/..$/target.pmk +.INCLUDE : target.mk + diff --git a/desktop/source/deployment/target.pmk b/desktop/source/deployment/target.pmk new file mode 100644 index 000000000000..82b41766b253 --- /dev/null +++ b/desktop/source/deployment/target.pmk @@ -0,0 +1,36 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +.IF "$(debug)" != "" + +# MSVC: no inlining +.IF "$(COM)" == "MSC" +CFLAGS += /Ob0 +.ENDIF + +.ENDIF + diff --git a/desktop/source/deployment/unopkg/makefile.mk b/desktop/source/deployment/unopkg/makefile.mk new file mode 100644 index 000000000000..06b39cd2d04e --- /dev/null +++ b/desktop/source/deployment/unopkg/makefile.mk @@ -0,0 +1,48 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/.. + +PRJNAME = desktop +TARGET = deployment_unopkg +ENABLE_EXCEPTIONS = TRUE + +.INCLUDE : settings.mk + +.IF "$(SYSTEM_DB)" == "YES" +CFLAGS+=-DSYSTEM_DB -I$(DB_INCLUDES) +.ENDIF + +SRS1NAME = $(TARGET) +SRC1FILES = \ + unopkg.src + +SLOFILES = + +.INCLUDE : ..$/target.pmk +.INCLUDE : target.mk + diff --git a/desktop/source/deployment/unopkg/unopkg.src b/desktop/source/deployment/unopkg/unopkg.src new file mode 100644 index 000000000000..dc204e265ec6 --- /dev/null +++ b/desktop/source/deployment/unopkg/unopkg.src @@ -0,0 +1,84 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "deployment.hrc" + + +String RID_STR_UNOPKG_ACCEPT_LIC_1 +{ + Text [ en-US ] = "Extension Software License Agreement of $NAME:"; +}; + +String RID_STR_UNOPKG_ACCEPT_LIC_2 +{ + Text [ en-US ] = "Read the complete License Agreement displayed above. " + "Accept the License Agreement by typing \"yes\" on the console " + "then press the Return key. Type \"no\" to decline and to abort the " + "extension setup."; +}; + +String RID_STR_UNOPKG_ACCEPT_LIC_3 +{ + Text [ en-US ] = "[Enter \"yes\" or \"no\"]:"; +}; + +String RID_STR_UNOPKG_ACCEPT_LIC_4 +{ + Text [ en-US ] = "Your input was not correct. Please enter \"yes\" or \"no\":"; +}; + +String RID_STR_UNOPKG_ACCEPT_LIC_YES +{ + Text [ en-US ] = "YES"; +}; + +String RID_STR_UNOPKG_ACCEPT_LIC_Y +{ + Text [ en-US ] = "Y"; +}; + +String RID_STR_UNOPKG_ACCEPT_LIC_NO +{ + Text [ en-US ] = "NO"; +}; + +String RID_STR_UNOPKG_ACCEPT_LIC_N +{ + Text [ en-US ] = "N"; +}; + +String RID_STR_CONCURRENTINSTANCE +{ + Text [ en-US ] = "unopkg cannot be started. The lock file indicates it as already running. " + "If this does not apply, delete the lock file at:"; +}; + +String RID_STR_UNOPKG_ERROR +{ + Text [ en-US ] = "ERROR: "; +}; + |