1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20
21 #include "macrodlg.hxx"
22 #include <basidesh.hxx>
23 #include <strings.hrc>
24 #include <iderid.hxx>
25
26 #include <iderdll.hxx>
27 #include "iderdll2.hxx"
28
29 #include "moduldlg.hxx"
30 #include <basic/basmgr.hxx>
31 #include <basic/sbmeth.hxx>
32 #include <basic/sbmod.hxx>
33 #include <com/sun/star/script/XLibraryContainer2.hpp>
34
35 #include <sfx2/app.hxx>
36 #include <sfx2/dispatch.hxx>
37 #include <sfx2/frame.hxx>
38 #include <sfx2/minfitem.hxx>
39 #include <sfx2/request.hxx>
40 #include <sfx2/sfxsids.hrc>
41 #include <tools/debug.hxx>
42 #include <vcl/commandevent.hxx>
43 #include <vcl/svapp.hxx>
44 #include <vcl/weld.hxx>
45 #include <osl/diagnose.h>
46
47 namespace basctl
48 {
49
50 using namespace ::com::sun::star;
51 using namespace ::com::sun::star::uno;
52
MacroChooser(weld::Window * pParnt,const Reference<frame::XFrame> & xDocFrame)53 MacroChooser::MacroChooser(weld::Window* pParnt, const Reference< frame::XFrame >& xDocFrame)
54 : SfxDialogController(pParnt, "modules/BasicIDE/ui/basicmacrodialog.ui", "BasicMacroDialog")
55 , m_xDocumentFrame(xDocFrame)
56 // the Sfx doesn't ask the BasicManager whether modified or not
57 // => start saving in case of a change without a into the BasicIDE.
58 , bForceStoreBasic(false)
59 , nMode(All)
60 , m_xMacroNameEdit(m_xBuilder->weld_entry("macronameedit"))
61 , m_xMacroFromTxT(m_xBuilder->weld_label("macrofromft"))
62 , m_xMacrosSaveInTxt(m_xBuilder->weld_label("macrotoft"))
63 , m_xBasicBox(new SbTreeListBox(m_xBuilder->weld_tree_view("libraries"), m_xDialog.get()))
64 , m_xBasicBoxIter(m_xBasicBox->make_iterator())
65 , m_xMacrosInTxt(m_xBuilder->weld_label("existingmacrosft"))
66 , m_xMacroBox(m_xBuilder->weld_tree_view("macros"))
67 , m_xMacroBoxIter(m_xMacroBox->make_iterator())
68 , m_xRunButton(m_xBuilder->weld_button("ok"))
69 , m_xCloseButton(m_xBuilder->weld_button("close"))
70 , m_xAssignButton(m_xBuilder->weld_button("assign"))
71 , m_xEditButton(m_xBuilder->weld_button("edit"))
72 , m_xDelButton(m_xBuilder->weld_button("delete"))
73 , m_xNewButton(m_xBuilder->weld_button("new"))
74 , m_xOrganizeButton(m_xBuilder->weld_button("organize"))
75 , m_xNewLibButton(m_xBuilder->weld_button("newlibrary"))
76 , m_xNewModButton(m_xBuilder->weld_button("newmodule"))
77 {
78 m_xBasicBox->set_size_request(m_xBasicBox->get_approximate_digit_width() * 30, m_xBasicBox->get_height_rows(18));
79 m_xMacroBox->set_size_request(m_xMacroBox->get_approximate_digit_width() * 30, m_xMacroBox->get_height_rows(18));
80
81 m_aMacrosInTxtBaseStr = m_xMacrosInTxt->get_label();
82
83 m_xRunButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
84 m_xCloseButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
85 m_xAssignButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
86 m_xEditButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
87 m_xDelButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
88 m_xNewButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
89 m_xOrganizeButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
90
91 // Buttons only for MacroChooser::Recording
92 m_xNewLibButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
93 m_xNewModButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) );
94 m_xNewLibButton->hide(); // default
95 m_xNewModButton->hide(); // default
96 m_xMacrosSaveInTxt->hide(); // default
97
98 m_xMacroNameEdit->connect_changed( LINK( this, MacroChooser, EditModifyHdl ) );
99
100 m_xBasicBox->connect_changed( LINK( this, MacroChooser, BasicSelectHdl ) );
101
102 m_xMacroBox->connect_row_activated( LINK( this, MacroChooser, MacroDoubleClickHdl ) );
103 m_xMacroBox->connect_changed( LINK( this, MacroChooser, MacroSelectHdl ) );
104 m_xMacroBox->connect_popup_menu( LINK( this, MacroChooser, ContextMenuHdl ) );
105
106 m_xBasicBox->SetMode( BrowseMode::Modules );
107
108 if (SfxDispatcher* pDispatcher = GetDispatcher())
109 pDispatcher->Execute( SID_BASICIDE_STOREALLMODULESOURCES );
110
111 m_xBasicBox->ScanAllEntries();
112 }
113
~MacroChooser()114 MacroChooser::~MacroChooser()
115 {
116 if (bForceStoreBasic)
117 {
118 SfxGetpApp()->SaveBasicAndDialogContainer();
119 bForceStoreBasic = false;
120 }
121 }
122
StoreMacroDescription()123 void MacroChooser::StoreMacroDescription()
124 {
125 m_xBasicBox->get_selected(m_xBasicBoxIter.get());
126 EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get());
127 OUString aMethodName;
128 if (m_xMacroBox->get_selected(m_xMacroBoxIter.get()))
129 aMethodName = m_xMacroBox->get_text(*m_xMacroBoxIter);
130 else
131 aMethodName = m_xMacroNameEdit->get_text();
132 if ( !aMethodName.isEmpty() )
133 {
134 aDesc.SetMethodName( aMethodName );
135 aDesc.SetType( OBJ_TYPE_METHOD );
136 }
137
138 if (ExtraData* pData = basctl::GetExtraData())
139 pData->SetLastEntryDescriptor( aDesc );
140 }
141
RestoreMacroDescription()142 void MacroChooser::RestoreMacroDescription()
143 {
144 EntryDescriptor aDesc;
145 if (Shell* pShell = GetShell())
146 {
147 if (BaseWindow* pCurWin = pShell->GetCurWindow())
148 aDesc = pCurWin->CreateEntryDescriptor();
149 }
150 else
151 {
152 if (ExtraData* pData = basctl::GetExtraData())
153 aDesc = pData->GetLastEntryDescriptor();
154 }
155
156 m_xBasicBox->SetCurrentEntry(aDesc);
157 BasicSelectHdl(m_xBasicBox->get_widget());
158
159 OUString aLastMacro( aDesc.GetMethodName() );
160 if (!aLastMacro.isEmpty())
161 {
162 // find entry in macro box
163 auto nIndex = m_xMacroBox->find_text(aLastMacro);
164 if (nIndex != -1)
165 m_xMacroBox->select(nIndex);
166 else
167 {
168 m_xMacroNameEdit->set_text(aLastMacro);
169 m_xMacroNameEdit->select_region(0, 0);
170 }
171 }
172 }
173
run()174 short MacroChooser::run()
175 {
176 RestoreMacroDescription();
177
178 // #104198 Check if "wrong" document is active
179 bool bSelectedEntry = m_xBasicBox->get_cursor(m_xBasicBoxIter.get());
180 EntryDescriptor aDesc(m_xBasicBox->GetEntryDescriptor(bSelectedEntry ? m_xBasicBoxIter.get() : nullptr));
181 const ScriptDocument& rSelectedDoc(aDesc.GetDocument());
182
183 // App Basic is always ok, so only check if shell was found
184 if( rSelectedDoc.isDocument() && !rSelectedDoc.isActive() )
185 {
186 // Search for the right entry
187 bool bValidIter = m_xBasicBox->get_iter_first(*m_xBasicBoxIter);
188 while (bValidIter)
189 {
190 EntryDescriptor aCmpDesc(m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get()));
191 const ScriptDocument& rCmpDoc( aCmpDesc.GetDocument() );
192 if (rCmpDoc.isDocument() && rCmpDoc.isActive())
193 {
194 std::unique_ptr<weld::TreeIter> xEntry(m_xBasicBox->make_iterator());
195 m_xBasicBox->copy_iterator(*m_xBasicBoxIter, *xEntry);
196 std::unique_ptr<weld::TreeIter> xLastValid(m_xBasicBox->make_iterator());
197 bool bValidEntryIter = true;
198 do
199 {
200 m_xBasicBox->copy_iterator(*xEntry, *xLastValid);
201 bValidEntryIter = m_xBasicBox->iter_children(*xEntry);
202 }
203 while (bValidEntryIter);
204 m_xBasicBox->set_cursor(*xLastValid);
205 }
206 bValidIter = m_xBasicBox->iter_next_sibling(*m_xBasicBoxIter);
207 }
208 }
209
210 CheckButtons();
211 UpdateFields();
212
213 // tdf#62955 - Allow searching a name with typing the first letter
214 m_xBasicBox->get_widget().grab_focus();
215
216 if ( StarBASIC::IsRunning() )
217 m_xCloseButton->grab_focus();
218
219 return SfxDialogController::run();
220 }
221
EnableButton(weld::Button & rButton,bool bEnable)222 void MacroChooser::EnableButton(weld::Button& rButton, bool bEnable)
223 {
224 if ( bEnable )
225 {
226 if (nMode == ChooseOnly || nMode == Recording)
227 rButton.set_sensitive(&rButton == m_xRunButton.get());
228 else
229 rButton.set_sensitive(true);
230 }
231 else
232 rButton.set_sensitive(false);
233 }
234
GetMacro()235 SbMethod* MacroChooser::GetMacro()
236 {
237 if (!m_xBasicBox->get_cursor(m_xBasicBoxIter.get()))
238 return nullptr;
239 SbModule* pModule = m_xBasicBox->FindModule(m_xBasicBoxIter.get());
240 if (!pModule)
241 return nullptr;
242 if (!m_xMacroBox->get_selected(m_xMacroBoxIter.get()))
243 return nullptr;
244 OUString aMacroName(m_xMacroBox->get_text(*m_xMacroBoxIter));
245 return pModule->FindMethod(aMacroName, SbxClassType::Method);
246 }
247
DeleteMacro()248 void MacroChooser::DeleteMacro()
249 {
250 SbMethod* pMethod = GetMacro();
251 DBG_ASSERT( pMethod, "DeleteMacro: No Macro !" );
252 if (!(pMethod && QueryDelMacro(pMethod->GetName(), m_xDialog.get())))
253 return;
254
255 if (SfxDispatcher* pDispatcher = GetDispatcher())
256 pDispatcher->Execute( SID_BASICIDE_STOREALLMODULESOURCES );
257
258 // mark current doc as modified:
259 StarBASIC* pBasic = FindBasic(pMethod);
260 assert(pBasic && "Basic?!");
261 BasicManager* pBasMgr = FindBasicManager( pBasic );
262 DBG_ASSERT( pBasMgr, "BasMgr?" );
263 ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) );
264 if ( aDocument.isDocument() )
265 {
266 aDocument.setDocumentModified();
267 if (SfxBindings* pBindings = GetBindingsPtr())
268 pBindings->Invalidate( SID_SAVEDOC );
269 }
270
271 SbModule* pModule = pMethod->GetModule();
272 assert(pModule && "DeleteMacro: No Module?!");
273 OUString aSource( pModule->GetSource32() );
274 sal_uInt16 nStart, nEnd;
275 pMethod->GetLineRange( nStart, nEnd );
276 pModule->GetMethods()->Remove( pMethod );
277 CutLines( aSource, nStart-1, nEnd-nStart+1 );
278 pModule->SetSource32( aSource );
279
280 // update module in library
281 OUString aLibName = pBasic->GetName();
282 OUString aModName = pModule->GetName();
283 OSL_VERIFY( aDocument.updateModule( aLibName, aModName, aSource ) );
284
285 bool bSelected = m_xMacroBox->get_selected(m_xMacroBoxIter.get());
286 DBG_ASSERT(bSelected, "DeleteMacro: Entry ?!");
287 m_xMacroBox->remove(*m_xMacroBoxIter);
288 bForceStoreBasic = true;
289 }
290
CreateMacro()291 SbMethod* MacroChooser::CreateMacro()
292 {
293 SbMethod* pMethod = nullptr;
294 m_xBasicBox->get_cursor(m_xBasicBoxIter.get());
295 EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get());
296 const ScriptDocument& aDocument( aDesc.GetDocument() );
297 OSL_ENSURE( aDocument.isAlive(), "MacroChooser::CreateMacro: no document!" );
298 if ( !aDocument.isAlive() )
299 return nullptr;
300
301 OUString aLibName( aDesc.GetLibName() );
302
303 if ( aLibName.isEmpty() )
304 aLibName = "Standard" ;
305
306 aDocument.getOrCreateLibrary( E_SCRIPTS, aLibName );
307
308 OUString aOULibName( aLibName );
309 Reference< script::XLibraryContainer > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ) );
310 if ( xModLibContainer.is() && xModLibContainer->hasByName( aOULibName ) && !xModLibContainer->isLibraryLoaded( aOULibName ) )
311 xModLibContainer->loadLibrary( aOULibName );
312 Reference< script::XLibraryContainer > xDlgLibContainer( aDocument.getLibraryContainer( E_DIALOGS ) );
313 if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aOULibName ) && !xDlgLibContainer->isLibraryLoaded( aOULibName ) )
314 xDlgLibContainer->loadLibrary( aOULibName );
315
316 BasicManager* pBasMgr = aDocument.getBasicManager();
317 StarBASIC* pBasic = pBasMgr ? pBasMgr->GetLib( aLibName ) : nullptr;
318 if ( pBasic )
319 {
320 SbModule* pModule = nullptr;
321 OUString aModName( aDesc.GetName() );
322 if ( !aModName.isEmpty() )
323 {
324 // extract the module name from the string like "Sheet1 (Example1)"
325 if( aDesc.GetLibSubName() == IDEResId(RID_STR_DOCUMENT_OBJECTS) )
326 {
327 aModName = aModName.getToken( 0, ' ' );
328 }
329 pModule = pBasic->FindModule( aModName );
330 }
331 else if ( !pBasic->GetModules().empty() )
332 pModule = pBasic->GetModules().front().get();
333
334 // Retain the desired macro name before the macro dialog box is forced to close
335 // by opening the module name dialog window when no module exists in the current library.
336 OUString aSubName = m_xMacroNameEdit->get_text();
337
338 if ( !pModule )
339 {
340 pModule = createModImpl(m_xDialog.get(), aDocument, *m_xBasicBox, aLibName, aModName, false);
341 }
342
343 DBG_ASSERT( !pModule || !pModule->FindMethod( aSubName, SbxClassType::Method ), "Macro exists already!" );
344 pMethod = pModule ? basctl::CreateMacro( pModule, aSubName ) : nullptr;
345 }
346
347 return pMethod;
348 }
349
SaveSetCurEntry(weld::TreeView & rBox,const weld::TreeIter & rEntry)350 void MacroChooser::SaveSetCurEntry(weld::TreeView& rBox, const weld::TreeIter& rEntry)
351 {
352 // the edit would be killed by the highlight otherwise:
353
354 OUString aSaveText(m_xMacroNameEdit->get_text());
355 int nStartPos, nEndPos;
356 m_xMacroNameEdit->get_selection_bounds(nStartPos, nEndPos);
357
358 rBox.set_cursor(rEntry);
359
360 m_xMacroNameEdit->set_text(aSaveText);
361 m_xMacroNameEdit->select_region(nStartPos, nEndPos);
362 }
363
CheckButtons()364 void MacroChooser::CheckButtons()
365 {
366 const bool bCurEntry = m_xBasicBox->get_cursor(m_xBasicBoxIter.get());
367 EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(bCurEntry ? m_xBasicBoxIter.get() : nullptr);
368 const bool bMacroEntry = m_xMacroBox->get_selected(nullptr);
369 SbMethod* pMethod = GetMacro();
370
371 // check, if corresponding libraries are readonly
372 bool bReadOnly = false;
373 sal_uInt16 nDepth = bCurEntry ? m_xBasicBox->get_iter_depth(*m_xBasicBoxIter) : 0;
374 if ( nDepth == 1 || nDepth == 2 )
375 {
376 const ScriptDocument& aDocument( aDesc.GetDocument() );
377 const OUString& aOULibName( aDesc.GetLibName() );
378 Reference< script::XLibraryContainer2 > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
379 Reference< script::XLibraryContainer2 > xDlgLibContainer( aDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY );
380 if ( ( xModLibContainer.is() && xModLibContainer->hasByName( aOULibName ) && xModLibContainer->isLibraryReadOnly( aOULibName ) ) ||
381 ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aOULibName ) && xDlgLibContainer->isLibraryReadOnly( aOULibName ) ) )
382 {
383 bReadOnly = true;
384 }
385 }
386
387 if (nMode != Recording)
388 {
389 // Run...
390 bool bEnable = pMethod != nullptr;
391 if (nMode != ChooseOnly && StarBASIC::IsRunning())
392 bEnable = false;
393 EnableButton(*m_xRunButton, bEnable);
394 }
395
396 // organising still possible?
397
398 // Assign...
399 EnableButton(*m_xAssignButton, pMethod != nullptr);
400
401 // Edit...
402 EnableButton(*m_xEditButton, bMacroEntry);
403
404 // Organizer...
405 EnableButton(*m_xOrganizeButton, !StarBASIC::IsRunning() && nMode == All);
406
407 // m_xDelButton/m_xNewButton ->...
408 bool bProtected = bCurEntry && m_xBasicBox->IsEntryProtected(m_xBasicBoxIter.get());
409 bool bShare = ( aDesc.GetLocation() == LIBRARY_LOCATION_SHARE );
410 bool bEnable = !StarBASIC::IsRunning() && nMode == All && !bProtected && !bReadOnly && !bShare;
411 EnableButton(*m_xDelButton, bEnable);
412 EnableButton(*m_xNewButton, bEnable);
413 if (nMode == All)
414 {
415 if (pMethod)
416 {
417 m_xDelButton->show();
418 m_xNewButton->hide();
419 }
420 else
421 {
422 m_xNewButton->show();
423 m_xDelButton->hide();
424 }
425 }
426
427 if (nMode == Recording)
428 {
429 // save button
430 m_xRunButton->set_sensitive(!bProtected && !bReadOnly && !bShare);
431 // new library button
432 m_xNewLibButton->set_sensitive(!bShare);
433 // new module button
434 m_xNewModButton->set_sensitive(!bProtected && !bReadOnly && !bShare);
435 }
436 }
437
IMPL_LINK_NOARG(MacroChooser,MacroDoubleClickHdl,weld::TreeView &,bool)438 IMPL_LINK_NOARG(MacroChooser, MacroDoubleClickHdl, weld::TreeView&, bool)
439 {
440 SbMethod* pMethod = GetMacro();
441 SbModule* pModule = pMethod ? pMethod->GetModule() : nullptr;
442 StarBASIC* pBasic = pModule ? static_cast<StarBASIC*>(pModule->GetParent()) : nullptr;
443 BasicManager* pBasMgr = pBasic ? FindBasicManager(pBasic) : nullptr;
444 ScriptDocument aDocument(ScriptDocument::getDocumentForBasicManager(pBasMgr));
445 if (aDocument.isDocument() && !aDocument.allowMacros())
446 {
447 std::unique_ptr<weld::MessageDialog> xError(
448 Application::CreateMessageDialog(m_xDialog.get(), VclMessageType::Warning,
449 VclButtonsType::Ok, IDEResId(RID_STR_CANNOTRUNMACRO)));
450 xError->run();
451 return true;
452 }
453
454 StoreMacroDescription();
455 if (nMode == Recording)
456 {
457 if (pMethod && !QueryReplaceMacro(pMethod->GetName(), m_xDialog.get()))
458 return true;
459 }
460
461 m_xDialog->response(Macro_OkRun);
462 return true;
463 }
464
IMPL_LINK_NOARG(MacroChooser,MacroSelectHdl,weld::TreeView &,void)465 IMPL_LINK_NOARG(MacroChooser, MacroSelectHdl, weld::TreeView&, void)
466 {
467 UpdateFields();
468 CheckButtons();
469 }
470
IMPL_LINK_NOARG(MacroChooser,BasicSelectHdl,weld::TreeView &,void)471 IMPL_LINK_NOARG(MacroChooser, BasicSelectHdl, weld::TreeView&, void)
472 {
473 m_xBasicBox->get_cursor(m_xBasicBoxIter.get());
474 SbModule* pModule = m_xBasicBox->FindModule(m_xBasicBoxIter.get());
475 m_xMacroBox->clear();
476 if (pModule)
477 {
478 m_xMacrosInTxt->set_label(m_aMacrosInTxtBaseStr + " " + pModule->GetName());
479
480 m_xMacroBox->freeze();
481
482 sal_uInt32 nMacroCount = pModule->GetMethods()->Count();
483 for ( sal_uInt32 iMeth = 0; iMeth < nMacroCount; iMeth++ )
484 {
485 SbMethod* pMethod = static_cast<SbMethod*>(pModule->GetMethods()->Get(iMeth));
486 assert(pMethod && "Method not found!");
487 if (pMethod->IsHidden())
488 continue;
489 m_xMacroBox->append_text(pMethod->GetName());
490 }
491
492 m_xMacroBox->thaw();
493
494 if (m_xMacroBox->get_iter_first(*m_xMacroBoxIter))
495 m_xMacroBox->set_cursor(*m_xMacroBoxIter);
496 }
497
498 UpdateFields();
499 CheckButtons();
500 }
501
IMPL_LINK_NOARG(MacroChooser,EditModifyHdl,weld::Entry &,void)502 IMPL_LINK_NOARG(MacroChooser, EditModifyHdl, weld::Entry&, void)
503 {
504 // select the module in which the macro is put at "new",
505 // if BasicManager or Lib is selecting
506 if (m_xBasicBox->get_cursor(m_xBasicBoxIter.get()))
507 {
508 sal_uInt16 nDepth = m_xBasicBox->get_iter_depth(*m_xBasicBoxIter);
509 if (nDepth == 1 && m_xBasicBox->IsEntryProtected(m_xBasicBoxIter.get()))
510 {
511 // then put to the respective Std-Lib...
512 m_xBasicBox->iter_parent(*m_xBasicBoxIter);
513 m_xBasicBox->iter_children(*m_xBasicBoxIter);
514 }
515 if (nDepth < 2)
516 {
517 std::unique_ptr<weld::TreeIter> xNewEntry(m_xBasicBox->make_iterator());
518 m_xBasicBox->copy_iterator(*m_xBasicBoxIter, *xNewEntry);
519 bool bCurEntry = true;
520 do
521 {
522 bCurEntry = m_xBasicBox->iter_children(*m_xBasicBoxIter);
523 if (bCurEntry)
524 {
525 m_xBasicBox->copy_iterator(*m_xBasicBoxIter, *xNewEntry);
526 nDepth = m_xBasicBox->get_iter_depth(*m_xBasicBoxIter);
527 }
528 }
529 while (bCurEntry && (nDepth < 2));
530 SaveSetCurEntry(m_xBasicBox->get_widget(), *xNewEntry);
531 }
532 auto nCount = m_xMacroBox->n_children();
533 if (nCount)
534 {
535 OUString aEdtText(m_xMacroNameEdit->get_text());
536 bool bFound = false;
537 bool bValidIter = m_xMacroBox->get_iter_first(*m_xMacroBoxIter);
538 while (bValidIter)
539 {
540 if (m_xMacroBox->get_text(*m_xMacroBoxIter).equalsIgnoreAsciiCase(aEdtText))
541 {
542 SaveSetCurEntry(*m_xMacroBox, *m_xMacroBoxIter);
543 bFound = true;
544 break;
545 }
546 bValidIter = m_xMacroBox->iter_next_sibling(*m_xMacroBoxIter);
547 }
548 if (!bFound)
549 {
550 bValidIter = m_xMacroBox->get_selected(m_xMacroBoxIter.get());
551 // if the entry exists ->Select ->Description...
552 if (bValidIter)
553 m_xMacroBox->unselect(*m_xMacroBoxIter);
554 }
555 }
556 }
557
558 CheckButtons();
559 }
560
IMPL_LINK(MacroChooser,ButtonHdl,weld::Button &,rButton,void)561 IMPL_LINK(MacroChooser, ButtonHdl, weld::Button&, rButton, void)
562 {
563 // apart from New/Record the Description is done by LoseFocus
564 if (&rButton == m_xRunButton.get())
565 {
566 StoreMacroDescription();
567
568 // #116444# check security settings before macro execution
569 if (nMode == All)
570 {
571 SbMethod* pMethod = GetMacro();
572 SbModule* pModule = pMethod ? pMethod->GetModule() : nullptr;
573 StarBASIC* pBasic = pModule ? static_cast<StarBASIC*>(pModule->GetParent()) : nullptr;
574 BasicManager* pBasMgr = pBasic ? FindBasicManager(pBasic) : nullptr;
575 if ( pBasMgr )
576 {
577 ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) );
578 if ( aDocument.isDocument() && !aDocument.allowMacros() )
579 {
580 std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_xDialog.get(),
581 VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_CANNOTRUNMACRO)));
582 xError->run();
583 return;
584 }
585 }
586 }
587 else if (nMode == Recording )
588 {
589 if ( !IsValidSbxName(m_xMacroNameEdit->get_text()) )
590 {
591 std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_xDialog.get(),
592 VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME)));
593 xError->run();
594 m_xMacroNameEdit->select_region(0, -1);
595 m_xMacroNameEdit->grab_focus();
596 return;
597 }
598
599 SbMethod* pMethod = GetMacro();
600 if (pMethod && !QueryReplaceMacro(pMethod->GetName(), m_xDialog.get()))
601 return;
602 }
603
604 m_xDialog->response(Macro_OkRun);
605 }
606 else if (&rButton == m_xCloseButton.get())
607 {
608 StoreMacroDescription();
609 m_xDialog->response(Macro_Close);
610 }
611 else if (&rButton == m_xEditButton.get() || &rButton == m_xDelButton.get() || &rButton == m_xNewButton.get())
612 {
613 m_xBasicBox->get_cursor(m_xBasicBoxIter.get());
614 EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get());
615 const ScriptDocument& aDocument( aDesc.GetDocument() );
616 DBG_ASSERT( aDocument.isAlive(), "MacroChooser::ButtonHdl: no document, or document is dead!" );
617 if ( !aDocument.isAlive() )
618 return;
619 BasicManager* pBasMgr = aDocument.getBasicManager();
620 const OUString& aLib( aDesc.GetLibName() );
621 OUString aMod( aDesc.GetName() );
622 // extract the module name from the string like "Sheet1 (Example1)"
623 if( aDesc.GetLibSubName() == IDEResId(RID_STR_DOCUMENT_OBJECTS) )
624 {
625 aMod = aMod.getToken( 0, ' ' );
626 }
627 const OUString& aSub( aDesc.GetMethodName() );
628 SfxMacroInfoItem aInfoItem( SID_BASICIDE_ARG_MACROINFO, pBasMgr, aLib, aMod, aSub, OUString() );
629 if (&rButton == m_xEditButton.get())
630 {
631 if (m_xMacroBox->get_selected(m_xMacroBoxIter.get()))
632 aInfoItem.SetMethod(m_xMacroBox->get_text(*m_xMacroBoxIter));
633 StoreMacroDescription();
634 m_xDialog->hide(); // tdf#126828 dismiss dialog before opening new window
635
636 SfxAllItemSet aArgs( SfxGetpApp()->GetPool() );
637 SfxRequest aRequest( SID_BASICIDE_APPEAR, SfxCallMode::SYNCHRON, aArgs );
638 SfxGetpApp()->ExecuteSlot( aRequest );
639
640 if (SfxDispatcher* pDispatcher = GetDispatcher())
641 {
642 pDispatcher->ExecuteList(SID_BASICIDE_EDITMACRO,
643 SfxCallMode::ASYNCHRON, { &aInfoItem });
644 }
645 m_xDialog->response(Macro_Edit);
646 }
647 else
648 {
649 if (&rButton == m_xDelButton.get())
650 {
651 DeleteMacro();
652 if (SfxDispatcher* pDispatcher = GetDispatcher())
653 {
654 pDispatcher->ExecuteList( SID_BASICIDE_UPDATEMODULESOURCE,
655 SfxCallMode::SYNCHRON, { &aInfoItem });
656 }
657 CheckButtons();
658 UpdateFields();
659 //if ( m_xMacroBox->GetCurEntry() ) // OV-Bug ?
660 // m_xMacroBox->Select( m_xMacroBox->GetCurEntry() );
661 }
662 else
663 {
664 if ( !IsValidSbxName(m_xMacroNameEdit->get_text()) )
665 {
666 std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_xDialog.get(),
667 VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME)));
668 xError->run();
669 m_xMacroNameEdit->select_region(0, -1);
670 m_xMacroNameEdit->grab_focus();
671 return;
672 }
673 SbMethod* pMethod = CreateMacro();
674 if ( pMethod )
675 {
676 aInfoItem.SetMethod( pMethod->GetName() );
677 aInfoItem.SetModule( pMethod->GetModule()->GetName() );
678 aInfoItem.SetLib( pMethod->GetModule()->GetParent()->GetName() );
679 SfxAllItemSet aArgs( SfxGetpApp()->GetPool() );
680 SfxRequest aRequest( SID_BASICIDE_APPEAR, SfxCallMode::SYNCHRON, aArgs );
681 SfxGetpApp()->ExecuteSlot( aRequest );
682
683 if (SfxDispatcher* pDispatcher = GetDispatcher())
684 {
685 pDispatcher->ExecuteList(SID_BASICIDE_EDITMACRO,
686 SfxCallMode::ASYNCHRON, { &aInfoItem });
687 }
688 StoreMacroDescription();
689 m_xDialog->response(Macro_New);
690 }
691 }
692 }
693 }
694 else if (&rButton == m_xAssignButton.get())
695 {
696 m_xBasicBox->get_cursor(m_xBasicBoxIter.get());
697 EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get());
698 const ScriptDocument& aDocument( aDesc.GetDocument() );
699 DBG_ASSERT( aDocument.isAlive(), "MacroChooser::ButtonHdl: no document, or document is dead!" );
700 if ( !aDocument.isAlive() )
701 return;
702 BasicManager* pBasMgr = aDocument.getBasicManager();
703 const OUString& aLib( aDesc.GetLibName() );
704 const OUString& aMod( aDesc.GetName() );
705 OUString aSub( m_xMacroNameEdit->get_text() );
706 SbMethod* pMethod = GetMacro();
707 DBG_ASSERT( pBasMgr, "BasMgr?" );
708 DBG_ASSERT( pMethod, "Method?" );
709 OUString aComment( GetInfo( pMethod ) );
710 SfxMacroInfoItem aItem( SID_MACROINFO, pBasMgr, aLib, aMod, aSub, aComment );
711 SfxAllItemSet Args( SfxGetpApp()->GetPool() );
712
713 SfxAllItemSet aInternalSet(SfxGetpApp()->GetPool());
714 if (m_xDocumentFrame.is())
715 aInternalSet.Put(SfxUnoFrameItem(SID_FILLFRAME, m_xDocumentFrame));
716
717 SfxRequest aRequest(SID_CONFIG, SfxCallMode::SYNCHRON, Args, aInternalSet);
718 aRequest.AppendItem( aItem );
719 SfxGetpApp()->ExecuteSlot( aRequest );
720 }
721 else if (&rButton == m_xNewLibButton.get())
722 {
723 m_xBasicBox->get_cursor(m_xBasicBoxIter.get());
724 EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get());
725 const ScriptDocument& aDocument( aDesc.GetDocument() );
726 createLibImpl(m_xDialog.get(), aDocument, nullptr, m_xBasicBox.get());
727 }
728 else if (&rButton == m_xNewModButton.get())
729 {
730 m_xBasicBox->get_cursor(m_xBasicBoxIter.get());
731 EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get());
732 const ScriptDocument& aDocument( aDesc.GetDocument() );
733 const OUString& aLibName( aDesc.GetLibName() );
734 createModImpl(m_xDialog.get(), aDocument, *m_xBasicBox, aLibName, OUString(), true);
735 }
736 else if (&rButton == m_xOrganizeButton.get())
737 {
738 StoreMacroDescription();
739
740 m_xBasicBox->get_selected(m_xBasicBoxIter.get());
741 auto xDlg(std::make_shared<OrganizeDialog>(m_xDialog.get(), 0));
742 weld::DialogController::runAsync(xDlg, [this](sal_Int32 nRet) {
743 if (nRet == RET_OK) // not only closed
744 {
745 m_xDialog->response(Macro_Edit);
746 return;
747 }
748
749 Shell* pShell = GetShell();
750 if ( pShell && pShell->IsAppBasicModified() )
751 bForceStoreBasic = true;
752
753 m_xBasicBox->UpdateEntries();
754 });
755 }
756 }
757
IMPL_LINK(MacroChooser,ContextMenuHdl,const CommandEvent &,rCEvt,bool)758 IMPL_LINK(MacroChooser, ContextMenuHdl, const CommandEvent&, rCEvt, bool)
759 {
760 if (rCEvt.GetCommand() != CommandEventId::ContextMenu || !m_xMacroBox->n_children())
761 return false;
762
763 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xMacroBox.get(), "modules/BasicIDE/ui/sortmenu.ui"));
764 std::unique_ptr<weld::Menu> xPopup(xBuilder->weld_menu("sortmenu"));
765 std::unique_ptr<weld::Menu> xDropMenu(xBuilder->weld_menu("sortsubmenu"));
766 xDropMenu->set_active("alphabetically", m_xMacroBox->get_sort_order());
767 xDropMenu->set_active("properorder", !m_xMacroBox->get_sort_order());
768
769 OString sCommand(xPopup->popup_at_rect(m_xMacroBox.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1))));
770 if (sCommand == "alphabetically")
771 {
772 m_xMacroBox->make_sorted();
773 }
774 else if (sCommand == "properorder")
775 {
776 m_xMacroBox->make_unsorted();
777 BasicSelectHdl(m_xBasicBox->get_widget());
778 }
779 else if (!sCommand.isEmpty())
780 {
781 SAL_WARN("basctl.basicide", "Unknown context menu action: " << sCommand );
782 }
783
784 return true;
785 }
786
UpdateFields()787 void MacroChooser::UpdateFields()
788 {
789 auto nMacroEntry = m_xMacroBox->get_selected_index();
790 m_xMacroNameEdit->set_text("");
791 if (nMacroEntry != -1)
792 m_xMacroNameEdit->set_text(m_xMacroBox->get_text(nMacroEntry));
793 }
794
SetMode(Mode nM)795 void MacroChooser::SetMode (Mode nM)
796 {
797 nMode = nM;
798 switch (nMode)
799 {
800 case All:
801 {
802 m_xRunButton->set_label(IDEResId(RID_STR_RUN));
803 EnableButton(*m_xDelButton, true);
804 EnableButton(*m_xNewButton, true);
805 EnableButton(*m_xOrganizeButton, true);
806 break;
807 }
808
809 case ChooseOnly:
810 {
811 m_xRunButton->set_label(IDEResId(RID_STR_CHOOSE));
812 EnableButton(*m_xDelButton, false);
813 EnableButton(*m_xNewButton, false);
814 EnableButton(*m_xOrganizeButton, false);
815 break;
816 }
817
818 case Recording:
819 {
820 m_xRunButton->set_label(IDEResId(RID_STR_RECORD));
821 EnableButton(*m_xDelButton, false);
822 EnableButton(*m_xNewButton, false);
823 EnableButton(*m_xOrganizeButton, false);
824
825 m_xAssignButton->hide();
826 m_xEditButton->hide();
827 m_xDelButton->hide();
828 m_xNewButton->hide();
829 m_xOrganizeButton->hide();
830 m_xMacroFromTxT->hide();
831
832 m_xNewLibButton->show();
833 m_xNewModButton->show();
834 m_xMacrosSaveInTxt->show();
835
836 break;
837 }
838 }
839 CheckButtons();
840 }
841
GetInfo(SbxVariable * pVar)842 OUString MacroChooser::GetInfo( SbxVariable* pVar )
843 {
844 OUString aComment;
845 SbxInfoRef xInfo = pVar->GetInfo();
846 if ( xInfo.is() )
847 aComment = xInfo->GetComment();
848 return aComment;
849 }
850
851
852 } // namespace basctl
853
854 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
855