Coverage Report

Created: 2026-11-06 11:29

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