office-gobmx/basctl/source/basicide/moduldlg.cxx
Caolán McNamara e4dbbcd7a5 cid#1636563 Unchecked return value
Change-Id: I8d9cf983ca8c96d1619aceff9113732814d09f09
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177773
Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com>
Tested-by: Jenkins
2024-12-04 12:01:56 +01:00

1052 lines
42 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <sal/config.h>
#include <strings.hrc>
#include <iderid.hxx>
#include <bitmaps.hlst>
#include "moduldlg.hxx"
#include <localizationmgr.hxx>
#include <basidesh.hxx>
#include <basobj.hxx>
#include <basic/basmgr.hxx>
#include <com/sun/star/script/XLibraryContainerPassword.hpp>
#include <com/sun/star/script/XLibraryContainer2.hpp>
#include <com/sun/star/frame/XController.hpp>
#include <comphelper/processfactory.hxx>
#include <sfx2/app.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/frame.hxx>
#include <sfx2/request.hxx>
#include <sfx2/sfxsids.hrc>
#include <svl/stritem.hxx>
#include <vcl/transfer.hxx>
#include <vcl/svapp.hxx>
#include <vcl/weld.hxx>
#include <tools/debug.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <xmlscript/xmldlg_imexp.hxx>
#include <com/sun/star/uno/XComponentContext.hpp>
namespace basctl
{
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::resource;
IMPL_LINK(ObjectPage, EditingEntryHdl, const weld::TreeIter&, rEntry, bool)
{
bool bRet = false;
sal_uInt16 nDepth = m_xBasicBox->get_iter_depth(rEntry);
if (nDepth >= 2)
{
EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(&rEntry);
const ScriptDocument& aDocument( aDesc.GetDocument() );
const OUString& aLibName( aDesc.GetLibName() );
Reference< script::XLibraryContainer2 > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
Reference< script::XLibraryContainer2 > xDlgLibContainer( aDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY );
if ( !( ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && xModLibContainer->isLibraryReadOnly( aLibName ) ) ||
( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && xDlgLibContainer->isLibraryReadOnly( aLibName ) ) ) )
{
// allow editing only for libraries, which are not readonly
bRet = true;
}
}
return bRet;
}
IMPL_LINK(ObjectPage, EditedEntryHdl, const IterString&, rIterString, bool)
{
const weld::TreeIter& rEntry = rIterString.first;
OUString sNewText = rIterString.second;
if ( !IsValidSbxName(sNewText) )
{
std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_pDialog->getDialog(),
VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME)));
xError->run();
return false;
}
OUString aCurText(m_xBasicBox->get_text(rEntry));
if ( aCurText == sNewText )
// nothing to do
return true;
EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(&rEntry);
const ScriptDocument& aDocument( aDesc.GetDocument() );
DBG_ASSERT( aDocument.isValid(), "ExtTreeListBox::EditedEntry: no document!" );
if ( !aDocument.isValid() )
return false;
const OUString& aLibName( aDesc.GetLibName() );
EntryType eType = aDesc.GetType();
bool bSuccess = eType == OBJ_TYPE_MODULE ?
RenameModule(m_pDialog->getDialog(), aDocument, aLibName, aCurText, sNewText) :
RenameDialog(m_pDialog->getDialog(), aDocument, aLibName, aCurText, sNewText);
if ( !bSuccess )
return false;
MarkDocumentModified( aDocument );
if (SfxDispatcher* pDispatcher = GetDispatcher())
{
SbxItem aSbxItem(SID_BASICIDE_ARG_SBX, aDocument, aLibName, sNewText, SbTreeListBox::ConvertType(eType));
pDispatcher->ExecuteList( SID_BASICIDE_SBXRENAMED,
SfxCallMode::SYNCHRON, { &aSbxItem });
}
// OV-Bug?!
m_xBasicBox->set_text(rEntry, sNewText);
m_xBasicBox->set_cursor(rEntry);
m_xBasicBox->unselect(rEntry);
m_xBasicBox->select(rEntry); // so that handler is called => update edit
return true;
}
void Shell::CopyDialogResources(
Reference< io::XInputStreamProvider >& io_xISP,
ScriptDocument const& rSourceDoc,
OUString const& rSourceLibName,
ScriptDocument const& rDestDoc,
OUString const& rDestLibName,
std::u16string_view rDlgName
)
{
if ( !io_xISP.is() )
return;
// Get StringResourceManager
Reference< container::XNameContainer > xSourceDialogLib( rSourceDoc.getLibrary( E_DIALOGS, rSourceLibName, true ) );
Reference< XStringResourceManager > xSourceMgr =
LocalizationMgr::getStringResourceFromDialogLibrary( xSourceDialogLib );
if( !xSourceMgr.is() )
return;
bool bSourceLocalized = xSourceMgr->getLocales().hasElements();
Reference< container::XNameContainer > xDestDialogLib( rDestDoc.getLibrary( E_DIALOGS, rDestLibName, true ) );
Reference< XStringResourceManager > xDestMgr =
LocalizationMgr::getStringResourceFromDialogLibrary( xDestDialogLib );
if( !xDestMgr.is() )
return;
bool bDestLocalized = xDestMgr->getLocales().hasElements();
if( !bSourceLocalized && !bDestLocalized )
return;
// create dialog model
const Reference< XComponentContext >& xContext = comphelper::getProcessComponentContext();
Reference< container::XNameContainer > xDialogModel( xContext->getServiceManager()->createInstanceWithContext
( u"com.sun.star.awt.UnoControlDialogModel"_ustr, xContext ), UNO_QUERY );
Reference< io::XInputStream > xInput( io_xISP->createInputStream() );
::xmlscript::importDialogModel( xInput, xDialogModel, xContext, rSourceDoc.isDocument() ? rSourceDoc.getDocument() : Reference< frame::XModel >() );
if( !xDialogModel.is() )
return;
if( bSourceLocalized && bDestLocalized )
{
LocalizationMgr::copyResourceForDroppedDialog( xDialogModel, rDlgName, xDestMgr, xSourceMgr );
}
else if( bSourceLocalized )
{
LocalizationMgr::resetResourceForDialog( xDialogModel, xSourceMgr );
}
else if( bDestLocalized )
{
LocalizationMgr::setResourceIDsForDialog( xDialogModel, xDestMgr );
}
io_xISP = ::xmlscript::exportDialogModel( xDialogModel, xContext, rDestDoc.isDocument() ? rDestDoc.getDocument() : Reference< frame::XModel >() );
}
void OrganizeDialog::SetCurrentEntry(const css::uno::Reference<css::frame::XFrame>& xDocFrame)
{
if (!xDocFrame)
return;
Reference<css::frame::XController> xController(xDocFrame->getController());
if (!xController)
return;
Reference<css::frame::XModel> xModel(xController->getModel());
if (!xModel)
return;
EntryDescriptor aDesc(ScriptDocument(xModel), LIBRARY_LOCATION_DOCUMENT, OUString(), OUString(), OUString(), OBJ_TYPE_DOCUMENT);
m_xModulePage->SetCurrentEntry(aDesc);
m_xDialogPage->SetCurrentEntry(aDesc);
}
// OrganizeDialog
OrganizeDialog::OrganizeDialog(weld::Window* pParent, const css::uno::Reference<css::frame::XFrame>& xDocFrame, sal_Int16 tabId)
: GenericDialogController(pParent, u"modules/BasicIDE/ui/organizedialog.ui"_ustr, u"OrganizeDialog"_ustr)
, m_xTabCtrl(m_xBuilder->weld_notebook(u"tabcontrol"_ustr))
, m_xModulePage(new ObjectPage(m_xTabCtrl->get_page(u"modules"_ustr), u"ModulePage"_ustr, BrowseMode::Modules, this))
, m_xDialogPage(new ObjectPage(m_xTabCtrl->get_page(u"dialogs"_ustr), u"DialogPage"_ustr, BrowseMode::Dialogs, this))
, m_xLibPage(new LibPage(m_xTabCtrl->get_page(u"libraries"_ustr), this))
{
m_xTabCtrl->connect_enter_page(LINK(this, OrganizeDialog, ActivatePageHdl));
SetCurrentEntry(xDocFrame);
OUString sPage;
if (tabId == 0)
sPage = "modules";
else if (tabId == 1)
sPage = "dialogs";
else
sPage = "libraries";
m_xTabCtrl->set_current_page(sPage);
ActivatePageHdl(sPage);
if (SfxDispatcher* pDispatcher = GetDispatcher())
pDispatcher->Execute( SID_BASICIDE_STOREALLMODULESOURCES );
}
IMPL_LINK(OrganizeDialog, ActivatePageHdl, const OUString&, rPage, void)
{
if (rPage == "modules")
m_xModulePage->ActivatePage();
else if (rPage == "dialogs")
m_xDialogPage->ActivatePage();
else if (rPage == "libraries")
m_xLibPage->ActivatePage();
}
OrganizeDialog::~OrganizeDialog()
{
}
OrganizePage::OrganizePage(weld::Container* pParent, const OUString& rUIFile, const OUString &rName, OrganizeDialog* pDialog)
: m_pDialog(pDialog)
, m_xBuilder(Application::CreateBuilder(pParent, rUIFile))
, m_xContainer(m_xBuilder->weld_container(rName))
{
}
OrganizePage::~OrganizePage()
{
}
class SbTreeListBoxDropTarget : public DropTargetHelper
{
private:
SbTreeListBox& m_rTreeView;
virtual sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt) override
{
// to enable the autoscroll when we're close to the edges
weld::TreeView& rWidget = m_rTreeView.get_widget();
rWidget.get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true);
weld::TreeView* pSource = rWidget.get_drag_source();
if (!pSource)
return DND_ACTION_NONE;
// tdf#145722 only return a DND_ACTION_MOVE possibility if that
// is requested as an option
const bool bCheckForMove = rEvt.mnAction & DND_ACTION_MOVE;
sal_Int8 nMode = DND_ACTION_NONE;
std::unique_ptr<weld::TreeIter> xEntry(pSource->make_iterator());
if (pSource->get_selected(xEntry.get()))
{
sal_uInt16 nDepth = pSource->get_iter_depth(*xEntry);
if (nDepth >= 2)
{
nMode = DND_ACTION_COPY;
if (bCheckForMove)
{
EntryDescriptor aDesc = m_rTreeView.GetEntryDescriptor(xEntry.get());
const ScriptDocument& aDocument( aDesc.GetDocument() );
const OUString& aLibName( aDesc.GetLibName() );
// allow MOVE mode only for libraries, which are not readonly
Reference< script::XLibraryContainer2 > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
Reference< script::XLibraryContainer2 > xDlgLibContainer( aDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY );
if ( !( ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && xModLibContainer->isLibraryReadOnly( aLibName ) ) ||
( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && xDlgLibContainer->isLibraryReadOnly( aLibName ) ) ) )
{
// Only allow copy for localized libraries
bool bAllowMove = true;
if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) )
{
// Get StringResourceManager
Reference< container::XNameContainer > xDialogLib( aDocument.getLibrary( E_DIALOGS, aLibName, true ) );
Reference< XStringResourceManager > xSourceMgr =
LocalizationMgr::getStringResourceFromDialogLibrary( xDialogLib );
if( xSourceMgr.is() )
bAllowMove = ( xSourceMgr->getLocales().getLength() == 0 );
}
if( bAllowMove )
nMode |= DND_ACTION_MOVE;
}
}
}
}
return nMode;
}
virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override
{
weld::TreeView& rWidget = m_rTreeView.get_widget();
weld::TreeView* pSource = rWidget.get_drag_source();
if (!pSource)
return DND_ACTION_NONE;
std::unique_ptr<weld::TreeIter> xEntry(rWidget.make_iterator());
bool bEntry = rWidget.get_dest_row_at_pos(rEvt.maPosPixel, xEntry.get(), true);
// don't drop on a BasicManager (nDepth == 0)
sal_uInt16 nDepth = bEntry ? m_rTreeView.get_iter_depth(*xEntry) : 0;
bool bValid = nDepth != 0;
// don't drop in the same library
std::unique_ptr<weld::TreeIter> xSelected(pSource->make_iterator());
bool bSelected = pSource->get_selected(xSelected.get());
if (!bSelected)
bValid = false;
else if (nDepth == 1)
{
std::unique_ptr<weld::TreeIter> xSelParent(pSource->make_iterator(xSelected.get()));
if (pSource->iter_parent(*xSelParent) && pSource->iter_compare(*xEntry, *xSelParent) == 0)
bValid = false;
}
else if (nDepth == 2)
{
std::unique_ptr<weld::TreeIter> xParent(pSource->make_iterator(xEntry.get()));
std::unique_ptr<weld::TreeIter> xSelParent(pSource->make_iterator(xSelected.get()));
if (pSource->iter_parent(*xParent) && pSource->iter_parent(*xSelParent) && pSource->iter_compare(*xParent, *xSelParent) == 0)
bValid = false;
}
// don't drop on a library, which is not loaded, readonly or password protected
// or which already has a module/dialog with this name
if ( bValid && ( nDepth > 0 ) )
{
// get source module/dialog name
EntryDescriptor aSourceDesc = m_rTreeView.GetEntryDescriptor(xSelected.get());
const OUString& aSourceName = aSourceDesc.GetName();
EntryType eSourceType = aSourceDesc.GetType();
// get target shell and target library name
EntryDescriptor aDestDesc = m_rTreeView.GetEntryDescriptor(xEntry.get());
ScriptDocument const& rDestDoc = aDestDesc.GetDocument();
const OUString& aDestLibName = aDestDesc.GetLibName();
// check if module library is not loaded, readonly or password protected
Reference< script::XLibraryContainer2 > xModLibContainer( rDestDoc.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
if ( xModLibContainer.is() && xModLibContainer->hasByName( aDestLibName ) )
{
if ( !xModLibContainer->isLibraryLoaded( aDestLibName ) )
bValid = false;
if ( xModLibContainer->isLibraryReadOnly( aDestLibName ) )
bValid = false;
Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY );
if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aDestLibName ) && !xPasswd->isLibraryPasswordVerified( aDestLibName ) )
bValid = false;
}
// check if dialog library is not loaded or readonly
Reference< script::XLibraryContainer2 > xDlgLibContainer( rDestDoc.getLibraryContainer( E_DIALOGS ), UNO_QUERY );
if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aDestLibName ) )
{
if ( !xDlgLibContainer->isLibraryLoaded( aDestLibName ) )
bValid = false;
if ( xDlgLibContainer->isLibraryReadOnly( aDestLibName ) )
bValid = false;
}
// check, if module/dialog with this name is already existing in target library
if ( ( eSourceType == OBJ_TYPE_MODULE && rDestDoc.hasModule( aDestLibName, aSourceName ) ) ||
( eSourceType == OBJ_TYPE_DIALOG && rDestDoc.hasDialog( aDestLibName, aSourceName ) ) )
{
bValid = false;
}
}
if (bValid)
NotifyCopyingMoving(*xEntry, rEvt.mnAction & DND_ACTION_MOVE);
return DND_ACTION_NONE;
}
void NotifyCopyingMoving(const weld::TreeIter& rTarget, bool bMove)
{
sal_uInt16 nDepth = m_rTreeView.get_iter_depth(rTarget);
std::unique_ptr<weld::TreeIter> xNewParent(m_rTreeView.make_iterator(&rTarget));
int nNewChildPos = 0;
DBG_ASSERT( nDepth, "Depth?" );
if ( nDepth >= 2 )
{
// Target = module/dialog => put module/dialog under the superordinate Basic
m_rTreeView.iter_parent(*xNewParent);
nNewChildPos = m_rTreeView.get_iter_index_in_parent(rTarget) + 1;
}
// get target shell and target library name
EntryDescriptor aDestDesc = m_rTreeView.GetEntryDescriptor(xNewParent.get());
const ScriptDocument& rDestDoc( aDestDesc.GetDocument() );
const OUString& aDestLibName( aDestDesc.GetLibName() );
// get source shell, library name and module/dialog name
std::unique_ptr<weld::TreeIter> xSelected(m_rTreeView.make_iterator());
if (!m_rTreeView.get_selected(xSelected.get()))
return;
EntryDescriptor aSourceDesc = m_rTreeView.GetEntryDescriptor(xSelected.get());
const ScriptDocument& rSourceDoc( aSourceDesc.GetDocument() );
const OUString& aSourceLibName( aSourceDesc.GetLibName() );
const OUString& aSourceName( aSourceDesc.GetName() );
EntryType eType = aSourceDesc.GetType();
// get dispatcher
SfxDispatcher* pDispatcher = GetDispatcher();
if ( bMove ) // move
{
// remove source module/dialog window
if ( rSourceDoc != rDestDoc || aSourceLibName != aDestLibName )
{
if( pDispatcher )
{
SbxItem aSbxItem( SID_BASICIDE_ARG_SBX, rSourceDoc, aSourceLibName, aSourceName, SbTreeListBox::ConvertType(eType) );
pDispatcher->ExecuteList( SID_BASICIDE_SBXDELETED,
SfxCallMode::SYNCHRON, { &aSbxItem });
}
}
try
{
if ( eType == OBJ_TYPE_MODULE ) // module
{
// get module
OUString aModule;
if ( rSourceDoc.getModule( aSourceLibName, aSourceName, aModule ) )
{
// remove module from source library
if ( rSourceDoc.removeModule( aSourceLibName, aSourceName ) )
{
MarkDocumentModified( rSourceDoc );
// insert module into target library
if ( rDestDoc.insertModule( aDestLibName, aSourceName, aModule ) )
MarkDocumentModified( rDestDoc );
}
}
}
else if ( eType == OBJ_TYPE_DIALOG ) // dialog
{
// get dialog
Reference< io::XInputStreamProvider > xISP;
if ( rSourceDoc.getDialog( aSourceLibName, aSourceName, xISP ) )
{
Shell::CopyDialogResources( xISP, rSourceDoc,
aSourceLibName, rDestDoc, aDestLibName, aSourceName );
// remove dialog from source library
if (RemoveDialog(rSourceDoc, aSourceLibName, aSourceName))
{
MarkDocumentModified(rSourceDoc);
// insert dialog into target library
if ( rDestDoc.insertDialog( aDestLibName, aSourceName, xISP ) )
MarkDocumentModified(rDestDoc);
}
}
}
}
catch (const uno::Exception& )
{
DBG_UNHANDLED_EXCEPTION("basctl.basicide");
}
}
else // copy
{
try
{
if ( eType == OBJ_TYPE_MODULE ) // module
{
// get module
OUString aModule;
if ( rSourceDoc.getModule( aSourceLibName, aSourceName, aModule ) )
{
// insert module into target library
if ( rDestDoc.insertModule( aDestLibName, aSourceName, aModule ) )
MarkDocumentModified( rDestDoc );
}
}
else if ( eType == OBJ_TYPE_DIALOG ) // dialog
{
// get dialog
Reference< io::XInputStreamProvider > xISP;
if ( rSourceDoc.getDialog( aSourceLibName, aSourceName, xISP ) )
{
Shell::CopyDialogResources( xISP, rSourceDoc,
aSourceLibName, rDestDoc, aDestLibName, aSourceName );
// insert dialog into target library
if ( rDestDoc.insertDialog( aDestLibName, aSourceName, xISP ) )
MarkDocumentModified( rDestDoc );
}
}
}
catch ( const Exception& )
{
DBG_UNHANDLED_EXCEPTION("basctl.basicide");
}
}
OUString sText(m_rTreeView.get_text(*xSelected));
OUString sId(m_rTreeView.get_id(*xSelected));
/// if copying then clone the userdata
if (Entry* pEntry = bMove ? nullptr : weld::fromId<Entry*>(sId))
{
assert(pEntry->GetType() != OBJ_TYPE_DOCUMENT);
std::unique_ptr<Entry> xNewUserData(std::make_unique<Entry>(*pEntry));
sId = weld::toId(xNewUserData.release());
}
std::unique_ptr<weld::TreeIter> xRet(m_rTreeView.make_iterator());
m_rTreeView.get_widget().insert(xNewParent.get(), nNewChildPos, &sText, &sId, nullptr, nullptr, false, xRet.get());
if (eType == OBJ_TYPE_MODULE)
m_rTreeView.get_widget().set_image(*xRet, RID_BMP_MODULE);
else if (eType == OBJ_TYPE_DIALOG)
m_rTreeView.get_widget().set_image(*xRet, RID_BMP_DIALOG);
if (!m_rTreeView.get_row_expanded(*xNewParent))
m_rTreeView.expand_row(*xNewParent);
m_rTreeView.select(*xRet);
if (bMove)
m_rTreeView.remove(*xSelected);
// create target module/dialog window
if ( rSourceDoc != rDestDoc || aSourceLibName != aDestLibName )
{
if( pDispatcher )
{
SbxItem aSbxItem( SID_BASICIDE_ARG_SBX, rDestDoc, aDestLibName, aSourceName, SbTreeListBox::ConvertType(eType) );
pDispatcher->ExecuteList( SID_BASICIDE_SBXINSERTED,
SfxCallMode::SYNCHRON, { &aSbxItem });
}
}
}
public:
SbTreeListBoxDropTarget(SbTreeListBox& rTreeView)
: DropTargetHelper(rTreeView.get_widget().get_drop_target())
, m_rTreeView(rTreeView)
{
}
};
// ObjectPage
ObjectPage::ObjectPage(weld::Container* pParent, const OUString &rName, BrowseMode nMode, OrganizeDialog* pDialog)
: OrganizePage(pParent, "modules/BasicIDE/ui/" + rName.toAsciiLowerCase() + ".ui",
rName, pDialog)
, m_xBasicBox(new SbTreeListBox(m_xBuilder->weld_tree_view(u"library"_ustr), pDialog->getDialog()))
, m_xEditButton(m_xBuilder->weld_button(u"edit"_ustr))
, m_xNewModButton(m_xBuilder->weld_button(u"newmodule"_ustr))
, m_xNewDlgButton(m_xBuilder->weld_button(u"newdialog"_ustr))
, m_xDelButton(m_xBuilder->weld_button(u"delete"_ustr))
{
Size aSize(m_xBasicBox->get_approximate_digit_width() * 40,
m_xBasicBox->get_height_rows(14));
m_xBasicBox->set_size_request(aSize.Width(), aSize.Height());
// tdf#93476 The dialogs should be listed alphabetically
m_xBasicBox->make_sorted();
m_xEditButton->connect_clicked( LINK( this, ObjectPage, ButtonHdl ) );
m_xDelButton->connect_clicked( LINK( this, ObjectPage, ButtonHdl ) );
m_xBasicBox->connect_changed( LINK( this, ObjectPage, BasicBoxHighlightHdl ) );
if( nMode & BrowseMode::Modules )
{
m_xNewModButton->connect_clicked( LINK( this, ObjectPage, ButtonHdl ) );
m_xNewDlgButton->hide();
}
else if ( nMode & BrowseMode::Dialogs )
{
m_xNewDlgButton->connect_clicked( LINK( this, ObjectPage, ButtonHdl ) );
m_xNewModButton->hide();
}
m_xDropTarget.reset(new SbTreeListBoxDropTarget(*m_xBasicBox));
// tdf#145722 explicitly claim COPY and MOVE are options
rtl::Reference<TransferDataContainer> xHelper(new TransferDataContainer);
m_xBasicBox->get_widget().enable_drag_source(xHelper, DND_ACTION_COPYMOVE);
m_xBasicBox->connect_editing(LINK(this, ObjectPage, EditingEntryHdl),
LINK(this, ObjectPage, EditedEntryHdl));
m_xBasicBox->SetMode( nMode );
m_xBasicBox->ScanAllEntries();
m_xEditButton->grab_focus();
CheckButtons();
}
ObjectPage::~ObjectPage()
{
}
void ObjectPage::ActivatePage()
{
m_xBasicBox->UpdateEntries();
CheckButtons();
}
void ObjectPage::CheckButtons()
{
// enable/disable edit button
std::unique_ptr<weld::TreeIter> xCurEntry(m_xBasicBox->make_iterator());
if (!m_xBasicBox->get_cursor(xCurEntry.get()))
xCurEntry.reset();
EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(xCurEntry.get());
const ScriptDocument& aDocument( aDesc.GetDocument() );
const OUString& aLibName( aDesc.GetLibName() );
const OUString& aLibSubName( aDesc.GetLibSubName() );
bool bVBAEnabled = aDocument.isInVBAMode();
BrowseMode nMode = m_xBasicBox->GetMode();
sal_uInt16 nDepth = xCurEntry ? m_xBasicBox->get_iter_depth(*xCurEntry) : 0;
if ( nDepth >= 2 )
{
if( bVBAEnabled && ( nMode & BrowseMode::Modules ) && ( nDepth == 2 ) )
m_xEditButton->set_sensitive(false);
else
m_xEditButton->set_sensitive(true);
}
else
m_xEditButton->set_sensitive(false);
// enable/disable new module/dialog buttons
LibraryLocation eLocation( aDesc.GetLocation() );
bool bReadOnly = false;
if ( nDepth > 0 )
{
Reference< script::XLibraryContainer2 > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
Reference< script::XLibraryContainer2 > xDlgLibContainer( aDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY );
if ( ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && xModLibContainer->isLibraryReadOnly( aLibName ) ) ||
( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && xDlgLibContainer->isLibraryReadOnly( aLibName ) ) )
{
bReadOnly = true;
}
}
if ( bReadOnly || eLocation == LIBRARY_LOCATION_SHARE )
{
m_xNewModButton->set_sensitive(false);
m_xNewDlgButton->set_sensitive(false);
}
else
{
m_xNewModButton->set_sensitive(true);
m_xNewDlgButton->set_sensitive(true);
}
// enable/disable delete button
if ( nDepth >= 2 && !bReadOnly && eLocation != LIBRARY_LOCATION_SHARE )
{
if( bVBAEnabled && ( nMode & BrowseMode::Modules ) && ( ( nDepth == 2 ) || aLibSubName == IDEResId(RID_STR_DOCUMENT_OBJECTS) ) )
m_xDelButton->set_sensitive(false);
else
m_xDelButton->set_sensitive(true);
}
else
m_xDelButton->set_sensitive(false);
}
IMPL_LINK_NOARG(ObjectPage, BasicBoxHighlightHdl, weld::TreeView&, void)
{
CheckButtons();
}
IMPL_LINK(ObjectPage, ButtonHdl, weld::Button&, rButton, void)
{
if (&rButton == m_xEditButton.get())
{
SfxAllItemSet aArgs( SfxGetpApp()->GetPool() );
SfxRequest aRequest( SID_BASICIDE_APPEAR, SfxCallMode::SYNCHRON, aArgs );
SfxGetpApp()->ExecuteSlot( aRequest );
SfxDispatcher* pDispatcher = GetDispatcher();
std::unique_ptr<weld::TreeIter> xCurEntry(m_xBasicBox->make_iterator());
if (!m_xBasicBox->get_cursor(xCurEntry.get()))
return;
if (m_xBasicBox->get_iter_depth(*xCurEntry) >= 2)
{
EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(xCurEntry.get());
if ( pDispatcher )
{
OUString aModName( aDesc.GetName() );
// extract the module name from the string like "Sheet1 (Example1)"
if( aDesc.GetLibSubName() == IDEResId(RID_STR_DOCUMENT_OBJECTS) )
{
aModName = aModName.getToken( 0, ' ' );
}
SbxItem aSbxItem( SID_BASICIDE_ARG_SBX, aDesc.GetDocument(), aDesc.GetLibName(),
aModName, SbTreeListBox::ConvertType( aDesc.GetType() ) );
pDispatcher->ExecuteList(SID_BASICIDE_SHOWSBX,
SfxCallMode::SYNCHRON, { &aSbxItem });
}
}
else // only Lib selected
{
DBG_ASSERT( m_xBasicBox->get_iter_depth(*xCurEntry) == 1, "No LibEntry?!" );
ScriptDocument aDocument( ScriptDocument::getApplicationScriptDocument() );
std::unique_ptr<weld::TreeIter> xParentEntry(m_xBasicBox->make_iterator(xCurEntry.get()));
if (m_xBasicBox->iter_parent(*xParentEntry))
{
DocumentEntry* pDocumentEntry = weld::fromId<DocumentEntry*>(m_xBasicBox->get_id(*xParentEntry));
if (pDocumentEntry)
aDocument = pDocumentEntry->GetDocument();
}
SfxUnoAnyItem aDocItem( SID_BASICIDE_ARG_DOCUMENT_MODEL, Any( aDocument.getDocumentOrNull() ) );
OUString aLibName(m_xBasicBox->get_text(*xCurEntry));
SfxStringItem aLibNameItem( SID_BASICIDE_ARG_LIBNAME, aLibName );
if ( pDispatcher )
{
pDispatcher->ExecuteList(SID_BASICIDE_LIBSELECTED,
SfxCallMode::ASYNCHRON, { &aDocItem, &aLibNameItem });
}
}
EndTabDialog();
}
else if (&rButton == m_xNewModButton.get())
NewModule();
else if (&rButton == m_xNewDlgButton.get())
NewDialog();
else if (&rButton == m_xDelButton.get())
DeleteCurrent();
}
bool ObjectPage::GetSelection( ScriptDocument& rDocument, OUString& rLibName )
{
bool bRet = false;
std::unique_ptr<weld::TreeIter> xCurEntry(m_xBasicBox->make_iterator());
if (!m_xBasicBox->get_cursor(xCurEntry.get()))
xCurEntry.reset();
EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(xCurEntry.get());
rDocument = aDesc.GetDocument();
rLibName = aDesc.GetLibName();
if ( rLibName.isEmpty() )
rLibName = "Standard" ;
DBG_ASSERT( rDocument.isAlive(), "ObjectPage::GetSelection: no or dead ScriptDocument in the selection!" );
if ( !rDocument.isAlive() )
return false;
// check if the module library is loaded
bool bOK = true;
OUString aLibName( rLibName );
Reference< script::XLibraryContainer > xModLibContainer( rDocument.getLibraryContainer( E_SCRIPTS ) );
if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && !xModLibContainer->isLibraryLoaded( aLibName ) )
{
// check password
Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY );
if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aLibName ) && !xPasswd->isLibraryPasswordVerified( aLibName ) )
{
OUString aPassword;
bOK = QueryPassword(m_pDialog->getDialog(), xModLibContainer, rLibName, aPassword);
}
// load library
if ( bOK )
xModLibContainer->loadLibrary( aLibName );
}
// check if the dialog library is loaded
Reference< script::XLibraryContainer > xDlgLibContainer( rDocument.getLibraryContainer( E_DIALOGS ) );
if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && !xDlgLibContainer->isLibraryLoaded( aLibName ) )
{
// load library
if ( bOK )
xDlgLibContainer->loadLibrary( aLibName );
}
if ( bOK )
bRet = true;
return bRet;
}
void ObjectPage::NewModule()
{
ScriptDocument aDocument( ScriptDocument::getApplicationScriptDocument() );
OUString aLibName;
if ( GetSelection( aDocument, aLibName ) )
{
createModImpl(m_pDialog->getDialog(), aDocument,
*m_xBasicBox, aLibName, OUString(), true);
}
}
void ObjectPage::NewDialog()
{
ScriptDocument aDocument( ScriptDocument::getApplicationScriptDocument() );
OUString aLibName;
if ( !GetSelection( aDocument, aLibName ) )
return;
aDocument.getOrCreateLibrary( E_DIALOGS, aLibName );
NewObjectDialog aNewDlg(m_pDialog->getDialog(), ObjectMode::Dialog, true);
aNewDlg.SetObjectName(aDocument.createObjectName(E_DIALOGS, aLibName));
if (aNewDlg.run() == RET_CANCEL)
return;
OUString aDlgName = aNewDlg.GetObjectName();
if (aDlgName.isEmpty())
aDlgName = aDocument.createObjectName( E_DIALOGS, aLibName);
if ( aDocument.hasDialog( aLibName, aDlgName ) )
{
std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_pDialog->getDialog(),
VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_SBXNAMEALLREADYUSED2)));
xError->run();
}
else
{
Reference< io::XInputStreamProvider > xISP;
if ( !aDocument.createDialog( aLibName, aDlgName, xISP ) )
return;
SbxItem aSbxItem( SID_BASICIDE_ARG_SBX, aDocument, aLibName, aDlgName, SBX_TYPE_DIALOG );
if (SfxDispatcher* pDispatcher = GetDispatcher())
{
pDispatcher->ExecuteList( SID_BASICIDE_SBXINSERTED,
SfxCallMode::SYNCHRON, { &aSbxItem });
}
LibraryLocation eLocation = aDocument.getLibraryLocation( aLibName );
std::unique_ptr<weld::TreeIter> xIter(m_xBasicBox->make_iterator());
bool bRootEntry = m_xBasicBox->FindRootEntry(aDocument, eLocation, *xIter);
if (bRootEntry)
{
if (!m_xBasicBox->get_row_expanded(*xIter))
m_xBasicBox->expand_row(*xIter);
bool bLibEntry = m_xBasicBox->FindEntry(aLibName, OBJ_TYPE_LIBRARY, *xIter);
DBG_ASSERT( bLibEntry, "LibEntry not found!" );
if (bLibEntry)
{
if (!m_xBasicBox->get_row_expanded(*xIter))
m_xBasicBox->expand_row(*xIter);
std::unique_ptr<weld::TreeIter> xSubRootEntry(m_xBasicBox->make_iterator(xIter.get()));
bool bDlgEntry = m_xBasicBox->FindEntry(aDlgName, OBJ_TYPE_DIALOG, *xIter);
if (!bDlgEntry)
{
m_xBasicBox->AddEntry(aDlgName, RID_BMP_DIALOG, xSubRootEntry.get(), false,
std::make_unique<Entry>(OBJ_TYPE_DIALOG), xIter.get());
assert(xIter && "Insert entry failed!");
}
m_xBasicBox->set_cursor(*xIter);
m_xBasicBox->select(*xIter);
}
}
}
}
void ObjectPage::DeleteCurrent()
{
std::unique_ptr<weld::TreeIter> xCurEntry(m_xBasicBox->make_iterator());
if (!m_xBasicBox->get_cursor(xCurEntry.get()))
xCurEntry.reset();
DBG_ASSERT( xCurEntry, "No current entry!" );
if (!xCurEntry)
return;
EntryDescriptor aDesc( m_xBasicBox->GetEntryDescriptor( xCurEntry.get() ) );
const ScriptDocument& aDocument( aDesc.GetDocument() );
DBG_ASSERT( aDocument.isAlive(), "ObjectPage::DeleteCurrent: no document!" );
if ( !aDocument.isAlive() )
return;
const OUString& aLibName( aDesc.GetLibName() );
const OUString& aName( aDesc.GetName() );
EntryType eType = aDesc.GetType();
if ( !(( eType == OBJ_TYPE_MODULE && QueryDelModule(aName, m_pDialog->getDialog()) ) ||
( eType == OBJ_TYPE_DIALOG && QueryDelDialog(aName, m_pDialog->getDialog()) )) )
return;
m_xBasicBox->remove(*xCurEntry);
if (m_xBasicBox->get_cursor(xCurEntry.get()))
m_xBasicBox->select(*xCurEntry);
if (SfxDispatcher* pDispatcher = GetDispatcher())
{
SbxItem aSbxItem( SID_BASICIDE_ARG_SBX, aDocument, aLibName, aName, SbTreeListBox::ConvertType( eType ) );
pDispatcher->ExecuteList( SID_BASICIDE_SBXDELETED,
SfxCallMode::SYNCHRON, { &aSbxItem });
}
try
{
bool bSuccess = false;
if ( eType == OBJ_TYPE_MODULE )
bSuccess = aDocument.removeModule( aLibName, aName );
else if ( eType == OBJ_TYPE_DIALOG )
bSuccess = RemoveDialog( aDocument, aLibName, aName );
if ( bSuccess )
MarkDocumentModified( aDocument );
}
catch (const container::NoSuchElementException& )
{
DBG_UNHANDLED_EXCEPTION("basctl.basicide");
}
}
void ObjectPage::EndTabDialog()
{
m_pDialog->response(RET_OK);
}
LibDialog::LibDialog(weld::Window* pParent)
: GenericDialogController(pParent, u"modules/BasicIDE/ui/importlibdialog.ui"_ustr, u"ImportLibDialog"_ustr)
, m_xStorageFrame(m_xBuilder->weld_frame(u"storageframe"_ustr))
, m_xLibBox(m_xBuilder->weld_tree_view(u"entries"_ustr))
, m_xReferenceBox(m_xBuilder->weld_check_button(u"ref"_ustr))
, m_xReplaceBox(m_xBuilder->weld_check_button(u"replace"_ustr))
{
m_xLibBox->set_size_request(m_xLibBox->get_approximate_digit_width() * 28,
m_xLibBox->get_height_rows(8));
m_xLibBox->enable_toggle_buttons(weld::ColumnToggleType::Check);
// tdf#93476 The libraries should be listed alphabetically
m_xLibBox->make_sorted();
}
LibDialog::~LibDialog()
{
}
void LibDialog::SetStorageName( std::u16string_view rName )
{
OUString aName = IDEResId(RID_STR_FILENAME) + rName;
m_xStorageFrame->set_label(aName);
}
// Helper function
SbModule* createModImpl(weld::Window* pWin, const ScriptDocument& rDocument,
SbTreeListBox& rBasicBox, const OUString& rLibName, const OUString& _aModName, bool bMain )
{
OSL_ENSURE( rDocument.isAlive(), "createModImpl: invalid document!" );
if ( !rDocument.isAlive() )
return nullptr;
SbModule* pModule = nullptr;
OUString aLibName( rLibName );
if ( aLibName.isEmpty() )
aLibName = "Standard" ;
rDocument.getOrCreateLibrary( E_SCRIPTS, aLibName );
OUString aModName = _aModName;
if ( aModName.isEmpty() )
aModName = rDocument.createObjectName( E_SCRIPTS, aLibName );
NewObjectDialog aNewDlg(pWin, ObjectMode::Module, true);
aNewDlg.SetObjectName(aModName);
if (aNewDlg.run() != RET_CANCEL)
{
if (!aNewDlg.GetObjectName().isEmpty())
aModName = aNewDlg.GetObjectName();
try
{
OUString sModuleCode;
// the module has existed
if( rDocument.hasModule( aLibName, aModName ) )
return nullptr;
if (!rDocument.createModule(aLibName, aModName, bMain, sModuleCode))
return nullptr;
BasicManager* pBasMgr = rDocument.getBasicManager();
StarBASIC* pBasic = pBasMgr? pBasMgr->GetLib( aLibName ) : nullptr;
if ( pBasic )
pModule = pBasic->FindModule( aModName );
SbxItem aSbxItem( SID_BASICIDE_ARG_SBX, rDocument, aLibName, aModName, SBX_TYPE_MODULE );
if (SfxDispatcher* pDispatcher = GetDispatcher())
{
pDispatcher->ExecuteList( SID_BASICIDE_SBXINSERTED,
SfxCallMode::SYNCHRON, { &aSbxItem });
}
LibraryLocation eLocation = rDocument.getLibraryLocation( aLibName );
std::unique_ptr<weld::TreeIter> xIter(rBasicBox.make_iterator());
bool bRootEntry = rBasicBox.FindRootEntry(rDocument, eLocation, *xIter);
if (bRootEntry)
{
if (!rBasicBox.get_row_expanded(*xIter))
rBasicBox.expand_row(*xIter);
bool bLibEntry = rBasicBox.FindEntry(aLibName, OBJ_TYPE_LIBRARY, *xIter);
DBG_ASSERT( bLibEntry, "LibEntry not found!" );
if (bLibEntry)
{
if (!rBasicBox.get_row_expanded(*xIter))
rBasicBox.expand_row(*xIter);
std::unique_ptr<weld::TreeIter> xSubRootEntry(rBasicBox.make_iterator(xIter.get()));
if (pBasic && rDocument.isInVBAMode())
{
// add the new module in the "Modules" entry
std::unique_ptr<weld::TreeIter> xLibSubEntry(rBasicBox.make_iterator(xIter.get()));
bool bLibSubEntry = rBasicBox.FindEntry(IDEResId(RID_STR_NORMAL_MODULES) , OBJ_TYPE_NORMAL_MODULES, *xLibSubEntry);
if (bLibSubEntry)
{
if (!rBasicBox.get_row_expanded(*xLibSubEntry))
rBasicBox.expand_row(*xLibSubEntry);
rBasicBox.copy_iterator(*xLibSubEntry, *xSubRootEntry);
}
}
std::unique_ptr<weld::TreeIter> xEntry(rBasicBox.make_iterator(xSubRootEntry.get()));
bool bEntry = rBasicBox.FindEntry(aModName, OBJ_TYPE_MODULE, *xEntry);
if (!bEntry)
{
rBasicBox.AddEntry(aModName, RID_BMP_MODULE, xSubRootEntry.get(), false,
std::make_unique<Entry>(OBJ_TYPE_MODULE), xEntry.get());
}
rBasicBox.set_cursor(*xEntry);
rBasicBox.select(*xEntry);
}
}
}
catch (const container::ElementExistException& )
{
std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(pWin,
VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_SBXNAMEALLREADYUSED2)));
xError->run();
}
catch (const container::NoSuchElementException& )
{
DBG_UNHANDLED_EXCEPTION("basctl.basicide");
}
}
return pModule;
}
} // namespace basctl
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */