diff options
Diffstat (limited to 'desktop/source/deployment/gui')
37 files changed, 11251 insertions, 0 deletions
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..4b631a45939a --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_dialog2.cxx @@ -0,0 +1,1787 @@ +/* -*- 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; + bool bNativeOK; + Rectangle aControlRegion( Point( 0, 0 ), m_aProgressBar.GetSizePixel() ); + Rectangle aNativeControlRegion, aNativeContentRegion; + if( (bNativeOK = 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; + bool bNativeOK; + Rectangle aControlRegion( Point( 0, 0 ), m_aProgressBar.GetSizePixel() ); + Rectangle aNativeControlRegion, aNativeContentRegion; + if( (bNativeOK = 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..db52d6395bd9 --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_extensioncmdqueue.cxx @@ -0,0 +1,1216 @@ +/* -*- 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 _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 ) +{ + ::osl::MutexGuard aGuard( m_mutex ); + + //If someone called stop then we do not add the extension -> game over! + if ( m_bStopped ) + return; + + if ( rExtensionURL.getLength() ) + { + TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::ADD, rExtensionURL, rRepository, bWarnUser ) ); + + m_queue.push( pEntry ); + m_eInput = START; + m_wakeup.set(); + } +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::removeExtension( const uno::Reference< deployment::XPackage > &rPackage ) +{ + ::osl::MutexGuard aGuard( m_mutex ); + + //If someone called stop then we do not remove the extension -> game over! + if ( m_bStopped ) + return; + + if ( rPackage.is() ) + { + TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::REMOVE, rPackage ) ); + + m_queue.push( pEntry ); + m_eInput = START; + m_wakeup.set(); + } +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::acceptLicense( const uno::Reference< deployment::XPackage > &rPackage ) +{ + ::osl::MutexGuard aGuard( m_mutex ); + + //If someone called stop then we do not remove the extension -> game over! + if ( m_bStopped ) + return; + + if ( rPackage.is() ) + { + TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::ACCEPT_LICENSE, rPackage ) ); + + m_queue.push( pEntry ); + m_eInput = START; + m_wakeup.set(); + } +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::enableExtension( const uno::Reference< deployment::XPackage > &rPackage, + const bool bEnable ) +{ + ::osl::MutexGuard aGuard( m_mutex ); + + //If someone called stop then we do not remove the extension -> game over! + if ( m_bStopped ) + return; + + if ( rPackage.is() ) + { + TExtensionCmd pEntry( new ExtensionCmd( bEnable ? ExtensionCmd::ENABLE : + ExtensionCmd::DISABLE, + rPackage ) ); + m_queue.push( pEntry ); + m_eInput = START; + m_wakeup.set(); + } +} + +//------------------------------------------------------------------------------ +void ExtensionCmdQueue::Thread::checkForUpdates( + const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList ) +{ + ::osl::MutexGuard aGuard( m_mutex ); + + //If someone called stop then we do not update the extension -> game over! + if ( m_bStopped ) + return; + + TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::CHECK_FOR_UPDATES, vExtensionList ) ); + m_queue.push( pEntry ); + m_eInput = START; + m_wakeup.set(); +} + +//------------------------------------------------------------------------------ +//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 dialog 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; +} + +//------------------------------------------------------------------------------ +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..1e0e489a4902 --- /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..94323f6c49d8 --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_service.cxx @@ -0,0 +1,379 @@ +/* -*- 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 void Main(); +}; + +//______________________________________________________________________________ +MyApp::~MyApp() +{ +} + +//______________________________________________________________________________ +MyApp::MyApp() +{ +} + +//______________________________________________________________________________ +void MyApp::Main() +{ +} + +//############################################################################## + +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_system.cxx b/desktop/source/deployment/gui/dp_gui_system.cxx new file mode 100644 index 000000000000..6230e72dc39d --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_system.cxx @@ -0,0 +1,62 @@ +/* -*- 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_system.hxx" +#ifdef WNT +#define WIN32_LEAN_AND_MEAN +#ifdef _MSC_VER +#pragma warning(push,1) /* disable warnings within system headers */ +#endif +#include <windows.h> +#ifdef _MSC_VER +#pragma warning(pop) +#endif +#endif + +namespace dp_gui { + +//We cannot distinguish Vista and 2008 Server +bool isVista() +{ +#ifdef WNT + OSVERSIONINFO osvi; + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osvi); + return osvi.dwMajorVersion >= 6; +#else + return false; +#endif +} + +} //namespace dp_gui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/gui/dp_gui_system.hxx b/desktop/source/deployment/gui/dp_gui_system.hxx new file mode 100644 index 000000000000..319d627d2dc8 --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_system.hxx @@ -0,0 +1,40 @@ +/* -*- 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_SYSTEM_HXX +#define INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_GUI_DP_GUI_SYSTEM_HXX + + +/// @HTML +namespace dp_gui { +bool isVista(); + +} +#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..d82f70e397e9 --- /dev/null +++ b/desktop/source/deployment/gui/dp_gui_updatedialog.cxx @@ -0,0 +1,1267 @@ +/* -*- 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" +#include "dp_gui_system.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 + + struct Entry { + explicit Entry( + css::uno::Reference< css::deployment::XPackage > const & thePackage, + rtl::OUString const & theVersion); + + css::uno::Reference< css::deployment::XPackage > package; + rtl::OUString version; + //Indicates that the extension provides its own update URLs. + //If this is true, then we must not use the default update + //URL to find the update information. + bool bProvidesOwnUpdate; + css::uno::Reference< css::xml::dom::XNode > info; + UpdateDialog::DisabledUpdate disableUpdate; + dp_gui::UpdateData updateData; + }; + + // A multimap in case an extension is installed in "user", "shared" or "bundled" + typedef std::map< rtl::OUString, Entry > Map; + + 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; + + void getOwnUpdateInformation( + css::uno::Reference< css::deployment::XPackage > const & package, + Map * map); + + ::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::Entry::Entry( + css::uno::Reference< css::deployment::XPackage > const & thePackage, + rtl::OUString const & theVersion): + + package(thePackage), + version(theVersion), + bProvidesOwnUpdate(false), + updateData(thePackage) +{ +} + +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; +} + +bool UpdateDialog::isReadOnly( const css::uno::Reference< css::deployment::XPackage > &xPackage ) const +{ + if ( m_xExtensionManager.is() && xPackage.is() ) + { + return m_xExtensionManager->isReadOnlyRepository( xPackage->getRepositoryName() ); + } + else + 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 +// OSL_ASSERT(isReadOnly(i->aInstalledPackage) == sal_False); + } + + + 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..685ce8b7c533 --- /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..52092a077a4b --- /dev/null +++ b/desktop/source/deployment/gui/makefile.mk @@ -0,0 +1,109 @@ +#************************************************************************* +# +# 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_system.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 + |