Coverage Report

Created: 2025-12-08 09:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/starmath/source/document.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 <sal/config.h>
21
22
#include <com/sun/star/accessibility/AccessibleEventId.hpp>
23
#include <com/sun/star/uno/Any.h>
24
25
#include <comphelper/fileformat.h>
26
#include <comphelper/accessibletexthelper.hxx>
27
#include <comphelper/string.hxx>
28
#include <rtl/ustrbuf.hxx>
29
#include <rtl/ustring.hxx>
30
#include <sal/log.hxx>
31
#include <unotools/eventcfg.hxx>
32
#include <sfx2/event.hxx>
33
#include <sfx2/app.hxx>
34
#include <sfx2/bindings.hxx>
35
#include <sfx2/docfile.hxx>
36
#include <sfx2/docfilt.hxx>
37
#include <sfx2/msg.hxx>
38
#include <sfx2/objface.hxx>
39
#include <sfx2/printer.hxx>
40
#include <sfx2/request.hxx>
41
#include <sfx2/viewfrm.hxx>
42
#include <comphelper/classids.hxx>
43
#include <sot/formats.hxx>
44
#include <sot/storage.hxx>
45
#include <svl/eitem.hxx>
46
#include <svl/intitem.hxx>
47
#include <svl/itempool.hxx>
48
#include <svl/slstitm.hxx>
49
#include <svl/hint.hxx>
50
#include <svl/stritem.hxx>
51
#include <svl/undo.hxx>
52
#include <svl/whiter.hxx>
53
#include <vcl/mapmod.hxx>
54
#include <vcl/virdev.hxx>
55
#include <tools/mapunit.hxx>
56
#include <vcl/settings.hxx>
57
58
#include <document.hxx>
59
#include <action.hxx>
60
#include <dialog.hxx>
61
#include <format.hxx>
62
#include <parse.hxx>
63
#include <starmath.hrc>
64
#include <strings.hrc>
65
#include <smmod.hxx>
66
#include <symbol.hxx>
67
#include <unomodel.hxx>
68
#include <utility.hxx>
69
#include <view.hxx>
70
#include "mathtype.hxx"
71
#include "ooxmlexport.hxx"
72
#include "ooxmlimport.hxx"
73
#include "rtfexport.hxx"
74
#include <mathmlimport.hxx>
75
#include <mathmlexport.hxx>
76
#include <svx/svxids.hrc>
77
#include <cursor.hxx>
78
#include <comphelper/diagnose_ex.hxx>
79
#include <visitors.hxx>
80
#include "accessibility.hxx"
81
#include <cfgitem.hxx>
82
#include <utility>
83
#include <oox/mathml/imexport.hxx>
84
#include <ElementsDockingWindow.hxx>
85
#include <smediteng.hxx>
86
#include <editeng/editund2.hxx>
87
88
#define ShellClass_SmDocShell
89
#include <smslots.hxx>
90
91
using namespace ::com::sun::star;
92
using namespace ::com::sun::star::accessibility;
93
using namespace ::com::sun::star::uno;
94
95
96
SFX_IMPL_SUPERCLASS_INTERFACE(SmDocShell, SfxObjectShell)
97
98
void SmDocShell::InitInterface_Impl()
99
1
{
100
1
    GetStaticInterface()->RegisterPopupMenu(u"view"_ustr);
101
1
}
102
103
void SmDocShell::SetSmSyntaxVersion(sal_Int16 nSmSyntaxVersion)
104
32.1k
{
105
32.1k
    mnSmSyntaxVersion = nSmSyntaxVersion;
106
32.1k
    maParser.reset(starmathdatabase::GetVersionSmParser(mnSmSyntaxVersion));
107
32.1k
}
108
109
SFX_IMPL_OBJECTFACTORY(SmDocShell, SvGlobalName(SO3_SM_CLASSID), u"smath"_ustr )
110
111
void SmDocShell::Notify(SfxBroadcaster&, const SfxHint& rHint)
112
0
{
113
0
    if (rHint.GetId() == SfxHintId::MathFormatChanged)
114
0
    {
115
0
        SetFormulaArranged(false);
116
117
0
        mnModifyCount++;     //! see comment for SID_GRAPHIC_SM in SmDocShell::GetState
118
119
0
        Repaint();
120
0
    }
121
0
}
122
123
void SmDocShell::LoadSymbols()
124
0
{
125
0
    SmModule::get()->GetSymbolManager().Load();
126
0
}
127
128
129
OUString SmDocShell::GetComment() const
130
0
{
131
0
    uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
132
0
        GetModel(), uno::UNO_QUERY_THROW);
133
0
    uno::Reference<document::XDocumentProperties> xDocProps(
134
0
        xDPS->getDocumentProperties());
135
0
    return xDocProps->getDescription();
136
0
}
137
138
139
void SmDocShell::SetText(const OUString& rBuffer)
140
4.69k
{
141
4.69k
    if (rBuffer == maText)
142
49
        return;
143
144
4.64k
    bool bIsEnabled = IsEnableSetModified();
145
4.64k
    if( bIsEnabled )
146
4.64k
        EnableSetModified( false );
147
148
4.64k
    maText = rBuffer;
149
4.64k
    SetFormulaArranged( false );
150
151
4.64k
    Parse();
152
153
4.64k
    SmViewShell *pViewSh = SmGetActiveView();
154
4.64k
    if (pViewSh)
155
0
    {
156
0
        pViewSh->GetViewFrame().GetBindings().Invalidate(SID_TEXT);
157
0
        if ( SfxObjectCreateMode::EMBEDDED == GetCreateMode() )
158
0
        {
159
            // have SwOleClient::FormatChanged() to align the modified formula properly
160
            // even if the visible area does not change (e.g. when formula text changes from
161
            // "{a over b + c} over d" to "d over {a over b + c}"
162
0
            SfxGetpApp()->NotifyEvent(SfxEventHint( SfxEventHintId::VisAreaChanged, GlobalEventConfig::GetEventName(GlobalEventId::VISAREACHANGED), this));
163
164
0
            Repaint();
165
0
        }
166
0
        else
167
0
            pViewSh->GetGraphicWidget().Invalidate();
168
0
    }
169
170
4.64k
    if ( bIsEnabled )
171
4.64k
        EnableSetModified( bIsEnabled );
172
4.64k
    SetModified();
173
174
    // launch accessible event if necessary
175
4.64k
    SmGraphicAccessible *pAcc = pViewSh ? pViewSh->GetGraphicWidget().GetAccessible_Impl() : nullptr;
176
4.64k
    if (pAcc)
177
0
    {
178
0
        Any aOldValue, aNewValue;
179
0
        if ( comphelper::OCommonAccessibleText::implInitTextChangedEvent( maText, rBuffer, aOldValue, aNewValue ) )
180
0
        {
181
0
            pAcc->LaunchEvent( AccessibleEventId::TEXT_CHANGED,
182
0
                    aOldValue, aNewValue );
183
0
        }
184
0
    }
185
186
4.64k
    if ( GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
187
4.64k
        OnDocumentPrinterChanged(nullptr);
188
4.64k
}
189
190
void SmDocShell::SetFormat(SmFormat const & rFormat)
191
330
{
192
330
    maFormat = rFormat;
193
330
    SetFormulaArranged( false );
194
330
    SetModified();
195
196
330
    mnModifyCount++;     //! see comment for SID_GRAPHIC_SM in SmDocShell::GetState
197
198
    // don't use SmGetActiveView since the view shell might not be active (0 pointer)
199
    // if for example the Basic Macro dialog currently has the focus. Thus:
200
330
    SfxViewFrame* pFrm = SfxViewFrame::GetFirst( this );
201
330
    while (pFrm)
202
0
    {
203
0
        pFrm->GetBindings().Invalidate(SID_GRAPHIC_SM);
204
0
        pFrm = SfxViewFrame::GetNext( *pFrm, this );
205
0
    }
206
330
}
207
208
OUString const & SmDocShell::GetAccessibleText()
209
0
{
210
0
    ArrangeFormula();
211
0
    if (maAccText.isEmpty())
212
0
    {
213
0
        OSL_ENSURE( mpTree, "Tree missing" );
214
0
        if (mpTree)
215
0
        {
216
0
            OUStringBuffer aBuf;
217
0
            mpTree->GetAccessibleText(aBuf);
218
0
            maAccText = aBuf.makeStringAndClear();
219
0
        }
220
0
    }
221
0
    return maAccText;
222
0
}
223
224
void SmDocShell::Parse()
225
4.75k
{
226
4.75k
    mpTree.reset();
227
4.75k
    ReplaceBadChars();
228
4.75k
    mpTree = maParser->Parse(maText);
229
4.75k
    mnModifyCount++;     //! see comment for SID_GRAPHIC_SM in SmDocShell::GetState
230
4.75k
    SetFormulaArranged( false );
231
4.75k
    InvalidateCursor();
232
4.75k
    maUsedSymbols = maParser->GetUsedSymbols();
233
4.75k
}
234
235
236
void SmDocShell::ArrangeFormula()
237
5.17k
{
238
5.17k
    if (mbFormulaArranged)
239
0
        return;
240
241
    // Only for the duration of the existence of this object the correct settings
242
    // at the printer are guaranteed!
243
5.17k
    SmPrinterAccess  aPrtAcc(*this);
244
5.17k
    OutputDevice* pOutDev = aPrtAcc.GetRefDev();
245
246
5.17k
    SAL_WARN_IF( !pOutDev, "starmath", "!! SmDocShell::ArrangeFormula: reference device missing !!");
247
248
    // if necessary get another OutputDevice for which we format
249
5.17k
    if (!pOutDev)
250
5.17k
    {
251
5.17k
        if (SmViewShell *pView = SmGetActiveView())
252
0
            pOutDev = &pView->GetGraphicWidget().GetDrawingArea()->get_ref_device();
253
5.17k
        else
254
5.17k
        {
255
5.17k
            pOutDev = &SmModule::get()->GetDefaultVirtualDev();
256
5.17k
            pOutDev->SetMapMode( MapMode(SmMapUnit()) );
257
5.17k
        }
258
5.17k
    }
259
5.17k
    OSL_ENSURE(pOutDev->GetMapMode().GetMapUnit() == SmMapUnit(),
260
5.17k
               "Sm : wrong MapMode");
261
262
5.17k
    const SmFormat &rFormat = GetFormat();
263
5.17k
    mpTree->Prepare(rFormat, *this, 0);
264
265
5.17k
    auto popIt = pOutDev->ScopedPush(vcl::PushFlags::TEXTLAYOUTMODE | vcl::PushFlags::TEXTLANGUAGE);
266
267
    // We want the device to always be LTR, we handle RTL formulas ourselves.
268
5.17k
    bool bOldRTL = pOutDev->IsRTLEnabled();
269
5.17k
    pOutDev->EnableRTL(false);
270
271
    // For RTL formulas, we want the brackets to be mirrored.
272
5.17k
    bool bRTL = GetFormat().IsRightToLeft();
273
5.17k
    pOutDev->SetLayoutMode(bRTL ? vcl::text::ComplexTextLayoutFlags::BiDiRtl
274
5.17k
                                : vcl::text::ComplexTextLayoutFlags::Default);
275
276
    // Numbers should not be converted, for now.
277
5.17k
    pOutDev->SetDigitLanguage( LANGUAGE_ENGLISH );
278
279
5.17k
    mpTree->Arrange(*pOutDev, rFormat);
280
281
5.17k
    pOutDev->EnableRTL(bOldRTL);
282
283
5.17k
    SetFormulaArranged(true);
284
285
    // invalidate accessible text
286
5.17k
    maAccText.clear();
287
5.17k
}
288
289
void SmDocShell::UpdateEditEngineDefaultFonts()
290
0
{
291
0
    SmEditEngine::setSmItemPool(mpEditEngineItemPool.get(), maLinguOptions);
292
0
}
293
294
EditEngine& SmDocShell::GetEditEngine()
295
0
{
296
0
    if (!mpEditEngine)
297
0
    {
298
        //!
299
        //! see also SmEditWindow::DataChanged !
300
        //!
301
0
        mpEditEngineItemPool = EditEngine::CreatePool();
302
0
        SmEditEngine::setSmItemPool(mpEditEngineItemPool.get(), maLinguOptions);
303
0
        mpEditEngine.reset( new SmEditEngine( mpEditEngineItemPool.get() ) );
304
0
        mpEditEngine->EraseVirtualDevice();
305
306
        // set initial text if the document already has some...
307
        // (may be the case when reloading a doc)
308
0
        OUString aTxt( GetText() );
309
0
        if (!aTxt.isEmpty())
310
0
            mpEditEngine->SetText( aTxt );
311
0
        mpEditEngine->ClearModifyFlag();
312
0
    }
313
0
    return *mpEditEngine;
314
0
}
315
316
317
void SmDocShell::DrawFormula(OutputDevice &rDev, Point &rPosition, bool bDrawSelection)
318
0
{
319
0
    if (!mpTree)
320
0
        Parse();
321
0
    OSL_ENSURE(mpTree, "Sm : NULL pointer");
322
323
0
    ArrangeFormula();
324
325
0
    bool bRTL = GetFormat().IsRightToLeft();
326
327
    // Problem: What happens to WYSIWYG? While we're active inplace, we don't have a reference
328
    // device and aren't aligned to that either. So now there can be a difference between the
329
    // VisArea (i.e. the size within the client) and the current size.
330
    // Idea: The difference could be adapted with SmNod::SetSize (no long-term solution)
331
332
0
    rPosition.AdjustX(maFormat.GetDistance( DIS_LEFTSPACE ) );
333
0
    rPosition.AdjustY(maFormat.GetDistance( DIS_TOPSPACE  ) );
334
335
0
    Point aPosition(rPosition);
336
0
    if (bRTL && rDev.GetOutDevType() != OUTDEV_WINDOW)
337
0
        aPosition.AdjustX(GetSize().Width()
338
0
                          - maFormat.GetDistance(DIS_LEFTSPACE)
339
0
                          - maFormat.GetDistance(DIS_RIGHTSPACE));
340
341
    //! in case of high contrast-mode (accessibility option!)
342
    //! the draw mode needs to be set to default, because when embedding
343
    //! Math for example in Calc in "a over b" the fraction bar may not
344
    //! be visible else. More generally: the FillColor may have been changed.
345
0
    DrawModeFlags nOldDrawMode = DrawModeFlags::Default;
346
0
    bool bRestoreDrawMode = false;
347
0
    if (OUTDEV_WINDOW == rDev.GetOutDevType() &&
348
0
        rDev.GetOwnerWindow()->GetSettings().GetStyleSettings().GetHighContrastMode())
349
0
    {
350
0
        nOldDrawMode = rDev.GetDrawMode();
351
0
        rDev.SetDrawMode( DrawModeFlags::Default );
352
0
        bRestoreDrawMode = true;
353
0
    }
354
355
0
    rDev.Push(vcl::PushFlags::TEXTLAYOUTMODE | vcl::PushFlags::TEXTLANGUAGE);
356
357
    // We want the device to always be LTR, we handle RTL formulas ourselves.
358
0
    bool bOldRTL = rDev.IsRTLEnabled();
359
0
    if (rDev.GetOutDevType() == OUTDEV_WINDOW)
360
0
        rDev.EnableRTL(bRTL);
361
0
    else
362
0
        rDev.EnableRTL(false);
363
364
0
    auto nLayoutFlags = vcl::text::ComplexTextLayoutFlags::Default;
365
0
    if (bRTL)
366
0
    {
367
        // For RTL formulas, we want the brackets to be mirrored.
368
0
        nLayoutFlags |= vcl::text::ComplexTextLayoutFlags::BiDiRtl;
369
0
        if (rDev.GetOutDevType() == OUTDEV_WINDOW)
370
0
            nLayoutFlags |= vcl::text::ComplexTextLayoutFlags::TextOriginLeft;
371
0
    }
372
373
0
    rDev.SetLayoutMode(nLayoutFlags);
374
375
    // Numbers should not be converted, for now.
376
0
    rDev.SetDigitLanguage( LANGUAGE_ENGLISH );
377
378
    //Set selection if any
379
0
    if(mpCursor && bDrawSelection){
380
0
        mpCursor->AnnotateSelection();
381
0
        SmSelectionDrawingVisitor(rDev, mpTree.get(), aPosition);
382
0
    }
383
384
    //Drawing using visitor
385
0
    SmDrawingVisitor(rDev, aPosition, mpTree.get(), GetFormat());
386
387
0
    rDev.EnableRTL(bOldRTL);
388
0
    rDev.Pop();
389
390
0
    if (bRestoreDrawMode)
391
0
        rDev.SetDrawMode( nOldDrawMode );
392
0
}
393
394
Size SmDocShell::GetSize()
395
5.17k
{
396
5.17k
    Size aRet;
397
398
5.17k
    if (!mpTree)
399
111
        Parse();
400
401
5.17k
    if (mpTree)
402
5.17k
    {
403
5.17k
        ArrangeFormula();
404
5.17k
        aRet = mpTree->GetSize();
405
406
5.17k
        if ( !aRet.Width() || aRet.Width() == 1 )
407
535
            aRet.setWidth( 2000 );
408
4.64k
        else
409
4.64k
            aRet.AdjustWidth(maFormat.GetDistance( DIS_LEFTSPACE ) +
410
4.64k
                             maFormat.GetDistance( DIS_RIGHTSPACE ) );
411
5.17k
        if ( !aRet.Height() )
412
0
            aRet.setHeight( 1000 );
413
5.17k
        else
414
5.17k
            aRet.AdjustHeight(maFormat.GetDistance( DIS_TOPSPACE ) +
415
5.17k
                             maFormat.GetDistance( DIS_BOTTOMSPACE ) );
416
5.17k
    }
417
418
5.17k
    return aRet;
419
5.17k
}
420
421
4.75k
void SmDocShell::InvalidateCursor(){
422
4.75k
    mpCursor.reset();
423
4.75k
}
424
425
0
SmCursor& SmDocShell::GetCursor(){
426
0
    if(!mpCursor)
427
0
        mpCursor.reset(new SmCursor(mpTree.get(), this));
428
0
    return *mpCursor;
429
0
}
430
431
0
bool SmDocShell::HasCursor() const { return mpCursor != nullptr; }
432
433
SmPrinterAccess::SmPrinterAccess( SmDocShell &rDocShell )
434
5.17k
{
435
5.17k
    pPrinter = rDocShell.GetPrt();
436
5.17k
    if ( pPrinter )
437
0
    {
438
0
        pPrinter->Push( vcl::PushFlags::MAPMODE );
439
0
        if ( SfxObjectCreateMode::EMBEDDED == rDocShell.GetCreateMode() )
440
0
        {
441
            // if it is an embedded object (without its own printer)
442
            // we change the MapMode temporarily.
443
            //!If it is a document with its own printer the MapMode should
444
            //!be set correct (once) elsewhere(!), in order to avoid numerous
445
            //!superfluous pushing and popping of the MapMode when using
446
            //!this class.
447
448
0
            const MapUnit eOld = pPrinter->GetMapMode().GetMapUnit();
449
0
            if ( SmMapUnit() != eOld )
450
0
            {
451
0
                MapMode aMap( pPrinter->GetMapMode() );
452
0
                aMap.SetMapUnit( SmMapUnit() );
453
0
                Point aTmp( aMap.GetOrigin() );
454
0
                aTmp.setX( OutputDevice::LogicToLogic( aTmp.X(), eOld, SmMapUnit() ) );
455
0
                aTmp.setY( OutputDevice::LogicToLogic( aTmp.Y(), eOld, SmMapUnit() ) );
456
0
                aMap.SetOrigin( aTmp );
457
0
                pPrinter->SetMapMode( aMap );
458
0
            }
459
0
        }
460
0
    }
461
5.17k
    pRefDev = rDocShell.GetRefDev();
462
5.17k
    if ( !pRefDev || pPrinter.get() == pRefDev.get() )
463
5.17k
        return;
464
465
0
    pRefDev->Push( vcl::PushFlags::MAPMODE );
466
0
    if ( SfxObjectCreateMode::EMBEDDED != rDocShell.GetCreateMode() )
467
0
        return;
468
469
    // if it is an embedded object (without its own printer)
470
    // we change the MapMode temporarily.
471
    //!If it is a document with its own printer the MapMode should
472
    //!be set correct (once) elsewhere(!), in order to avoid numerous
473
    //!superfluous pushing and popping of the MapMode when using
474
    //!this class.
475
476
0
    const MapUnit eOld = pRefDev->GetMapMode().GetMapUnit();
477
0
    if ( SmMapUnit() != eOld )
478
0
    {
479
0
        MapMode aMap( pRefDev->GetMapMode() );
480
0
        aMap.SetMapUnit( SmMapUnit() );
481
0
        Point aTmp( aMap.GetOrigin() );
482
0
        aTmp.setX( OutputDevice::LogicToLogic( aTmp.X(), eOld, SmMapUnit() ) );
483
0
        aTmp.setY( OutputDevice::LogicToLogic( aTmp.Y(), eOld, SmMapUnit() ) );
484
0
        aMap.SetOrigin( aTmp );
485
0
        pRefDev->SetMapMode( aMap );
486
0
    }
487
0
}
488
489
SmPrinterAccess::~SmPrinterAccess()
490
5.17k
{
491
5.17k
    if ( pPrinter )
492
0
        pPrinter->Pop();
493
5.17k
    if ( pRefDev && pRefDev != pPrinter )
494
0
        pRefDev->Pop();
495
5.17k
}
496
497
Printer* SmDocShell::GetPrt()
498
10.3k
{
499
10.3k
    if (SfxObjectCreateMode::EMBEDDED == GetCreateMode())
500
10.3k
    {
501
        // Normally the server provides the printer. But if it doesn't provide one (e.g. because
502
        // there is no connection) it still can be the case that we know the printer because it
503
        // has been passed on by the server in OnDocumentPrinterChanged and being kept temporarily.
504
10.3k
        Printer* pPrt = GetDocumentPrinter();
505
10.3k
        if (!pPrt && mpTmpPrinter)
506
0
            pPrt = mpTmpPrinter;
507
10.3k
        return pPrt;
508
10.3k
    }
509
0
    else if (!mpPrinter)
510
0
    {
511
0
        auto pOptions = std::make_unique<SfxItemSetFixed<
512
0
                SID_PRINTTITLE, SID_PRINTZOOM,
513
0
                SID_NO_RIGHT_SPACES, SID_SAVE_ONLY_USED_SYMBOLS,
514
0
                SID_AUTO_CLOSE_BRACKETS, SID_SMEDITWINDOWZOOM,
515
0
                SID_INLINE_EDIT_ENABLE, SID_INLINE_EDIT_ENABLE>>(GetPool());
516
0
        SmModule::get()->GetConfig()->ConfigToItemSet(*pOptions);
517
0
        mpPrinter = VclPtr<SfxPrinter>::Create(std::move(pOptions));
518
0
        mpPrinter->SetMapMode(MapMode(SmMapUnit()));
519
0
    }
520
0
    return mpPrinter;
521
10.3k
}
522
523
OutputDevice* SmDocShell::GetRefDev()
524
5.17k
{
525
5.17k
    if (SfxObjectCreateMode::EMBEDDED == GetCreateMode())
526
5.17k
    {
527
5.17k
        OutputDevice* pOutDev = GetDocumentRefDev();
528
5.17k
        if (pOutDev)
529
0
            return pOutDev;
530
5.17k
    }
531
532
5.17k
    return GetPrt();
533
5.17k
}
534
535
void SmDocShell::SetPrinter( SfxPrinter *pNew )
536
203
{
537
203
    mpPrinter.disposeAndClear();
538
203
    mpPrinter = pNew;    //Transfer ownership
539
203
    mpPrinter->SetMapMode( MapMode(SmMapUnit()) );
540
203
    SetFormulaArranged(false);
541
203
    Repaint();
542
203
}
543
544
void SmDocShell::OnDocumentPrinterChanged( Printer *pPrt )
545
4.64k
{
546
4.64k
    mpTmpPrinter = pPrt;
547
4.64k
    SetFormulaArranged(false);
548
4.64k
    Size aOldSize = GetVisArea().GetSize();
549
4.64k
    Repaint();
550
4.64k
    if( aOldSize != GetVisArea().GetSize() && !maText.isEmpty() )
551
4.64k
        SetModified();
552
4.64k
    mpTmpPrinter = nullptr;
553
4.64k
}
554
555
void SmDocShell::Repaint()
556
4.84k
{
557
4.84k
    bool bIsEnabled = IsEnableSetModified();
558
4.84k
    if (bIsEnabled)
559
4.84k
        EnableSetModified( false );
560
561
4.84k
    SetFormulaArranged(false);
562
563
4.84k
    Size aVisSize = GetSize();
564
4.84k
    SetVisAreaSize(aVisSize);
565
4.84k
    if (SmViewShell* pViewSh = SmGetActiveView())
566
0
        pViewSh->GetGraphicWidget().Invalidate();
567
568
4.84k
    if (bIsEnabled)
569
4.84k
        EnableSetModified(bIsEnabled);
570
4.84k
}
571
572
SmDocShell::SmDocShell( SfxModelFlags i_nSfxCreationFlags )
573
27.4k
    : SfxObjectShell(i_nSfxCreationFlags)
574
27.4k
    , m_pMlElementTree(nullptr)
575
27.4k
    , mpPrinter(nullptr)
576
27.4k
    , mpTmpPrinter(nullptr)
577
27.4k
    , mnModifyCount(0)
578
27.4k
    , mbFormulaArranged(false)
579
27.4k
{
580
27.4k
    SvtLinguConfig().GetOptions(maLinguOptions);
581
582
27.4k
    SetPool(&SfxGetpApp()->GetPool());
583
584
27.4k
    auto* config = SmModule::get()->GetConfig();
585
27.4k
    mnSmSyntaxVersion = config->GetDefaultSmSyntaxVersion();
586
27.4k
    maFormat = config->GetStandardFormat();
587
588
27.4k
    StartListening(maFormat);
589
27.4k
    StartListening(*config);
590
591
27.4k
    SetBaseModel(new SmModel(this));
592
27.4k
    SetSmSyntaxVersion(mnSmSyntaxVersion);
593
594
27.4k
    SetMapUnit(SmMapUnit());
595
27.4k
}
596
597
SmDocShell::~SmDocShell()
598
27.4k
{
599
27.4k
    EndListening(maFormat);
600
27.4k
    EndListening(*SmModule::get()->GetConfig());
601
602
27.4k
    mpCursor.reset();
603
27.4k
    mpEditEngine.reset();
604
27.4k
    mpEditEngineItemPool.clear();
605
27.4k
    mpPrinter.disposeAndClear();
606
607
27.4k
    mathml::SmMlIteratorFree(m_pMlElementTree);
608
27.4k
}
609
610
bool SmDocShell::ConvertFrom(SfxMedium &rMedium)
611
0
{
612
0
    bool     bSuccess = false;
613
0
    const OUString& rFltName = rMedium.GetFilter()->GetFilterName();
614
615
0
    OSL_ENSURE( rFltName != STAROFFICE_XML, "Wrong filter!");
616
617
0
    if ( rFltName == MATHML_XML )
618
0
    {
619
0
        if (mpTree)
620
0
        {
621
0
            mpTree.reset();
622
0
            InvalidateCursor();
623
0
        }
624
0
        rtl::Reference<SmModel> xModel(dynamic_cast<SmModel*>(GetModel().get()));
625
0
        SmXMLImportWrapper aEquation(xModel);
626
0
        aEquation.useHTMLMLEntities(true);
627
0
        bSuccess = ( ERRCODE_NONE == aEquation.Import(rMedium) );
628
0
    }
629
0
    else
630
0
    {
631
0
        SvStream *pStream = rMedium.GetInStream();
632
0
        if ( pStream )
633
0
        {
634
0
            if ( SotStorage::IsStorageFile( pStream ) )
635
0
            {
636
0
                rtl::Reference<SotStorage> aStorage = new SotStorage(pStream, false);
637
0
                if ( aStorage->IsStream(u"Equation Native"_ustr) )
638
0
                {
639
                    // is this a MathType Storage?
640
0
                    OUStringBuffer aBuffer;
641
0
                    MathType aEquation(aBuffer);
642
0
                    bSuccess = aEquation.Parse( aStorage.get() );
643
0
                    if ( bSuccess )
644
0
                    {
645
0
                        maText = aBuffer.makeStringAndClear();
646
0
                        Parse();
647
0
                    }
648
0
                }
649
0
            }
650
0
        }
651
0
    }
652
653
0
    if ( GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
654
0
    {
655
0
        SetFormulaArranged( false );
656
0
        Repaint();
657
0
    }
658
659
0
    FinishedLoading();
660
0
    return bSuccess;
661
0
}
662
663
664
bool SmDocShell::InitNew( const uno::Reference < embed::XStorage >& xStorage )
665
27.4k
{
666
27.4k
    bool bRet = false;
667
27.4k
    if ( SfxObjectShell::InitNew( xStorage ) )
668
27.4k
    {
669
27.4k
        bRet = true;
670
27.4k
        SetVisArea(tools::Rectangle(Point(0, 0), Size(2000, 1000)));
671
27.4k
    }
672
27.4k
    return bRet;
673
27.4k
}
674
675
676
bool SmDocShell::Load( SfxMedium& rMedium )
677
0
{
678
0
    bool bRet = false;
679
0
    if( SfxObjectShell::Load( rMedium ))
680
0
    {
681
0
        uno::Reference < embed::XStorage > xStorage = GetMedium()->GetStorage();
682
0
        if (xStorage->hasByName(u"content.xml"_ustr) && xStorage->isStreamElement(u"content.xml"_ustr))
683
0
        {
684
            // is this a fabulous math package ?
685
0
            rtl::Reference<SmModel> xModel(dynamic_cast<SmModel*>(GetModel().get()));
686
0
            SmXMLImportWrapper aEquation(xModel);
687
0
            auto nError = aEquation.Import(rMedium);
688
0
            bRet = ERRCODE_NONE == nError;
689
0
            SetError(nError);
690
0
        }
691
0
    }
692
693
0
    if ( GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
694
0
    {
695
0
        SetFormulaArranged( false );
696
0
        Repaint();
697
0
    }
698
699
0
    FinishedLoading();
700
0
    return bRet;
701
0
}
702
703
704
bool SmDocShell::Save()
705
0
{
706
    //! apply latest changes if necessary
707
0
    UpdateText();
708
709
0
    if ( SfxObjectShell::Save() )
710
0
    {
711
0
        if (!mpTree)
712
0
            Parse();
713
0
        if( mpTree )
714
0
            ArrangeFormula();
715
716
0
        SmXMLExportWrapper aEquation(GetModel());
717
0
        aEquation.SetFlat(false);
718
0
        return aEquation.Export(*GetMedium());
719
0
    }
720
721
0
    return false;
722
0
}
723
724
/*
725
 * replace bad characters that can not be saved. (#i74144)
726
 * */
727
void SmDocShell::ReplaceBadChars()
728
4.75k
{
729
4.75k
    bool bReplace = false;
730
731
4.75k
    if (!mpEditEngine)
732
4.75k
        return;
733
734
0
    OUStringBuffer aBuf( mpEditEngine->GetText() );
735
736
0
    for (sal_Int32 i = 0;  i < aBuf.getLength();  ++i)
737
0
    {
738
0
        if (aBuf[i] < ' ' && aBuf[i] != '\r' && aBuf[i] != '\n' && aBuf[i] != '\t')
739
0
        {
740
0
            aBuf[i] = ' ';
741
0
            bReplace = true;
742
0
        }
743
0
    }
744
745
0
    if (bReplace)
746
0
        maText = aBuf.makeStringAndClear();
747
0
}
748
749
750
void SmDocShell::UpdateText()
751
0
{
752
0
    if (mpEditEngine && mpEditEngine->IsModified())
753
0
    {
754
0
        OUString aEngTxt( mpEditEngine->GetText() );
755
0
        if (GetText() != aEngTxt)
756
0
            SetText( aEngTxt );
757
0
    }
758
0
}
759
760
761
bool SmDocShell::SaveAs( SfxMedium& rMedium )
762
0
{
763
0
    bool bRet = false;
764
765
    //! apply latest changes if necessary
766
0
    UpdateText();
767
768
0
    if ( SfxObjectShell::SaveAs( rMedium ) )
769
0
    {
770
0
        if (!mpTree)
771
0
            Parse();
772
0
        if( mpTree )
773
0
            ArrangeFormula();
774
775
0
        SmXMLExportWrapper aEquation(GetModel());
776
0
        aEquation.SetFlat(false);
777
0
        bRet = aEquation.Export(rMedium);
778
0
    }
779
0
    return bRet;
780
0
}
781
782
bool SmDocShell::ConvertTo( SfxMedium &rMedium )
783
0
{
784
0
    bool bRet = false;
785
0
    std::shared_ptr<const SfxFilter> pFlt = rMedium.GetFilter();
786
0
    if( pFlt )
787
0
    {
788
0
        if( !mpTree )
789
0
            Parse();
790
0
        if( mpTree )
791
0
            ArrangeFormula();
792
793
0
        const OUString& rFltName = pFlt->GetFilterName();
794
0
        if(rFltName == STAROFFICE_XML)
795
0
        {
796
0
            SmXMLExportWrapper aEquation(GetModel());
797
0
            aEquation.SetFlat(false);
798
0
            bRet = aEquation.Export(rMedium);
799
0
        }
800
0
        else if(rFltName == MATHML_XML)
801
0
        {
802
0
            SmXMLExportWrapper aEquation(GetModel());
803
0
            aEquation.SetFlat(true);
804
0
            aEquation.SetUseHTMLMLEntities(true);
805
0
            bRet = aEquation.Export(rMedium);
806
0
        }
807
0
        else if (pFlt->GetFilterName() == "MathType 3.x")
808
0
            bRet = WriteAsMathType3( rMedium );
809
0
    }
810
0
    return bRet;
811
0
}
812
813
void SmDocShell::writeFormulaOoxml(
814
        ::sax_fastparser::FSHelperPtr const& pSerializer,
815
        oox::core::OoxmlVersion const version,
816
        oox::drawingml::DocumentType const documentType,
817
        const sal_Int8 nAlign)
818
0
{
819
0
    if( !mpTree )
820
0
        Parse();
821
0
    if( mpTree )
822
0
        ArrangeFormula();
823
0
    SmOoxmlExport aEquation(mpTree.get(), version, documentType);
824
0
    if(documentType == oox::drawingml::DOCUMENT_DOCX)
825
0
        aEquation.ConvertFromStarMath( pSerializer, nAlign);
826
0
    else
827
0
        aEquation.ConvertFromStarMath(pSerializer, oox::FormulaImExportBase::eFormulaAlign::INLINE);
828
0
}
829
830
void SmDocShell::writeFormulaRtf(OStringBuffer& rBuffer, rtl_TextEncoding nEncoding)
831
0
{
832
0
    if (!mpTree)
833
0
        Parse();
834
0
    if (mpTree)
835
0
        ArrangeFormula();
836
0
    SmRtfExport aEquation(mpTree.get());
837
0
    aEquation.ConvertFromStarMath(rBuffer, nEncoding);
838
0
}
839
840
void SmDocShell::readFormulaOoxml( oox::formulaimport::XmlStream& stream )
841
0
{
842
0
    SmOoxmlImport aEquation( stream );
843
0
    SetText( aEquation.ConvertToStarMath());
844
0
}
845
846
void SmDocShell::Execute(SfxRequest& rReq)
847
0
{
848
0
    switch (rReq.GetSlot())
849
0
    {
850
0
        case SID_TEXTMODE:
851
0
        {
852
0
            SmFormat aOldFormat  = GetFormat();
853
0
            SmFormat aNewFormat( aOldFormat );
854
0
            aNewFormat.SetTextmode(!aOldFormat.IsTextmode());
855
856
0
            SfxUndoManager *pTmpUndoMgr = GetUndoManager();
857
0
            if (pTmpUndoMgr)
858
0
                pTmpUndoMgr->AddUndoAction(
859
0
                    std::make_unique<SmFormatAction>(this, aOldFormat, aNewFormat));
860
861
0
            SetFormat( aNewFormat );
862
0
            Repaint();
863
0
        }
864
0
        break;
865
866
0
        case SID_AUTO_REDRAW :
867
0
        {
868
0
            auto* config = SmModule::get()->GetConfig();
869
0
            config->SetAutoRedraw(!config->IsAutoRedraw());
870
0
        }
871
0
        break;
872
873
0
        case SID_LOADSYMBOLS:
874
0
            LoadSymbols();
875
0
        break;
876
877
0
        case SID_SAVESYMBOLS:
878
0
            SaveSymbols();
879
0
        break;
880
881
0
        case SID_FONT:
882
0
        {
883
            // get device used to retrieve the FontList
884
0
            OutputDevice *pDev = GetPrinter();
885
0
            if (!pDev || pDev->GetFontFaceCollectionCount() == 0)
886
0
                pDev = &SmModule::get()->GetDefaultVirtualDev();
887
0
            OSL_ENSURE (pDev, "device for font list missing" );
888
889
0
            auto pFontTypeDialog = std::make_shared<SmFontTypeDialog>(rReq.GetFrameWeld(), pDev);
890
0
            auto xOldFormat = std::make_shared<SmFormat>(GetFormat());
891
0
            pFontTypeDialog->ReadFrom(*xOldFormat);
892
0
            weld::DialogController::runAsync( pFontTypeDialog, [xOldFormat=std::move(xOldFormat), pFontTypeDialog, this](sal_Int32 nResult) {
893
0
                if (nResult == RET_OK)
894
0
                {
895
0
                    SmFormat aNewFormat(*xOldFormat);
896
0
                    pFontTypeDialog->WriteTo(aNewFormat);
897
898
0
                    SfxUndoManager *pTmpUndoMgr = GetUndoManager();
899
0
                    if (pTmpUndoMgr)
900
0
                        pTmpUndoMgr->AddUndoAction(
901
0
                            std::make_unique<SmFormatAction>(this, *xOldFormat, aNewFormat));
902
903
0
                    SetFormat( aNewFormat );
904
0
                    Repaint();
905
0
                }
906
0
            });
907
0
        }
908
0
        break;
909
910
0
        case SID_FONTSIZE:
911
0
        {
912
0
            auto pFontSizeDialog = std::make_shared<SmFontSizeDialog>(rReq.GetFrameWeld());
913
0
            auto xOldFormat = std::make_shared<SmFormat>(GetFormat());
914
0
            pFontSizeDialog->ReadFrom(*xOldFormat);
915
0
            weld::DialogController::runAsync(pFontSizeDialog, [xOldFormat=std::move(xOldFormat), pFontSizeDialog, this](sal_Int32 nResult) {
916
0
                if (nResult == RET_OK)
917
0
                {
918
0
                    SmFormat aNewFormat(*xOldFormat);
919
0
                    pFontSizeDialog->WriteTo(aNewFormat);
920
921
0
                    SfxUndoManager *pTmpUndoMgr = GetUndoManager();
922
0
                    if (pTmpUndoMgr)
923
0
                        pTmpUndoMgr->AddUndoAction(
924
0
                            std::make_unique<SmFormatAction>(this, *xOldFormat, aNewFormat));
925
926
0
                    SetFormat( aNewFormat );
927
0
                    Repaint();
928
0
                }
929
0
            });
930
0
        }
931
0
        break;
932
933
0
        case SID_DISTANCE:
934
0
        {
935
0
            auto pDistanceDialog = std::make_shared<SmDistanceDialog>(rReq.GetFrameWeld());
936
0
            auto xOldFormat = std::make_shared<SmFormat>(GetFormat());
937
0
            pDistanceDialog->ReadFrom(*xOldFormat);
938
0
            weld::DialogController::runAsync(pDistanceDialog, [xOldFormat=std::move(xOldFormat), pDistanceDialog, this](sal_Int32 nResult) {
939
0
                if (nResult == RET_OK)
940
0
                {
941
0
                    SmFormat aNewFormat(*xOldFormat);
942
0
                    pDistanceDialog->WriteTo(aNewFormat);
943
944
0
                    SfxUndoManager *pTmpUndoMgr = GetUndoManager();
945
0
                    if (pTmpUndoMgr)
946
0
                        pTmpUndoMgr->AddUndoAction(
947
0
                            std::make_unique<SmFormatAction>(this, *xOldFormat, aNewFormat));
948
949
0
                    SetFormat( aNewFormat );
950
0
                    Repaint();
951
0
                }
952
0
            });
953
0
        }
954
0
        break;
955
956
0
        case SID_ALIGN:
957
0
        {
958
0
            auto pAlignDialog = std::make_shared<SmAlignDialog>(rReq.GetFrameWeld());
959
0
            auto xOldFormat = std::make_shared<SmFormat>(GetFormat());
960
0
            pAlignDialog->ReadFrom(*xOldFormat);
961
0
            weld::DialogController::runAsync(pAlignDialog, [xOldFormat=std::move(xOldFormat), pAlignDialog, this](sal_Int32 nResult) {
962
0
                if (nResult == RET_OK)
963
0
                {
964
0
                    SmFormat aNewFormat(*xOldFormat);
965
0
                    pAlignDialog->WriteTo(aNewFormat);
966
967
0
                    auto* config = SmModule::get()->GetConfig();
968
0
                    SmFormat aFmt(config->GetStandardFormat());
969
0
                    pAlignDialog->WriteTo( aFmt );
970
0
                    config->SetStandardFormat(aFmt);
971
972
0
                    SfxUndoManager *pTmpUndoMgr = GetUndoManager();
973
0
                    if (pTmpUndoMgr)
974
0
                        pTmpUndoMgr->AddUndoAction(
975
0
                            std::make_unique<SmFormatAction>(this, *xOldFormat, aNewFormat));
976
977
0
                    SetFormat( aNewFormat );
978
0
                    Repaint();
979
0
                }
980
0
            });
981
0
        }
982
0
        break;
983
984
0
        case SID_TEXT:
985
0
        {
986
0
            const SfxStringItem& rItem = rReq.GetArgs()->Get(SID_TEXT);
987
0
            if (GetText() != rItem.GetValue())
988
0
                SetText(rItem.GetValue());
989
0
        }
990
0
        break;
991
992
0
        case SID_UNDO:
993
0
        case SID_REDO:
994
0
        {
995
0
            SfxUndoManager* pTmpUndoMgr = GetUndoManager();
996
0
            if( pTmpUndoMgr )
997
0
            {
998
0
                sal_uInt16 nId = rReq.GetSlot(), nCnt = 1;
999
0
                const SfxItemSet* pArgs = rReq.GetArgs();
1000
0
                const SfxPoolItem* pItem;
1001
0
                if( pArgs && SfxItemState::SET == pArgs->GetItemState( nId, false, &pItem ))
1002
0
                    nCnt = static_cast<const SfxUInt16Item*>(pItem)->GetValue();
1003
1004
0
                bool (SfxUndoManager::*fnDo)();
1005
1006
0
                size_t nCount;
1007
0
                if( SID_UNDO == rReq.GetSlot() )
1008
0
                {
1009
0
                    nCount = pTmpUndoMgr->GetUndoActionCount();
1010
0
                    fnDo = &SfxUndoManager::Undo;
1011
0
                }
1012
0
                else
1013
0
                {
1014
0
                    nCount = pTmpUndoMgr->GetRedoActionCount();
1015
0
                    fnDo = &SfxUndoManager::Redo;
1016
0
                }
1017
1018
0
                try
1019
0
                {
1020
0
                    for( ; nCnt && nCount; --nCnt, --nCount )
1021
0
                        (pTmpUndoMgr->*fnDo)();
1022
0
                }
1023
0
                catch( const Exception& )
1024
0
                {
1025
0
                    DBG_UNHANDLED_EXCEPTION("starmath");
1026
0
                }
1027
0
            }
1028
0
            Repaint();
1029
0
            UpdateText();
1030
0
            SfxViewFrame* pFrm = SfxViewFrame::GetFirst( this );
1031
0
            while( pFrm )
1032
0
            {
1033
0
                SfxBindings& rBind = pFrm->GetBindings();
1034
0
                rBind.Invalidate(SID_UNDO);
1035
0
                rBind.Invalidate(SID_REDO);
1036
0
                rBind.Invalidate(SID_REPEAT);
1037
0
                rBind.Invalidate(SID_CLEARHISTORY);
1038
0
                pFrm = SfxViewFrame::GetNext( *pFrm, this );
1039
0
            }
1040
0
        }
1041
0
        break;
1042
0
    }
1043
1044
0
    rReq.Done();
1045
0
}
1046
1047
1048
void SmDocShell::GetState(SfxItemSet &rSet)
1049
0
{
1050
0
    SfxWhichIter aIter(rSet);
1051
1052
0
    for (sal_uInt16 nWh = aIter.FirstWhich();  0 != nWh;  nWh = aIter.NextWhich())
1053
0
    {
1054
0
        switch (nWh)
1055
0
        {
1056
0
        case SID_TEXTMODE:
1057
0
            rSet.Put(SfxBoolItem(SID_TEXTMODE, GetFormat().IsTextmode()));
1058
0
            break;
1059
1060
0
        case SID_DOCTEMPLATE :
1061
0
            rSet.DisableItem(SID_DOCTEMPLATE);
1062
0
            break;
1063
1064
0
        case SID_AUTO_REDRAW :
1065
0
            rSet.Put(SfxBoolItem(SID_AUTO_REDRAW, SmModule::get()->GetConfig()->IsAutoRedraw()));
1066
0
            break;
1067
1068
0
        case SID_MODIFYSTATUS:
1069
0
            {
1070
0
                sal_Unicode cMod = ' ';
1071
0
                if (IsModified())
1072
0
                    cMod = '*';
1073
0
                rSet.Put(SfxStringItem(SID_MODIFYSTATUS, OUString(cMod)));
1074
0
            }
1075
0
            break;
1076
1077
0
        case SID_TEXT:
1078
0
            rSet.Put(SfxStringItem(SID_TEXT, GetText()));
1079
0
            break;
1080
1081
0
        case SID_GRAPHIC_SM:
1082
            //! very old (pre UNO) and ugly hack to invalidate the SmGraphicWidget.
1083
            //! If mnModifyCount gets changed then the call below will implicitly notify
1084
            //! SmGraphicController::StateChanged and there the window gets invalidated.
1085
            //! Thus all the 'mnModifyCount++' before invalidating this slot.
1086
0
            rSet.Put(SfxInt16Item(SID_GRAPHIC_SM, mnModifyCount));
1087
0
            break;
1088
1089
0
        case SID_UNDO:
1090
0
        case SID_REDO:
1091
0
            {
1092
0
                SfxViewFrame* pFrm = SfxViewFrame::GetFirst( this );
1093
0
                if( pFrm )
1094
0
                    pFrm->GetSlotState( nWh, nullptr, &rSet );
1095
0
                else
1096
0
                    rSet.DisableItem( nWh );
1097
0
            }
1098
0
            break;
1099
1100
0
        case SID_GETUNDOSTRINGS:
1101
0
        case SID_GETREDOSTRINGS:
1102
0
            {
1103
0
                SfxUndoManager* pTmpUndoMgr = GetUndoManager();
1104
0
                if( pTmpUndoMgr )
1105
0
                {
1106
0
                    OUString(SfxUndoManager::*fnGetComment)( size_t, bool const ) const;
1107
1108
0
                    size_t nCount;
1109
0
                    if( SID_GETUNDOSTRINGS == nWh )
1110
0
                    {
1111
0
                        nCount = pTmpUndoMgr->GetUndoActionCount();
1112
0
                        fnGetComment = &SfxUndoManager::GetUndoActionComment;
1113
0
                    }
1114
0
                    else
1115
0
                    {
1116
0
                        nCount = pTmpUndoMgr->GetRedoActionCount();
1117
0
                        fnGetComment = &SfxUndoManager::GetRedoActionComment;
1118
0
                    }
1119
0
                    if (nCount)
1120
0
                    {
1121
0
                        OUStringBuffer aBuf;
1122
0
                        for (size_t n = 0; n < nCount; ++n)
1123
0
                        {
1124
0
                            aBuf.append((pTmpUndoMgr->*fnGetComment)( n, SfxUndoManager::TopLevel ));
1125
0
                            aBuf.append('\n');
1126
0
                        }
1127
1128
0
                        SfxStringListItem aItem( nWh );
1129
0
                        aItem.SetString( aBuf.makeStringAndClear() );
1130
0
                        rSet.Put( aItem );
1131
0
                    }
1132
0
                }
1133
0
                else
1134
0
                    rSet.DisableItem( nWh );
1135
0
            }
1136
0
            break;
1137
0
        }
1138
0
    }
1139
0
}
1140
1141
1142
SfxUndoManager *SmDocShell::GetUndoManager()
1143
0
{
1144
0
    if (!mpEditEngine)
1145
0
        GetEditEngine();
1146
0
    return &mpEditEngine->GetUndoManager();
1147
0
}
1148
1149
1150
void SmDocShell::SaveSymbols()
1151
0
{
1152
0
    SmModule::get()->GetSymbolManager().Save();
1153
0
}
1154
1155
1156
void SmDocShell::Draw(OutputDevice *pDevice,
1157
                      const JobSetup &,
1158
                      sal_uInt16 /*nAspect*/,
1159
                      bool /*bOutputForScreen*/)
1160
0
{
1161
0
    pDevice->IntersectClipRegion(GetVisArea());
1162
0
    Point atmppoint;
1163
0
    DrawFormula(*pDevice, atmppoint);
1164
0
}
1165
1166
SfxItemPool& SmDocShell::GetPool()
1167
203
{
1168
203
    return SfxGetpApp()->GetPool();
1169
203
}
1170
1171
void SmDocShell::SetVisArea(const tools::Rectangle & rVisArea)
1172
35.1k
{
1173
35.1k
    tools::Rectangle aNewRect(rVisArea);
1174
1175
35.1k
    aNewRect.SetPos(Point());
1176
1177
35.1k
    if (aNewRect.IsWidthEmpty())
1178
1
        aNewRect.SetRight( 2000 );
1179
35.1k
    if (aNewRect.IsHeightEmpty())
1180
1
        aNewRect.SetBottom( 1000 );
1181
1182
35.1k
    bool bIsEnabled = IsEnableSetModified();
1183
35.1k
    if ( bIsEnabled )
1184
30.3k
        EnableSetModified( false );
1185
1186
    //TODO/LATER: it's unclear how this interacts with the SFX code
1187
    // If outplace editing, then don't resize the OutplaceWindow. But the
1188
    // ObjectShell has to resize.
1189
35.1k
    bool bUnLockFrame;
1190
35.1k
    if( GetCreateMode() == SfxObjectCreateMode::EMBEDDED && !IsInPlaceActive() && GetFrame() )
1191
0
    {
1192
0
        GetFrame()->LockAdjustPosSizePixel();
1193
0
        bUnLockFrame = true;
1194
0
    }
1195
35.1k
    else
1196
35.1k
        bUnLockFrame = false;
1197
1198
35.1k
    SfxObjectShell::SetVisArea( aNewRect );
1199
1200
35.1k
    if( bUnLockFrame )
1201
0
        GetFrame()->UnlockAdjustPosSizePixel();
1202
1203
35.1k
    if ( bIsEnabled )
1204
30.3k
        EnableSetModified( bIsEnabled );
1205
35.1k
}
1206
1207
1208
void SmDocShell::FillClass(SvGlobalName* pClassName,
1209
                           SotClipboardFormatId*  pFormat,
1210
                           OUString* pFullTypeName,
1211
                           sal_Int32 nFileFormat,
1212
                           bool bTemplate /* = false */) const
1213
27.4k
{
1214
27.4k
    if (nFileFormat == SOFFICE_FILEFORMAT_60 )
1215
0
    {
1216
0
        *pClassName     = SvGlobalName(SO3_SM_CLASSID_60);
1217
0
        *pFormat        = SotClipboardFormatId::STARMATH_60;
1218
0
        *pFullTypeName  = SmResId(STR_MATH_DOCUMENT_FULLTYPE_CURRENT);
1219
0
    }
1220
27.4k
    else if (nFileFormat == SOFFICE_FILEFORMAT_8 )
1221
27.4k
    {
1222
27.4k
        *pClassName     = SvGlobalName(SO3_SM_CLASSID_60);
1223
27.4k
        *pFormat        = bTemplate ? SotClipboardFormatId::STARMATH_8_TEMPLATE : SotClipboardFormatId::STARMATH_8;
1224
27.4k
        *pFullTypeName  = SmResId(STR_MATH_DOCUMENT_FULLTYPE_CURRENT);
1225
27.4k
    }
1226
27.4k
}
1227
1228
void SmDocShell::SetModified(bool bModified)
1229
9.62k
{
1230
9.62k
    if( IsEnableSetModified() )
1231
9.62k
    {
1232
9.62k
        SfxObjectShell::SetModified( bModified );
1233
9.62k
        Broadcast(SfxHint(SfxHintId::DocChanged));
1234
9.62k
    }
1235
9.62k
}
1236
1237
bool SmDocShell::WriteAsMathType3( SfxMedium& rMedium )
1238
0
{
1239
0
    OUStringBuffer aTextAsBuffer(maText);
1240
0
    MathType aEquation(aTextAsBuffer, mpTree.get());
1241
0
    return aEquation.ConvertFromStarMath( rMedium );
1242
0
}
1243
1244
void SmDocShell::SetRightToLeft(bool bRTL)
1245
0
{
1246
0
    SmFormat aOldFormat = GetFormat();
1247
0
    if (aOldFormat.IsRightToLeft() == bRTL)
1248
0
        return;
1249
1250
0
    SmFormat aNewFormat(aOldFormat);
1251
0
    aNewFormat.SetRightToLeft(bRTL);
1252
1253
0
    SfxUndoManager* pTmpUndoMgr = GetUndoManager();
1254
0
    if (pTmpUndoMgr)
1255
0
        pTmpUndoMgr->AddUndoAction(
1256
0
            std::make_unique<SmFormatAction>(this, aOldFormat, aNewFormat));
1257
1258
0
    SetFormat(aNewFormat);
1259
0
    Repaint();
1260
0
}
1261
1262
static Size GetTextLineSize(OutputDevice const& rDevice, const OUString& rLine)
1263
0
{
1264
0
    Size aSize(rDevice.GetTextWidth(rLine), rDevice.GetTextHeight());
1265
0
    const tools::Long nTabPos = rLine.isEmpty() ? 0 : rDevice.approximate_digit_width() * 8;
1266
1267
0
    if (nTabPos)
1268
0
    {
1269
0
        aSize.setWidth(0);
1270
0
        sal_Int32 nPos = 0;
1271
0
        do
1272
0
        {
1273
0
            if (nPos > 0)
1274
0
                aSize.setWidth(((aSize.Width() / nTabPos) + 1) * nTabPos);
1275
1276
0
            const OUString aText = rLine.getToken(0, '\t', nPos);
1277
0
            aSize.AdjustWidth(rDevice.GetTextWidth(aText));
1278
0
        } while (nPos >= 0);
1279
0
    }
1280
1281
0
    return aSize;
1282
0
}
1283
1284
static Size GetTextSize(OutputDevice const& rDevice, std::u16string_view rText,
1285
                        tools::Long MaxWidth)
1286
0
{
1287
0
    Size aSize;
1288
0
    Size aTextSize;
1289
0
    if (rText.empty())
1290
0
        return aTextSize;
1291
1292
0
    sal_Int32 nPos = 0;
1293
0
    do
1294
0
    {
1295
0
        OUString aLine(o3tl::getToken(rText, 0, '\n', nPos));
1296
0
        aLine = aLine.replaceAll("\r", "");
1297
1298
0
        aSize = GetTextLineSize(rDevice, aLine);
1299
1300
0
        if (aSize.Width() > MaxWidth)
1301
0
        {
1302
0
            do
1303
0
            {
1304
0
                OUString aText;
1305
0
                sal_Int32 m = aLine.getLength();
1306
0
                sal_Int32 nLen = m;
1307
1308
0
                for (sal_Int32 n = 0; n < nLen; n++)
1309
0
                {
1310
0
                    sal_Unicode cLineChar = aLine[n];
1311
0
                    if ((cLineChar == ' ') || (cLineChar == '\t'))
1312
0
                    {
1313
0
                        aText = aLine.copy(0, n);
1314
0
                        if (GetTextLineSize(rDevice, aText).Width() < MaxWidth)
1315
0
                            m = n;
1316
0
                        else
1317
0
                            break;
1318
0
                    }
1319
0
                }
1320
1321
0
                aText = aLine.copy(0, m);
1322
0
                aLine = aLine.replaceAt(0, m, u"");
1323
0
                aSize = GetTextLineSize(rDevice, aText);
1324
0
                aTextSize.AdjustHeight(aSize.Height());
1325
0
                aTextSize.setWidth(std::clamp(aSize.Width(), aTextSize.Width(), MaxWidth));
1326
1327
0
                aLine = comphelper::string::stripStart(aLine, ' ');
1328
0
                aLine = comphelper::string::stripStart(aLine, '\t');
1329
0
                aLine = comphelper::string::stripStart(aLine, ' ');
1330
0
            } while (!aLine.isEmpty());
1331
0
        }
1332
0
        else
1333
0
        {
1334
0
            aTextSize.AdjustHeight(aSize.Height());
1335
0
            aTextSize.setWidth(std::max(aTextSize.Width(), aSize.Width()));
1336
0
        }
1337
0
    } while (nPos >= 0);
1338
1339
0
    return aTextSize;
1340
0
}
1341
1342
static void DrawTextLine(OutputDevice& rDevice, const Point& rPosition, const OUString& rLine)
1343
0
{
1344
0
    Point aPoint(rPosition);
1345
0
    const tools::Long nTabPos = rLine.isEmpty() ? 0 : rDevice.approximate_digit_width() * 8;
1346
1347
0
    if (nTabPos)
1348
0
    {
1349
0
        sal_Int32 nPos = 0;
1350
0
        do
1351
0
        {
1352
0
            if (nPos > 0)
1353
0
                aPoint.setX(((aPoint.X() / nTabPos) + 1) * nTabPos);
1354
1355
0
            OUString aText = rLine.getToken(0, '\t', nPos);
1356
0
            rDevice.DrawText(aPoint, aText);
1357
0
            aPoint.AdjustX(rDevice.GetTextWidth(aText));
1358
0
        } while (nPos >= 0);
1359
0
    }
1360
0
    else
1361
0
        rDevice.DrawText(aPoint, rLine);
1362
0
}
1363
1364
static void DrawText(OutputDevice& rDevice, const Point& rPosition, std::u16string_view rText,
1365
                     sal_uInt16 MaxWidth)
1366
0
{
1367
0
    if (rText.empty())
1368
0
        return;
1369
1370
0
    Point aPoint(rPosition);
1371
0
    Size aSize;
1372
1373
0
    sal_Int32 nPos = 0;
1374
0
    do
1375
0
    {
1376
0
        OUString aLine(o3tl::getToken(rText, 0, '\n', nPos));
1377
0
        aLine = aLine.replaceAll("\r", "");
1378
0
        aSize = GetTextLineSize(rDevice, aLine);
1379
0
        if (aSize.Width() > MaxWidth)
1380
0
        {
1381
0
            do
1382
0
            {
1383
0
                OUString aText;
1384
0
                sal_Int32 m = aLine.getLength();
1385
0
                sal_Int32 nLen = m;
1386
1387
0
                for (sal_Int32 n = 0; n < nLen; n++)
1388
0
                {
1389
0
                    sal_Unicode cLineChar = aLine[n];
1390
0
                    if ((cLineChar == ' ') || (cLineChar == '\t'))
1391
0
                    {
1392
0
                        aText = aLine.copy(0, n);
1393
0
                        if (GetTextLineSize(rDevice, aText).Width() < MaxWidth)
1394
0
                            m = n;
1395
0
                        else
1396
0
                            break;
1397
0
                    }
1398
0
                }
1399
0
                aText = aLine.copy(0, m);
1400
0
                aLine = aLine.replaceAt(0, m, u"");
1401
1402
0
                DrawTextLine(rDevice, aPoint, aText);
1403
0
                aPoint.AdjustY(aSize.Height());
1404
1405
0
                aLine = comphelper::string::stripStart(aLine, ' ');
1406
0
                aLine = comphelper::string::stripStart(aLine, '\t');
1407
0
                aLine = comphelper::string::stripStart(aLine, ' ');
1408
0
            } while (GetTextLineSize(rDevice, aLine).Width() > MaxWidth);
1409
1410
            // print the remaining text
1411
0
            if (!aLine.isEmpty())
1412
0
            {
1413
0
                DrawTextLine(rDevice, aPoint, aLine);
1414
0
                aPoint.AdjustY(aSize.Height());
1415
0
            }
1416
0
        }
1417
0
        else
1418
0
        {
1419
0
            DrawTextLine(rDevice, aPoint, aLine);
1420
0
            aPoint.AdjustY(aSize.Height());
1421
0
        }
1422
0
    } while (nPos >= 0);
1423
0
}
1424
1425
void SmDocShell::Impl_Print(OutputDevice& rOutDev, const SmPrintUIOptions& rPrintUIOptions,
1426
                tools::Rectangle aOutRect)
1427
0
{
1428
0
    const bool bIsPrintTitle = rPrintUIOptions.getBoolValue(PRTUIOPT_TITLE_ROW, true);
1429
0
    const bool bIsPrintFrame = rPrintUIOptions.getBoolValue(PRTUIOPT_BORDER, true);
1430
0
    const bool bIsPrintFormulaText = rPrintUIOptions.getBoolValue(PRTUIOPT_FORMULA_TEXT, true);
1431
0
    SmPrintSize ePrintSize(static_cast<SmPrintSize>(
1432
0
        rPrintUIOptions.getIntValue(PRTUIOPT_PRINT_FORMAT, PRINT_SIZE_NORMAL)));
1433
0
    const sal_uInt16 nZoomFactor
1434
0
        = static_cast<sal_uInt16>(rPrintUIOptions.getIntValue(PRTUIOPT_PRINT_SCALE, 100));
1435
1436
0
    auto popIt = rOutDev.ScopedPush();
1437
0
    rOutDev.SetLineColor(COL_BLACK);
1438
1439
    // output text on top
1440
0
    if (bIsPrintTitle)
1441
0
    {
1442
0
        Size aSize600(0, 600);
1443
0
        Size aSize650(0, 650);
1444
0
        vcl::Font aFont(FAMILY_DONTKNOW, aSize600);
1445
1446
0
        aFont.SetAlignment(ALIGN_TOP);
1447
0
        aFont.SetWeight(WEIGHT_BOLD);
1448
0
        aFont.SetFontSize(aSize650);
1449
0
        aFont.SetColor(COL_BLACK);
1450
0
        rOutDev.SetFont(aFont);
1451
1452
0
        Size aTitleSize(GetTextSize(rOutDev, GetTitle(), aOutRect.GetWidth() - 200));
1453
1454
0
        aFont.SetWeight(WEIGHT_NORMAL);
1455
0
        aFont.SetFontSize(aSize600);
1456
0
        rOutDev.SetFont(aFont);
1457
1458
0
        Size aDescSize(GetTextSize(rOutDev, GetComment(), aOutRect.GetWidth() - 200));
1459
1460
0
        if (bIsPrintFrame)
1461
0
            rOutDev.DrawRect(tools::Rectangle(
1462
0
                aOutRect.TopLeft(), Size(aOutRect.GetWidth(), 100 + aTitleSize.Height() + 200
1463
0
                                                                  + aDescSize.Height() + 100)));
1464
0
        aOutRect.AdjustTop(200);
1465
1466
        // output title
1467
0
        aFont.SetWeight(WEIGHT_BOLD);
1468
0
        aFont.SetFontSize(aSize650);
1469
0
        rOutDev.SetFont(aFont);
1470
0
        Point aPoint(aOutRect.Left() + (aOutRect.GetWidth() - aTitleSize.Width()) / 2,
1471
0
                     aOutRect.Top());
1472
0
        DrawText(rOutDev, aPoint, GetTitle(),
1473
0
                 sal::static_int_cast<sal_uInt16>(aOutRect.GetWidth() - 200));
1474
0
        aOutRect.AdjustTop(aTitleSize.Height() + 200);
1475
1476
        // output description
1477
0
        aFont.SetWeight(WEIGHT_NORMAL);
1478
0
        aFont.SetFontSize(aSize600);
1479
0
        rOutDev.SetFont(aFont);
1480
0
        aPoint.setX(aOutRect.Left() + (aOutRect.GetWidth() - aDescSize.Width()) / 2);
1481
0
        aPoint.setY(aOutRect.Top());
1482
0
        DrawText(rOutDev, aPoint, GetComment(),
1483
0
                 sal::static_int_cast<sal_uInt16>(aOutRect.GetWidth() - 200));
1484
0
        aOutRect.AdjustTop(aDescSize.Height() + 300);
1485
0
    }
1486
1487
    // output text on bottom
1488
0
    if (bIsPrintFormulaText)
1489
0
    {
1490
0
        vcl::Font aFont(FAMILY_DONTKNOW, Size(0, 600));
1491
0
        aFont.SetAlignment(ALIGN_TOP);
1492
0
        aFont.SetColor(COL_BLACK);
1493
1494
        // get size
1495
0
        rOutDev.SetFont(aFont);
1496
1497
0
        Size aSize(GetTextSize(rOutDev, GetText(), aOutRect.GetWidth() - 200));
1498
1499
0
        aOutRect.AdjustBottom(-(aSize.Height() + 600));
1500
1501
0
        if (bIsPrintFrame)
1502
0
            rOutDev.DrawRect(tools::Rectangle(
1503
0
                aOutRect.BottomLeft(), Size(aOutRect.GetWidth(), 200 + aSize.Height() + 200)));
1504
1505
0
        Point aPoint(aOutRect.Left() + (aOutRect.GetWidth() - aSize.Width()) / 2,
1506
0
                     aOutRect.Bottom() + 300);
1507
0
        DrawText(rOutDev, aPoint, GetText(),
1508
0
                 sal::static_int_cast<sal_uInt16>(aOutRect.GetWidth() - 200));
1509
0
        aOutRect.AdjustBottom(-200);
1510
0
    }
1511
1512
0
    if (bIsPrintFrame)
1513
0
        rOutDev.DrawRect(aOutRect);
1514
1515
0
    aOutRect.AdjustTop(100);
1516
0
    aOutRect.AdjustLeft(100);
1517
0
    aOutRect.AdjustBottom(-100);
1518
0
    aOutRect.AdjustRight(-100);
1519
1520
0
    Size aSize(GetSize());
1521
1522
0
    MapMode OutputMapMode;
1523
0
    switch (ePrintSize)
1524
0
    {
1525
0
        case PRINT_SIZE_NORMAL:
1526
0
            OutputMapMode = MapMode(SmMapUnit());
1527
0
            break;
1528
1529
0
        case PRINT_SIZE_SCALED:
1530
0
            if (!aSize.IsEmpty())
1531
0
            {
1532
0
                sal_uInt16 nZ
1533
0
                    = std::min(o3tl::convert(aOutRect.GetWidth(), 100, aSize.Width()),
1534
0
                               o3tl::convert(aOutRect.GetHeight(), 100, aSize.Height()));
1535
0
                if (bIsPrintFrame && nZ > MINZOOM)
1536
0
                    nZ -= 10;
1537
0
                Fraction aFraction(std::clamp(nZ, MINZOOM, MAXZOOM), 100);
1538
1539
0
                OutputMapMode = MapMode(SmMapUnit(), Point(), aFraction, aFraction);
1540
0
            }
1541
0
            else
1542
0
                OutputMapMode = MapMode(SmMapUnit());
1543
0
            break;
1544
1545
0
        case PRINT_SIZE_ZOOMED:
1546
0
        {
1547
0
            Fraction aFraction(nZoomFactor, 100);
1548
1549
0
            OutputMapMode = MapMode(SmMapUnit(), Point(), aFraction, aFraction);
1550
0
            break;
1551
0
        }
1552
0
    }
1553
1554
0
    aSize = OutputDevice::LogicToLogic(aSize, OutputMapMode, MapMode(SmMapUnit()));
1555
1556
0
    Point aPos(aOutRect.Left() + (aOutRect.GetWidth() - aSize.Width()) / 2,
1557
0
               aOutRect.Top() + (aOutRect.GetHeight() - aSize.Height()) / 2);
1558
1559
0
    aPos = OutputDevice::LogicToLogic(aPos, MapMode(SmMapUnit()), OutputMapMode);
1560
0
    aOutRect = OutputDevice::LogicToLogic(aOutRect, MapMode(SmMapUnit()), OutputMapMode);
1561
1562
0
    rOutDev.SetMapMode(OutputMapMode);
1563
0
    rOutDev.SetClipRegion(vcl::Region(aOutRect));
1564
0
    DrawFormula(rOutDev, aPos);
1565
0
    rOutDev.SetClipRegion();
1566
0
}
1567
1568
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */