Coverage Report

Created: 2026-06-30 11:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/source/ui/app/inputwin.cxx
Line
Count
Source
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
#include <memory>
21
#include <algorithm>
22
#include <string_view>
23
24
#include <editeng/eeitem.hxx>
25
26
#include <sfx2/app.hxx>
27
#include <sfx2/chalign.hxx>
28
#include <editeng/adjustitem.hxx>
29
#include <editeng/editview.hxx>
30
#include <editeng/editstat.hxx>
31
#include <editeng/lspcitem.hxx>
32
#include <editeng/fhgtitem.hxx>
33
#include <editeng/wghtitem.hxx>
34
#include <editeng/postitem.hxx>
35
#include <editeng/langitem.hxx>
36
#include <sfx2/bindings.hxx>
37
#include <sfx2/viewfrm.hxx>
38
#include <sfx2/dispatch.hxx>
39
#include <sfx2/event.hxx>
40
#include <editeng/scriptspaceitem.hxx>
41
#include <vcl/commandevent.hxx>
42
#include <vcl/cursor.hxx>
43
#include <vcl/help.hxx>
44
#include <vcl/image.hxx>
45
#include <vcl/ptrstyle.hxx>
46
#include <vcl/settings.hxx>
47
#include <svl/stritem.hxx>
48
#include <vcl/svapp.hxx>
49
#include <vcl/weld/Menu.hxx>
50
#include <vcl/weld/Window.hxx>
51
#include <vcl/weld/weldutils.hxx>
52
#include <unotools/charclass.hxx>
53
54
#include <inputwin.hxx>
55
#include <scmod.hxx>
56
#include <global.hxx>
57
#include <scresid.hxx>
58
#include <strings.hrc>
59
#include <globstr.hrc>
60
#include <bitmaps.hlst>
61
#include <reffact.hxx>
62
#include <editutil.hxx>
63
#include <inputhdl.hxx>
64
#include <tabvwsh.hxx>
65
#include <document.hxx>
66
#include <docsh.hxx>
67
#include <appoptio.hxx>
68
#include <rangenam.hxx>
69
#include <rangeutl.hxx>
70
#include <docfunc.hxx>
71
#include <funcdesc.hxx>
72
#include <editeng/fontitem.hxx>
73
#include <AccessibleEditObject.hxx>
74
#include <AccessibleText.hxx>
75
#include <comphelper/lok.hxx>
76
#include <comphelper/string.hxx>
77
#include <com/sun/star/frame/XLayoutManager.hpp>
78
#include <helpids.h>
79
#include <output.hxx>
80
81
namespace com::sun::star::accessibility { class XAccessible; }
82
83
const tools::Long THESIZE = 1000000;            // Should be more than enough!
84
const tools::Long INPUTLINE_INSET_MARGIN = 2;   // Space between border and interior widgets of input line
85
const tools::Long LEFT_OFFSET = 5;              // Left offset of input line
86
//TODO const long BUTTON_OFFSET = 2;            // Space between input line and button to expand/collapse
87
const tools::Long INPUTWIN_MULTILINES = 6;      // Initial number of lines within multiline dropdown
88
const tools::Long TOOLBOX_WINDOW_HEIGHT = 22;   // Height of toolbox window in pixels - TODO: The same on all systems?
89
const tools::Long POSITION_COMBOBOX_WIDTH = 18; // Width of position combobox in characters
90
const int RESIZE_HOTSPOT_HEIGHT = 4;
91
92
using com::sun::star::uno::Reference;
93
using com::sun::star::uno::UNO_QUERY;
94
95
using com::sun::star::frame::XLayoutManager;
96
using com::sun::star::beans::XPropertySet;
97
98
namespace {
99
100
constexpr ToolBoxItemId SID_INPUT_FUNCTION (SC_VIEW_START + 47);
101
constexpr ToolBoxItemId SID_INPUT_SUM     (SC_VIEW_START + 48);
102
constexpr ToolBoxItemId SID_INPUT_EQUAL   (SC_VIEW_START + 49);
103
constexpr ToolBoxItemId SID_INPUT_CANCEL  (SC_VIEW_START + 50);
104
constexpr ToolBoxItemId SID_INPUT_OK      (SC_VIEW_START + 51);
105
106
enum ScNameInputType
107
{
108
    SC_NAME_INPUT_CELL,
109
    SC_NAME_INPUT_RANGE,
110
    SC_NAME_INPUT_NAMEDRANGE_LOCAL,
111
    SC_NAME_INPUT_NAMEDRANGE_GLOBAL,
112
    SC_NAME_INPUT_DATABASE,
113
    SC_NAME_INPUT_ROW,
114
    SC_NAME_INPUT_SHEET,
115
    SC_NAME_INPUT_DEFINE,
116
    SC_NAME_INPUT_BAD_NAME,
117
    SC_NAME_INPUT_BAD_SELECTION,
118
    SC_MANAGE_NAMES
119
};
120
121
}
122
123
SFX_IMPL_CHILDWINDOW_WITHID(ScInputWindowWrapper,FID_INPUTLINE_STATUS)
124
125
ScInputWindowWrapper::ScInputWindowWrapper( vcl::Window*          pParentP,
126
                                            sal_uInt16           nId,
127
                                            SfxBindings*     pBindings,
128
                                            SfxChildWinInfo* /* pInfo */ )
129
0
    :   SfxChildWindow( pParentP, nId )
130
0
{
131
0
    VclPtr<ScInputWindow> pWin = VclPtr<ScInputWindow>::Create( pParentP, pBindings );
132
0
    SetWindow( pWin );
133
134
0
    pWin->Show();
135
136
0
    pWin->SetSizePixel( pWin->CalcWindowSizePixel() );
137
138
0
    SetAlignment(SfxChildAlignment::LOWESTTOP);
139
0
    pBindings->Invalidate( FID_TOGGLEINPUTLINE );
140
0
}
141
142
/**
143
 * GetInfo is disposed of if there's a SFX_IMPL_TOOLBOX!
144
 */
145
SfxChildWinInfo ScInputWindowWrapper::GetInfo() const
146
0
{
147
0
    SfxChildWinInfo aInfo = SfxChildWindow::GetInfo();
148
0
    return aInfo;
149
0
}
150
151
152
static ScTabViewShell* lcl_chooseRuntimeImpl( const SfxBindings* pBind )
153
0
{
154
0
    ScTabViewShell* pViewSh = nullptr;
155
0
    SfxDispatcher* pDisp = pBind->GetDispatcher();
156
0
    if ( pDisp )
157
0
    {
158
0
        SfxViewFrame* pViewFrm = pDisp->GetFrame();
159
0
        if ( pViewFrm )
160
0
            pViewSh = dynamic_cast<ScTabViewShell*>( pViewFrm->GetViewShell()  );
161
0
    }
162
0
    return pViewSh;
163
0
}
164
165
ScInputWindow::ScInputWindow( vcl::Window* pParent, const SfxBindings* pBind ) :
166
        // With WB_CLIPCHILDREN otherwise we get flickering
167
0
        ToolBox         ( pParent, WinBits(WB_CLIPCHILDREN | WB_BORDER | WB_NOSHADOW) ),
168
0
        aWndPos(VclPtr<ScPosWnd>::Create(this)),
169
0
        mxTextWindow    ( VclPtr<ScInputBarGroup>::Create( this, lcl_chooseRuntimeImpl(pBind)) ),
170
0
        pInputHdl       ( nullptr ),
171
0
        mpViewShell     ( nullptr ),
172
0
        mnMaxY          (0),
173
0
        mnStandardItemHeight(0),
174
0
        bIsOkCancelMode ( false ),
175
0
        bInResize       ( false )
176
0
{
177
    // #i73615# don't rely on SfxViewShell::Current while constructing the input line
178
    // (also for GetInputHdl below)
179
0
    ScTabViewShell* pViewSh = nullptr;
180
0
    SfxDispatcher* pDisp = pBind->GetDispatcher();
181
0
    if ( pDisp )
182
0
    {
183
0
        SfxViewFrame* pViewFrm = pDisp->GetFrame();
184
0
        if ( pViewFrm )
185
0
            pViewSh = dynamic_cast<ScTabViewShell*>( pViewFrm->GetViewShell()  );
186
0
    }
187
0
    OSL_ENSURE( pViewSh, "no view shell for input window" );
188
189
0
    mpViewShell = pViewSh;
190
191
    // Position window, 3 buttons, input window
192
0
    if (!comphelper::LibreOfficeKit::isActive())
193
0
    {
194
0
        InsertWindow    (ToolBoxItemId(1), aWndPos.get(), ToolBoxItemBits::NONE, 0);
195
0
        InsertSeparator (1);
196
0
        InsertItem      (SID_INPUT_FUNCTION, Image(StockImage::Yes, RID_BMP_INPUT_FUNCTION), ToolBoxItemBits::NONE, 2);
197
0
    }
198
199
    // sigma and equal buttons
200
0
    {
201
0
        InsertItem      (SID_INPUT_SUM,      Image(StockImage::Yes, RID_BMP_INPUT_SUM), ToolBoxItemBits::DROPDOWN, 3);
202
0
        InsertItem      (SID_INPUT_EQUAL,    Image(StockImage::Yes, RID_BMP_INPUT_EQUAL), ToolBoxItemBits::NONE, 4);
203
0
        InsertItem      (SID_INPUT_CANCEL,   Image(StockImage::Yes, RID_BMP_INPUT_CANCEL), ToolBoxItemBits::NONE, 5);
204
0
        InsertItem      (SID_INPUT_OK,       Image(StockImage::Yes, RID_BMP_INPUT_OK), ToolBoxItemBits::NONE, 6);
205
0
    }
206
207
0
    InsertWindow    (ToolBoxItemId(7), mxTextWindow.get(), ToolBoxItemBits::NONE, 7);
208
0
    SetDropdownClickHdl( LINK( this, ScInputWindow, DropdownClickHdl ));
209
210
0
    if (!comphelper::LibreOfficeKit::isActive())
211
0
    {
212
0
        aWndPos   ->SetQuickHelpText(ScResId(SCSTR_QHELP_POSWND));
213
0
        aWndPos   ->SetHelpId       (HID_INSWIN_POS);
214
215
0
        mxTextWindow->SetQuickHelpText(ScResId(SCSTR_QHELP_INPUTWND));
216
0
        mxTextWindow->SetHelpId       (HID_INSWIN_INPUT);
217
218
        // No SetHelpText: the helptexts come from the Help
219
0
        SetItemText (SID_INPUT_FUNCTION, ScResId(SCSTR_QHELP_BTNCALC));
220
0
        SetHelpId   (SID_INPUT_FUNCTION, HID_INSWIN_CALC);
221
0
    }
222
223
    // sigma and equal buttons
224
0
    {
225
0
        SetHelpId   (SID_INPUT_SUM, HID_INSWIN_SUM);
226
0
        SetHelpId   (SID_INPUT_EQUAL, HID_INSWIN_FUNC);
227
0
        SetHelpId   (SID_INPUT_CANCEL, HID_INSWIN_CANCEL);
228
0
        SetHelpId   (SID_INPUT_OK, HID_INSWIN_OK);
229
230
0
        if (!comphelper::LibreOfficeKit::isActive())
231
0
        {
232
0
            SetItemText ( SID_INPUT_SUM, ScResId( SCSTR_QHELP_BTNSUM ) );
233
0
            SetItemText ( SID_INPUT_EQUAL, ScResId( SCSTR_QHELP_BTNEQUAL ) );
234
0
            SetItemText ( SID_INPUT_CANCEL, ScResId( SCSTR_QHELP_BTNCANCEL ) );
235
0
            SetItemText ( SID_INPUT_OK, ScResId( SCSTR_QHELP_BTNOK ) );
236
0
        }
237
238
0
        EnableItem( SID_INPUT_CANCEL, false );
239
0
        EnableItem( SID_INPUT_OK, false );
240
241
0
        HideItem( SID_INPUT_CANCEL );
242
0
        HideItem( SID_INPUT_OK );
243
244
0
        mnStandardItemHeight = GetItemRect(SID_INPUT_SUM).GetHeight();
245
0
    }
246
247
0
    SetHelpId( HID_SC_INPUTWIN ); // For the whole input row
248
249
0
    if (!comphelper::LibreOfficeKit::isActive())
250
0
        aWndPos   ->Show();
251
0
    mxTextWindow->Show();
252
253
0
    pInputHdl = ScModule::get()->GetInputHdl( pViewSh, false ); // use own handler even if ref-handler is set
254
0
    if (pInputHdl)
255
0
        pInputHdl->SetInputWindow( this );
256
257
0
    if (pInputHdl && !pInputHdl->GetFormString().isEmpty())
258
0
    {
259
        // Switch over while the Function AutoPilot is active
260
        // -> show content of the Function AutoPilot again
261
        // Also show selection (remember at the InputHdl)
262
0
        mxTextWindow->SetTextString(pInputHdl->GetFormString(), true);
263
0
    }
264
0
    else if (pInputHdl && pInputHdl->IsInputMode())
265
0
    {
266
        // If the input row was hidden while editing (e.g. when editing a formula
267
        // and then switching to another document or the help), display the text
268
        // we just edited from the InputHandler
269
0
        mxTextWindow->SetTextString(pInputHdl->GetEditString(), true); // Display text
270
0
        if ( pInputHdl->IsTopMode() )
271
0
            pInputHdl->SetMode( SC_INPUT_TABLE ); // Focus ends up at the bottom anyways
272
0
    }
273
0
    else if (pViewSh)
274
0
    {
275
        // Don't stop editing in LOK a remote user might be editing.
276
0
        const bool bStopEditing = !comphelper::LibreOfficeKit::isActive();
277
0
        pViewSh->UpdateInputHandler(true, bStopEditing); // Absolutely necessary update
278
0
    }
279
280
0
    SetToolbarLayoutMode( ToolBoxLayoutMode::Locked );
281
282
0
    SetAccessibleName(ScResId(STR_ACC_TOOLBAR_FORMULA));
283
0
}
Unexecuted instantiation: ScInputWindow::ScInputWindow(vcl::Window*, SfxBindings const*)
Unexecuted instantiation: ScInputWindow::ScInputWindow(vcl::Window*, SfxBindings const*)
284
285
ScInputWindow::~ScInputWindow()
286
0
{
287
0
    disposeOnce();
288
0
}
289
290
void ScInputWindow::dispose()
291
0
{
292
0
    bool bDown = !ScGlobal::oSysLocale; // after Clear?
293
294
    //  if any view's input handler has a pointer to this input window, reset it
295
    //  (may be several ones, #74522#)
296
    //  member pInputHdl is not used here
297
298
0
    if ( !bDown )
299
0
    {
300
0
        SfxViewShell* pSh = SfxViewShell::GetFirst( true, checkSfxViewShell<ScTabViewShell> );
301
0
        while ( pSh )
302
0
        {
303
0
            ScInputHandler* pHdl = static_cast<ScTabViewShell*>(pSh)->GetInputHandler();
304
0
            if ( pHdl && pHdl->GetInputWindow() == this )
305
0
            {
306
0
                pHdl->SetInputWindow( nullptr );
307
0
                pHdl->StopInputWinEngine( false );  // reset pTopView pointer
308
0
            }
309
0
            pSh = SfxViewShell::GetNext( *pSh, true, checkSfxViewShell<ScTabViewShell> );
310
0
        }
311
0
    }
312
313
0
    if (comphelper::LibreOfficeKit::isActive())
314
0
    {
315
0
        if (GetLOKNotifier())
316
0
            ReleaseLOKNotifier();
317
0
    }
318
319
0
    mxTextWindow.disposeAndClear();
320
0
    aWndPos.disposeAndClear();
321
322
0
    ToolBox::dispose();
323
0
}
324
325
void ScInputWindow::SetInputHandler( ScInputHandler* pNew )
326
0
{
327
    //  Is called in the Activate of the View ...
328
0
    if ( pNew != pInputHdl )
329
0
    {
330
        // On Reload (last version) the pInputHdl is the InputHandler of the old, deleted
331
        // ViewShell: so don't touch it here!
332
0
        pInputHdl = pNew;
333
0
        if (pInputHdl)
334
0
            pInputHdl->SetInputWindow( this );
335
0
    }
336
0
}
337
338
void ScInputWindow::Select()
339
0
{
340
0
    ScModule* pScMod = ScModule::get();
341
0
    ToolBox::Select();
342
343
0
    ToolBoxItemId curItemId = GetCurItemId();
344
0
    if (curItemId == SID_INPUT_FUNCTION)
345
0
    {
346
        //! new method at ScModule to query if function autopilot is open
347
0
        SfxViewFrame* pViewFrm = SfxViewFrame::Current();
348
0
        if ( pViewFrm && ( comphelper::LibreOfficeKit::isActive() || !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) ) )
349
0
        {
350
0
            pViewFrm->GetDispatcher()->Execute( SID_OPENDLG_FUNCTION,
351
0
                                        SfxCallMode::SYNCHRON | SfxCallMode::RECORD );
352
353
            // The Toolbox will be disabled anyways, so we don't need to switch here,
354
            // regardless whether it succeeded or not!
355
//                  SetOkCancelMode();
356
0
        }
357
0
    }
358
0
    else if (curItemId == SID_INPUT_CANCEL)
359
0
    {
360
0
        pScMod->InputCancelHandler();
361
0
        SetSumAssignMode();
362
0
    }
363
0
    else if (curItemId == SID_INPUT_OK)
364
0
    {
365
0
        pScMod->InputEnterHandler();
366
0
        SetSumAssignMode();
367
0
        mxTextWindow->Invalidate(); // Or else the Selection remains
368
0
    }
369
0
    else if (curItemId == SID_INPUT_SUM)
370
0
    {
371
0
        bool bRangeFinder = false;
372
0
        bool bSubTotal = false;
373
0
        AutoSum(bRangeFinder, bSubTotal, ocSum);
374
0
    }
375
0
    else if (curItemId == SID_INPUT_EQUAL)
376
0
    {
377
0
        StartFormula();
378
0
    }
379
0
}
380
381
void ScInputWindow::StartFormula()
382
0
{
383
0
    ScModule* pScMod = ScModule::get();
384
0
    mxTextWindow->StartEditEngine(ScInputHandler::ErrorMessage);
385
0
    if ( pScMod->IsEditMode() ) // Isn't if e.g. protected
386
0
    {
387
0
        mxTextWindow->StartEditEngine(ScInputHandler::ErrorMessage);
388
389
0
        sal_Int32 nStartPos = 1;
390
0
        sal_Int32 nEndPos = 1;
391
392
0
        ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current()  );
393
0
        if ( pViewSh )
394
0
        {
395
0
            const OUString& rString = mxTextWindow->GetTextString();
396
0
            const sal_Int32 nLen = rString.getLength();
397
398
0
            ScDocument& rDoc = pViewSh->GetViewData().GetDocument();
399
0
            CellType eCellType = rDoc.GetCellType( pViewSh->GetViewData().GetCurPos() );
400
0
            switch ( eCellType )
401
0
            {
402
0
                case CELLTYPE_VALUE:
403
0
                {
404
0
                    nEndPos = nLen + 1;
405
0
                    mxTextWindow->SetTextString("=" +  rString, true);
406
0
                    break;
407
0
                }
408
0
                case CELLTYPE_STRING:
409
0
                case CELLTYPE_EDIT:
410
0
                    nStartPos = 0;
411
0
                    nEndPos = nLen;
412
0
                    break;
413
0
                case CELLTYPE_FORMULA:
414
0
                    nEndPos = nLen;
415
0
                    break;
416
0
                default:
417
0
                    mxTextWindow->SetTextString(u"="_ustr, true);
418
0
                    break;
419
0
            }
420
0
        }
421
422
0
        EditView* pView = mxTextWindow->GetEditView();
423
0
        if (pView)
424
0
        {
425
0
            sal_Int32 nStartPara = 0, nEndPara = 0;
426
0
            if (comphelper::LibreOfficeKit::isActive())
427
0
            {
428
0
                TextGrabFocus();
429
0
            }
430
0
            pView->SetSelection(ESelection(nStartPara, nStartPos, nEndPara, nEndPos));
431
0
            pScMod->InputChanged(pView);
432
0
            SetOkCancelMode();
433
0
            pView->SetEditEngineUpdateLayout(true);
434
0
        }
435
0
    }
436
0
}
437
438
void ScInputWindow::PixelInvalidate(const tools::Rectangle* pRectangle)
439
0
{
440
0
    if (comphelper::LibreOfficeKit::isDialogPainting() || !comphelper::LibreOfficeKit::isActive())
441
0
        return;
442
443
0
    if (pRectangle)
444
0
    {
445
0
        tools::Rectangle aRect(*pRectangle);
446
0
        aRect.Move(-GetOutOffXPixel(), -GetOutOffYPixel());
447
0
        Window::PixelInvalidate(&aRect);
448
0
    }
449
0
    else
450
0
    {
451
0
        Window::PixelInvalidate(nullptr);
452
0
    }
453
0
}
454
455
void ScInputWindow::SetSizePixel( const Size& rNewSize )
456
0
{
457
0
    const vcl::ILibreOfficeKitNotifier* pNotifier = GetLOKNotifier();
458
0
    if (pNotifier)
459
0
    {
460
0
        if (vcl::Window* pFrameWindowImpl = GetParent())
461
0
        {
462
0
            if (vcl::Window* pWorkWindow = pFrameWindowImpl->GetParent())
463
0
            {
464
0
                if (vcl::Window* pImplBorderWindow = pWorkWindow->GetParent())
465
0
                {
466
0
                    Size aSize = pImplBorderWindow->GetSizePixel();
467
0
                    aSize.setWidth(rNewSize.getWidth());
468
0
                    pImplBorderWindow->SetSizePixel(aSize);
469
0
                }
470
0
            }
471
0
        }
472
0
    }
473
474
0
    ToolBox::SetSizePixel(rNewSize);
475
0
}
476
477
void ScInputWindow::Resize()
478
0
{
479
0
    ToolBox::Resize();
480
481
0
    Size aStartSize = GetSizePixel();
482
0
    Size aSize = aStartSize;
483
484
0
    auto nLines = mxTextWindow->GetNumLines();
485
    //(-10) to allow margin between sidebar and formulabar
486
0
    tools::Long margin = (comphelper::LibreOfficeKit::isActive()) ? 10 : 0;
487
0
    Size aTextWindowSize(aSize.Width() - mxTextWindow->GetPosPixel().X() - LEFT_OFFSET - margin,
488
0
                         mxTextWindow->GetPixelHeightForLines(nLines));
489
0
    mxTextWindow->SetSizePixel(aTextWindowSize);
490
491
0
    int nTopOffset = 0;
492
0
    if (nLines > 1)
493
0
    {
494
        // Initially there is 1 line and the edit is vertically centered in the toolbar
495
        // Later, if expanded then the vertical position of the edit will remain at
496
        // that initial position, so when calculating the overall size of the expanded
497
        // toolbar we have to include that initial offset in order to not make
498
        // the edit overlap the RESIZE_HOTSPOT_HEIGHT area so that dragging to resize
499
        // is still possible.
500
0
        int nNormalHeight = mxTextWindow->GetPixelHeightForLines(1);
501
0
        int nInitialTopMargin = (mnStandardItemHeight - nNormalHeight) / 2;
502
0
        if (nInitialTopMargin > 0)
503
0
            nTopOffset = nInitialTopMargin;
504
0
    }
505
506
    // add empty space of RESIZE_HOTSPOT_HEIGHT so resize is possible when hovering there
507
0
    aSize.setHeight(CalcWindowSizePixel().Height() + RESIZE_HOTSPOT_HEIGHT + nTopOffset);
508
509
0
    if (aStartSize != aSize)
510
0
        SetSizePixel(aSize);
511
512
0
    Invalidate();
513
0
}
514
515
void ScInputWindow::NotifyLOKClient()
516
0
{
517
0
    if (comphelper::LibreOfficeKit::isActive() && !GetLOKNotifier() && mpViewShell)
518
0
        SetLOKNotifier(mpViewShell);
519
0
}
520
521
void ScInputWindow::SetFuncString( const OUString& rString, bool bDoEdit )
522
0
{
523
    //! new method at ScModule to query if function autopilot is open
524
0
    SfxViewFrame* pViewFrm = SfxViewFrame::Current();
525
0
    EnableButtons( pViewFrm && !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) );
526
0
    mxTextWindow->StartEditEngine(ScInputHandler::ErrorMessage);
527
528
0
    ScModule* pScMod = ScModule::get();
529
0
    if ( !pScMod->IsEditMode() )
530
0
        return;
531
532
0
    if ( bDoEdit )
533
0
        mxTextWindow->TextGrabFocus();
534
0
    mxTextWindow->SetTextString(rString, true);
535
0
    EditView* pView = mxTextWindow->GetEditView();
536
0
    if (!pView)
537
0
        return;
538
539
0
    sal_Int32 nLen = rString.getLength();
540
541
0
    if ( nLen > 0 )
542
0
    {
543
0
        nLen--;
544
0
        pView->SetSelection(ESelection(0, nLen));
545
0
    }
546
547
0
    pScMod->InputChanged(pView);
548
0
    if ( bDoEdit )
549
0
        SetOkCancelMode(); // Not the case if immediately followed by Enter/Cancel
550
551
0
    pView->SetEditEngineUpdateLayout(true);
552
0
}
553
554
void ScInputWindow::SetPosString( const OUString& rStr )
555
0
{
556
0
    aWndPos->SetPos( rStr );
557
0
}
558
559
void ScInputWindow::SetTextString( const OUString& rString, bool bKitUpdate )
560
0
{
561
0
    if (rString.getLength() <= 32767)
562
0
        mxTextWindow->SetTextString(rString, bKitUpdate);
563
0
    else
564
0
        mxTextWindow->SetTextString(rString.copy(0, 32767), bKitUpdate);
565
0
}
566
567
void ScInputWindow::SetOkCancelMode()
568
0
{
569
    //! new method at ScModule to query if function autopilot is open
570
0
    SfxViewFrame* pViewFrm = SfxViewFrame::Current();
571
0
    EnableButtons( pViewFrm && !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) );
572
573
0
    if (bIsOkCancelMode)
574
0
        return;
575
576
0
    EnableItem  ( SID_INPUT_SUM,   false );
577
0
    EnableItem  ( SID_INPUT_EQUAL, false );
578
0
    HideItem    ( SID_INPUT_SUM );
579
0
    HideItem    ( SID_INPUT_EQUAL );
580
581
0
    ShowItem    ( SID_INPUT_CANCEL, true );
582
0
    ShowItem    ( SID_INPUT_OK,     true );
583
0
    EnableItem  ( SID_INPUT_CANCEL, true );
584
0
    EnableItem  ( SID_INPUT_OK,     true );
585
586
0
    bIsOkCancelMode = true;
587
0
}
588
589
void ScInputWindow::SetSumAssignMode()
590
0
{
591
    //! new method at ScModule to query if function autopilot is open
592
0
    SfxViewFrame* pViewFrm = SfxViewFrame::Current();
593
0
    EnableButtons( pViewFrm && !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) );
594
595
0
    if (!bIsOkCancelMode)
596
0
        return;
597
598
0
    EnableItem  ( SID_INPUT_CANCEL, false );
599
0
    EnableItem  ( SID_INPUT_OK,     false );
600
0
    HideItem    ( SID_INPUT_CANCEL );
601
0
    HideItem    ( SID_INPUT_OK );
602
603
0
    ShowItem    ( SID_INPUT_SUM,    true );
604
0
    ShowItem    ( SID_INPUT_EQUAL,  true );
605
0
    EnableItem  ( SID_INPUT_SUM,    true );
606
0
    EnableItem  ( SID_INPUT_EQUAL,  true );
607
608
0
    bIsOkCancelMode = false;
609
610
0
    SetFormulaMode(false); // No editing -> no formula
611
0
}
612
613
void ScInputWindow::SetFormulaMode( bool bSet )
614
0
{
615
0
    if (!comphelper::LibreOfficeKit::isActive())
616
0
        aWndPos->SetFormulaMode(bSet);
617
0
    mxTextWindow->SetFormulaMode(bSet);
618
0
}
619
620
bool ScInputWindow::IsInputActive()
621
0
{
622
0
    return mxTextWindow->IsInputActive();
623
0
}
624
625
EditView* ScInputWindow::GetEditView()
626
0
{
627
0
    return mxTextWindow->GetEditView();
628
0
}
629
630
vcl::Window* ScInputWindow::GetEditWindow()
631
0
{
632
0
    return mxTextWindow;
633
0
}
634
635
Point ScInputWindow::GetCursorScreenPixelPos(bool bBelow)
636
0
{
637
0
    return mxTextWindow->GetCursorScreenPixelPos(bBelow);
638
0
}
639
640
void ScInputWindow::MakeDialogEditView()
641
0
{
642
0
    mxTextWindow->MakeDialogEditView();
643
0
}
644
645
void ScInputWindow::StopEditEngine( bool bAll )
646
0
{
647
0
    mxTextWindow->StopEditEngine( bAll );
648
0
}
649
650
void ScInputWindow::TextGrabFocus()
651
0
{
652
0
    mxTextWindow->TextGrabFocus();
653
0
}
654
655
void ScInputWindow::TextInvalidate()
656
0
{
657
0
    mxTextWindow->Invalidate();
658
0
}
659
660
void ScInputWindow::SwitchToTextWin()
661
0
{
662
    // used for shift-ctrl-F2
663
664
0
    mxTextWindow->StartEditEngine(ScInputHandler::ErrorMessage);
665
0
    if (ScModule::get()->IsEditMode())
666
0
    {
667
0
        mxTextWindow->TextGrabFocus();
668
0
        EditView* pView = mxTextWindow->GetEditView();
669
0
        if (pView)
670
0
        {
671
0
            pView->SetSelection(ESelection::AtEnd()); // set cursor to end of text
672
0
        }
673
0
    }
674
0
}
675
676
void ScInputWindow::PosGrabFocus()
677
0
{
678
0
    if (!comphelper::LibreOfficeKit::isActive())
679
0
        aWndPos->GrabFocus();
680
0
}
681
682
void ScInputWindow::EnableButtons( bool bEnable )
683
0
{
684
    //  when enabling buttons, always also enable the input window itself
685
0
    if ( bEnable && !IsEnabled() )
686
0
        Enable();
687
688
0
    EnableItem( SID_INPUT_FUNCTION,                                   bEnable );
689
0
    EnableItem( bIsOkCancelMode ? SID_INPUT_CANCEL : SID_INPUT_SUM,   bEnable );
690
0
    EnableItem( bIsOkCancelMode ? SID_INPUT_OK     : SID_INPUT_EQUAL, bEnable );
691
//  Invalidate();
692
0
}
693
694
void ScInputWindow::NumLinesChanged()
695
0
{
696
0
    mxTextWindow->NumLinesChanged();
697
0
}
698
699
void ScInputWindow::StateChanged( StateChangedType nType )
700
0
{
701
0
    ToolBox::StateChanged( nType );
702
703
0
    if ( nType == StateChangedType::InitShow ) Resize();
704
0
}
705
706
void ScInputWindow::DataChanged( const DataChangedEvent& rDCEvt )
707
0
{
708
0
    if ( rDCEvt.GetType() == DataChangedEventType::SETTINGS && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
709
0
    {
710
        //  update item images
711
0
        SetItemImage(SID_INPUT_FUNCTION, Image(StockImage::Yes, RID_BMP_INPUT_FUNCTION));
712
0
        if ( bIsOkCancelMode )
713
0
        {
714
0
            SetItemImage(SID_INPUT_CANCEL, Image(StockImage::Yes, RID_BMP_INPUT_CANCEL));
715
0
            SetItemImage(SID_INPUT_OK,     Image(StockImage::Yes, RID_BMP_INPUT_OK));
716
0
        }
717
0
        else
718
0
        {
719
0
            SetItemImage(SID_INPUT_SUM,   Image(StockImage::Yes, RID_BMP_INPUT_SUM));
720
0
            SetItemImage(SID_INPUT_EQUAL, Image(StockImage::Yes, RID_BMP_INPUT_EQUAL));
721
0
        }
722
0
    }
723
724
0
    ToolBox::DataChanged( rDCEvt );
725
0
}
726
727
bool ScInputWindow::IsPointerAtResizePos()
728
0
{
729
0
    return GetOutputSizePixel().Height() - GetPointerPosPixel().Y() <= RESIZE_HOTSPOT_HEIGHT;
730
0
}
731
732
void ScInputWindow::MouseMove( const MouseEvent& rMEvt )
733
0
{
734
0
    Point aPosPixel = GetPointerPosPixel();
735
736
0
    ScInputBarGroup* pGroupBar = mxTextWindow.get();
737
738
0
    if (bInResize || IsPointerAtResizePos())
739
0
        SetPointer(PointerStyle::WindowSSize);
740
0
    else
741
0
        SetPointer(PointerStyle::Arrow);
742
743
0
    if (bInResize)
744
0
    {
745
        // detect direction
746
0
        tools::Long nResizeThreshold = tools::Long(TOOLBOX_WINDOW_HEIGHT * 0.7);
747
0
        bool bResetPointerPos = false;
748
749
        // Detect attempt to expand toolbar too much
750
0
        if (aPosPixel.Y() >= mnMaxY)
751
0
        {
752
0
            bResetPointerPos = true;
753
0
            aPosPixel.setY( mnMaxY );
754
0
        } // or expanding down
755
0
        else if (GetOutputSizePixel().Height() - aPosPixel.Y() < -nResizeThreshold)
756
0
        {
757
0
            pGroupBar->IncrementVerticalSize();
758
0
            bResetPointerPos = true;
759
0
        } // or shrinking up
760
0
        else if ((GetOutputSizePixel().Height() - aPosPixel.Y()) > nResizeThreshold)
761
0
        {
762
0
            bResetPointerPos = true;
763
0
            pGroupBar->DecrementVerticalSize();
764
0
        }
765
766
0
        if (bResetPointerPos)
767
0
        {
768
0
            aPosPixel.setY(  GetOutputSizePixel().Height() );
769
0
            SetPointerPosPixel(aPosPixel);
770
0
        }
771
0
    }
772
773
0
    ToolBox::MouseMove(rMEvt);
774
0
}
775
776
void ScInputWindow::MouseButtonDown( const MouseEvent& rMEvt )
777
0
{
778
0
    if (rMEvt.IsLeft())
779
0
    {
780
0
        if (IsPointerAtResizePos())
781
0
        {
782
            // Don't leave the mouse pointer leave *this* window
783
0
            CaptureMouse();
784
0
            bInResize = true;
785
786
            // find the height of the gridwin, we don't want to be
787
            // able to expand the toolbar too far so we need to
788
            // calculate an upper limit
789
            // I'd prefer to leave at least a single column header and a
790
            // row but I don't know how to get that value in pixels.
791
            // Use TOOLBOX_WINDOW_HEIGHT for the moment
792
0
            if (ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell())
793
0
            {
794
0
                mnMaxY = GetOutputSizePixel().Height() + (pViewSh->GetGridHeight(SC_SPLIT_TOP)
795
0
                       + pViewSh->GetGridHeight(SC_SPLIT_BOTTOM)) - TOOLBOX_WINDOW_HEIGHT;
796
0
            }
797
0
        }
798
0
    }
799
800
0
    ToolBox::MouseButtonDown( rMEvt );
801
0
}
802
void ScInputWindow::MouseButtonUp( const MouseEvent& rMEvt )
803
0
{
804
0
    ReleaseMouse();
805
0
    if ( rMEvt.IsLeft() )
806
0
    {
807
0
        bInResize = false;
808
0
        mnMaxY = 0;
809
0
    }
810
811
0
    ToolBox::MouseButtonUp( rMEvt );
812
0
}
813
814
void ScInputWindow::AutoSum( bool& bRangeFinder, bool& bSubTotal, OpCode eCode )
815
0
{
816
0
    ScModule* pScMod = ScModule::get();
817
0
    ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current()  );
818
0
    if ( !pViewSh )
819
0
        return;
820
821
0
    const OUString aFormula = pViewSh->DoAutoSum(bRangeFinder, bSubTotal, eCode);
822
0
    if ( aFormula.isEmpty() )
823
0
        return;
824
825
0
    SetFuncString( aFormula );
826
0
    const sal_Int32 aOpen = aFormula.indexOf('(');
827
0
    const sal_Int32 aLen  = aFormula.getLength();
828
0
    if (!(bRangeFinder && pScMod->IsEditMode()))
829
0
        return;
830
831
0
    ScInputHandler* pHdl = pScMod->GetInputHdl( pViewSh );
832
0
    if ( !pHdl )
833
0
        return;
834
835
0
    pHdl->InitRangeFinder( aFormula );
836
837
    //! SetSelection at the InputHandler?
838
    //! Set bSelIsRef?
839
0
    if ( aOpen != -1 && aLen > aOpen )
840
0
    {
841
0
        ESelection aSel( 0, aOpen + (bSubTotal ? 3 : 1), 0, aLen-1 );
842
0
        EditView* pTableView = pHdl->GetTableView();
843
0
        if ( pTableView )
844
0
            pTableView->SetSelection( aSel );
845
0
        EditView* pTopView = pHdl->GetTopView();
846
0
        if ( pTopView )
847
0
            pTopView->SetSelection( aSel );
848
0
    }
849
0
}
850
851
ScInputBarGroup::ScInputBarGroup(vcl::Window* pParent, ScTabViewShell* pViewSh)
852
0
    : InterimItemWindow(pParent, u"modules/scalc/ui/inputbar.ui"_ustr, u"InputBar"_ustr, true)
853
0
    , mxBackground(m_xBuilder->weld_container(u"background"_ustr))
854
0
    , mxTextWndGroup(new ScTextWndGroup(*this, pViewSh))
855
0
    , mxButtonUp(m_xBuilder->weld_button(u"up"_ustr))
856
0
    , mxButtonDown(m_xBuilder->weld_button(u"down"_ustr))
857
0
{
858
0
    InitControlBase(m_xContainer.get());
859
860
0
    SetPaintTransparent(false);
861
0
    SetBackgrounds();
862
863
0
    mxButtonUp->connect_clicked(LINK(this, ScInputBarGroup, ClickHdl));
864
0
    mxButtonDown->connect_clicked(LINK(this, ScInputBarGroup, ClickHdl));
865
866
0
    if (!comphelper::LibreOfficeKit::isActive())
867
0
    {
868
0
        mxButtonUp->set_tooltip_text(ScResId( SCSTR_QHELP_COLLAPSE_FORMULA));
869
0
        mxButtonDown->set_tooltip_text(ScResId(SCSTR_QHELP_EXPAND_FORMULA));
870
0
    }
871
872
0
    int nHeight = mxTextWndGroup->GetPixelHeightForLines(1);
873
0
    mxButtonUp->set_size_request(-1, nHeight);
874
0
    mxButtonDown->set_size_request(-1, nHeight);
875
876
0
    mxButtonDown->show();
877
878
    // tdf#154042 Use an initial height of one row so the Toolbar positions
879
    // this in the same place regardless of how many rows it eventually shows
880
0
    Size aSize(GetSizePixel().Width(), nHeight);
881
0
    SetSizePixel(aSize);
882
0
}
Unexecuted instantiation: ScInputBarGroup::ScInputBarGroup(vcl::Window*, ScTabViewShell*)
Unexecuted instantiation: ScInputBarGroup::ScInputBarGroup(vcl::Window*, ScTabViewShell*)
883
884
void ScInputBarGroup::SetBackgrounds()
885
0
{
886
0
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
887
0
    SetBackground(rStyleSettings.GetFaceColor());
888
    // match to bg used in ScTextWnd::SetDrawingArea to the margin area is drawn with the
889
    // same desired bg
890
0
    mxBackground->set_background(rStyleSettings.GetFieldColor());
891
0
}
892
893
void ScInputBarGroup::DataChanged(const DataChangedEvent& rDCEvt)
894
0
{
895
0
    InterimItemWindow::DataChanged(rDCEvt);
896
0
    if ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE))
897
0
    {
898
0
        SetBackgrounds();
899
0
        Invalidate();
900
0
    }
901
0
}
902
903
Point ScInputBarGroup::GetCursorScreenPixelPos(bool bBelow)
904
0
{
905
0
    return mxTextWndGroup->GetCursorScreenPixelPos(bBelow);
906
0
}
907
908
ScInputBarGroup::~ScInputBarGroup()
909
0
{
910
0
    disposeOnce();
911
0
}
912
913
void ScInputBarGroup::dispose()
914
0
{
915
0
    mxTextWndGroup.reset();
916
0
    mxButtonUp.reset();
917
0
    mxButtonDown.reset();
918
0
    mxBackground.reset();
919
0
    InterimItemWindow::dispose();
920
0
}
921
922
void ScInputBarGroup::InsertAccessibleTextData( ScAccessibleEditLineTextData& rTextData )
923
0
{
924
0
    mxTextWndGroup->InsertAccessibleTextData(rTextData);
925
0
}
926
927
void ScInputBarGroup::RemoveAccessibleTextData( ScAccessibleEditLineTextData& rTextData )
928
0
{
929
0
    mxTextWndGroup->RemoveAccessibleTextData(rTextData);
930
0
}
931
932
const OUString& ScInputBarGroup::GetTextString() const
933
0
{
934
0
    return mxTextWndGroup->GetTextString();
935
0
}
936
937
void ScInputBarGroup::SetTextString(const OUString& rString, bool bKitUpdate)
938
0
{
939
0
    mxTextWndGroup->SetTextString(rString, bKitUpdate);
940
0
}
941
942
void ScInputBarGroup::Resize()
943
0
{
944
0
    mxTextWndGroup->SetScrollPolicy();
945
0
    InterimItemWindow::Resize();
946
0
}
947
948
void ScInputBarGroup::StopEditEngine(bool bAll)
949
0
{
950
0
    mxTextWndGroup->StopEditEngine(bAll);
951
0
}
952
953
void ScInputBarGroup::StartEditEngine(const ErrorHdl& errorHdl)
954
0
{
955
0
    mxTextWndGroup->StartEditEngine(errorHdl);
956
0
}
957
958
void ScInputBarGroup::MakeDialogEditView()
959
0
{
960
0
    mxTextWndGroup->MakeDialogEditView();
961
0
}
962
963
EditView* ScInputBarGroup::GetEditView() const
964
0
{
965
0
    return mxTextWndGroup->GetEditView();
966
0
}
967
968
bool ScInputBarGroup::HasEditView() const
969
0
{
970
0
    return mxTextWndGroup->HasEditView();
971
0
}
972
973
bool ScInputBarGroup::IsInputActive()
974
0
{
975
0
    return mxTextWndGroup->IsInputActive();
976
0
}
977
978
void ScInputBarGroup::SetFormulaMode(bool bSet)
979
0
{
980
0
    mxTextWndGroup->SetFormulaMode(bSet);
981
0
}
982
983
void ScInputBarGroup::IncrementVerticalSize()
984
0
{
985
0
    mxTextWndGroup->SetNumLines(mxTextWndGroup->GetNumLines() + 1);
986
0
    TriggerToolboxLayout();
987
0
}
988
989
void ScInputBarGroup::DecrementVerticalSize()
990
0
{
991
0
    if (mxTextWndGroup->GetNumLines() > 1)
992
0
    {
993
0
        mxTextWndGroup->SetNumLines(mxTextWndGroup->GetNumLines() - 1);
994
0
        TriggerToolboxLayout();
995
0
    }
996
0
}
997
998
void ScInputWindow::MenuHdl(std::u16string_view command)
999
0
{
1000
0
    if (command.empty())
1001
0
        return;
1002
1003
0
    bool bSubTotal = false;
1004
0
    bool bRangeFinder = false;
1005
0
    OpCode eCode = ocSum;
1006
0
    if ( command ==  u"sum" )
1007
0
    {
1008
0
        eCode = ocSum;
1009
0
    }
1010
0
    else if ( command == u"average" )
1011
0
    {
1012
0
        eCode = ocAverage;
1013
0
    }
1014
0
    else if ( command == u"max" )
1015
0
    {
1016
0
        eCode = ocMax;
1017
0
    }
1018
0
    else if ( command == u"min" )
1019
0
    {
1020
0
        eCode = ocMin;
1021
0
    }
1022
0
    else if ( command == u"count" )
1023
0
    {
1024
0
        eCode = ocCount;
1025
0
    }
1026
0
    else if ( command == u"counta" )
1027
0
    {
1028
0
        eCode = ocCount2;
1029
0
    }
1030
0
    else if ( command == u"product" )
1031
0
    {
1032
0
        eCode = ocProduct;
1033
0
    }
1034
0
    else if (command == u"stdev")
1035
0
    {
1036
0
        eCode = ocStDev;
1037
0
    }
1038
0
    else if (command == u"stdevp")
1039
0
    {
1040
0
        eCode = ocStDevP;
1041
0
    }
1042
0
    else if (command == u"var")
1043
0
    {
1044
0
        eCode = ocVar;
1045
0
    }
1046
0
    else if (command == u"varp")
1047
0
    {
1048
0
        eCode = ocVarP;
1049
0
    }
1050
1051
0
    AutoSum( bRangeFinder, bSubTotal, eCode );
1052
0
}
1053
1054
IMPL_LINK_NOARG(ScInputWindow, DropdownClickHdl, ToolBox *, void)
1055
0
{
1056
0
    ToolBoxItemId nCurID = GetCurItemId();
1057
0
    EndSelection();
1058
1059
0
    if (nCurID == SID_INPUT_SUM)
1060
0
    {
1061
0
        tools::Rectangle aRect(GetItemRect(SID_INPUT_SUM));
1062
0
        weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);
1063
0
        std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, u"modules/scalc/ui/autosum.ui"_ustr));
1064
0
        std::unique_ptr<weld::Menu> xPopMenu(xBuilder->weld_menu(u"menu"_ustr));
1065
0
        MenuHdl(xPopMenu->popup_at_rect(pPopupParent, aRect));
1066
0
    }
1067
0
}
1068
1069
IMPL_LINK_NOARG(ScInputBarGroup, ClickHdl, weld::Button&, void)
1070
0
{
1071
0
    if (mxTextWndGroup->GetNumLines() > 1)
1072
0
        mxTextWndGroup->SetNumLines(1);
1073
0
    else
1074
0
        mxTextWndGroup->SetNumLines(mxTextWndGroup->GetLastNumExpandedLines());
1075
1076
0
    NumLinesChanged();
1077
0
}
1078
1079
void ScInputBarGroup::NumLinesChanged()
1080
0
{
1081
0
    if (mxTextWndGroup->GetNumLines() > 1)
1082
0
    {
1083
0
        mxButtonDown->hide();
1084
0
        mxButtonUp->show();
1085
0
        mxTextWndGroup->SetLastNumExpandedLines(mxTextWndGroup->GetNumLines());
1086
0
    }
1087
0
    else
1088
0
    {
1089
0
        mxButtonUp->hide();
1090
0
        mxButtonDown->show();
1091
0
    }
1092
0
    TriggerToolboxLayout();
1093
1094
    // Restore focus to input line(s) if necessary
1095
0
    ScInputHandler* pHdl = ScModule::get()->GetInputHdl();
1096
0
    if ( pHdl && pHdl->IsTopMode() )
1097
0
        mxTextWndGroup->TextGrabFocus();
1098
0
}
1099
1100
void ScInputBarGroup::TriggerToolboxLayout()
1101
0
{
1102
    // layout changes are expensive and un-necessary.
1103
0
    if (comphelper::LibreOfficeKit::isActive())
1104
0
        return;
1105
1106
0
    vcl::Window *w=GetParent();
1107
0
    ScInputWindow &rParent = dynamic_cast<ScInputWindow&>(*w);
1108
0
    SfxViewFrame* pViewFrm = SfxViewFrame::Current();
1109
1110
0
    if ( !pViewFrm )
1111
0
        return;
1112
1113
0
    Reference< css::beans::XPropertySet > xPropSet( pViewFrm->GetFrame().GetFrameInterface(), UNO_QUERY );
1114
0
    Reference< css::frame::XLayoutManager > xLayoutManager;
1115
1116
0
    if ( xPropSet.is() )
1117
0
    {
1118
0
        css::uno::Any aValue = xPropSet->getPropertyValue(u"LayoutManager"_ustr);
1119
0
        aValue >>= xLayoutManager;
1120
0
    }
1121
1122
0
    if ( !xLayoutManager.is() )
1123
0
        return;
1124
1125
0
    xLayoutManager->lock();
1126
0
    DataChangedEvent aFakeUpdate( DataChangedEventType::SETTINGS, nullptr,  AllSettingsFlags::STYLE );
1127
1128
    // this basically will trigger the repositioning of the
1129
    // items in the toolbar from ImplFormat ( which is controlled by
1130
    // mnWinHeight ) which in turn is updated in ImplCalcItem which is
1131
    // controlled by mbCalc. Additionally the ImplFormat above is
1132
    // controlled via mbFormat. It seems the easiest way to get these
1133
    // booleans set is to send in the fake event below.
1134
0
    rParent.DataChanged( aFakeUpdate);
1135
1136
    // highest item in toolbar will have been calculated via the
1137
    // event above. Call resize on InputBar to pick up the height
1138
    // change
1139
0
    rParent.Resize();
1140
1141
    // unlock relayouts the toolbars in the 4 quadrants
1142
0
    xLayoutManager->unlock();
1143
0
}
1144
1145
void ScInputBarGroup::TextGrabFocus()
1146
0
{
1147
0
    mxTextWndGroup->TextGrabFocus();
1148
0
}
1149
1150
constexpr tools::Long gnBorderWidth = (INPUTLINE_INSET_MARGIN + 1) * 2;
1151
constexpr tools::Long gnBorderHeight = INPUTLINE_INSET_MARGIN + 1;
1152
1153
ScTextWndGroup::ScTextWndGroup(ScInputBarGroup& rParent, ScTabViewShell* pViewSh)
1154
0
    : mxTextWnd(new ScTextWnd(*this, pViewSh))
1155
0
    , mxScrollWin(rParent.GetBuilder().weld_scrolled_window(u"scrolledwindow"_ustr, true))
1156
0
    , mxTextWndWin(new weld::CustomWeld(rParent.GetBuilder(), u"sc_input_window"_ustr, *mxTextWnd))
1157
0
    , mrParent(rParent)
1158
0
{
1159
0
    mxScrollWin->connect_vadjustment_value_changed(LINK(this, ScTextWndGroup, Impl_ScrollHdl));
1160
0
    if (ScTabViewShell* pActiveViewShell = comphelper::LibreOfficeKit::isActive() ?
1161
0
            dynamic_cast<ScTabViewShell*>(SfxViewShell::Current()) : nullptr)
1162
0
    {
1163
0
        pActiveViewShell->LOKSendFormulabarUpdate(nullptr, u""_ustr, ESelection());
1164
0
    }
1165
0
}
1166
1167
Point ScTextWndGroup::GetCursorScreenPixelPos(bool bBelow)
1168
0
{
1169
0
    Point aPos;
1170
0
    if (!HasEditView())
1171
0
        return aPos;
1172
0
    EditView* pEditView = GetEditView();
1173
0
    vcl::Cursor* pCur = pEditView->GetCursor();
1174
0
    if (!pCur)
1175
0
        return aPos;
1176
0
    Point aLogicPos = pCur->GetPos();
1177
0
    if (bBelow)
1178
0
        aLogicPos.AdjustY(pCur->GetHeight());
1179
0
    aPos = GetEditViewDevice().LogicToPixel(aLogicPos);
1180
0
    bool bRTL = mrParent.IsRTLEnabled();
1181
0
    if (bRTL)
1182
0
        aPos.setX(mxTextWnd->GetOutputSizePixel().Width() - aPos.X() + gnBorderWidth);
1183
0
    else
1184
0
        aPos.AdjustX(gnBorderWidth + 1);
1185
1186
0
    return mrParent.OutputToScreenPixel(aPos);
1187
0
}
1188
1189
ScTextWndGroup::~ScTextWndGroup()
1190
0
{
1191
0
}
1192
1193
void ScTextWndGroup::InsertAccessibleTextData(ScAccessibleEditLineTextData& rTextData)
1194
0
{
1195
0
    mxTextWnd->InsertAccessibleTextData(rTextData);
1196
0
}
1197
1198
EditView* ScTextWndGroup::GetEditView() const
1199
0
{
1200
0
    return mxTextWnd->GetEditView();
1201
0
}
1202
1203
const OutputDevice& ScTextWndGroup::GetEditViewDevice() const
1204
0
{
1205
0
    return mxTextWnd->GetEditViewDevice();
1206
0
}
1207
1208
tools::Long ScTextWndGroup::GetLastNumExpandedLines() const
1209
0
{
1210
0
    return mxTextWnd->GetLastNumExpandedLines();
1211
0
}
1212
1213
void ScTextWndGroup::SetLastNumExpandedLines(tools::Long nLastExpandedLines)
1214
0
{
1215
0
    mxTextWnd->SetLastNumExpandedLines(nLastExpandedLines);
1216
0
}
1217
1218
tools::Long ScTextWndGroup::GetNumLines() const
1219
0
{
1220
0
    return mxTextWnd->GetNumLines();
1221
0
}
1222
1223
int ScTextWndGroup::GetPixelHeightForLines(tools::Long nLines)
1224
0
{
1225
0
    return mxTextWnd->GetPixelHeightForLines(nLines) + 2 * gnBorderHeight;
1226
0
}
1227
1228
weld::ScrolledWindow& ScTextWndGroup::GetScrollWin()
1229
0
{
1230
0
    return *mxScrollWin;
1231
0
}
1232
1233
const OUString& ScTextWndGroup::GetTextString() const
1234
0
{
1235
0
    return mxTextWnd->GetTextString();
1236
0
}
1237
1238
bool ScTextWndGroup::HasEditView() const
1239
0
{
1240
0
    return mxTextWnd->HasEditView();
1241
0
}
1242
1243
bool ScTextWndGroup::IsInputActive()
1244
0
{
1245
0
    return mxTextWnd->IsInputActive();
1246
0
}
1247
1248
void ScTextWndGroup::MakeDialogEditView()
1249
0
{
1250
0
    mxTextWnd->MakeDialogEditView();
1251
0
}
1252
1253
void ScTextWndGroup::RemoveAccessibleTextData(ScAccessibleEditLineTextData& rTextData)
1254
0
{
1255
0
    mxTextWnd->RemoveAccessibleTextData(rTextData);
1256
0
}
1257
1258
void ScTextWndGroup::SetScrollPolicy()
1259
0
{
1260
0
    if (mxTextWnd->GetNumLines() > 2)
1261
0
        mxScrollWin->set_vpolicy(VclPolicyType::ALWAYS);
1262
0
    else
1263
0
        mxScrollWin->set_vpolicy(VclPolicyType::NEVER);
1264
0
}
1265
1266
void ScTextWndGroup::SetNumLines(tools::Long nLines)
1267
0
{
1268
0
    mxTextWnd->SetNumLines(nLines);
1269
0
}
1270
1271
void ScTextWndGroup::SetFormulaMode(bool bSet)
1272
0
{
1273
0
    mxTextWnd->SetFormulaMode(bSet);
1274
0
}
1275
1276
void ScTextWndGroup::SetTextString(const OUString& rString, bool bKitUpdate)
1277
0
{
1278
0
    mxTextWnd->SetTextString(rString, bKitUpdate);
1279
0
}
1280
1281
void ScTextWndGroup::StartEditEngine(const ErrorHdl& errorHdl)
1282
0
{
1283
0
    mxTextWnd->StartEditEngine(errorHdl);
1284
0
}
1285
1286
void ScTextWndGroup::StopEditEngine(bool bAll)
1287
0
{
1288
0
    mxTextWnd->StopEditEngine( bAll );
1289
0
}
1290
1291
void ScTextWndGroup::TextGrabFocus()
1292
0
{
1293
0
    mxTextWnd->TextGrabFocus();
1294
0
}
1295
1296
IMPL_LINK_NOARG(ScTextWndGroup, Impl_ScrollHdl, weld::ScrolledWindow&, void)
1297
0
{
1298
0
    mxTextWnd->DoScroll();
1299
0
}
1300
1301
void ScTextWnd::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect )
1302
0
{
1303
0
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1304
0
    Color aBgColor = rStyleSettings.GetFieldColor();
1305
0
    rRenderContext.SetBackground(aBgColor);
1306
1307
    // tdf#137713 we rely on GetEditView creating it if it doesn't already exist so
1308
    // GetEditView() must be called unconditionally
1309
0
    if (EditView* pView = GetEditView())
1310
0
    {
1311
0
        if (mbInvalidate)
1312
0
        {
1313
0
            pView->Invalidate();
1314
0
            mbInvalidate = false;
1315
0
        }
1316
0
    }
1317
1318
0
    if (comphelper::LibreOfficeKit::isActive() && m_xEditEngine)
1319
0
    {
1320
        // EditEngine/EditView works in twips logical coordinates, so set the device map-mode to twips before painting
1321
        // and use twips version of the painting area 'rRect'.
1322
        // Document zoom should not be included in this conversion.
1323
0
        tools::Rectangle aLogicRect = OutputDevice::LogicToLogic(rRect, MapMode(MapUnit::MapPixel), MapMode(MapUnit::MapTwip));
1324
0
        MapMode aOriginalMode = rRenderContext.GetMapMode();
1325
0
        rRenderContext.SetMapMode(MapMode(MapUnit::MapTwip));
1326
0
        WeldEditView::Paint(rRenderContext, aLogicRect);
1327
0
        rRenderContext.SetMapMode(aOriginalMode);
1328
0
    }
1329
0
    else
1330
0
        WeldEditView::Paint(rRenderContext, rRect);
1331
0
}
1332
1333
EditView* ScTextWnd::GetEditView() const
1334
0
{
1335
0
    if ( !m_xEditView )
1336
0
        const_cast<ScTextWnd&>(*this).InitEditEngine();
1337
0
    return m_xEditView.get();
1338
0
}
1339
1340
0
bool ScTextWnd::HasEditView() const { return m_xEditView != nullptr; }
1341
1342
const OutputDevice& ScTextWnd::GetEditViewDevice() const
1343
0
{
1344
0
    return EditViewOutputDevice();
1345
0
}
1346
1347
int ScTextWnd::GetPixelHeightForLines(tools::Long nLines)
1348
0
{
1349
0
    OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
1350
0
    return rDevice.LogicToPixel(Size(0, nLines * rDevice.GetTextHeight())).Height() + 1;
1351
0
}
1352
1353
tools::Long ScTextWnd::GetNumLines() const
1354
0
{
1355
0
    ScViewData& rViewData = mpViewShell->GetViewData();
1356
0
    return rViewData.GetFormulaBarLines();
1357
0
}
1358
1359
void ScTextWnd::SetNumLines(tools::Long nLines)
1360
0
{
1361
0
    ScViewData& rViewData = mpViewShell->GetViewData();
1362
0
    rViewData.SetFormulaBarLines(nLines);
1363
0
    if ( nLines > 1 )
1364
0
    {
1365
        // SetFormulaBarLines sanitizes the height, so get the sanitized value
1366
0
        mnLastExpandedLines = rViewData.GetFormulaBarLines();
1367
0
        Resize();
1368
0
    }
1369
0
}
1370
1371
void ScTextWnd::Resize()
1372
0
{
1373
0
    if (m_xEditView)
1374
0
    {
1375
0
        Size aOutputSize = GetOutputSizePixel();
1376
0
        OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
1377
0
        tools::Rectangle aOutputArea = rDevice.PixelToLogic( tools::Rectangle( Point(), aOutputSize ));
1378
0
        m_xEditView->SetOutputArea( aOutputArea );
1379
1380
        // Don't leave an empty area at the bottom if we can move the text down.
1381
0
        tools::Long nMaxVisAreaTop = m_xEditEngine->GetTextHeight() - aOutputArea.GetHeight();
1382
0
        if (m_xEditView->GetVisArea().Top() > nMaxVisAreaTop)
1383
0
        {
1384
0
            m_xEditView->Scroll(0, m_xEditView->GetVisArea().Top() - nMaxVisAreaTop);
1385
0
        }
1386
1387
0
        m_xEditEngine->SetPaperSize( rDevice.PixelToLogic( Size( aOutputSize.Width(), 10000 ) ) );
1388
0
    }
1389
1390
    // skip WeldEditView's Resize();
1391
0
    weld::CustomWidgetController::Resize();
1392
1393
0
    SetScrollBarRange();
1394
0
}
1395
1396
int ScTextWnd::GetEditEngTxtHeight() const
1397
0
{
1398
0
    return m_xEditView ? m_xEditView->getEditEngine().GetTextHeight() : 0;
1399
0
}
1400
1401
void ScTextWnd::SetScrollBarRange()
1402
0
{
1403
0
    if (!m_xEditView)
1404
0
        return;
1405
1406
0
    OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
1407
0
    Size aOutputSize = rDevice.GetOutputSize();
1408
1409
0
    int nUpper = GetEditEngTxtHeight();
1410
0
    int nCurrentDocPos = m_xEditView->GetVisArea().Top();
1411
0
    int nStepIncrement = GetTextHeight();
1412
0
    int nPageIncrement = aOutputSize.Height();
1413
0
    int nPageSize = aOutputSize.Height();
1414
1415
    /* limit the page size to below nUpper because gtk's gtk_scrolled_window_start_deceleration has
1416
       effectively...
1417
1418
       lower = gtk_adjustment_get_lower
1419
       upper = gtk_adjustment_get_upper - gtk_adjustment_get_page_size
1420
1421
       and requires that upper > lower or the deceleration animation never ends
1422
    */
1423
0
    nPageSize = std::min(nPageSize, nUpper);
1424
1425
0
    weld::ScrolledWindow& rVBar = mrGroupBar.GetScrollWin();
1426
0
    rVBar.vadjustment_configure(nCurrentDocPos, nUpper, nStepIncrement, nPageIncrement, nPageSize);
1427
0
}
1428
1429
void ScTextWnd::DoScroll()
1430
0
{
1431
0
    if (m_xEditView)
1432
0
    {
1433
0
        weld::ScrolledWindow& rVBar = mrGroupBar.GetScrollWin();
1434
0
        auto currentDocPos = m_xEditView->GetVisArea().Top();
1435
0
        auto nDiff = currentDocPos - rVBar.vadjustment_get_value();
1436
        // we expect SetScrollBarRange callback to be triggered by Scroll
1437
        // to set where we ended up
1438
0
        m_xEditView->Scroll(0, nDiff);
1439
0
    }
1440
0
}
1441
1442
void ScTextWnd::StartEditEngine(const ErrorHdl& errorHdl)
1443
0
{
1444
    // Don't activate if we're a modal dialog ourselves (Doc-modal dialog)
1445
0
    SfxObjectShell* pObjSh = SfxObjectShell::Current();
1446
0
    if ( pObjSh && pObjSh->IsInModalMode() )
1447
0
        return;
1448
1449
0
    if ( !m_xEditView || !m_xEditEngine )
1450
0
    {
1451
0
        InitEditEngine();
1452
0
    }
1453
1454
0
    ScInputHandler* pHdl = mpViewShell->GetInputHandler();
1455
0
    if (pHdl)
1456
0
    {
1457
0
        pHdl->SetMode(SC_INPUT_TOP, nullptr, static_cast<ScEditEngineDefaulter*>(m_xEditEngine.get()),
1458
0
                      errorHdl);
1459
0
    }
1460
1461
0
    SfxViewFrame* pViewFrm = SfxViewFrame::Current();
1462
0
    if (pViewFrm)
1463
0
        pViewFrm->GetBindings().Invalidate( SID_ATTR_INSERT );
1464
0
}
1465
1466
static void lcl_ExtendEditFontAttribs( SfxItemSet& rSet )
1467
0
{
1468
0
    const SfxPoolItem& rFontItem = rSet.Get( EE_CHAR_FONTINFO );
1469
0
    std::unique_ptr<SfxPoolItem> pNewItem(rFontItem.Clone());
1470
0
    pNewItem->SetWhich(EE_CHAR_FONTINFO_CJK);
1471
0
    rSet.Put( *pNewItem );
1472
0
    pNewItem->SetWhich(EE_CHAR_FONTINFO_CTL);
1473
0
    rSet.Put( *pNewItem );
1474
0
    const SfxPoolItem& rHeightItem = rSet.Get( EE_CHAR_FONTHEIGHT );
1475
0
    pNewItem.reset(rHeightItem.Clone());
1476
0
    pNewItem->SetWhich(EE_CHAR_FONTHEIGHT_CJK);
1477
0
    rSet.Put( *pNewItem );
1478
0
    pNewItem->SetWhich(EE_CHAR_FONTHEIGHT_CTL);
1479
0
    rSet.Put( *pNewItem );
1480
0
    const SfxPoolItem& rWeightItem = rSet.Get( EE_CHAR_WEIGHT );
1481
0
    pNewItem.reset(rWeightItem.Clone());
1482
0
    pNewItem->SetWhich(EE_CHAR_WEIGHT_CJK);
1483
0
    rSet.Put( *pNewItem );
1484
0
    pNewItem->SetWhich(EE_CHAR_WEIGHT_CTL);
1485
0
    rSet.Put( *pNewItem );
1486
0
    const SfxPoolItem& rItalicItem = rSet.Get( EE_CHAR_ITALIC );
1487
0
    pNewItem.reset(rItalicItem.Clone());
1488
0
    pNewItem->SetWhich(EE_CHAR_ITALIC_CJK);
1489
0
    rSet.Put( *pNewItem );
1490
0
    pNewItem->SetWhich(EE_CHAR_ITALIC_CTL);
1491
0
    rSet.Put( *pNewItem );
1492
0
    const SfxPoolItem& rLangItem = rSet.Get( EE_CHAR_LANGUAGE );
1493
0
    pNewItem.reset(rLangItem.Clone());
1494
0
    pNewItem->SetWhich(EE_CHAR_LANGUAGE_CJK);
1495
0
    rSet.Put( *pNewItem );
1496
0
    pNewItem->SetWhich(EE_CHAR_LANGUAGE_CTL);
1497
0
    rSet.Put( *pNewItem );
1498
0
}
1499
1500
static void lcl_ModifyRTLDefaults( SfxItemSet& rSet )
1501
0
{
1502
0
    rSet.Put( SvxAdjustItem( SvxAdjust::Right, EE_PARA_JUST ) );
1503
1504
    // always using rtl writing direction would break formulas
1505
    //rSet.Put( SvxFrameDirectionItem( SvxFrameDirection::Horizontal_RL_TB, EE_PARA_WRITINGDIR ) );
1506
1507
    // PaperSize width is limited to USHRT_MAX in RTL mode (because of EditEngine's
1508
    // sal_uInt16 values in EditLine), so the text may be wrapped and line spacing must be
1509
    // increased to not see the beginning of the next line.
1510
0
    SvxLineSpacingItem aItem( LINE_SPACE_DEFAULT_HEIGHT, EE_PARA_SBL );
1511
0
    aItem.SetPropLineSpace( 200 );
1512
0
    rSet.Put( aItem );
1513
0
}
1514
1515
static void lcl_ModifyRTLVisArea( EditView* pEditView )
1516
0
{
1517
0
    tools::Rectangle aVisArea = pEditView->GetVisArea();
1518
0
    Size aPaper = pEditView->getEditEngine().GetPaperSize();
1519
0
    tools::Long nDiff = aPaper.Width() - aVisArea.Right();
1520
0
    aVisArea.AdjustLeft(nDiff );
1521
0
    aVisArea.AdjustRight(nDiff );
1522
0
    pEditView->SetVisArea(aVisArea);
1523
0
}
1524
1525
void ScTextWnd::InitEditEngine()
1526
0
{
1527
0
    std::unique_ptr<ScFieldEditEngine> pNew;
1528
0
    ScDocShell* pDocSh = nullptr;
1529
0
    if ( mpViewShell )
1530
0
    {
1531
0
        pDocSh = mpViewShell->GetViewData().GetDocShell();
1532
0
        ScDocument& rDoc = mpViewShell->GetViewData().GetDocument();
1533
0
        pNew = std::make_unique<ScFieldEditEngine>(&rDoc, rDoc.GetEditEnginePool());
1534
0
    }
1535
0
    else
1536
0
        pNew = std::make_unique<ScFieldEditEngine>(nullptr, EditEngine::CreatePool().get(), true);
1537
0
    pNew->SetExecuteURL( false );
1538
0
    m_xEditEngine = std::move(pNew);
1539
1540
0
    Size barSize = GetOutputSizePixel();
1541
0
    m_xEditEngine->SetUpdateLayout( false );
1542
0
    m_xEditEngine->SetPaperSize( GetDrawingArea()->get_ref_device().PixelToLogic(Size(barSize.Width(),10000)) );
1543
0
    m_xEditEngine->SetWordDelimiters(
1544
0
                    ScEditUtil::ModifyDelimiters( m_xEditEngine->GetWordDelimiters() ) );
1545
0
    m_xEditEngine->SetReplaceLeadingSingleQuotationMark( false );
1546
1547
0
    UpdateAutoCorrFlag();
1548
1549
0
    {
1550
0
        SfxItemSet aSet( m_xEditEngine->GetEmptyItemSet() );
1551
0
        EditEngine::SetFontInfoInItemSet( aSet, aTextFont );
1552
0
        lcl_ExtendEditFontAttribs( aSet );
1553
        // turn off script spacing to match DrawText output
1554
0
        aSet.Put( SvxScriptSpaceItem( false, EE_PARA_ASIANCJKSPACING ) );
1555
0
        if ( bIsRTL )
1556
0
            lcl_ModifyRTLDefaults( aSet );
1557
0
        static_cast<ScEditEngineDefaulter*>(m_xEditEngine.get())->SetDefaults( std::move(aSet) );
1558
0
    }
1559
1560
    // If the Cell contains URLFields, they need to be taken over into the entry row,
1561
    // or else the position is not correct anymore
1562
0
    bool bFilled = false;
1563
0
    ScInputHandler* pHdl = ScModule::get()->GetInputHdl();
1564
0
    if ( pHdl ) //! Test if it's the right InputHdl?
1565
0
        bFilled = pHdl->GetTextAndFields(static_cast<ScEditEngineDefaulter&>(*m_xEditEngine));
1566
1567
0
    m_xEditEngine->SetUpdateLayout( true );
1568
1569
    // aString is the truth ...
1570
0
    if (bFilled && m_xEditEngine->GetText() == aString)
1571
0
        Invalidate(); // Repaint for (filled) Field
1572
0
    else
1573
0
        static_cast<ScEditEngineDefaulter*>(m_xEditEngine.get())->SetTextCurrentDefaults(aString); // At least the right text then
1574
1575
0
    m_xEditView = std::make_unique<EditView>(*m_xEditEngine, nullptr);
1576
1577
    // we get cursor, selection etc. messages from the VCL/window layer
1578
    // otherwise these are injected into the document causing confusion.
1579
0
    m_xEditView->SuppressLOKMessages(true);
1580
1581
0
    m_xEditView->setEditViewCallbacks(this);
1582
0
    m_xEditView->SetInsertMode(bIsInsertMode);
1583
1584
0
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1585
0
    Color aBgColor = rStyleSettings.GetFieldColor();
1586
0
    m_xEditView->SetBackgroundColor(aBgColor);
1587
1588
0
    if (pAcc)
1589
0
    {
1590
0
        pAcc->InitAcc(nullptr, m_xEditView.get(),
1591
0
                      ScResId(STR_ACC_EDITLINE_NAME),
1592
0
                      ScResId(STR_ACC_EDITLINE_DESCR));
1593
0
    }
1594
1595
0
    if (comphelper::LibreOfficeKit::isActive())
1596
0
        m_xEditView->RegisterViewShell(mpViewShell);
1597
1598
    // Text from Clipboard is taken over as ASCII in a single row
1599
0
    EVControlBits n = m_xEditView->GetControlWord();
1600
0
    m_xEditView->SetControlWord( n | EVControlBits::SINGLELINEPASTE );
1601
1602
0
    m_xEditEngine->InsertView( m_xEditView.get(), EE_APPEND );
1603
1604
0
    Resize();
1605
1606
0
    if ( bIsRTL )
1607
0
        lcl_ModifyRTLVisArea( m_xEditView.get() );
1608
1609
0
    m_xEditEngine->SetModifyHdl(LINK(this, ScTextWnd, ModifyHdl));
1610
0
    m_xEditEngine->SetStatusEventHdl(LINK(this, ScTextWnd, EditStatusHdl));
1611
1612
0
    if (!maAccTextDatas.empty())
1613
0
        maAccTextDatas.back()->StartEdit();
1614
1615
    // as long as EditEngine and DrawText sometimes differ for CTL text,
1616
    // repaint now to have the EditEngine's version visible
1617
0
    if (pDocSh)
1618
0
    {
1619
0
        ScDocument& rDoc = pDocSh->GetDocument(); // any document
1620
0
        SvtScriptType nScript = rDoc.GetStringScriptType( aString );
1621
0
        if ( nScript & SvtScriptType::COMPLEX )
1622
0
            Invalidate();
1623
0
    }
1624
0
}
1625
1626
ScTextWnd::ScTextWnd(ScTextWndGroup& rParent, ScTabViewShell* pViewSh) :
1627
0
        bIsRTL(AllSettings::GetLayoutRTL()),
1628
0
        bIsInsertMode(true),
1629
0
        bFormulaMode (false),
1630
0
        bInputMode   (false),
1631
0
        mpViewShell(pViewSh),
1632
0
        mrGroupBar(rParent),
1633
0
        mnLastExpandedLines(INPUTWIN_MULTILINES),
1634
0
        mbInvalidate(false)
1635
0
{
1636
0
}
1637
1638
ScTextWnd::~ScTextWnd()
1639
0
{
1640
0
    while (!maAccTextDatas.empty()) {
1641
0
        maAccTextDatas.back()->Dispose();
1642
0
    }
1643
0
}
1644
1645
bool ScTextWnd::MouseMove( const MouseEvent& rMEvt )
1646
0
{
1647
0
    return m_xEditView && m_xEditView->MouseMove(rMEvt);
1648
0
}
1649
1650
bool ScTextWnd::CanFocus() const
1651
0
{
1652
0
    return ScModule::get()->IsEditMode();
1653
0
}
1654
1655
void ScTextWnd::UpdateFocus(const ErrorHdl& errorHdl)
1656
0
{
1657
0
    if (!HasFocus())
1658
0
    {
1659
0
        StartEditEngine(errorHdl);
1660
0
        if (CanFocus())
1661
0
            TextGrabFocus();
1662
0
    }
1663
0
}
1664
1665
bool ScTextWnd::MouseButtonDown( const MouseEvent& rMEvt )
1666
0
{
1667
    // tdf#169351 If trying to set focus to the formula bar triggers an error
1668
    // dialog, intercept the launch of that dialog to detect this case, and in
1669
    // that case abandon the mouse handler.
1670
0
    bool bCanceled(false);
1671
0
    auto errorHdl = [&bCanceled](ScTabViewShell* pActiveViewShell, TranslateId messageId) {
1672
0
        ScInputHandler::ErrorMessage(pActiveViewShell, messageId);
1673
0
        bCanceled = true;
1674
0
    };
1675
1676
0
    UpdateFocus(errorHdl);
1677
1678
0
    if (bCanceled)
1679
0
        return true;
1680
1681
0
    bool bClickOnSelection = false;
1682
0
    if (m_xEditView)
1683
0
    {
1684
0
        m_xEditView->SetEditEngineUpdateLayout( true );
1685
0
        bClickOnSelection = m_xEditView->IsSelectionAtPoint(rMEvt.GetPosPixel());
1686
0
    }
1687
0
    if (!bClickOnSelection)
1688
0
    {
1689
0
        rtl::Reference<TransferDataContainer> xTransferable(new TransferDataContainer);
1690
0
        GetDrawingArea()->enable_drag_source(xTransferable, DND_ACTION_NONE);
1691
0
    }
1692
0
    else
1693
0
    {
1694
0
        rtl::Reference<TransferDataContainer> xTransferable(m_xHelper);
1695
0
        GetDrawingArea()->enable_drag_source(xTransferable, DND_ACTION_COPY);
1696
0
    }
1697
0
    return WeldEditView::MouseButtonDown(rMEvt);
1698
0
}
1699
1700
bool ScTextWnd::MouseButtonUp( const MouseEvent& rMEvt )
1701
0
{
1702
0
    bool bRet = WeldEditView::MouseButtonUp(rMEvt);
1703
0
    if (bRet)
1704
0
    {
1705
0
        if ( rMEvt.IsMiddle() &&
1706
0
                 Application::GetSettings().GetMouseSettings().GetMiddleButtonAction() == MouseMiddleButtonAction::PasteSelection )
1707
0
        {
1708
            //  EditView may have pasted from selection
1709
0
            ScModule::get()->InputChanged(m_xEditView.get());
1710
0
        }
1711
0
        else
1712
0
            ScModule::get()->InputSelection(m_xEditView.get());
1713
0
    }
1714
0
    return bRet;
1715
0
}
1716
1717
bool ScTextWnd::Command( const CommandEvent& rCEvt )
1718
0
{
1719
0
    if (!m_xEditView)
1720
0
        return false;
1721
1722
0
    bool bConsumed = false;
1723
1724
0
    bInputMode = true;
1725
0
    CommandEventId nCommand = rCEvt.GetCommand();
1726
1727
0
    ScModule* pScMod = ScModule::get();
1728
1729
0
    bool bExtInput = nCommand == CommandEventId::StartExtTextInput ||
1730
0
                     nCommand == CommandEventId::EndExtTextInput ||
1731
0
                     nCommand == CommandEventId::ExtTextInput ||
1732
0
                     nCommand == CommandEventId::CursorPos ||
1733
0
                     nCommand == CommandEventId::QueryCharPosition;
1734
1735
0
    if (bExtInput)
1736
0
    {
1737
0
        if (ScInputHandler* pInputHdl = pScMod->GetInputHdl())
1738
0
        {
1739
            // Similar to ScGridWindow::Command (and ScTextWnd::KeyInput)
1740
            // forward the CommandEvent to both EditEngines, the inputbar one
1741
            // and the main document one.
1742
0
            pInputHdl->InputCommand(rCEvt);
1743
0
            bConsumed = true;
1744
0
        }
1745
0
    }
1746
0
    else
1747
0
    {
1748
0
        ScTabViewShell* pStartViewSh = ScTabViewShell::GetActiveViewShell();
1749
1750
        // don't modify the font defaults here - the right defaults are
1751
        // already set in StartEditEngine when the EditEngine is created
1752
1753
        // Prevent that the EditView is lost when switching between Views
1754
0
        pScMod->SetInEditCommand( true );
1755
0
        m_xEditView->Command( rCEvt );
1756
0
        pScMod->SetInEditCommand( false );
1757
1758
        //  CommandEventId::StartDrag does not mean by far that the content was actually changed,
1759
        //  so don't trigger an InputChanged.
1760
        //! Detect if dragged with Move or forbid Drag&Move somehow
1761
1762
0
        if ( nCommand == CommandEventId::StartDrag )
1763
0
        {
1764
            // Is dragged onto another View?
1765
0
            ScTabViewShell* pEndViewSh = ScTabViewShell::GetActiveViewShell();
1766
0
            if ( pEndViewSh != pStartViewSh && pStartViewSh != nullptr )
1767
0
            {
1768
0
                ScViewData& rViewData = pStartViewSh->GetViewData();
1769
0
                ScInputHandler* pHdl = pScMod->GetInputHdl( pStartViewSh );
1770
0
                if ( pHdl && rViewData.HasEditView( rViewData.GetActivePart() ) )
1771
0
                {
1772
0
                    pHdl->CancelHandler();
1773
0
                    rViewData.GetView()->ShowCursor(); // Missing for KillEditView, due to being inactive
1774
0
                }
1775
0
            }
1776
0
        }
1777
0
        else if ( nCommand == CommandEventId::InputLanguageChange )
1778
0
        {
1779
            // #i55929# Font and font size state depends on input language if nothing is selected,
1780
            // so the slots have to be invalidated when the input language is changed.
1781
1782
0
            SfxViewFrame* pViewFrm = SfxViewFrame::Current();
1783
0
            if (pViewFrm)
1784
0
            {
1785
0
                SfxBindings& rBindings = pViewFrm->GetBindings();
1786
0
                rBindings.Invalidate( SID_ATTR_CHAR_FONT );
1787
0
                rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
1788
0
            }
1789
0
        }
1790
0
        else if ( nCommand == CommandEventId::ContextMenu )
1791
0
        {
1792
0
            bConsumed = true;
1793
0
            SfxViewFrame* pViewFrm = SfxViewFrame::Current();
1794
0
            if (pViewFrm)
1795
0
            {
1796
0
                Point aPos = rCEvt.GetMousePosPixel();
1797
0
                if (!rCEvt.IsMouseEvent())
1798
0
                {
1799
0
                    Size aSize = GetOutputSizePixel();
1800
0
                    aPos = Point(aSize.Width() / 2, aSize.Height() / 2);
1801
0
                }
1802
0
                if (IsMouseCaptured())
1803
0
                    ReleaseMouse();
1804
0
                UpdateFocus(ScInputHandler::ErrorMessage);
1805
0
                pViewFrm->GetDispatcher()->ExecutePopup(u"formulabar"_ustr, &mrGroupBar.GetVclParent(), &aPos);
1806
0
            }
1807
0
        }
1808
0
        else if ( nCommand == CommandEventId::Wheel )
1809
0
        {
1810
            //don't call InputChanged for CommandEventId::Wheel
1811
0
        }
1812
0
        else if ( nCommand == CommandEventId::GestureSwipe )
1813
0
        {
1814
            //don't call InputChanged for CommandEventId::GestureSwipe
1815
0
        }
1816
0
        else if ( nCommand == CommandEventId::GestureLongPress )
1817
0
        {
1818
            //don't call InputChanged for CommandEventId::GestureLongPress
1819
0
        }
1820
0
        else if ( nCommand == CommandEventId::ModKeyChange )
1821
0
        {
1822
            //pass alt press/release to parent impl
1823
0
        }
1824
0
        else
1825
0
        {
1826
            // I suspect this path doesn't get call anymore or it's called
1827
            // and shouldn't be
1828
0
            SAL_WARN("sc.core", "Likely we lost input bar formatting");
1829
0
            pScMod->InputChanged(m_xEditView.get());
1830
0
        }
1831
0
    }
1832
1833
0
    if ( comphelper::LibreOfficeKit::isActive() && nCommand == CommandEventId::CursorPos )
1834
0
    {
1835
        // LOK uses this to setup caret position because drawingarea is replaced
1836
        // with text input field, it sends logical caret position (start, end) not pixels
1837
1838
0
        StartEditEngine(ScInputHandler::ErrorMessage);
1839
0
        TextGrabFocus();
1840
1841
0
        Point aSelectionStartEnd = rCEvt.GetMousePosPixel();
1842
1843
0
        sal_Int32 nPosStart, nPosEnd;
1844
0
        nPosStart = m_xEditView->GetPosNoField(0, aSelectionStartEnd.X());
1845
0
        nPosEnd = m_xEditView->GetPosNoField(0, aSelectionStartEnd.Y());
1846
1847
0
        m_xEditView->SetSelection(ESelection(0, nPosStart, 0, nPosEnd));
1848
0
        pScMod->InputSelection(m_xEditView.get());
1849
1850
0
        bConsumed = true;
1851
0
    }
1852
1853
0
    bInputMode = false;
1854
1855
0
    return bConsumed;
1856
0
}
1857
1858
bool ScTextWnd::StartDrag()
1859
0
{
1860
    // tdf#145248 don't start a drag if actively selecting
1861
0
    if (m_xEditView && !m_xEditEngine->IsInSelectionMode())
1862
0
    {
1863
0
        OUString sSelection = m_xEditView->GetSelected();
1864
0
        m_xHelper->SetData(sSelection);
1865
0
        return sSelection.isEmpty();
1866
0
    }
1867
0
    return true;
1868
0
}
1869
1870
bool ScTextWnd::KeyInput(const KeyEvent& rKEvt)
1871
0
{
1872
0
    bool bUsed = true;
1873
0
    bInputMode = true;
1874
0
    if (!ScModule::get()->InputKeyEvent(rKEvt))
1875
0
    {
1876
0
        bUsed = false;
1877
0
        ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
1878
0
        if ( pViewSh )
1879
0
            bUsed = pViewSh->SfxKeyInput(rKEvt); // Only accelerators, no input
1880
0
    }
1881
0
    bInputMode = false;
1882
0
    return bUsed;
1883
0
}
1884
1885
void ScTextWnd::GetFocus()
1886
0
{
1887
0
    ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
1888
0
    if ( pViewSh )
1889
0
        pViewSh->SetFormShellAtTop( false ); // focus in input line -> FormShell no longer on top
1890
0
    WeldEditView::GetFocus();
1891
0
}
1892
1893
void ScTextWnd::SetFormulaMode( bool bSet )
1894
0
{
1895
0
    if ( bSet != bFormulaMode )
1896
0
    {
1897
0
        bFormulaMode = bSet;
1898
0
        UpdateAutoCorrFlag();
1899
0
    }
1900
0
}
1901
1902
void ScTextWnd::UpdateAutoCorrFlag()
1903
0
{
1904
0
    if (m_xEditEngine)
1905
0
    {
1906
0
        EEControlBits nControl = m_xEditEngine->GetControlWord();
1907
0
        EEControlBits nOld = nControl;
1908
0
        if ( bFormulaMode )
1909
0
            nControl &= ~EEControlBits::AUTOCORRECT; // No AutoCorrect in Formulas
1910
0
        else
1911
0
            nControl |= EEControlBits::AUTOCORRECT; // Else do enable it
1912
1913
0
        if ( nControl != nOld )
1914
0
            m_xEditEngine->SetControlWord( nControl );
1915
0
    }
1916
0
}
1917
1918
void ScTextWnd::EditViewScrollStateChange()
1919
0
{
1920
    // editengine height has changed or editview scroll pos has changed
1921
0
    SetScrollBarRange();
1922
0
}
1923
1924
IMPL_LINK_NOARG(ScTextWnd, ModifyHdl, LinkParamNone*, void)
1925
0
{
1926
0
    if (m_xEditView && !bInputMode)
1927
0
    {
1928
0
        ScInputHandler* pHdl = ScModule::get()->GetInputHdl();
1929
1930
        //  Use the InputHandler's InOwnChange flag to prevent calling InputChanged
1931
        //  while an InputHandler method is modifying the EditEngine content
1932
1933
0
        if ( pHdl && !pHdl->IsInOwnChange() )
1934
0
            pHdl->InputChanged( m_xEditView.get(), true );  // #i20282# InputChanged must know if called from modify handler
1935
0
    }
1936
0
}
1937
1938
IMPL_LINK_NOARG(ScTextWnd, EditStatusHdl, EditStatus&, void)
1939
0
{
1940
0
    SetScrollBarRange();
1941
0
    DoScroll();
1942
0
    Invalidate();
1943
0
}
1944
1945
void ScTextWnd::StopEditEngine( bool bAll )
1946
0
{
1947
0
    if (!m_xEditEngine)
1948
0
        return;
1949
1950
0
    if (m_xEditView)
1951
0
    {
1952
0
        if (!maAccTextDatas.empty())
1953
0
            maAccTextDatas.back()->EndEdit();
1954
1955
0
        ScModule* pScMod = ScModule::get();
1956
1957
0
        if (!bAll)
1958
0
            pScMod->InputSelection( m_xEditView.get() );
1959
0
        aString = m_xEditEngine->GetText();
1960
0
        bIsInsertMode = m_xEditView->IsInsertMode();
1961
0
        bool bSelection = m_xEditView->HasSelection();
1962
0
        m_xEditEngine->SetStatusEventHdl(Link<EditStatus&, void>());
1963
0
        m_xEditEngine->SetModifyHdl(Link<LinkParamNone*,void>());
1964
0
        m_xEditView.reset();
1965
0
        m_xEditEngine.reset();
1966
1967
0
        ScInputHandler* pHdl = mpViewShell->GetInputHandler();
1968
1969
0
        if (pHdl && pHdl->IsEditMode() && !bAll)
1970
0
            pHdl->SetMode(SC_INPUT_TABLE);
1971
1972
0
        SfxViewFrame* pViewFrm = SfxViewFrame::Current();
1973
0
        if (pViewFrm)
1974
0
            pViewFrm->GetBindings().Invalidate( SID_ATTR_INSERT );
1975
1976
0
        if (bSelection)
1977
0
            Invalidate(); // So that the Selection is not left there
1978
0
    }
1979
1980
0
    if (comphelper::LibreOfficeKit::isActive())
1981
0
    {
1982
        // Clear
1983
0
        std::vector<ReferenceMark> aReferenceMarks;
1984
0
        ScInputHandler::SendReferenceMarks( mpViewShell, aReferenceMarks );
1985
0
    }
1986
0
}
1987
1988
static sal_Int32 findFirstNonMatchingChar(const OUString& rStr1, const OUString& rStr2)
1989
0
{
1990
    // Search the string for unmatching chars
1991
0
    const sal_Unicode*  pStr1 = rStr1.getStr();
1992
0
    const sal_Unicode*  pStr2 = rStr2.getStr();
1993
0
    sal_Int32      i = 0;
1994
0
    while ( i < rStr1.getLength() )
1995
0
    {
1996
        // Abort on the first unmatching char
1997
0
        if ( *pStr1 != *pStr2 )
1998
0
            return i;
1999
0
        ++pStr1;
2000
0
        ++pStr2;
2001
0
        ++i;
2002
0
    }
2003
2004
0
    return i;
2005
0
}
2006
2007
void ScTextWnd::SetTextString( const OUString& rNewString, bool bKitUpdate )
2008
0
{
2009
    // Ideally it would be best to create on demand the EditEngine/EditView here, but... for
2010
    // the initialisation scenario where a cell is first clicked on we end up with the text in the
2011
    // inputbar window scrolled to the bottom if we do that here ( because the tableview and topview
2012
    // are synced I guess ).
2013
    // should fix that I suppose :-/ need to look a bit further into that
2014
0
    mbInvalidate = true; // ensure next Paint ( that uses editengine ) call will call Invalidate first
2015
2016
0
    if ( rNewString != aString )
2017
0
    {
2018
0
        bInputMode = true;
2019
2020
        // Find position of the change, only paint the rest
2021
0
        if (!m_xEditEngine)
2022
0
        {
2023
0
            bool bPaintAll = GetNumLines() > 1 || bIsRTL;
2024
0
            if (!bPaintAll)
2025
0
            {
2026
                //  test if CTL script type is involved
2027
0
                SvtScriptType nOldScript = SvtScriptType::NONE;
2028
0
                SvtScriptType nNewScript = SvtScriptType::NONE;
2029
0
                SfxObjectShell* pObjSh = SfxObjectShell::Current();
2030
0
                if ( auto pDocShell = dynamic_cast<ScDocShell*>( pObjSh) )
2031
0
                {
2032
                    //  any document can be used (used only for its break iterator)
2033
0
                    ScDocument& rDoc = pDocShell->GetDocument();
2034
0
                    nOldScript = rDoc.GetStringScriptType( aString );
2035
0
                    nNewScript = rDoc.GetStringScriptType( rNewString );
2036
0
                }
2037
0
                bPaintAll = ( nOldScript & SvtScriptType::COMPLEX ) || ( nNewScript & SvtScriptType::COMPLEX );
2038
0
            }
2039
2040
0
            if ( bPaintAll )
2041
0
            {
2042
                // In multiline mode, or if CTL is involved, the whole text has to be redrawn
2043
0
                Invalidate();
2044
0
            }
2045
0
            else
2046
0
            {
2047
0
                tools::Long nTextSize = 0;
2048
0
                sal_Int32 nDifPos;
2049
0
                if (rNewString.getLength() > aString.getLength())
2050
0
                    nDifPos = findFirstNonMatchingChar(rNewString, aString);
2051
0
                else
2052
0
                    nDifPos = findFirstNonMatchingChar(aString, rNewString);
2053
2054
0
                tools::Long nSize1 = GetTextWidth(aString);
2055
0
                tools::Long nSize2 = GetTextWidth(rNewString);
2056
0
                if ( nSize1>0 && nSize2>0 )
2057
0
                    nTextSize = std::max( nSize1, nSize2 );
2058
0
                else
2059
0
                    nTextSize = GetOutputSizePixel().Width(); // Overflow
2060
2061
0
                Point aLogicStart = GetDrawingArea()->get_ref_device().PixelToLogic(Point(0,0));
2062
0
                tools::Long nStartPos = aLogicStart.X();
2063
0
                tools::Long nInvPos = nStartPos;
2064
0
                if (nDifPos)
2065
0
                    nInvPos += GetTextWidth(aString.copy(0,nDifPos));
2066
2067
0
                Invalidate(tools::Rectangle(nInvPos, 0, nStartPos+nTextSize, GetOutputSizePixel().Height() - 1));
2068
0
            }
2069
0
        }
2070
0
        else
2071
0
        {
2072
0
            static_cast<ScEditEngineDefaulter*>(m_xEditEngine.get())->SetTextCurrentDefaults(rNewString);
2073
0
        }
2074
2075
0
        aString = rNewString;
2076
2077
0
        if (!maAccTextDatas.empty())
2078
0
            maAccTextDatas.back()->TextChanged();
2079
2080
0
        bInputMode = false;
2081
0
    }
2082
2083
0
    if (ScTabViewShell* pActiveViewShell = bKitUpdate && comphelper::LibreOfficeKit::isActive() ?
2084
0
            dynamic_cast<ScTabViewShell*>(SfxViewShell::Current()) : nullptr)
2085
0
    {
2086
0
        ESelection aSel = m_xEditView ? m_xEditView->GetSelection() : ESelection();
2087
0
        pActiveViewShell->LOKSendFormulabarUpdate(m_xEditView.get(), rNewString, aSel);
2088
0
    }
2089
2090
0
    SetScrollBarRange();
2091
0
    DoScroll();
2092
0
}
2093
2094
const OUString& ScTextWnd::GetTextString() const
2095
0
{
2096
0
    return aString;
2097
0
}
2098
2099
bool ScTextWnd::IsInputActive()
2100
0
{
2101
0
    return HasFocus();
2102
0
}
2103
2104
void ScTextWnd::MakeDialogEditView()
2105
0
{
2106
0
    if ( m_xEditView ) return;
2107
2108
0
    std::unique_ptr<ScFieldEditEngine> pNew;
2109
0
    ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
2110
0
    if ( pViewSh )
2111
0
    {
2112
0
        ScDocument& rDoc = pViewSh->GetViewData().GetDocument();
2113
0
        pNew = std::make_unique<ScFieldEditEngine>(&rDoc, rDoc.GetEditEnginePool());
2114
0
    }
2115
0
    else
2116
0
        pNew = std::make_unique<ScFieldEditEngine>(nullptr, EditEngine::CreatePool().get(), true);
2117
0
    pNew->SetExecuteURL( false );
2118
0
    m_xEditEngine = std::move(pNew);
2119
2120
0
    const bool bPrevUpdateLayout = m_xEditEngine->SetUpdateLayout( false );
2121
0
    m_xEditEngine->SetWordDelimiters( m_xEditEngine->GetWordDelimiters() + "=" );
2122
0
    m_xEditEngine->SetPaperSize( Size( bIsRTL ? USHRT_MAX : THESIZE, 300 ) );
2123
2124
0
    SfxItemSet aSet( m_xEditEngine->GetEmptyItemSet() );
2125
0
    EditEngine::SetFontInfoInItemSet( aSet, aTextFont );
2126
0
    lcl_ExtendEditFontAttribs( aSet );
2127
0
    if ( bIsRTL )
2128
0
        lcl_ModifyRTLDefaults( aSet );
2129
0
    static_cast<ScEditEngineDefaulter*>(m_xEditEngine.get())->SetDefaults( std::move(aSet) );
2130
0
    m_xEditEngine->SetUpdateLayout( bPrevUpdateLayout );
2131
2132
0
    m_xEditView = std::make_unique<EditView>(*m_xEditEngine, nullptr);
2133
0
    m_xEditView->setEditViewCallbacks(this);
2134
2135
0
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2136
0
    Color aBgColor = rStyleSettings.GetFieldColor();
2137
0
    m_xEditView->SetBackgroundColor(aBgColor);
2138
2139
0
    if (pAcc)
2140
0
    {
2141
0
        pAcc->InitAcc(nullptr, m_xEditView.get(),
2142
0
                      ScResId(STR_ACC_EDITLINE_NAME),
2143
0
                      ScResId(STR_ACC_EDITLINE_DESCR));
2144
0
    }
2145
2146
0
    if (comphelper::LibreOfficeKit::isActive())
2147
0
        m_xEditView->RegisterViewShell(mpViewShell);
2148
0
    m_xEditEngine->InsertView( m_xEditView.get(), EE_APPEND );
2149
2150
0
    Resize();
2151
2152
0
    if ( bIsRTL )
2153
0
        lcl_ModifyRTLVisArea( m_xEditView.get() );
2154
2155
0
    if (!maAccTextDatas.empty())
2156
0
        maAccTextDatas.back()->StartEdit();
2157
0
}
2158
2159
void ScTextWnd::ImplInitSettings()
2160
0
{
2161
0
    bIsRTL = AllSettings::GetLayoutRTL();
2162
2163
0
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2164
2165
0
    Color aBgColor= rStyleSettings.GetFieldColor();
2166
0
    Color aTxtColor= rStyleSettings.GetWindowTextColor();
2167
2168
0
    aTextFont.SetFillColor   ( aBgColor );
2169
0
    aTextFont.SetColor       (aTxtColor);
2170
0
    Invalidate();
2171
0
}
2172
2173
void ScTextWnd::SetDrawingArea(weld::DrawingArea* pDrawingArea)
2174
0
{
2175
    // bypass WeldEditView::SetDrawingArea
2176
0
    weld::CustomWidgetController::SetDrawingArea(pDrawingArea);
2177
2178
    // set cursor
2179
0
    pDrawingArea->set_cursor(PointerStyle::Text);
2180
2181
    // initialize dnd, deliberately just a simple string so
2182
    // we don't transfer the happenstance formatting in
2183
    // the input line
2184
0
    m_xHelper.set(new svt::OStringTransferable(OUString()));
2185
0
    rtl::Reference<TransferDataContainer> xHelper(m_xHelper);
2186
0
    SetDragDataTransferable(xHelper, DND_ACTION_COPY);
2187
2188
0
    OutputDevice& rDevice = pDrawingArea->get_ref_device();
2189
0
    pDrawingArea->set_margin_start(gnBorderWidth);
2190
0
    pDrawingArea->set_margin_end(gnBorderWidth);
2191
    // leave 1 for the width of the scrolledwindow border
2192
0
    pDrawingArea->set_margin_top(gnBorderHeight - 1);
2193
0
    pDrawingArea->set_margin_bottom(gnBorderHeight - 1);
2194
2195
    // always use application font, so a font with cjk chars can be installed
2196
0
    vcl::Font aAppFont = Application::GetSettings().GetStyleSettings().GetAppFont();
2197
0
    weld::SetPointFont(rDevice, aAppFont);
2198
2199
0
    aTextFont = rDevice.GetFont();
2200
0
    Size aFontSize = aTextFont.GetFontSize();
2201
0
    aTextFont.SetFontSize(rDevice.PixelToLogic(aFontSize, MapMode(MapUnit::MapTwip)));
2202
2203
0
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2204
2205
0
    Color aBgColor = rStyleSettings.GetFieldColor();
2206
0
    Color aTxtColor = rStyleSettings.GetWindowTextColor();
2207
2208
0
    aTextFont.SetTransparent(true);
2209
0
    aTextFont.SetFillColor(aBgColor);
2210
0
    aTextFont.SetColor(aTxtColor);
2211
0
    aTextFont.SetWeight(WEIGHT_NORMAL);
2212
2213
0
    Size aSize(1, GetPixelHeightForLines(1));
2214
0
    pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
2215
2216
0
    rDevice.SetBackground(aBgColor);
2217
0
    rDevice.SetLineColor(COL_BLACK);
2218
0
    rDevice.SetMapMode(MapMode(MapUnit::MapTwip));
2219
0
    rDevice.SetFont(aTextFont);
2220
2221
0
    EnableRTL(false); // EditEngine can't be used with VCL EnableRTL
2222
0
}
2223
2224
rtl::Reference<comphelper::OAccessible> ScTextWnd::CreateAccessible()
2225
0
{
2226
0
    pAcc = new ScAccessibleEditLineObject(this);
2227
0
    return pAcc;
2228
0
}
2229
2230
void ScTextWnd::InsertAccessibleTextData( ScAccessibleEditLineTextData& rTextData )
2231
0
{
2232
0
    OSL_ENSURE( ::std::find( maAccTextDatas.begin(), maAccTextDatas.end(), &rTextData ) == maAccTextDatas.end(),
2233
0
        "ScTextWnd::InsertAccessibleTextData - passed object already registered" );
2234
0
    maAccTextDatas.push_back( &rTextData );
2235
0
}
2236
2237
void ScTextWnd::RemoveAccessibleTextData( ScAccessibleEditLineTextData& rTextData )
2238
0
{
2239
0
    AccTextDataVector::iterator aEnd = maAccTextDatas.end();
2240
0
    AccTextDataVector::iterator aIt = ::std::find( maAccTextDatas.begin(), aEnd, &rTextData );
2241
0
    OSL_ENSURE( aIt != aEnd, "ScTextWnd::RemoveAccessibleTextData - passed object not registered" );
2242
0
    if( aIt != aEnd )
2243
0
        maAccTextDatas.erase( aIt );
2244
0
}
2245
2246
void ScTextWnd::StyleUpdated()
2247
0
{
2248
0
    ImplInitSettings();
2249
0
    CustomWidgetController::Invalidate();
2250
0
}
2251
2252
void ScTextWnd::TextGrabFocus()
2253
0
{
2254
0
    GrabFocus();
2255
0
}
2256
2257
// Position window
2258
ScPosWnd::ScPosWnd(vcl::Window* pParent)
2259
0
    : InterimItemWindow(pParent, u"modules/scalc/ui/posbox.ui"_ustr, u"PosBox"_ustr, true)
2260
0
    , m_xWidget(m_xBuilder->weld_combo_box(u"pos_window"_ustr))
2261
0
    , m_nAsyncGetFocusId(nullptr)
2262
0
    , nTipVisible(nullptr)
2263
0
    , bFormulaMode(false)
2264
0
{
2265
0
    InitControlBase(m_xWidget.get());
2266
2267
    // Use calculation according to tdf#132338 to align combobox width to width of fontname combobox within formatting toolbar;
2268
    // formatting toolbar is placed above formulabar when using multiple toolbars typically
2269
2270
0
    m_xWidget->set_entry_width_chars(1);
2271
0
    Size aSize(LogicToPixel(Size(POSITION_COMBOBOX_WIDTH * 4, 0), MapMode(MapUnit::MapAppFont)));
2272
0
    m_xWidget->set_size_request(aSize.Width(), -1);
2273
0
    SetSizePixel(m_xContainer->get_preferred_size());
2274
2275
0
    FillRangeNames(true);
2276
2277
0
    StartListening( *SfxGetpApp() ); // For Navigator rangename updates
2278
2279
0
    m_xWidget->connect_key_press(LINK(this, ScPosWnd, KeyInputHdl));
2280
0
    m_xWidget->connect_entry_activate(LINK(this, ScPosWnd, ActivateHdl));
2281
0
    m_xWidget->connect_changed(LINK(this, ScPosWnd, ModifyHdl));
2282
0
    m_xWidget->connect_focus_in(LINK(this, ScPosWnd, FocusInHdl));
2283
0
    m_xWidget->connect_focus_out(LINK(this, ScPosWnd, FocusOutHdl));
2284
0
}
Unexecuted instantiation: ScPosWnd::ScPosWnd(vcl::Window*)
Unexecuted instantiation: ScPosWnd::ScPosWnd(vcl::Window*)
2285
2286
ScPosWnd::~ScPosWnd()
2287
0
{
2288
0
    disposeOnce();
2289
0
}
2290
2291
void ScPosWnd::dispose()
2292
0
{
2293
0
    EndListening( *SfxGetpApp() );
2294
2295
0
    HideTip();
2296
2297
0
    if (m_nAsyncGetFocusId)
2298
0
    {
2299
0
        Application::RemoveUserEvent(m_nAsyncGetFocusId);
2300
0
        m_nAsyncGetFocusId = nullptr;
2301
0
    }
2302
0
    m_xWidget.reset();
2303
2304
0
    InterimItemWindow::dispose();
2305
0
}
2306
2307
void ScPosWnd::SetFormulaMode( bool bSet )
2308
0
{
2309
0
    if ( bSet != bFormulaMode )
2310
0
    {
2311
2312
0
        if ( bSet )
2313
0
            FillFunctions();
2314
0
        else
2315
0
            FillRangeNames();
2316
2317
0
        bFormulaMode = bSet;
2318
2319
0
        HideTip();
2320
0
    }
2321
0
}
2322
2323
void ScPosWnd::SetPos( const OUString& rPosStr )
2324
0
{
2325
0
    if ( aPosStr != rPosStr )
2326
0
    {
2327
0
        aPosStr = rPosStr;
2328
0
        m_xWidget->set_entry_text(aPosStr);
2329
0
    }
2330
0
}
2331
2332
// static
2333
OUString ScPosWnd::createLocalRangeName(std::u16string_view rName, std::u16string_view rTableName)
2334
0
{
2335
0
    return OUString::Concat(rName) + " (" + rTableName + ")";
2336
0
}
2337
2338
void ScPosWnd::FillRangeNames(bool initialize)
2339
0
{
2340
0
    std::set<OUString> aSet;
2341
0
    SfxObjectShell* pObjSh = SfxObjectShell::Current();
2342
0
    if (auto pDocShell = dynamic_cast<ScDocShell*>(pObjSh))
2343
0
    {
2344
0
        ScDocument& rDoc = pDocShell->GetDocument();
2345
2346
0
        ScRange aDummy;
2347
0
        ScRangeName* pRangeNames = rDoc.GetRangeName();
2348
0
        for (const auto& rEntry : *pRangeNames)
2349
0
        {
2350
0
            if (rEntry.second->IsValidReference(aDummy))
2351
0
                aSet.insert(rEntry.second->GetName());
2352
0
        }
2353
0
        for (SCTAB i = 0; i < rDoc.GetTableCount(); ++i)
2354
0
        {
2355
0
            ScRangeName* pLocalRangeName = rDoc.GetRangeName(i);
2356
0
            if (pLocalRangeName && !pLocalRangeName->empty())
2357
0
            {
2358
0
                OUString aTableName;
2359
0
                rDoc.GetName(i, aTableName);
2360
0
                for (const auto& rEntry : *pLocalRangeName)
2361
0
                {
2362
0
                    if (rEntry.second->IsValidReference(aDummy))
2363
0
                        aSet.insert(createLocalRangeName(rEntry.second->GetName(), aTableName));
2364
0
                }
2365
0
            }
2366
0
        }
2367
0
    }
2368
2369
0
    if (!bFormulaMode && !initialize && aSet == aRangeNames)
2370
0
        return;
2371
2372
0
    aRangeNames = aSet;
2373
2374
0
    m_xWidget->clear();
2375
0
    m_xWidget->freeze();
2376
0
    m_xWidget->append_text(ScResId(STR_MANAGE_NAMES));
2377
0
    m_xWidget->append_separator(u"separator"_ustr);
2378
0
    for (const auto& rItem : aSet)
2379
0
    {
2380
0
        m_xWidget->append_text(rItem);
2381
0
    }
2382
0
    m_xWidget->thaw();
2383
0
    if (!aPosStr.isEmpty())
2384
0
        m_xWidget->set_entry_text(aPosStr);
2385
0
}
2386
2387
void ScPosWnd::FillFunctions()
2388
0
{
2389
0
    m_xWidget->clear();
2390
0
    m_xWidget->freeze();
2391
2392
0
    OUString aFirstName;
2393
0
    const ScAppOptions& rOpt = ScModule::get()->GetAppOptions();
2394
0
    sal_uInt16 nMRUCount = rOpt.GetLRUFuncListCount();
2395
0
    const sal_uInt16* pMRUList = rOpt.GetLRUFuncList();
2396
0
    if (pMRUList)
2397
0
    {
2398
0
        const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
2399
0
        sal_uInt32 nListCount = pFuncList->GetCount();
2400
0
        for (sal_uInt16 i=0; i<nMRUCount; i++)
2401
0
        {
2402
0
            sal_uInt16 nId = pMRUList[i];
2403
0
            for (sal_uInt32 j=0; j<nListCount; j++)
2404
0
            {
2405
0
                const ScFuncDesc* pDesc = pFuncList->GetFunction( j );
2406
0
                if ( pDesc->nFIndex == nId && pDesc->mxFuncName )
2407
0
                {
2408
0
                    m_xWidget->append_text(*pDesc->mxFuncName);
2409
0
                    if (aFirstName.isEmpty())
2410
0
                        aFirstName = *pDesc->mxFuncName;
2411
0
                    break; // Stop searching
2412
0
                }
2413
0
            }
2414
0
        }
2415
0
    }
2416
2417
    //! Re-add entry "Other..." for Function AutoPilot if it can work with text that
2418
    // has been entered so far
2419
2420
    //  m_xWidget->append_text(ScResId(STR_FUNCTIONLIST_MORE));
2421
2422
0
    m_xWidget->thaw();
2423
0
    m_xWidget->set_entry_text(aFirstName);
2424
0
}
2425
2426
void ScPosWnd::Notify( SfxBroadcaster&, const SfxHint& rHint )
2427
0
{
2428
0
    if ( bFormulaMode )
2429
0
        return;
2430
2431
0
    const SfxHintId nHintId = rHint.GetId();
2432
    // Does the list of range names need updating?
2433
0
    if (nHintId == SfxHintId::ThisIsAnSfxEventHint)
2434
0
    {
2435
0
        SfxEventHintId nEventId = static_cast<const SfxEventHint&>(rHint).GetEventId();
2436
0
        if ( nEventId == SfxEventHintId::ActivateDoc )
2437
0
            FillRangeNames();
2438
0
    }
2439
0
    else
2440
0
    {
2441
0
        if (nHintId == SfxHintId::ScAreasChanged || nHintId == SfxHintId::ScNavigatorUpdateAll)
2442
0
            FillRangeNames();
2443
0
    }
2444
0
}
2445
2446
void ScPosWnd::HideTip()
2447
0
{
2448
0
    if (nTipVisible)
2449
0
    {
2450
0
        Help::HidePopover(this, nTipVisible);
2451
0
        nTipVisible = nullptr;
2452
0
    }
2453
0
}
2454
2455
static ScNameInputType lcl_GetInputType( const OUString& rText )
2456
0
{
2457
0
    ScNameInputType eRet = SC_NAME_INPUT_BAD_NAME;      // the more general error
2458
2459
0
    ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
2460
0
    if ( pViewSh )
2461
0
    {
2462
0
        ScViewData& rViewData = pViewSh->GetViewData();
2463
0
        ScDocument& rDoc = rViewData.GetDocument();
2464
0
        SCTAB nTab = rViewData.CurrentTabForData();
2465
0
        ScAddress::Details aDetails( rDoc.GetAddressConvention());
2466
2467
        // test in same order as in SID_CURRENTCELL execute
2468
2469
0
        ScRange aRange;
2470
0
        ScAddress aAddress;
2471
0
        SCTAB nNameTab;
2472
0
        sal_Int32 nNumeric;
2473
2474
        // From the context we know that when testing for a range name
2475
        // sheet-local scope names have " (sheetname)" appended and global
2476
        // names don't and can't contain ')', so we can force one or the other.
2477
0
        const RutlNameScope eNameScope =
2478
0
            ((!rText.isEmpty() && rText[rText.getLength()-1] == ')') ? RUTL_NAMES_LOCAL : RUTL_NAMES_GLOBAL);
2479
2480
0
        if (rText == ScResId(STR_MANAGE_NAMES))
2481
0
            eRet = SC_MANAGE_NAMES;
2482
0
        else if ( aRange.Parse( rText, rDoc, aDetails ) & ScRefFlags::VALID )
2483
0
            eRet = SC_NAME_INPUT_RANGE;
2484
0
        else if ( aAddress.Parse( rText, rDoc, aDetails ) & ScRefFlags::VALID )
2485
0
            eRet = SC_NAME_INPUT_CELL;
2486
0
        else if ( ScRangeUtil::MakeRangeFromName( rText, rDoc, nTab, aRange, eNameScope, aDetails ) )
2487
0
        {
2488
0
            eRet = ((eNameScope == RUTL_NAMES_LOCAL) ? SC_NAME_INPUT_NAMEDRANGE_LOCAL :
2489
0
                    SC_NAME_INPUT_NAMEDRANGE_GLOBAL);
2490
0
        }
2491
0
        else if ( ScRangeUtil::MakeRangeFromName( rText, rDoc, nTab, aRange, RUTL_DBASE, aDetails ) )
2492
0
            eRet = SC_NAME_INPUT_DATABASE;
2493
0
        else if ( comphelper::string::isdigitAsciiString( rText ) &&
2494
0
                  ( nNumeric = rText.toInt32() ) > 0 && nNumeric <= rDoc.MaxRow()+1 )
2495
0
            eRet = SC_NAME_INPUT_ROW;
2496
0
        else if ( rDoc.GetTable( rText, nNameTab ) )
2497
0
            eRet = SC_NAME_INPUT_SHEET;
2498
0
        else if (ScRangeData::IsNameValid(rText, rDoc)
2499
0
                 == ScRangeData::IsNameValidType::NAME_VALID) // nothing found, create new range?
2500
0
        {
2501
0
            if ( rViewData.GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
2502
0
                eRet = SC_NAME_INPUT_DEFINE;
2503
0
            else
2504
0
                eRet = SC_NAME_INPUT_BAD_SELECTION;
2505
0
        }
2506
0
        else
2507
0
            eRet = SC_NAME_INPUT_BAD_NAME;
2508
0
    }
2509
2510
0
    return eRet;
2511
0
}
2512
2513
IMPL_LINK_NOARG(ScPosWnd, ModifyHdl, weld::ComboBox&, void)
2514
0
{
2515
0
    HideTip();
2516
2517
0
    if (m_xWidget->changed_by_direct_pick())
2518
0
    {
2519
0
        DoEnter();
2520
0
        return;
2521
0
    }
2522
2523
0
    if (bFormulaMode)
2524
0
        return;
2525
2526
    // determine the action that would be taken for the current input
2527
2528
0
    ScNameInputType eType = lcl_GetInputType(m_xWidget->get_active_text());      // uses current view
2529
0
    TranslateId pStrId;
2530
0
    switch ( eType )
2531
0
    {
2532
0
        case SC_NAME_INPUT_CELL:
2533
0
            pStrId = STR_NAME_INPUT_CELL;
2534
0
            break;
2535
0
        case SC_NAME_INPUT_RANGE:
2536
0
        case SC_NAME_INPUT_NAMEDRANGE_LOCAL:
2537
0
        case SC_NAME_INPUT_NAMEDRANGE_GLOBAL:
2538
0
            pStrId = STR_NAME_INPUT_RANGE;      // named range or range reference
2539
0
            break;
2540
0
        case SC_NAME_INPUT_DATABASE:
2541
0
            pStrId = STR_NAME_INPUT_DBRANGE;
2542
0
            break;
2543
0
        case SC_NAME_INPUT_ROW:
2544
0
            pStrId = STR_NAME_INPUT_ROW;
2545
0
            break;
2546
0
        case SC_NAME_INPUT_SHEET:
2547
0
            pStrId = STR_NAME_INPUT_SHEET;
2548
0
            break;
2549
0
        case SC_NAME_INPUT_DEFINE:
2550
0
            pStrId = STR_NAME_INPUT_DEFINE;
2551
0
            break;
2552
0
        default:
2553
            // other cases (error): no tip help
2554
0
            break;
2555
0
    }
2556
2557
0
    if (!pStrId)
2558
0
        return;
2559
2560
    // show the help tip at the text cursor position
2561
0
    Point aPos;
2562
0
    vcl::Cursor* pCur = GetCursor();
2563
0
    if (pCur)
2564
0
        aPos = LogicToPixel( pCur->GetPos() );
2565
0
    aPos = OutputToScreenPixel( aPos );
2566
0
    tools::Rectangle aRect( aPos, aPos );
2567
2568
0
    OUString aText = ScResId(pStrId);
2569
0
    QuickHelpFlags const nAlign = QuickHelpFlags::Left|QuickHelpFlags::Bottom;
2570
0
    nTipVisible = Help::ShowPopover(this, aRect, aText, nAlign);
2571
0
}
2572
2573
void ScPosWnd::DoEnter()
2574
0
{
2575
0
    bool bOpenManageNamesDialog = false;
2576
0
    OUString aText = m_xWidget->get_active_text();
2577
0
    if ( !aText.isEmpty() )
2578
0
    {
2579
0
        if ( bFormulaMode )
2580
0
        {
2581
0
            ScModule* pScMod = ScModule::get();
2582
0
            if ( aText == ScResId(STR_FUNCTIONLIST_MORE) )
2583
0
            {
2584
                // Function AutoPilot
2585
                //! Continue working with the text entered so far
2586
2587
                //! new method at ScModule to query if function autopilot is open
2588
0
                SfxViewFrame* pViewFrm = SfxViewFrame::Current();
2589
0
                if ( pViewFrm && !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) )
2590
0
                    pViewFrm->GetDispatcher()->Execute( SID_OPENDLG_FUNCTION,
2591
0
                                              SfxCallMode::SYNCHRON | SfxCallMode::RECORD );
2592
0
            }
2593
0
            else
2594
0
            {
2595
0
                ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current()  );
2596
0
                ScInputHandler* pHdl = pScMod->GetInputHdl( pViewSh );
2597
0
                if (pHdl)
2598
0
                    pHdl->InsertFunction( aText );
2599
0
            }
2600
0
        }
2601
0
        else
2602
0
        {
2603
            // depending on the input, select something or create a new named range
2604
2605
0
            ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
2606
0
            if ( pViewSh )
2607
0
            {
2608
0
                ScViewData& rViewData = pViewSh->GetViewData();
2609
0
                ScDocShell* pDocShell = rViewData.GetDocShell();
2610
0
                ScDocument& rDoc = pDocShell->GetDocument();
2611
2612
0
                ScNameInputType eType = lcl_GetInputType( aText );
2613
0
                if ( eType == SC_NAME_INPUT_BAD_NAME || eType == SC_NAME_INPUT_BAD_SELECTION )
2614
0
                {
2615
0
                    TranslateId pId = (eType == SC_NAME_INPUT_BAD_NAME) ? STR_NAME_ERROR_NAME : STR_NAME_ERROR_SELECTION;
2616
0
                    pViewSh->ErrorMessage(pId);
2617
0
                }
2618
0
                else if ( eType == SC_NAME_INPUT_DEFINE )
2619
0
                {
2620
0
                    ScRangeName* pNames = rDoc.GetRangeName();
2621
0
                    ScRange aSelection;
2622
0
                    if ( pNames && !pNames->findByUpperName(ScGlobal::getCharClass().uppercase(aText)) &&
2623
0
                            (rViewData.GetSimpleArea( aSelection ) == SC_MARK_SIMPLE) )
2624
0
                    {
2625
0
                        ScRangeName aNewRanges( *pNames );
2626
0
                        ScAddress aCursor( rViewData.GetCurX(), rViewData.GetCurY(), rViewData.CurrentTabForData() );
2627
0
                        OUString aContent(aSelection.Format(rDoc, ScRefFlags::RANGE_ABS_3D, rDoc.GetAddressConvention()));
2628
0
                        ScRangeData* pNew = new ScRangeData( rDoc, aText, aContent, aCursor );
2629
0
                        if ( aNewRanges.insert(pNew) )
2630
0
                        {
2631
0
                            pDocShell->GetDocFunc().ModifyRangeNames( aNewRanges );
2632
0
                            pViewSh->UpdateInputHandler(true);
2633
0
                        }
2634
0
                    }
2635
0
                }
2636
0
                else if (eType == SC_MANAGE_NAMES)
2637
0
                {
2638
                    // dialog is only set below after calling 'ReleaseFocus_Impl' to ensure it gets focus
2639
0
                    bOpenManageNamesDialog = true;
2640
0
                }
2641
0
                else
2642
0
                {
2643
0
                    bool bForceGlobalName = false;
2644
                    // for all selection types, execute the SID_CURRENTCELL slot.
2645
0
                    if (eType == SC_NAME_INPUT_CELL || eType == SC_NAME_INPUT_RANGE)
2646
0
                    {
2647
                        // Note that SID_CURRENTCELL always expects address to
2648
                        // be in Calc A1 format.  Convert the text.
2649
0
                        ScRange aRange(0,0, rViewData.CurrentTabForData());
2650
0
                        aRange.ParseAny(aText, rDoc, rDoc.GetAddressConvention());
2651
0
                        aText = aRange.Format(rDoc, ScRefFlags::RANGE_ABS_3D, ::formula::FormulaGrammar::CONV_OOO);
2652
0
                    }
2653
0
                    else if (eType == SC_NAME_INPUT_NAMEDRANGE_GLOBAL)
2654
0
                    {
2655
0
                        bForceGlobalName = true;
2656
0
                    }
2657
2658
0
                    SfxStringItem aPosItem( SID_CURRENTCELL, aText );
2659
0
                    SfxBoolItem aUnmarkItem( FN_PARAM_1, true );        // remove existing selection
2660
                    // FN_PARAM_2 reserved for AlignToCursor
2661
0
                    SfxBoolItem aForceGlobalName( FN_PARAM_3, bForceGlobalName );
2662
2663
0
                    pViewSh->GetViewData().GetDispatcher().ExecuteList( SID_CURRENTCELL,
2664
0
                                        SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
2665
0
                                        { &aPosItem, &aUnmarkItem, &aForceGlobalName });
2666
0
                }
2667
0
            }
2668
0
        }
2669
0
    }
2670
0
    else
2671
0
        m_xWidget->set_entry_text(aPosStr);
2672
2673
0
    ReleaseFocus_Impl();
2674
2675
0
    if (bOpenManageNamesDialog)
2676
0
    {
2677
0
        const sal_uInt16 nId  = ScNameDlgWrapper::GetChildWindowId();
2678
0
        if (ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell())
2679
0
        {
2680
0
            SfxViewFrame& rViewFrm = pViewSh->GetViewFrame();
2681
0
            SfxChildWindow* pWnd = rViewFrm.GetChildWindow( nId );
2682
0
            ScModule::get()->SetRefDialog(nId, pWnd == nullptr);
2683
0
        }
2684
0
    }
2685
0
}
2686
2687
IMPL_LINK_NOARG(ScPosWnd, ActivateHdl, weld::ComboBox&, bool)
2688
0
{
2689
0
    DoEnter();
2690
0
    return true;
2691
0
}
2692
2693
IMPL_LINK(ScPosWnd, KeyInputHdl, const KeyEvent&, rKEvt, bool)
2694
0
{
2695
0
    bool bHandled = true;
2696
2697
0
    switch (rKEvt.GetKeyCode().GetCode())
2698
0
    {
2699
0
        case KEY_RETURN:
2700
0
            bHandled = ActivateHdl(*m_xWidget);
2701
0
            break;
2702
0
        case KEY_ESCAPE:
2703
0
            if (nTipVisible)
2704
0
            {
2705
                // escape when the tip help is shown: only hide the tip
2706
0
                HideTip();
2707
0
            }
2708
0
            else
2709
0
            {
2710
0
                if (!bFormulaMode)
2711
0
                    m_xWidget->set_entry_text(aPosStr);
2712
0
                ReleaseFocus_Impl();
2713
0
            }
2714
0
            break;
2715
0
        default:
2716
0
            bHandled = false;
2717
0
            break;
2718
0
    }
2719
2720
0
    return bHandled || ChildKeyInput(rKEvt);
2721
0
}
2722
2723
IMPL_LINK_NOARG(ScPosWnd, OnAsyncGetFocus, void*, void)
2724
0
{
2725
0
    m_nAsyncGetFocusId = nullptr;
2726
0
    m_xWidget->select_entry_region(0, -1);
2727
0
}
2728
2729
IMPL_LINK_NOARG(ScPosWnd, FocusInHdl, weld::Widget&, void)
2730
0
{
2731
0
    if (m_nAsyncGetFocusId)
2732
0
        return;
2733
    // do it async to defeat entry in combobox having its own ideas about the focus
2734
0
    m_nAsyncGetFocusId = Application::PostUserEvent(LINK(this, ScPosWnd, OnAsyncGetFocus));
2735
0
}
2736
2737
IMPL_LINK_NOARG(ScPosWnd, FocusOutHdl, weld::Widget&, void)
2738
0
{
2739
0
    if (m_nAsyncGetFocusId)
2740
0
    {
2741
0
        Application::RemoveUserEvent(m_nAsyncGetFocusId);
2742
0
        m_nAsyncGetFocusId = nullptr;
2743
0
    }
2744
2745
0
    HideTip();
2746
0
}
2747
2748
void ScPosWnd::ReleaseFocus_Impl()
2749
0
{
2750
0
    HideTip();
2751
2752
0
    SfxViewShell* pCurSh = SfxViewShell::Current();
2753
0
    ScInputHandler* pHdl = ScModule::get()->GetInputHdl(dynamic_cast<ScTabViewShell*>(pCurSh));
2754
0
    if ( pHdl && pHdl->IsTopMode() )
2755
0
    {
2756
        // Focus back in input row?
2757
0
        ScInputWindow* pInputWin = pHdl->GetInputWindow();
2758
0
        if (pInputWin)
2759
0
        {
2760
0
            pInputWin->TextGrabFocus();
2761
0
            return;
2762
0
        }
2763
0
    }
2764
2765
    // Set focus to active View
2766
0
    if ( pCurSh )
2767
0
    {
2768
0
        vcl::Window* pShellWnd = pCurSh->GetWindow();
2769
2770
0
        if ( pShellWnd )
2771
0
            pShellWnd->GrabFocus();
2772
0
    }
2773
0
}
2774
2775
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */