office-gobmx/basctl/source/basicide/macrodlg.cxx
Caolán McNamara e1e6ff49a2 tdf#153434 crash on "new" macro with no cursor
probably good in trunk since:

commit 6e2bd11251
Date:   Sun Aug 7 12:49:11 2022 +0100

    tdf#150291 Revert "Fix crash when no valid EntryDescriptor found"

but still visible in 7-4

Change-Id: I63898ed3e33f73f8a93528872449539c5df6574f
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/146645
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
2023-02-08 09:00:40 +00:00

879 lines
33 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 "macrodlg.hxx"
#include <basidesh.hxx>
#include <strings.hrc>
#include <iderid.hxx>
#include <iderdll.hxx>
#include "iderdll2.hxx"
#include "moduldlg.hxx"
#include <basic/basmgr.hxx>
#include <basic/sbmeth.hxx>
#include <basic/sbmod.hxx>
#include <com/sun/star/script/XLibraryContainer2.hpp>
#include <sal/log.hxx>
#include <sfx2/app.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/frame.hxx>
#include <sfx2/minfitem.hxx>
#include <sfx2/request.hxx>
#include <sfx2/sfxsids.hrc>
#include <tools/debug.hxx>
#include <vcl/commandevent.hxx>
#include <vcl/svapp.hxx>
#include <vcl/weld.hxx>
#include <osl/diagnose.h>
namespace basctl
{
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
MacroChooser::MacroChooser(weld::Window* pParnt, const Reference< frame::XFrame >& xDocFrame)
: SfxDialogController(pParnt, "modules/BasicIDE/ui/basicmacrodialog.ui", "BasicMacroDialog")
, m_xDocumentFrame(xDocFrame)
// the Sfx doesn't ask the BasicManager whether modified or not
// => start saving in case of a change without a into the BasicIDE.
, bForceStoreBasic(false)
, nMode(All)
, m_xMacroNameEdit(m_xBuilder->weld_entry("macronameedit"))
, m_xMacroFromTxT(m_xBuilder->weld_label("macrofromft"))
, m_xMacrosSaveInTxt(m_xBuilder->weld_label("macrotoft"))
, m_xBasicBox(new SbTreeListBox(m_xBuilder->weld_tree_view("libraries"), m_xDialog.get()))
, m_xBasicBoxIter(m_xBasicBox->make_iterator())
, m_xMacrosInTxt(m_xBuilder->weld_label("existingmacrosft"))
, m_xMacroBox(m_xBuilder->weld_tree_view("macros"))
, m_xMacroBoxIter(m_xMacroBox->make_iterator())
, m_xRunButton(m_xBuilder->weld_button("ok"))
, m_xCloseButton(m_xBuilder->weld_button("close"))
, m_xAssignButton(m_xBuilder->weld_button("assign"))
, m_xEditButton(m_xBuilder->weld_button("edit"))
, m_xDelButton(m_xBuilder->weld_button("delete"))
, m_xNewButton(m_xBuilder->weld_button("new"))
, m_xOrganizeButton(m_xBuilder->weld_button("organize"))
, m_xNewLibButton(m_xBuilder->weld_button("newlibrary"))
, m_xNewModButton(m_xBuilder->weld_button("newmodule"))
{
m_xBasicBox->set_size_request(m_xBasicBox->get_approximate_digit_width() * 30, m_xBasicBox->get_height_rows(18));
m_xMacroBox->set_size_request(m_xMacroBox->get_approximate_digit_width() * 30, m_xMacroBox->get_height_rows(18));
m_aMacrosInTxtBaseStr = m_xMacrosInTxt->get_label();
m_xRunButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
m_xCloseButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
m_xAssignButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
m_xEditButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
m_xDelButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
m_xNewButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
m_xOrganizeButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
// Buttons only for MacroChooser::Recording
m_xNewLibButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
m_xNewModButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
m_xNewLibButton->hide(); // default
m_xNewModButton->hide(); // default
m_xMacrosSaveInTxt->hide(); // default
m_xMacroNameEdit->connect_changed( LINK( this, MacroChooser, EditModifyHdl ) );
m_xBasicBox->connect_changed( LINK( this, MacroChooser, BasicSelectHdl ) );
m_xMacroBox->connect_row_activated( LINK( this, MacroChooser, MacroDoubleClickHdl ) );
m_xMacroBox->connect_changed( LINK( this, MacroChooser, MacroSelectHdl ) );
m_xMacroBox->connect_popup_menu( LINK( this, MacroChooser, ContextMenuHdl ) );
m_xBasicBox->SetMode( BrowseMode::Modules );
if (SfxDispatcher* pDispatcher = GetDispatcher())
pDispatcher->Execute( SID_BASICIDE_STOREALLMODULESOURCES );
m_xBasicBox->ScanAllEntries();
}
MacroChooser::~MacroChooser()
{
if (bForceStoreBasic)
{
SfxGetpApp()->SaveBasicAndDialogContainer();
bForceStoreBasic = false;
}
}
void MacroChooser::StoreMacroDescription()
{
if (!m_xBasicBox->get_selected(m_xBasicBoxIter.get()))
return;
EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get());
OUString aMethodName;
if (m_xMacroBox->get_selected(m_xMacroBoxIter.get()))
aMethodName = m_xMacroBox->get_text(*m_xMacroBoxIter);
else
aMethodName = m_xMacroNameEdit->get_text();
if ( !aMethodName.isEmpty() )
{
aDesc.SetMethodName( aMethodName );
aDesc.SetType( OBJ_TYPE_METHOD );
}
if (ExtraData* pData = basctl::GetExtraData())
pData->SetLastEntryDescriptor( aDesc );
}
void MacroChooser::RestoreMacroDescription()
{
// The following call is a workaround to ensure the last used macro is scrolled to in kf5
m_xDialog->resize_to_request();
EntryDescriptor aDesc;
if (Shell* pShell = GetShell())
{
if (BaseWindow* pCurWin = pShell->GetCurWindow())
aDesc = pCurWin->CreateEntryDescriptor();
}
else
{
if (ExtraData* pData = basctl::GetExtraData())
aDesc = pData->GetLastEntryDescriptor();
}
m_xBasicBox->SetCurrentEntry(aDesc);
BasicSelectHdl(m_xBasicBox->get_widget());
OUString aLastMacro( aDesc.GetMethodName() );
if (!aLastMacro.isEmpty())
{
// find entry in macro box
auto nIndex = m_xMacroBox->find_text(aLastMacro);
if (nIndex != -1)
m_xMacroBox->select(nIndex);
else
{
m_xMacroNameEdit->set_text(aLastMacro);
m_xMacroNameEdit->select_region(0, 0);
}
}
}
short MacroChooser::run()
{
RestoreMacroDescription();
// #104198 Check if "wrong" document is active
bool bSelectedEntry = m_xBasicBox->get_cursor(m_xBasicBoxIter.get());
EntryDescriptor aDesc(m_xBasicBox->GetEntryDescriptor(bSelectedEntry ? m_xBasicBoxIter.get() : nullptr));
const ScriptDocument& rSelectedDoc(aDesc.GetDocument());
// App Basic is always ok, so only check if shell was found
if( rSelectedDoc.isDocument() && !rSelectedDoc.isActive() )
{
// Search for the right entry
bool bValidIter = m_xBasicBox->get_iter_first(*m_xBasicBoxIter);
while (bValidIter)
{
EntryDescriptor aCmpDesc(m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get()));
const ScriptDocument& rCmpDoc( aCmpDesc.GetDocument() );
if (rCmpDoc.isDocument() && rCmpDoc.isActive())
{
std::unique_ptr<weld::TreeIter> xEntry(m_xBasicBox->make_iterator());
m_xBasicBox->copy_iterator(*m_xBasicBoxIter, *xEntry);
std::unique_ptr<weld::TreeIter> xLastValid(m_xBasicBox->make_iterator());
bool bValidEntryIter = true;
do
{
m_xBasicBox->copy_iterator(*xEntry, *xLastValid);
bValidEntryIter = m_xBasicBox->iter_children(*xEntry);
}
while (bValidEntryIter);
m_xBasicBox->set_cursor(*xLastValid);
}
bValidIter = m_xBasicBox->iter_next_sibling(*m_xBasicBoxIter);
}
}
CheckButtons();
UpdateFields();
// tdf#62955 - Allow searching a name with typing the first letter
m_xBasicBox->get_widget().grab_focus();
if ( StarBASIC::IsRunning() )
m_xCloseButton->grab_focus();
return SfxDialogController::run();
}
void MacroChooser::EnableButton(weld::Button& rButton, bool bEnable)
{
if ( bEnable )
{
if (nMode == ChooseOnly || nMode == Recording)
rButton.set_sensitive(&rButton == m_xRunButton.get());
else
rButton.set_sensitive(true);
}
else
rButton.set_sensitive(false);
}
SbMethod* MacroChooser::GetMacro()
{
if (!m_xBasicBox->get_cursor(m_xBasicBoxIter.get()))
return nullptr;
SbModule* pModule = m_xBasicBox->FindModule(m_xBasicBoxIter.get());
if (!pModule)
return nullptr;
if (!m_xMacroBox->get_selected(m_xMacroBoxIter.get()))
return nullptr;
OUString aMacroName(m_xMacroBox->get_text(*m_xMacroBoxIter));
return pModule->FindMethod(aMacroName, SbxClassType::Method);
}
void MacroChooser::DeleteMacro()
{
SbMethod* pMethod = GetMacro();
DBG_ASSERT( pMethod, "DeleteMacro: No Macro !" );
if (!(pMethod && QueryDelMacro(pMethod->GetName(), m_xDialog.get())))
return;
if (SfxDispatcher* pDispatcher = GetDispatcher())
pDispatcher->Execute( SID_BASICIDE_STOREALLMODULESOURCES );
// mark current doc as modified:
StarBASIC* pBasic = FindBasic(pMethod);
assert(pBasic && "Basic?!");
BasicManager* pBasMgr = FindBasicManager( pBasic );
DBG_ASSERT( pBasMgr, "BasMgr?" );
ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) );
if ( aDocument.isDocument() )
{
aDocument.setDocumentModified();
if (SfxBindings* pBindings = GetBindingsPtr())
pBindings->Invalidate( SID_SAVEDOC );
}
SbModule* pModule = pMethod->GetModule();
assert(pModule && "DeleteMacro: No Module?!");
OUString aSource( pModule->GetSource32() );
sal_uInt16 nStart, nEnd;
pMethod->GetLineRange( nStart, nEnd );
pModule->GetMethods()->Remove( pMethod );
CutLines( aSource, nStart-1, nEnd-nStart+1 );
pModule->SetSource32( aSource );
// update module in library
OUString aLibName = pBasic->GetName();
OUString aModName = pModule->GetName();
OSL_VERIFY( aDocument.updateModule( aLibName, aModName, aSource ) );
bool bSelected = m_xMacroBox->get_selected(m_xMacroBoxIter.get());
DBG_ASSERT(bSelected, "DeleteMacro: Entry ?!");
m_xMacroBox->remove(*m_xMacroBoxIter);
bForceStoreBasic = true;
}
SbMethod* MacroChooser::CreateMacro()
{
SbMethod* pMethod = nullptr;
if (!m_xBasicBox->get_cursor(m_xBasicBoxIter.get()) && !m_xBasicBox->get_iter_first(*m_xBasicBoxIter))
{
SAL_WARN("basctl.basicide", "neither cursor set nor root entry to use as fallback");
return nullptr;
}
EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get());
const ScriptDocument& aDocument( aDesc.GetDocument() );
OSL_ENSURE( aDocument.isAlive(), "MacroChooser::CreateMacro: no document!" );
if ( !aDocument.isAlive() )
return nullptr;
OUString aLibName( aDesc.GetLibName() );
if ( aLibName.isEmpty() )
aLibName = "Standard" ;
aDocument.getOrCreateLibrary( E_SCRIPTS, aLibName );
OUString aOULibName( aLibName );
Reference< script::XLibraryContainer > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ) );
if ( xModLibContainer.is() && xModLibContainer->hasByName( aOULibName ) && !xModLibContainer->isLibraryLoaded( aOULibName ) )
xModLibContainer->loadLibrary( aOULibName );
Reference< script::XLibraryContainer > xDlgLibContainer( aDocument.getLibraryContainer( E_DIALOGS ) );
if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aOULibName ) && !xDlgLibContainer->isLibraryLoaded( aOULibName ) )
xDlgLibContainer->loadLibrary( aOULibName );
BasicManager* pBasMgr = aDocument.getBasicManager();
StarBASIC* pBasic = pBasMgr ? pBasMgr->GetLib( aLibName ) : nullptr;
if ( pBasic )
{
SbModule* pModule = nullptr;
OUString aModName( aDesc.GetName() );
if ( !aModName.isEmpty() )
{
// extract the module name from the string like "Sheet1 (Example1)"
if( aDesc.GetLibSubName() == IDEResId(RID_STR_DOCUMENT_OBJECTS) )
{
aModName = aModName.getToken( 0, ' ' );
}
pModule = pBasic->FindModule( aModName );
}
else if ( !pBasic->GetModules().empty() )
pModule = pBasic->GetModules().front().get();
// Retain the desired macro name before the macro dialog box is forced to close
// by opening the module name dialog window when no module exists in the current library.
OUString aSubName = m_xMacroNameEdit->get_text();
if ( !pModule )
{
pModule = createModImpl(m_xDialog.get(), aDocument, *m_xBasicBox, aLibName, aModName, false);
}
DBG_ASSERT( !pModule || !pModule->FindMethod( aSubName, SbxClassType::Method ), "Macro exists already!" );
pMethod = pModule ? basctl::CreateMacro( pModule, aSubName ) : nullptr;
}
return pMethod;
}
void MacroChooser::SaveSetCurEntry(weld::TreeView& rBox, const weld::TreeIter& rEntry)
{
// the edit would be killed by the highlight otherwise:
OUString aSaveText(m_xMacroNameEdit->get_text());
int nStartPos, nEndPos;
m_xMacroNameEdit->get_selection_bounds(nStartPos, nEndPos);
rBox.set_cursor(rEntry);
m_xMacroNameEdit->set_text(aSaveText);
m_xMacroNameEdit->select_region(nStartPos, nEndPos);
}
void MacroChooser::CheckButtons()
{
const bool bCurEntry = m_xBasicBox->get_cursor(m_xBasicBoxIter.get());
EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(bCurEntry ? m_xBasicBoxIter.get() : nullptr);
const bool bMacroEntry = m_xMacroBox->get_selected(nullptr);
SbMethod* pMethod = GetMacro();
// check, if corresponding libraries are readonly
bool bReadOnly = false;
sal_uInt16 nDepth = bCurEntry ? m_xBasicBox->get_iter_depth(*m_xBasicBoxIter) : 0;
if ( nDepth == 1 || nDepth == 2 )
{
const ScriptDocument& aDocument( aDesc.GetDocument() );
const OUString& aOULibName( 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( aOULibName ) && xModLibContainer->isLibraryReadOnly( aOULibName ) ) ||
( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aOULibName ) && xDlgLibContainer->isLibraryReadOnly( aOULibName ) ) )
{
bReadOnly = true;
}
}
if (nMode != Recording)
{
// Run...
bool bEnable = pMethod != nullptr;
if (nMode != ChooseOnly && StarBASIC::IsRunning())
bEnable = false;
EnableButton(*m_xRunButton, bEnable);
}
// organising still possible?
// Assign...
EnableButton(*m_xAssignButton, pMethod != nullptr);
// Edit...
EnableButton(*m_xEditButton, bMacroEntry);
// Organizer...
EnableButton(*m_xOrganizeButton, !StarBASIC::IsRunning() && nMode == All);
// m_xDelButton/m_xNewButton ->...
bool bProtected = bCurEntry && m_xBasicBox->IsEntryProtected(m_xBasicBoxIter.get());
bool bShare = ( aDesc.GetLocation() == LIBRARY_LOCATION_SHARE );
bool bEnable = !StarBASIC::IsRunning() && nMode == All && !bProtected && !bReadOnly && !bShare;
EnableButton(*m_xDelButton, bEnable);
EnableButton(*m_xNewButton, bEnable);
if (nMode == All)
{
if (pMethod)
{
m_xDelButton->show();
m_xNewButton->hide();
}
else
{
m_xNewButton->show();
m_xDelButton->hide();
}
}
if (nMode == Recording)
{
// save button
m_xRunButton->set_sensitive(!bProtected && !bReadOnly && !bShare);
// new library button
m_xNewLibButton->set_sensitive(!bShare);
// new module button
m_xNewModButton->set_sensitive(!bProtected && !bReadOnly && !bShare);
}
}
IMPL_LINK_NOARG(MacroChooser, MacroDoubleClickHdl, weld::TreeView&, bool)
{
SbMethod* pMethod = GetMacro();
SbModule* pModule = pMethod ? pMethod->GetModule() : nullptr;
StarBASIC* pBasic = pModule ? static_cast<StarBASIC*>(pModule->GetParent()) : nullptr;
BasicManager* pBasMgr = pBasic ? FindBasicManager(pBasic) : nullptr;
ScriptDocument aDocument(ScriptDocument::getDocumentForBasicManager(pBasMgr));
if (aDocument.isDocument() && !aDocument.allowMacros())
{
std::unique_ptr<weld::MessageDialog> xError(
Application::CreateMessageDialog(m_xDialog.get(), VclMessageType::Warning,
VclButtonsType::Ok, IDEResId(RID_STR_CANNOTRUNMACRO)));
xError->run();
return true;
}
StoreMacroDescription();
if (nMode == Recording)
{
if (pMethod && !QueryReplaceMacro(pMethod->GetName(), m_xDialog.get()))
return true;
}
m_xDialog->response(Macro_OkRun);
return true;
}
IMPL_LINK_NOARG(MacroChooser, MacroSelectHdl, weld::TreeView&, void)
{
UpdateFields();
CheckButtons();
}
IMPL_LINK_NOARG(MacroChooser, BasicSelectHdl, weld::TreeView&, void)
{
SbModule* pModule = nullptr;
if (m_xBasicBox->get_cursor(m_xBasicBoxIter.get()))
pModule = m_xBasicBox->FindModule(m_xBasicBoxIter.get());
m_xMacroBox->clear();
if (pModule)
{
m_xMacrosInTxt->set_label(m_aMacrosInTxtBaseStr + " " + pModule->GetName());
m_xMacroBox->freeze();
sal_uInt32 nMacroCount = pModule->GetMethods()->Count();
for ( sal_uInt32 iMeth = 0; iMeth < nMacroCount; iMeth++ )
{
SbMethod* pMethod = static_cast<SbMethod*>(pModule->GetMethods()->Get(iMeth));
assert(pMethod && "Method not found!");
if (pMethod->IsHidden())
continue;
m_xMacroBox->append_text(pMethod->GetName());
}
m_xMacroBox->thaw();
if (m_xMacroBox->get_iter_first(*m_xMacroBoxIter))
m_xMacroBox->set_cursor(*m_xMacroBoxIter);
}
UpdateFields();
CheckButtons();
}
IMPL_LINK_NOARG(MacroChooser, EditModifyHdl, weld::Entry&, void)
{
// select the module in which the macro is put at "new",
// if BasicManager or Lib is selecting
if (m_xBasicBox->get_cursor(m_xBasicBoxIter.get()))
{
sal_uInt16 nDepth = m_xBasicBox->get_iter_depth(*m_xBasicBoxIter);
if (nDepth == 1 && m_xBasicBox->IsEntryProtected(m_xBasicBoxIter.get()))
{
// then put to the respective Std-Lib...
m_xBasicBox->iter_parent(*m_xBasicBoxIter);
m_xBasicBox->iter_children(*m_xBasicBoxIter);
}
if (nDepth < 2)
{
std::unique_ptr<weld::TreeIter> xNewEntry(m_xBasicBox->make_iterator());
m_xBasicBox->copy_iterator(*m_xBasicBoxIter, *xNewEntry);
bool bCurEntry = true;
do
{
bCurEntry = m_xBasicBox->iter_children(*m_xBasicBoxIter);
if (bCurEntry)
{
m_xBasicBox->copy_iterator(*m_xBasicBoxIter, *xNewEntry);
nDepth = m_xBasicBox->get_iter_depth(*m_xBasicBoxIter);
}
}
while (bCurEntry && (nDepth < 2));
SaveSetCurEntry(m_xBasicBox->get_widget(), *xNewEntry);
}
auto nCount = m_xMacroBox->n_children();
if (nCount)
{
OUString aEdtText(m_xMacroNameEdit->get_text());
bool bFound = false;
bool bValidIter = m_xMacroBox->get_iter_first(*m_xMacroBoxIter);
while (bValidIter)
{
if (m_xMacroBox->get_text(*m_xMacroBoxIter).equalsIgnoreAsciiCase(aEdtText))
{
SaveSetCurEntry(*m_xMacroBox, *m_xMacroBoxIter);
bFound = true;
break;
}
bValidIter = m_xMacroBox->iter_next_sibling(*m_xMacroBoxIter);
}
if (!bFound)
{
bValidIter = m_xMacroBox->get_selected(m_xMacroBoxIter.get());
// if the entry exists ->Select ->Description...
if (bValidIter)
m_xMacroBox->unselect(*m_xMacroBoxIter);
}
}
}
CheckButtons();
}
IMPL_LINK(MacroChooser, ButtonHdl, weld::Button&, rButton, void)
{
// apart from New/Record the Description is done by LoseFocus
if (&rButton == m_xRunButton.get())
{
StoreMacroDescription();
// #116444# check security settings before macro execution
if (nMode == All)
{
SbMethod* pMethod = GetMacro();
SbModule* pModule = pMethod ? pMethod->GetModule() : nullptr;
StarBASIC* pBasic = pModule ? static_cast<StarBASIC*>(pModule->GetParent()) : nullptr;
BasicManager* pBasMgr = pBasic ? FindBasicManager(pBasic) : nullptr;
if ( pBasMgr )
{
ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) );
if ( aDocument.isDocument() && !aDocument.allowMacros() )
{
std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_xDialog.get(),
VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_CANNOTRUNMACRO)));
xError->run();
return;
}
}
}
else if (nMode == Recording )
{
if ( !IsValidSbxName(m_xMacroNameEdit->get_text()) )
{
std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_xDialog.get(),
VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME)));
xError->run();
m_xMacroNameEdit->select_region(0, -1);
m_xMacroNameEdit->grab_focus();
return;
}
SbMethod* pMethod = GetMacro();
if (pMethod && !QueryReplaceMacro(pMethod->GetName(), m_xDialog.get()))
return;
}
m_xDialog->response(Macro_OkRun);
}
else if (&rButton == m_xCloseButton.get())
{
StoreMacroDescription();
m_xDialog->response(Macro_Close);
}
else if (&rButton == m_xEditButton.get() || &rButton == m_xDelButton.get() || &rButton == m_xNewButton.get())
{
if (!m_xBasicBox->get_cursor(m_xBasicBoxIter.get()) && !m_xBasicBox->get_iter_first(*m_xBasicBoxIter))
{
SAL_WARN("basctl.basicide", "neither cursor set nor root entry to use as fallback");
return;
}
EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get());
const ScriptDocument& aDocument( aDesc.GetDocument() );
DBG_ASSERT( aDocument.isAlive(), "MacroChooser::ButtonHdl: no document, or document is dead!" );
if ( !aDocument.isAlive() )
return;
BasicManager* pBasMgr = aDocument.getBasicManager();
const OUString& aLib( aDesc.GetLibName() );
OUString aMod( aDesc.GetName() );
// extract the module name from the string like "Sheet1 (Example1)"
if( aDesc.GetLibSubName() == IDEResId(RID_STR_DOCUMENT_OBJECTS) )
{
aMod = aMod.getToken( 0, ' ' );
}
const OUString& aSub( aDesc.GetMethodName() );
SfxMacroInfoItem aInfoItem( SID_BASICIDE_ARG_MACROINFO, pBasMgr, aLib, aMod, aSub, OUString() );
if (&rButton == m_xEditButton.get())
{
if (m_xMacroBox->get_selected(m_xMacroBoxIter.get()))
aInfoItem.SetMethod(m_xMacroBox->get_text(*m_xMacroBoxIter));
StoreMacroDescription();
m_xDialog->hide(); // tdf#126828 dismiss dialog before opening new window
SfxAllItemSet aArgs( SfxGetpApp()->GetPool() );
SfxRequest aRequest( SID_BASICIDE_APPEAR, SfxCallMode::SYNCHRON, aArgs );
SfxGetpApp()->ExecuteSlot( aRequest );
if (SfxDispatcher* pDispatcher = GetDispatcher())
{
pDispatcher->ExecuteList(SID_BASICIDE_EDITMACRO,
SfxCallMode::ASYNCHRON, { &aInfoItem });
}
m_xDialog->response(Macro_Edit);
}
else
{
if (&rButton == m_xDelButton.get())
{
DeleteMacro();
if (SfxDispatcher* pDispatcher = GetDispatcher())
{
pDispatcher->ExecuteList( SID_BASICIDE_UPDATEMODULESOURCE,
SfxCallMode::SYNCHRON, { &aInfoItem });
}
CheckButtons();
UpdateFields();
//if ( m_xMacroBox->GetCurEntry() ) // OV-Bug ?
// m_xMacroBox->Select( m_xMacroBox->GetCurEntry() );
}
else
{
if ( !IsValidSbxName(m_xMacroNameEdit->get_text()) )
{
std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_xDialog.get(),
VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME)));
xError->run();
m_xMacroNameEdit->select_region(0, -1);
m_xMacroNameEdit->grab_focus();
return;
}
SbMethod* pMethod = CreateMacro();
if ( pMethod )
{
aInfoItem.SetMethod( pMethod->GetName() );
aInfoItem.SetModule( pMethod->GetModule()->GetName() );
aInfoItem.SetLib( pMethod->GetModule()->GetParent()->GetName() );
SfxAllItemSet aArgs( SfxGetpApp()->GetPool() );
SfxRequest aRequest( SID_BASICIDE_APPEAR, SfxCallMode::SYNCHRON, aArgs );
SfxGetpApp()->ExecuteSlot( aRequest );
if (SfxDispatcher* pDispatcher = GetDispatcher())
{
pDispatcher->ExecuteList(SID_BASICIDE_EDITMACRO,
SfxCallMode::ASYNCHRON, { &aInfoItem });
}
StoreMacroDescription();
m_xDialog->response(Macro_New);
}
}
}
}
else if (&rButton == m_xAssignButton.get())
{
if (!m_xBasicBox->get_cursor(m_xBasicBoxIter.get()) && !m_xBasicBox->get_iter_first(*m_xBasicBoxIter))
{
SAL_WARN("basctl.basicide", "neither cursor set nor root entry to use as fallback");
return;
}
EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get());
const ScriptDocument& aDocument( aDesc.GetDocument() );
DBG_ASSERT( aDocument.isAlive(), "MacroChooser::ButtonHdl: no document, or document is dead!" );
if ( !aDocument.isAlive() )
return;
BasicManager* pBasMgr = aDocument.getBasicManager();
const OUString& aLib( aDesc.GetLibName() );
const OUString& aMod( aDesc.GetName() );
OUString aSub( m_xMacroNameEdit->get_text() );
SbMethod* pMethod = GetMacro();
DBG_ASSERT( pBasMgr, "BasMgr?" );
DBG_ASSERT( pMethod, "Method?" );
OUString aComment( GetInfo( pMethod ) );
SfxMacroInfoItem aItem( SID_MACROINFO, pBasMgr, aLib, aMod, aSub, aComment );
SfxAllItemSet Args( SfxGetpApp()->GetPool() );
SfxAllItemSet aInternalSet(SfxGetpApp()->GetPool());
if (m_xDocumentFrame.is())
aInternalSet.Put(SfxUnoFrameItem(SID_FILLFRAME, m_xDocumentFrame));
SfxRequest aRequest(SID_CONFIGACCEL, SfxCallMode::SYNCHRON, Args, aInternalSet);
aRequest.AppendItem( aItem );
SfxGetpApp()->ExecuteSlot( aRequest );
}
else if (&rButton == m_xNewLibButton.get())
{
if (!m_xBasicBox->get_cursor(m_xBasicBoxIter.get()) && !m_xBasicBox->get_iter_first(*m_xBasicBoxIter))
{
SAL_WARN("basctl.basicide", "neither cursor set nor root entry to use as fallback");
return;
}
EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get());
const ScriptDocument& aDocument( aDesc.GetDocument() );
createLibImpl(m_xDialog.get(), aDocument, nullptr, m_xBasicBox.get());
}
else if (&rButton == m_xNewModButton.get())
{
if (!m_xBasicBox->get_cursor(m_xBasicBoxIter.get()) && !m_xBasicBox->get_iter_first(*m_xBasicBoxIter))
{
SAL_WARN("basctl.basicide", "neither cursor set nor root entry to use as fallback");
return;
}
EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get());
const ScriptDocument& aDocument( aDesc.GetDocument() );
const OUString& aLibName( aDesc.GetLibName() );
createModImpl(m_xDialog.get(), aDocument, *m_xBasicBox, aLibName, OUString(), true);
}
else if (&rButton == m_xOrganizeButton.get())
{
StoreMacroDescription();
m_xBasicBox->get_selected(m_xBasicBoxIter.get());
auto xDlg(std::make_shared<OrganizeDialog>(m_xDialog.get(), nullptr, 0));
weld::DialogController::runAsync(xDlg, [this](sal_Int32 nRet) {
if (nRet == RET_OK) // not only closed
{
m_xDialog->response(Macro_Edit);
return;
}
Shell* pShell = GetShell();
if ( pShell && pShell->IsAppBasicModified() )
bForceStoreBasic = true;
m_xBasicBox->UpdateEntries();
});
}
}
IMPL_LINK(MacroChooser, ContextMenuHdl, const CommandEvent&, rCEvt, bool)
{
if (rCEvt.GetCommand() != CommandEventId::ContextMenu || !m_xMacroBox->n_children())
return false;
std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xMacroBox.get(), "modules/BasicIDE/ui/sortmenu.ui"));
std::unique_ptr<weld::Menu> xPopup(xBuilder->weld_menu("sortmenu"));
std::unique_ptr<weld::Menu> xDropMenu(xBuilder->weld_menu("sortsubmenu"));
xDropMenu->set_active("alphabetically", m_xMacroBox->get_sort_order());
xDropMenu->set_active("properorder", !m_xMacroBox->get_sort_order());
OString sCommand(xPopup->popup_at_rect(m_xMacroBox.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1))));
if (sCommand == "alphabetically")
{
m_xMacroBox->make_sorted();
}
else if (sCommand == "properorder")
{
m_xMacroBox->make_unsorted();
BasicSelectHdl(m_xBasicBox->get_widget());
}
else if (!sCommand.isEmpty())
{
SAL_WARN("basctl.basicide", "Unknown context menu action: " << sCommand );
}
return true;
}
void MacroChooser::UpdateFields()
{
auto nMacroEntry = m_xMacroBox->get_selected_index();
m_xMacroNameEdit->set_text("");
if (nMacroEntry != -1)
m_xMacroNameEdit->set_text(m_xMacroBox->get_text(nMacroEntry));
}
void MacroChooser::SetMode (Mode nM)
{
nMode = nM;
switch (nMode)
{
case All:
{
m_xRunButton->set_label(IDEResId(RID_STR_RUN));
EnableButton(*m_xDelButton, true);
EnableButton(*m_xNewButton, true);
EnableButton(*m_xOrganizeButton, true);
break;
}
case ChooseOnly:
{
m_xRunButton->set_label(IDEResId(RID_STR_CHOOSE));
EnableButton(*m_xDelButton, false);
EnableButton(*m_xNewButton, false);
EnableButton(*m_xOrganizeButton, false);
break;
}
case Recording:
{
m_xRunButton->set_label(IDEResId(RID_STR_RECORD));
EnableButton(*m_xDelButton, false);
EnableButton(*m_xNewButton, false);
EnableButton(*m_xOrganizeButton, false);
m_xAssignButton->hide();
m_xEditButton->hide();
m_xDelButton->hide();
m_xNewButton->hide();
m_xOrganizeButton->hide();
m_xMacroFromTxT->hide();
m_xNewLibButton->show();
m_xNewModButton->show();
m_xMacrosSaveInTxt->show();
break;
}
}
CheckButtons();
}
OUString MacroChooser::GetInfo( SbxVariable* pVar )
{
OUString aComment;
SbxInfoRef xInfo = pVar->GetInfo();
if ( xInfo.is() )
aComment = xInfo->GetComment();
return aComment;
}
} // namespace basctl
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */