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 <com/sun/star/accessibility/AccessibleEventId.hpp>
21 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
22 #include <com/sun/star/frame/Desktop.hpp>
23 #include <com/sun/star/frame/XFramesSupplier.hpp>
24 #include <com/sun/star/container/XChild.hpp>
25
26 #include <comphelper/processfactory.hxx>
27 #include <comphelper/servicehelper.hxx>
28 #include <comphelper/storagehelper.hxx>
29 #include <comphelper/string.hxx>
30 #include <i18nutil/unicode.hxx>
31 #include <officecfg/Office/Common.hxx>
32 #include <sfx2/dispatch.hxx>
33 #include <sfx2/docfile.hxx>
34 #include <sfx2/docfilt.hxx>
35 #include <sfx2/docinsert.hxx>
36 #include <sfx2/filedlghelper.hxx>
37 #include <sfx2/infobar.hxx>
38 #include <sfx2/msg.hxx>
39 #include <sfx2/objface.hxx>
40 #include <sfx2/printer.hxx>
41 #include <sfx2/request.hxx>
42 #include <sfx2/viewfac.hxx>
43 #include <svl/eitem.hxx>
44 #include <svl/itemset.hxx>
45 #include <svl/poolitem.hxx>
46 #include <svl/stritem.hxx>
47 #include <vcl/transfer.hxx>
48 #include <svtools/colorcfg.hxx>
49 #include <svl/whiter.hxx>
50 #include <svx/zoomslideritem.hxx>
51 #include <editeng/editeng.hxx>
52 #include <editeng/editview.hxx>
53 #include <svx/svxdlg.hxx>
54 #include <sfx2/zoomitem.hxx>
55 #include <vcl/commandevent.hxx>
56 #include <vcl/event.hxx>
57 #include <vcl/settings.hxx>
58 #include <vcl/virdev.hxx>
59 #include <sal/log.hxx>
60 #include <tools/svborder.hxx>
61
62 #include <unotools/streamwrap.hxx>
63
64 #include <unomodel.hxx>
65 #include <view.hxx>
66 #include <cfgitem.hxx>
67 #include <dialog.hxx>
68 #include <document.hxx>
69 #include <starmath.hrc>
70 #include <strings.hrc>
71 #include <smmod.hxx>
72 #include <mathmlimport.hxx>
73 #include <cursor.hxx>
74 #include "accessibility.hxx"
75 #include <ElementsDockingWindow.hxx>
76 #include <helpids.h>
77
78 #define MINZOOM sal_uInt16(25)
79 #define MAXZOOM sal_uInt16(800)
80
81 // space around the edit window, in pixels
82 // fdo#69111: Increased border on the top so that the window is
83 // easier to tear off.
84 #define CMD_BOX_PADDING 3
85 #define CMD_BOX_PADDING_TOP 11
86
87 #define ShellClass_SmViewShell
88 #include <smslots.hxx>
89
90 using namespace css;
91 using namespace css::accessibility;
92 using namespace css::uno;
93
SmGraphicWindow(SmViewShell & rShell)94 SmGraphicWindow::SmGraphicWindow(SmViewShell& rShell)
95 : InterimItemWindow(&rShell.GetViewFrame()->GetWindow(), "modules/smath/ui/mathwindow.ui", "MathWindow")
96 , nZoom(100)
97 // continue to use user-scrolling to make this work equivalent to how it 'always' worked
98 , mxScrolledWindow(m_xBuilder->weld_scrolled_window("scrolledwindow", true))
99 , mxGraphic(new SmGraphicWidget(rShell, *this))
100 , mxGraphicWin(new weld::CustomWeld(*m_xBuilder, "mathview", *mxGraphic))
101 {
102 InitControlBase(mxGraphic->GetDrawingArea());
103
104 nColumnPixW = nLinePixH = GetSettings().GetStyleSettings().GetScrollBarSize();
105
106 mxScrolledWindow->connect_hadjustment_changed(LINK(this, SmGraphicWindow, ScrollHdl));
107 mxScrolledWindow->connect_vadjustment_changed(LINK(this, SmGraphicWindow, ScrollHdl));
108
109 // docking windows are usually hidden (often already done in the
110 // resource) and will be shown by the sfx framework.
111 Hide();
112 }
113
dispose()114 void SmGraphicWindow::dispose()
115 {
116 InitControlBase(nullptr);
117 mxGraphicWin.reset();
118 mxGraphic.reset();
119 mxScrolledWindow.reset();
120 InterimItemWindow::dispose();
121 }
122
~SmGraphicWindow()123 SmGraphicWindow::~SmGraphicWindow()
124 {
125 disposeOnce();
126 }
127
Resize()128 void SmGraphicWindow::Resize()
129 {
130 InterimItemWindow::Resize();
131
132 // get the new output-size in pixel
133 Size aOutPixSz = GetOutputSizePixel();
134
135 // determine the size of the output-area and if we need scrollbars
136 const auto nScrSize = mxScrolledWindow->get_scroll_thickness();
137 bool bVVisible = false; // by default no vertical-ScrollBar
138 bool bHVisible = false; // by default no horizontal-ScrollBar
139 bool bChanged; // determines if a visiblility was changed
140 do
141 {
142 bChanged = false;
143
144 // does we need a vertical ScrollBar
145 if ( aOutPixSz.Width() < aTotPixSz.Width() && !bHVisible )
146 {
147 bHVisible = true;
148 aOutPixSz.AdjustHeight( -nScrSize );
149 bChanged = true;
150 }
151
152 // does we need a horizontal ScrollBar
153 if ( aOutPixSz.Height() < aTotPixSz.Height() && !bVVisible )
154 {
155 bVVisible = true;
156 aOutPixSz.AdjustWidth( -nScrSize );
157 bChanged = true;
158 }
159
160 }
161 while ( bChanged ); // until no visibility has changed
162
163 // store the old offset and map-mode
164 MapMode aMap(GetGraphicMapMode());
165 Point aOldPixOffset(aPixOffset);
166
167 // justify (right/bottom borders should never exceed the virtual window)
168 Size aPixDelta;
169 if ( aPixOffset.X() < 0 &&
170 aPixOffset.X() + aTotPixSz.Width() < aOutPixSz.Width() )
171 aPixDelta.setWidth(
172 aOutPixSz.Width() - ( aPixOffset.X() + aTotPixSz.Width() ) );
173 if ( aPixOffset.Y() < 0 &&
174 aPixOffset.Y() + aTotPixSz.Height() < aOutPixSz.Height() )
175 aPixDelta.setHeight(
176 aOutPixSz.Height() - ( aPixOffset.Y() + aTotPixSz.Height() ) );
177 if ( aPixDelta.Width() || aPixDelta.Height() )
178 {
179 aPixOffset.AdjustX(aPixDelta.Width() );
180 aPixOffset.AdjustY(aPixDelta.Height() );
181 }
182
183 // for axis without scrollbar restore the origin
184 if ( !bVVisible || !bHVisible )
185 {
186 aPixOffset = Point(
187 bHVisible
188 ? aPixOffset.X()
189 : (aOutPixSz.Width()-aTotPixSz.Width()) / 2,
190 bVVisible
191 ? aPixOffset.Y()
192 : (aOutPixSz.Height()-aTotPixSz.Height()) / 2 );
193 }
194 if (bHVisible && mxScrolledWindow->get_hpolicy() == VclPolicyType::NEVER)
195 aPixOffset.setX( 0 );
196 if (bVVisible && mxScrolledWindow->get_vpolicy() == VclPolicyType::NEVER)
197 aPixOffset.setY( 0 );
198
199 // select the shifted map-mode
200 if (aPixOffset != aOldPixOffset)
201 SetGraphicMapMode(aMap);
202
203 // show or hide scrollbars
204 mxScrolledWindow->set_vpolicy(bVVisible ? VclPolicyType::ALWAYS : VclPolicyType::NEVER);
205 mxScrolledWindow->set_hpolicy(bHVisible ? VclPolicyType::ALWAYS : VclPolicyType::NEVER);
206
207 // resize scrollbars and set their ranges
208 if ( bHVisible )
209 {
210 mxScrolledWindow->hadjustment_configure(-aPixOffset.X(), 0, aTotPixSz.Width(), nColumnPixW,
211 aOutPixSz.Width(), aOutPixSz.Width());
212 }
213 if ( bVVisible )
214 {
215 mxScrolledWindow->vadjustment_configure(-aPixOffset.Y(), 0, aTotPixSz.Height(), nLinePixH,
216 aOutPixSz.Height(), aOutPixSz.Height());
217 }
218 }
219
IMPL_LINK_NOARG(SmGraphicWindow,ScrollHdl,weld::ScrolledWindow &,void)220 IMPL_LINK_NOARG(SmGraphicWindow, ScrollHdl, weld::ScrolledWindow&, void)
221 {
222 MapMode aMap(GetGraphicMapMode());
223 Point aNewPixOffset(aPixOffset);
224
225 // scrolling horizontally?
226 if (mxScrolledWindow->get_hpolicy() == VclPolicyType::ALWAYS)
227 aNewPixOffset.setX(-mxScrolledWindow->hadjustment_get_value());
228
229 // scrolling vertically?
230 if (mxScrolledWindow->get_vpolicy() == VclPolicyType::ALWAYS)
231 aNewPixOffset.setY(-mxScrolledWindow->vadjustment_get_value());
232
233 // scrolling?
234 if (aPixOffset == aNewPixOffset)
235 return;
236
237 // recompute the logical scroll units
238 aPixOffset = aNewPixOffset;
239
240 SetGraphicMapMode(aMap);
241 }
242
SetGraphicMapMode(const MapMode & rNewMapMode)243 void SmGraphicWindow::SetGraphicMapMode(const MapMode& rNewMapMode)
244 {
245 OutputDevice& rDevice = mxGraphic->GetDrawingArea()->get_ref_device();
246 MapMode aMap( rNewMapMode );
247 aMap.SetOrigin( aMap.GetOrigin() + rDevice.PixelToLogic( aPixOffset, aMap ) );
248 rDevice.SetMapMode( aMap );
249 mxGraphic->Invalidate();
250 }
251
GetGraphicMapMode() const252 MapMode SmGraphicWindow::GetGraphicMapMode() const
253 {
254 OutputDevice& rDevice = mxGraphic->GetDrawingArea()->get_ref_device();
255 MapMode aMap(rDevice.GetMapMode());
256 aMap.SetOrigin( aMap.GetOrigin() - rDevice.PixelToLogic( aPixOffset ) );
257 return aMap;
258 }
259
SetTotalSize(const Size & rNewSize)260 void SmGraphicWindow::SetTotalSize( const Size& rNewSize )
261 {
262 OutputDevice& rDevice = mxGraphic->GetDrawingArea()->get_ref_device();
263 aTotPixSz = rDevice.LogicToPixel(rNewSize);
264 Resize();
265 }
266
GetTotalSize() const267 Size SmGraphicWindow::GetTotalSize() const
268 {
269 OutputDevice& rDevice = mxGraphic->GetDrawingArea()->get_ref_device();
270 return rDevice.PixelToLogic(aTotPixSz);
271 }
272
ShowContextMenu(const CommandEvent & rCEvt)273 void SmGraphicWindow::ShowContextMenu(const CommandEvent& rCEvt)
274 {
275 GetParent()->ToTop();
276 Point aPos(5, 5);
277 if (rCEvt.IsMouseEvent())
278 aPos = rCEvt.GetMousePosPixel();
279
280 // added for replaceability of context menus
281 SfxDispatcher::ExecutePopup( this, &aPos );
282 }
283
SmGraphicWidget(SmViewShell & rShell,SmGraphicWindow & rGraphicWindow)284 SmGraphicWidget::SmGraphicWidget(SmViewShell& rShell, SmGraphicWindow& rGraphicWindow)
285 : mrGraphicWindow(rGraphicWindow)
286 , bIsCursorVisible(false)
287 , bIsLineVisible(false)
288 , mrViewShell(rShell)
289 {
290 }
291
SetDrawingArea(weld::DrawingArea * pDrawingArea)292 void SmGraphicWidget::SetDrawingArea(weld::DrawingArea* pDrawingArea)
293 {
294 weld::CustomWidgetController::SetDrawingArea(pDrawingArea);
295
296 OutputDevice& rDevice = pDrawingArea->get_ref_device();
297
298 rDevice.SetBackground(SM_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor);
299
300 const Fraction aFraction(1, 1);
301 rDevice.SetMapMode(MapMode(MapUnit::Map100thMM, Point(), aFraction, aFraction));
302
303 SetTotalSize();
304
305 SetHelpId(HID_SMA_WIN_DOCUMENT);
306
307 ShowLine(false);
308 CaretBlinkInit();
309 }
310
~SmGraphicWidget()311 SmGraphicWidget::~SmGraphicWidget()
312 {
313 if (mxAccessible.is())
314 mxAccessible->ClearWin(); // make Accessible nonfunctional
315 mxAccessible.clear();
316 CaretBlinkStop();
317 }
318
MouseButtonDown(const MouseEvent & rMEvt)319 bool SmGraphicWidget::MouseButtonDown(const MouseEvent& rMEvt)
320 {
321 GrabFocus();
322
323 // set formula-cursor and selection of edit window according to the
324 // position clicked at
325
326 SAL_WARN_IF( rMEvt.GetClicks() == 0, "starmath", "0 clicks" );
327 if ( !rMEvt.IsLeft() )
328 return true;
329
330 OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
331 // get click position relative to formula
332 Point aPos(rDevice.PixelToLogic(rMEvt.GetPosPixel()) - GetFormulaDrawPos());
333
334 const SmNode *pTree = mrViewShell.GetDoc()->GetFormulaTree();
335 if (!pTree)
336 return true;
337
338 if (IsInlineEditEnabled()) {
339 mrViewShell.GetDoc()->GetCursor().MoveTo(&rDevice, aPos, !rMEvt.IsShift());
340 return true;
341 }
342 const SmNode *pNode = nullptr;
343 // if it was clicked inside the formula then get the appropriate node
344 if (pTree->OrientedDist(aPos) <= 0)
345 pNode = pTree->FindRectClosestTo(aPos);
346
347 if (!pNode)
348 return true;
349
350 SmEditWindow* pEdit = mrViewShell.GetEditWindow();
351 if (!pEdit)
352 return true;
353 const SmToken aToken (pNode->GetToken());
354
355 // set selection to the beginning of the token
356 pEdit->SetSelection(pNode->GetSelection());
357 SetCursor(pNode);
358
359 // allow for immediate editing and
360 //! implicitly synchronize the cursor position mark in this window
361 pEdit->GrabFocus();
362
363 return true;
364 }
365
MouseMove(const MouseEvent & rMEvt)366 bool SmGraphicWidget::MouseMove(const MouseEvent &rMEvt)
367 {
368 if (rMEvt.IsLeft() && IsInlineEditEnabled())
369 {
370 OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
371 Point aPos(rDevice.PixelToLogic(rMEvt.GetPosPixel()) - GetFormulaDrawPos());
372 mrViewShell.GetDoc()->GetCursor().MoveTo(&rDevice, aPos, false);
373
374 CaretBlinkStop();
375 SetIsCursorVisible(true);
376 CaretBlinkStart();
377 RepaintViewShellDoc();
378 }
379 return true;
380 }
381
IsInlineEditEnabled()382 bool SmGraphicWidget::IsInlineEditEnabled()
383 {
384 return SmViewShell::IsInlineEditEnabled();
385 }
386
GetFocus()387 void SmGraphicWidget::GetFocus()
388 {
389 if (!IsInlineEditEnabled())
390 return;
391 if (mrViewShell.GetEditWindow())
392 mrViewShell.GetEditWindow()->Flush();
393 //Let view shell know what insertions should be done in visual editor
394 mrViewShell.SetInsertIntoEditWindow(false);
395 SetIsCursorVisible(true);
396 ShowLine(true);
397 CaretBlinkStart();
398 RepaintViewShellDoc();
399 }
400
LoseFocus()401 void SmGraphicWidget::LoseFocus()
402 {
403 if (mxAccessible.is())
404 {
405 uno::Any aOldValue, aNewValue;
406 aOldValue <<= AccessibleStateType::FOCUSED;
407 // aNewValue remains empty
408 mxAccessible->LaunchEvent( AccessibleEventId::STATE_CHANGED,
409 aOldValue, aNewValue );
410 }
411 if (!IsInlineEditEnabled())
412 return;
413 SetIsCursorVisible(false);
414 ShowLine(false);
415 CaretBlinkStop();
416 RepaintViewShellDoc();
417 }
418
RepaintViewShellDoc()419 void SmGraphicWidget::RepaintViewShellDoc()
420 {
421 SmDocShell* pDoc = mrViewShell.GetDoc();
422 if (pDoc)
423 pDoc->Repaint();
424 }
425
IMPL_LINK_NOARG(SmGraphicWidget,CaretBlinkTimerHdl,Timer *,void)426 IMPL_LINK_NOARG(SmGraphicWidget, CaretBlinkTimerHdl, Timer *, void)
427 {
428 if (IsCursorVisible())
429 SetIsCursorVisible(false);
430 else
431 SetIsCursorVisible(true);
432
433 RepaintViewShellDoc();
434 }
435
CaretBlinkInit()436 void SmGraphicWidget::CaretBlinkInit()
437 {
438 aCaretBlinkTimer.SetInvokeHandler(LINK(this, SmGraphicWidget, CaretBlinkTimerHdl));
439 aCaretBlinkTimer.SetTimeout(Application::GetSettings().GetStyleSettings().GetCursorBlinkTime());
440 }
441
CaretBlinkStart()442 void SmGraphicWidget::CaretBlinkStart()
443 {
444 if (!IsInlineEditEnabled())
445 return;
446 if (aCaretBlinkTimer.GetTimeout() != STYLE_CURSOR_NOBLINKTIME)
447 aCaretBlinkTimer.Start();
448 }
449
CaretBlinkStop()450 void SmGraphicWidget::CaretBlinkStop()
451 {
452 if (!IsInlineEditEnabled())
453 return;
454 aCaretBlinkTimer.Stop();
455 }
456
457 // shows or hides the formula-cursor depending on 'bShow' is true or not
ShowCursor(bool bShow)458 void SmGraphicWidget::ShowCursor(bool bShow)
459 {
460 if (IsInlineEditEnabled())
461 return;
462
463 bool bInvert = bShow != IsCursorVisible();
464 if (bInvert)
465 {
466 OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
467 InvertFocusRect(rDevice, aCursorRect);
468 }
469
470 SetIsCursorVisible(bShow);
471 }
472
ShowLine(bool bShow)473 void SmGraphicWidget::ShowLine(bool bShow)
474 {
475 if (!IsInlineEditEnabled())
476 return;
477
478 bIsLineVisible = bShow;
479 }
480
SetCursor(const SmNode * pNode)481 void SmGraphicWidget::SetCursor(const SmNode *pNode)
482 {
483 if (IsInlineEditEnabled())
484 return;
485
486 const SmNode *pTree = mrViewShell.GetDoc()->GetFormulaTree();
487
488 // get appropriate rectangle
489 Point aOffset (pNode->GetTopLeft() - pTree->GetTopLeft()),
490 aTLPos (GetFormulaDrawPos() + aOffset);
491 aTLPos.AdjustX( -(pNode->GetItalicLeftSpace()) );
492 Size aSize (pNode->GetItalicSize());
493
494 SetCursor(tools::Rectangle(aTLPos, aSize));
495 }
496
SetCursor(const tools::Rectangle & rRect)497 void SmGraphicWidget::SetCursor(const tools::Rectangle &rRect)
498 // sets cursor to new position (rectangle) 'rRect'.
499 // The old cursor will be removed, and the new one will be shown if
500 // that is activated in the ConfigItem
501 {
502 if (IsInlineEditEnabled())
503 return;
504
505 SmModule *pp = SM_MOD();
506
507 if (IsCursorVisible())
508 ShowCursor(false); // clean up remainings of old cursor
509 aCursorRect = rRect;
510 if (pp->GetConfig()->IsShowFormulaCursor())
511 ShowCursor(true); // draw new cursor
512 }
513
SetCursorPos(sal_uInt16 nRow,sal_uInt16 nCol)514 const SmNode * SmGraphicWidget::SetCursorPos(sal_uInt16 nRow, sal_uInt16 nCol)
515 // looks for a VISIBLE node in the formula tree with its token at
516 // (or around) the position 'nRow', 'nCol' in the edit window
517 // (row and column numbering starts with 1 there!).
518 // If there is such a node the formula-cursor is set to cover that nodes
519 // rectangle. If not the formula-cursor will be hidden.
520 // In any case the search result is being returned.
521 {
522 if (IsInlineEditEnabled())
523 return nullptr;
524
525 // find visible node with token at nRow, nCol
526 const SmNode *pTree = mrViewShell.GetDoc()->GetFormulaTree(),
527 *pNode = nullptr;
528 if (pTree)
529 pNode = pTree->FindTokenAt(nRow, nCol);
530
531 if (pNode)
532 SetCursor(pNode);
533 else
534 ShowCursor(false);
535
536 return pNode;
537 }
538
Paint(vcl::RenderContext & rRenderContext,const tools::Rectangle &)539 void SmGraphicWidget::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
540 {
541 SmDocShell& rDoc = *mrViewShell.GetDoc();
542 Point aPoint;
543
544 rDoc.DrawFormula(rRenderContext, aPoint, true); //! modifies aPoint to be the topleft
545 //! corner of the formula
546 aFormulaDrawPos = aPoint;
547 if (IsInlineEditEnabled())
548 {
549 //Draw cursor if any...
550 if (mrViewShell.GetDoc()->HasCursor() && IsLineVisible())
551 mrViewShell.GetDoc()->GetCursor().Draw(rRenderContext, aPoint, IsCursorVisible());
552 }
553 else
554 {
555 SetIsCursorVisible(false); // (old) cursor must be drawn again
556
557 const SmEditWindow* pEdit = mrViewShell.GetEditWindow();
558 if (pEdit)
559 { // get new position for formula-cursor (for possible altered formula)
560 sal_Int32 nRow;
561 sal_uInt16 nCol;
562 SmGetLeftSelectionPart(pEdit->GetSelection(), nRow, nCol);
563 const SmNode *pFound = SetCursorPos(static_cast<sal_uInt16>(nRow), nCol);
564
565 SmModule *pp = SM_MOD();
566 if (pFound && pp->GetConfig()->IsShowFormulaCursor())
567 ShowCursor(true);
568 }
569 }
570 }
571
SetTotalSize()572 void SmGraphicWidget::SetTotalSize()
573 {
574 SmDocShell &rDoc = *mrViewShell.GetDoc();
575 OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
576 const Size aTmp(rDevice.PixelToLogic(rDevice.LogicToPixel(rDoc.GetSize())));
577 if (aTmp != mrGraphicWindow.GetTotalSize())
578 mrGraphicWindow.SetTotalSize(aTmp);
579 }
580
KeyInput(const KeyEvent & rKEvt)581 bool SmGraphicWidget::KeyInput(const KeyEvent& rKEvt)
582 {
583 if (!IsInlineEditEnabled())
584 return mrViewShell.KeyInput(rKEvt);
585
586 bool bConsumed = true;
587
588 SmCursor& rCursor = mrViewShell.GetDoc()->GetCursor();
589 KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction();
590 if (eFunc == KeyFuncType::COPY)
591 rCursor.Copy();
592 else if (eFunc == KeyFuncType::CUT)
593 rCursor.Cut();
594 else if (eFunc == KeyFuncType::PASTE)
595 rCursor.Paste();
596 else {
597 OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
598 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
599 switch(nCode)
600 {
601 case KEY_LEFT:
602 {
603 rCursor.Move(&rDevice, MoveLeft, !rKEvt.GetKeyCode().IsShift());
604 }break;
605 case KEY_RIGHT:
606 {
607 rCursor.Move(&rDevice, MoveRight, !rKEvt.GetKeyCode().IsShift());
608 }break;
609 case KEY_UP:
610 {
611 rCursor.Move(&rDevice, MoveUp, !rKEvt.GetKeyCode().IsShift());
612 }break;
613 case KEY_DOWN:
614 {
615 rCursor.Move(&rDevice, MoveDown, !rKEvt.GetKeyCode().IsShift());
616 }break;
617 case KEY_RETURN:
618 {
619 if(!rKEvt.GetKeyCode().IsShift())
620 rCursor.InsertRow();
621 }break;
622 case KEY_DELETE:
623 {
624 if(!rCursor.HasSelection()){
625 rCursor.Move(&rDevice, MoveRight, false);
626 if(rCursor.HasComplexSelection()) break;
627 }
628 rCursor.Delete();
629 }break;
630 case KEY_BACKSPACE:
631 {
632 rCursor.DeletePrev(&rDevice);
633 }break;
634 case KEY_ADD:
635 rCursor.InsertElement(PlusElement);
636 break;
637 case KEY_SUBTRACT:
638 if(rKEvt.GetKeyCode().IsShift())
639 rCursor.InsertSubSup(RSUB);
640 else
641 rCursor.InsertElement(MinusElement);
642 break;
643 case KEY_MULTIPLY:
644 rCursor.InsertElement(CDotElement);
645 break;
646 case KEY_DIVIDE:
647 rCursor.InsertFraction();
648 break;
649 case KEY_LESS:
650 rCursor.InsertElement(LessThanElement);
651 break;
652 case KEY_GREATER:
653 rCursor.InsertElement(GreaterThanElement);
654 break;
655 case KEY_EQUAL:
656 rCursor.InsertElement(EqualElement);
657 break;
658 default:
659 {
660 sal_Unicode code = rKEvt.GetCharCode();
661
662 if(code == ' ') {
663 rCursor.InsertElement(BlankElement);
664 }else if(code == '^') {
665 rCursor.InsertSubSup(RSUP);
666 }else if(code == '(') {
667 rCursor.InsertBrackets(SmBracketType::Round);
668 }else if(code == '[') {
669 rCursor.InsertBrackets(SmBracketType::Square);
670 }else if(code == '{') {
671 rCursor.InsertBrackets(SmBracketType::Curly);
672 }else if(code == '!') {
673 rCursor.InsertElement(FactorialElement);
674 }else if(code == '%') {
675 rCursor.InsertElement(PercentElement);
676 }
677 else if ((code == ')' && rCursor.IsAtTailOfBracket(SmBracketType::Round))
678 || (code == ']' && rCursor.IsAtTailOfBracket(SmBracketType::Square))
679 || (code == '}' && rCursor.IsAtTailOfBracket(SmBracketType::Curly)))
680 {
681 rCursor.Move(&rDevice, MoveRight);
682 }
683 else{
684 if(code != 0){
685 rCursor.InsertText(OUString(code));
686 }else if (!mrViewShell.KeyInput(rKEvt))
687 bConsumed = false;
688 }
689 }
690 }
691 }
692 CaretBlinkStop();
693 CaretBlinkStart();
694 SetIsCursorVisible(true);
695 RepaintViewShellDoc();
696
697 return bConsumed;
698 }
699
Command(const CommandEvent & rCEvt)700 bool SmGraphicWidget::Command(const CommandEvent& rCEvt)
701 {
702 bool bCallBase = true;
703 if (!mrViewShell.GetViewFrame()->GetFrame().IsInPlace())
704 {
705 switch ( rCEvt.GetCommand() )
706 {
707 case CommandEventId::ContextMenu:
708 // purely for "ExecutePopup" taking a vcl::Window and
709 // we assume SmGraphicWindow 0,0 is at SmEditWindow 0,0
710 mrGraphicWindow.ShowContextMenu(rCEvt);
711 bCallBase = false;
712 break;
713
714 case CommandEventId::Wheel:
715 {
716 const CommandWheelData* pWData = rCEvt.GetWheelData();
717 if ( pWData && CommandWheelMode::ZOOM == pWData->GetMode() )
718 {
719 sal_uInt16 nTmpZoom = mrGraphicWindow.GetZoom();
720 if( 0 > pWData->GetDelta() )
721 nTmpZoom -= 10;
722 else
723 nTmpZoom += 10;
724 mrGraphicWindow.SetZoom(nTmpZoom);
725 bCallBase = false;
726 }
727 }
728 break;
729
730 default: break;
731 }
732 }
733 return !bCallBase;
734 }
735
SetZoom(sal_uInt16 Factor)736 void SmGraphicWindow::SetZoom(sal_uInt16 Factor)
737 {
738 nZoom = std::clamp(Factor, MINZOOM, MAXZOOM);
739 Fraction aFraction(nZoom, 100);
740 SetGraphicMapMode(MapMode(MapUnit::Map100thMM, Point(), aFraction, aFraction));
741 mxGraphic->SetTotalSize();
742 SmViewShell& rViewSh = mxGraphic->GetView();
743 rViewSh.GetViewFrame()->GetBindings().Invalidate(SID_ATTR_ZOOM);
744 rViewSh.GetViewFrame()->GetBindings().Invalidate(SID_ATTR_ZOOMSLIDER);
745 }
746
ZoomToFitInWindow()747 void SmGraphicWindow::ZoomToFitInWindow()
748 {
749 SmViewShell& rViewSh = mxGraphic->GetView();
750 SmDocShell& rDoc = *rViewSh.GetDoc();
751
752 // set defined mapmode before calling 'LogicToPixel' below
753 SetGraphicMapMode(MapMode(MapUnit::Map100thMM));
754
755 OutputDevice& rDevice = mxGraphic->GetDrawingArea()->get_ref_device();
756 Size aSize(rDevice.LogicToPixel(rDoc.GetSize()));
757 Size aWindowSize(GetSizePixel());
758
759 if (!aSize.IsEmpty())
760 {
761 tools::Long nVal = std::min ((85 * aWindowSize.Width()) / aSize.Width(),
762 (85 * aWindowSize.Height()) / aSize.Height());
763 SetZoom ( sal::static_int_cast< sal_uInt16 >(nVal) );
764 }
765 }
766
CreateAccessible()767 uno::Reference< XAccessible > SmGraphicWidget::CreateAccessible()
768 {
769 if (!mxAccessible.is())
770 {
771 mxAccessible = new SmGraphicAccessible( this );
772 }
773 return mxAccessible;
774 }
775
776 /**************************************************************************/
SmGraphicController(SmGraphicWidget & rSmGraphic,sal_uInt16 nId_,SfxBindings & rBindings)777 SmGraphicController::SmGraphicController(SmGraphicWidget &rSmGraphic,
778 sal_uInt16 nId_,
779 SfxBindings &rBindings) :
780 SfxControllerItem(nId_, rBindings),
781 rGraphic(rSmGraphic)
782 {
783 }
784
StateChanged(sal_uInt16 nSID,SfxItemState eState,const SfxPoolItem * pState)785 void SmGraphicController::StateChanged(sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState)
786 {
787 rGraphic.SetTotalSize();
788 rGraphic.Invalidate();
789 SfxControllerItem::StateChanged (nSID, eState, pState);
790 }
791
792 /**************************************************************************/
SmEditController(SmEditWindow & rSmEdit,sal_uInt16 nId_,SfxBindings & rBindings)793 SmEditController::SmEditController(SmEditWindow &rSmEdit,
794 sal_uInt16 nId_,
795 SfxBindings &rBindings) :
796 SfxControllerItem(nId_, rBindings),
797 rEdit(rSmEdit)
798 {
799 }
800
StateChanged(sal_uInt16 nSID,SfxItemState eState,const SfxPoolItem * pState)801 void SmEditController::StateChanged(sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState)
802 {
803 const SfxStringItem *pItem = dynamic_cast<const SfxStringItem*>( pState);
804
805 if ((pItem != nullptr) && (rEdit.GetText() != pItem->GetValue()))
806 rEdit.SetText(pItem->GetValue());
807 SfxControllerItem::StateChanged (nSID, eState, pState);
808 }
809
810 /**************************************************************************/
SmCmdBoxWindow(SfxBindings * pBindings_,SfxChildWindow * pChildWindow,vcl::Window * pParent)811 SmCmdBoxWindow::SmCmdBoxWindow(SfxBindings *pBindings_, SfxChildWindow *pChildWindow,
812 vcl::Window *pParent)
813 : SfxDockingWindow(pBindings_, pChildWindow, pParent, "EditWindow", "modules/smath/ui/editwindow.ui")
814 , m_xEdit(new SmEditWindow(*this, *m_xBuilder))
815 , aController(*m_xEdit, SID_TEXT, *pBindings_)
816 , bExiting(false)
817 {
818 set_id("math_edit");
819
820 SetHelpId( HID_SMA_COMMAND_WIN );
821 SetSizePixel(LogicToPixel(Size(292 , 94), MapMode(MapUnit::MapAppFont)));
822 SetText(SmResId(STR_CMDBOXWINDOW));
823
824 Hide();
825
826 aInitialFocusTimer.SetInvokeHandler(LINK(this, SmCmdBoxWindow, InitialFocusTimerHdl));
827 aInitialFocusTimer.SetTimeout(100);
828 }
829
WidgetToWindowPos(const weld::Widget & rWidget,const Point & rPos)830 Point SmCmdBoxWindow::WidgetToWindowPos(const weld::Widget& rWidget, const Point& rPos)
831 {
832 Point aRet(rPos);
833 int x(0), y(0), width(0), height(0);
834 rWidget.get_extents_relative_to(*m_xContainer, x, y, width, height);
835 aRet.Move(x, y);
836 aRet.Move(m_xBox->GetPosPixel().X(), m_xBox->GetPosPixel().Y());
837 return aRet;
838 }
839
ShowContextMenu(const Point & rPos)840 void SmCmdBoxWindow::ShowContextMenu(const Point& rPos)
841 {
842 ToTop();
843 SmViewShell *pViewSh = GetView();
844 if (pViewSh)
845 pViewSh->GetViewFrame()->GetDispatcher()->ExecutePopup("edit", this, &rPos);
846 }
847
Command(const CommandEvent & rCEvt)848 void SmCmdBoxWindow::Command(const CommandEvent& rCEvt)
849 {
850 if (rCEvt.GetCommand() == CommandEventId::ContextMenu)
851 {
852 ShowContextMenu(rCEvt.GetMousePosPixel());
853 return;
854 }
855
856 SfxDockingWindow::Command(rCEvt);
857 }
858
~SmCmdBoxWindow()859 SmCmdBoxWindow::~SmCmdBoxWindow ()
860 {
861 disposeOnce();
862 }
863
dispose()864 void SmCmdBoxWindow::dispose()
865 {
866 aInitialFocusTimer.Stop();
867 bExiting = true;
868 aController.dispose();
869 m_xEdit.reset();
870 SfxDockingWindow::dispose();
871 }
872
GetView()873 SmViewShell * SmCmdBoxWindow::GetView()
874 {
875 SfxDispatcher *pDispatcher = GetBindings().GetDispatcher();
876 SfxViewShell *pView = pDispatcher ? pDispatcher->GetFrame()->GetViewShell() : nullptr;
877 return dynamic_cast<SmViewShell*>( pView);
878 }
879
CalcDockingSize(SfxChildAlignment eAlign)880 Size SmCmdBoxWindow::CalcDockingSize(SfxChildAlignment eAlign)
881 {
882 switch (eAlign)
883 {
884 case SfxChildAlignment::LEFT:
885 case SfxChildAlignment::RIGHT:
886 return Size();
887 default:
888 break;
889 }
890 return SfxDockingWindow::CalcDockingSize(eAlign);
891 }
892
CheckAlignment(SfxChildAlignment eActual,SfxChildAlignment eWish)893 SfxChildAlignment SmCmdBoxWindow::CheckAlignment(SfxChildAlignment eActual,
894 SfxChildAlignment eWish)
895 {
896 switch (eWish)
897 {
898 case SfxChildAlignment::TOP:
899 case SfxChildAlignment::BOTTOM:
900 case SfxChildAlignment::NOALIGNMENT:
901 return eWish;
902 default:
903 break;
904 }
905
906 return eActual;
907 }
908
StateChanged(StateChangedType nStateChange)909 void SmCmdBoxWindow::StateChanged( StateChangedType nStateChange )
910 {
911 if (StateChangedType::InitShow == nStateChange)
912 {
913 Resize(); // avoid SmEditWindow not being painted correctly
914
915 // set initial position of window in floating mode
916 if (IsFloatingMode())
917 AdjustPosition(); //! don't change pos in docking-mode !
918
919 aInitialFocusTimer.Start();
920 }
921
922 SfxDockingWindow::StateChanged( nStateChange );
923 }
924
IMPL_LINK_NOARG(SmCmdBoxWindow,InitialFocusTimerHdl,Timer *,void)925 IMPL_LINK_NOARG( SmCmdBoxWindow, InitialFocusTimerHdl, Timer *, void )
926 {
927 // We want to have the focus in the edit window once Math has been opened
928 // to allow for immediate typing.
929 // Problem: There is no proper way to do this
930 // Thus: this timer based solution has been implemented (see GrabFocus below)
931
932 // Follow-up problem (#i114910): grabbing the focus may bust the help system since
933 // it relies on getting the current frame which conflicts with grabbing the focus.
934 // Thus aside from the 'GrabFocus' call everything else is to get the
935 // help reliably working despite using 'GrabFocus'.
936
937 try
938 {
939 uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create( comphelper::getProcessComponentContext() );
940
941 m_xEdit->GrabFocus();
942
943 SmViewShell* pView = GetView();
944 assert(pView);
945 bool bInPlace = pView->GetViewFrame()->GetFrame().IsInPlace();
946 uno::Reference< frame::XFrame > xFrame( GetBindings().GetDispatcher()->GetFrame()->GetFrame().GetFrameInterface());
947 if ( bInPlace )
948 {
949 uno::Reference<container::XChild> xModel(pView->GetDoc()->GetModel(),
950 uno::UNO_QUERY_THROW);
951 uno::Reference< frame::XModel > xParent( xModel->getParent(), uno::UNO_QUERY_THROW );
952 uno::Reference< frame::XController > xParentCtrler( xParent->getCurrentController() );
953 uno::Reference< frame::XFramesSupplier > xParentFrame( xParentCtrler->getFrame(), uno::UNO_QUERY_THROW );
954 xParentFrame->setActiveFrame( xFrame );
955 }
956 else
957 {
958 xDesktop->setActiveFrame( xFrame );
959 }
960 }
961 catch (uno::Exception &)
962 {
963 SAL_WARN( "starmath", "failed to properly set initial focus to edit window" );
964 }
965 }
966
AdjustPosition()967 void SmCmdBoxWindow::AdjustPosition()
968 {
969 const tools::Rectangle aRect( Point(), GetParent()->GetOutputSizePixel() );
970 Point aTopLeft( Point( aRect.Left(),
971 aRect.Bottom() - GetSizePixel().Height() ) );
972 Point aPos( GetParent()->OutputToScreenPixel( aTopLeft ) );
973 if (aPos.X() < 0)
974 aPos.setX( 0 );
975 if (aPos.Y() < 0)
976 aPos.setY( 0 );
977 SetPosPixel( aPos );
978 }
979
ToggleFloatingMode()980 void SmCmdBoxWindow::ToggleFloatingMode()
981 {
982 SfxDockingWindow::ToggleFloatingMode();
983
984 if (GetFloatingWindow())
985 GetFloatingWindow()->SetMinOutputSizePixel(Size (200, 50));
986 }
987
GetFocus()988 void SmCmdBoxWindow::GetFocus()
989 {
990 if (!bExiting)
991 m_xEdit->GrabFocus();
992 }
993
994 SFX_IMPL_DOCKINGWINDOW_WITHID(SmCmdBoxWrapper, SID_CMDBOXWINDOW);
995
SmCmdBoxWrapper(vcl::Window * pParentWindow,sal_uInt16 nId,SfxBindings * pBindings,SfxChildWinInfo * pInfo)996 SmCmdBoxWrapper::SmCmdBoxWrapper(vcl::Window *pParentWindow, sal_uInt16 nId,
997 SfxBindings *pBindings,
998 SfxChildWinInfo *pInfo) :
999 SfxChildWindow(pParentWindow, nId)
1000 {
1001 VclPtrInstance<SmCmdBoxWindow> pDialog(pBindings, this, pParentWindow);
1002 SetWindow(pDialog);
1003 // make window docked to the bottom initially (after first start)
1004 SetAlignment(SfxChildAlignment::BOTTOM);
1005 pDialog->setDeferredProperties();
1006 pDialog->set_border_width(CMD_BOX_PADDING);
1007 pDialog->set_margin_top(CMD_BOX_PADDING_TOP);
1008 pDialog->Initialize(pInfo);
1009 }
1010
SFX_IMPL_SUPERCLASS_INTERFACE(SmViewShell,SfxViewShell)1011 SFX_IMPL_SUPERCLASS_INTERFACE(SmViewShell, SfxViewShell)
1012
1013 void SmViewShell::InitInterface_Impl()
1014 {
1015 GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_TOOLS,
1016 SfxVisibilityFlags::Standard | SfxVisibilityFlags::FullScreen | SfxVisibilityFlags::Server,
1017 ToolbarId::Math_Toolbox);
1018 //Dummy-Objectbar, to avoid quiver while activating
1019
1020 GetStaticInterface()->RegisterChildWindow(SmCmdBoxWrapper::GetChildWindowId());
1021 GetStaticInterface()->RegisterChildWindow(SmElementsDockingWindowWrapper::GetChildWindowId());
1022 GetStaticInterface()->RegisterChildWindow(SfxInfoBarContainerChild::GetChildWindowId());
1023 }
1024
1025 SFX_IMPL_NAMED_VIEWFACTORY(SmViewShell, "Default")
1026 {
1027 SFX_VIEW_REGISTRATION(SmDocShell);
1028 }
1029
InnerResizePixel(const Point & rOfs,const Size & rSize,bool)1030 void SmViewShell::InnerResizePixel(const Point &rOfs, const Size &rSize, bool)
1031 {
1032 Size aObjSize = GetObjectShell()->GetVisArea().GetSize();
1033 if ( !aObjSize.IsEmpty() )
1034 {
1035 Size aProvidedSize = GetWindow()->PixelToLogic(rSize, MapMode(MapUnit::Map100thMM));
1036 SfxViewShell::SetZoomFactor( Fraction( aProvidedSize.Width(), aObjSize.Width() ),
1037 Fraction( aProvidedSize.Height(), aObjSize.Height() ) );
1038 }
1039
1040 SetBorderPixel( SvBorder() );
1041 mxGraphicWindow->SetPosSizePixel(rOfs, rSize);
1042 GetGraphicWidget().SetTotalSize();
1043 }
1044
OuterResizePixel(const Point & rOfs,const Size & rSize)1045 void SmViewShell::OuterResizePixel(const Point &rOfs, const Size &rSize)
1046 {
1047 mxGraphicWindow->SetPosSizePixel(rOfs, rSize);
1048 if (GetDoc()->IsPreview())
1049 mxGraphicWindow->ZoomToFitInWindow();
1050 }
1051
QueryObjAreaPixel(tools::Rectangle & rRect) const1052 void SmViewShell::QueryObjAreaPixel( tools::Rectangle& rRect ) const
1053 {
1054 rRect.SetSize(mxGraphicWindow->GetSizePixel());
1055 }
1056
SetZoomFactor(const Fraction & rX,const Fraction & rY)1057 void SmViewShell::SetZoomFactor( const Fraction &rX, const Fraction &rY )
1058 {
1059 const Fraction &rFrac = std::min(rX, rY);
1060 mxGraphicWindow->SetZoom(sal::static_int_cast<sal_uInt16>(tools::Long(rFrac * Fraction( 100, 1 ))));
1061
1062 //To avoid rounding errors base class regulates crooked values too
1063 //if necessary
1064 SfxViewShell::SetZoomFactor( rX, rY );
1065 }
1066
GetTextLineSize(OutputDevice const & rDevice,const OUString & rLine)1067 Size SmViewShell::GetTextLineSize(OutputDevice const & rDevice, const OUString& rLine)
1068 {
1069 Size aSize(rDevice.GetTextWidth(rLine), rDevice.GetTextHeight());
1070 const tools::Long nTabPos = rLine.isEmpty() ? 0 : rDevice.approximate_digit_width() * 8;
1071
1072 if (nTabPos)
1073 {
1074 aSize.setWidth( 0 );
1075 sal_Int32 nPos = 0;
1076 do
1077 {
1078 if (nPos > 0)
1079 aSize.setWidth( ((aSize.Width() / nTabPos) + 1) * nTabPos );
1080
1081 const OUString aText = rLine.getToken(0, '\t', nPos);
1082 aSize.AdjustWidth(rDevice.GetTextWidth(aText) );
1083 }
1084 while (nPos >= 0);
1085 }
1086
1087 return aSize;
1088 }
1089
GetTextSize(OutputDevice const & rDevice,const OUString & rText,tools::Long MaxWidth)1090 Size SmViewShell::GetTextSize(OutputDevice const & rDevice, const OUString& rText, tools::Long MaxWidth)
1091 {
1092 Size aSize;
1093 Size aTextSize;
1094 if (rText.isEmpty())
1095 return aTextSize;
1096
1097 sal_Int32 nPos = 0;
1098 do
1099 {
1100 OUString aLine = rText.getToken(0, '\n', nPos);
1101 aLine = aLine.replaceAll("\r", "");
1102
1103 aSize = GetTextLineSize(rDevice, aLine);
1104
1105 if (aSize.Width() > MaxWidth)
1106 {
1107 do
1108 {
1109 OUString aText;
1110 sal_Int32 m = aLine.getLength();
1111 sal_Int32 nLen = m;
1112
1113 for (sal_Int32 n = 0; n < nLen; n++)
1114 {
1115 sal_Unicode cLineChar = aLine[n];
1116 if ((cLineChar == ' ') || (cLineChar == '\t'))
1117 {
1118 aText = aLine.copy(0, n);
1119 if (GetTextLineSize(rDevice, aText).Width() < MaxWidth)
1120 m = n;
1121 else
1122 break;
1123 }
1124 }
1125
1126 aText = aLine.copy(0, m);
1127 aLine = aLine.replaceAt(0, m, "");
1128 aSize = GetTextLineSize(rDevice, aText);
1129 aTextSize.AdjustHeight(aSize.Height() );
1130 aTextSize.setWidth( std::clamp(aSize.Width(), aTextSize.Width(), MaxWidth) );
1131
1132 aLine = comphelper::string::stripStart(aLine, ' ');
1133 aLine = comphelper::string::stripStart(aLine, '\t');
1134 aLine = comphelper::string::stripStart(aLine, ' ');
1135 }
1136 while (!aLine.isEmpty());
1137 }
1138 else
1139 {
1140 aTextSize.AdjustHeight(aSize.Height() );
1141 aTextSize.setWidth( std::max(aTextSize.Width(), aSize.Width()) );
1142 }
1143 }
1144 while (nPos >= 0);
1145
1146 return aTextSize;
1147 }
1148
DrawTextLine(OutputDevice & rDevice,const Point & rPosition,const OUString & rLine)1149 void SmViewShell::DrawTextLine(OutputDevice& rDevice, const Point& rPosition, const OUString& rLine)
1150 {
1151 Point aPoint(rPosition);
1152 const tools::Long nTabPos = rLine.isEmpty() ? 0 : rDevice.approximate_digit_width() * 8;
1153
1154 if (nTabPos)
1155 {
1156 sal_Int32 nPos = 0;
1157 do
1158 {
1159 if (nPos > 0)
1160 aPoint.setX( ((aPoint.X() / nTabPos) + 1) * nTabPos );
1161
1162 OUString aText = rLine.getToken(0, '\t', nPos);
1163 rDevice.DrawText(aPoint, aText);
1164 aPoint.AdjustX(rDevice.GetTextWidth(aText) );
1165 }
1166 while ( nPos >= 0 );
1167 }
1168 else
1169 rDevice.DrawText(aPoint, rLine);
1170 }
1171
DrawText(OutputDevice & rDevice,const Point & rPosition,const OUString & rText,sal_uInt16 MaxWidth)1172 void SmViewShell::DrawText(OutputDevice& rDevice, const Point& rPosition, const OUString& rText, sal_uInt16 MaxWidth)
1173 {
1174 if (rText.isEmpty())
1175 return;
1176
1177 Point aPoint(rPosition);
1178 Size aSize;
1179
1180 sal_Int32 nPos = 0;
1181 do
1182 {
1183 OUString aLine = rText.getToken(0, '\n', nPos);
1184 aLine = aLine.replaceAll("\r", "");
1185 aSize = GetTextLineSize(rDevice, aLine);
1186 if (aSize.Width() > MaxWidth)
1187 {
1188 do
1189 {
1190 OUString aText;
1191 sal_Int32 m = aLine.getLength();
1192 sal_Int32 nLen = m;
1193
1194 for (sal_Int32 n = 0; n < nLen; n++)
1195 {
1196 sal_Unicode cLineChar = aLine[n];
1197 if ((cLineChar == ' ') || (cLineChar == '\t'))
1198 {
1199 aText = aLine.copy(0, n);
1200 if (GetTextLineSize(rDevice, aText).Width() < MaxWidth)
1201 m = n;
1202 else
1203 break;
1204 }
1205 }
1206 aText = aLine.copy(0, m);
1207 aLine = aLine.replaceAt(0, m, "");
1208
1209 DrawTextLine(rDevice, aPoint, aText);
1210 aPoint.AdjustY(aSize.Height() );
1211
1212 aLine = comphelper::string::stripStart(aLine, ' ');
1213 aLine = comphelper::string::stripStart(aLine, '\t');
1214 aLine = comphelper::string::stripStart(aLine, ' ');
1215 }
1216 while (GetTextLineSize(rDevice, aLine).Width() > MaxWidth);
1217
1218 // print the remaining text
1219 if (!aLine.isEmpty())
1220 {
1221 DrawTextLine(rDevice, aPoint, aLine);
1222 aPoint.AdjustY(aSize.Height() );
1223 }
1224 }
1225 else
1226 {
1227 DrawTextLine(rDevice, aPoint, aLine);
1228 aPoint.AdjustY(aSize.Height() );
1229 }
1230 }
1231 while ( nPos >= 0 );
1232 }
1233
Impl_Print(OutputDevice & rOutDev,const SmPrintUIOptions & rPrintUIOptions,tools::Rectangle aOutRect)1234 void SmViewShell::Impl_Print(OutputDevice &rOutDev, const SmPrintUIOptions &rPrintUIOptions, tools::Rectangle aOutRect )
1235 {
1236 const bool bIsPrintTitle = rPrintUIOptions.getBoolValue( PRTUIOPT_TITLE_ROW, true );
1237 const bool bIsPrintFrame = rPrintUIOptions.getBoolValue( PRTUIOPT_BORDER, true );
1238 const bool bIsPrintFormulaText = rPrintUIOptions.getBoolValue( PRTUIOPT_FORMULA_TEXT, true );
1239 SmPrintSize ePrintSize( static_cast< SmPrintSize >( rPrintUIOptions.getIntValue( PRTUIOPT_PRINT_FORMAT, PRINT_SIZE_NORMAL ) ));
1240 const sal_uInt16 nZoomFactor = static_cast< sal_uInt16 >(rPrintUIOptions.getIntValue( PRTUIOPT_PRINT_SCALE, 100 ));
1241
1242 rOutDev.Push();
1243 rOutDev.SetLineColor( COL_BLACK );
1244
1245 // output text on top
1246 if (bIsPrintTitle)
1247 {
1248 Size aSize600 (0, 600);
1249 Size aSize650 (0, 650);
1250 vcl::Font aFont(FAMILY_DONTKNOW, aSize600);
1251
1252 aFont.SetAlignment(ALIGN_TOP);
1253 aFont.SetWeight(WEIGHT_BOLD);
1254 aFont.SetFontSize(aSize650);
1255 aFont.SetColor( COL_BLACK );
1256 rOutDev.SetFont(aFont);
1257
1258 Size aTitleSize (GetTextSize(rOutDev, GetDoc()->GetTitle(), aOutRect.GetWidth() - 200));
1259
1260 aFont.SetWeight(WEIGHT_NORMAL);
1261 aFont.SetFontSize(aSize600);
1262 rOutDev.SetFont(aFont);
1263
1264 Size aDescSize (GetTextSize(rOutDev, GetDoc()->GetComment(), aOutRect.GetWidth() - 200));
1265
1266 if (bIsPrintFrame)
1267 rOutDev.DrawRect(tools::Rectangle(aOutRect.TopLeft(),
1268 Size(aOutRect.GetWidth(), 100 + aTitleSize.Height() + 200 + aDescSize.Height() + 100)));
1269 aOutRect.AdjustTop(200 );
1270
1271 // output title
1272 aFont.SetWeight(WEIGHT_BOLD);
1273 aFont.SetFontSize(aSize650);
1274 rOutDev.SetFont(aFont);
1275 Point aPoint(aOutRect.Left() + (aOutRect.GetWidth() - aTitleSize.Width()) / 2,
1276 aOutRect.Top());
1277 DrawText(rOutDev, aPoint, GetDoc()->GetTitle(),
1278 sal::static_int_cast< sal_uInt16 >(aOutRect.GetWidth() - 200));
1279 aOutRect.AdjustTop(aTitleSize.Height() + 200 );
1280
1281 // output description
1282 aFont.SetWeight(WEIGHT_NORMAL);
1283 aFont.SetFontSize(aSize600);
1284 rOutDev.SetFont(aFont);
1285 aPoint.setX( aOutRect.Left() + (aOutRect.GetWidth() - aDescSize.Width()) / 2 );
1286 aPoint.setY( aOutRect.Top() );
1287 DrawText(rOutDev, aPoint, GetDoc()->GetComment(),
1288 sal::static_int_cast< sal_uInt16 >(aOutRect.GetWidth() - 200));
1289 aOutRect.AdjustTop(aDescSize.Height() + 300 );
1290 }
1291
1292 // output text on bottom
1293 if (bIsPrintFormulaText)
1294 {
1295 vcl::Font aFont(FAMILY_DONTKNOW, Size(0, 600));
1296 aFont.SetAlignment(ALIGN_TOP);
1297 aFont.SetColor( COL_BLACK );
1298
1299 // get size
1300 rOutDev.SetFont(aFont);
1301
1302 Size aSize (GetTextSize(rOutDev, GetDoc()->GetText(), aOutRect.GetWidth() - 200));
1303
1304 aOutRect.AdjustBottom( -(aSize.Height() + 600) );
1305
1306 if (bIsPrintFrame)
1307 rOutDev.DrawRect(tools::Rectangle(aOutRect.BottomLeft(),
1308 Size(aOutRect.GetWidth(), 200 + aSize.Height() + 200)));
1309
1310 Point aPoint (aOutRect.Left() + (aOutRect.GetWidth() - aSize.Width()) / 2,
1311 aOutRect.Bottom() + 300);
1312 DrawText(rOutDev, aPoint, GetDoc()->GetText(),
1313 sal::static_int_cast< sal_uInt16 >(aOutRect.GetWidth() - 200));
1314 aOutRect.AdjustBottom( -200 );
1315 }
1316
1317 if (bIsPrintFrame)
1318 rOutDev.DrawRect(aOutRect);
1319
1320 aOutRect.AdjustTop(100 );
1321 aOutRect.AdjustLeft(100 );
1322 aOutRect.AdjustBottom( -100 );
1323 aOutRect.AdjustRight( -100 );
1324
1325 Size aSize (GetDoc()->GetSize());
1326
1327 MapMode OutputMapMode;
1328 // PDF export should always use PRINT_SIZE_NORMAL ...
1329 if (!rPrintUIOptions.getBoolValue( "IsPrinter" ) )
1330 ePrintSize = PRINT_SIZE_NORMAL;
1331 switch (ePrintSize)
1332 {
1333 case PRINT_SIZE_NORMAL:
1334 OutputMapMode = MapMode(MapUnit::Map100thMM);
1335 break;
1336
1337 case PRINT_SIZE_SCALED:
1338 if (!aSize.IsEmpty())
1339 {
1340 Size OutputSize (rOutDev.LogicToPixel(Size(aOutRect.GetWidth(),
1341 aOutRect.GetHeight()), MapMode(MapUnit::Map100thMM)));
1342 Size GraphicSize (rOutDev.LogicToPixel(aSize, MapMode(MapUnit::Map100thMM)));
1343 sal_uInt16 nZ = sal::static_int_cast<sal_uInt16>(std::min(tools::Long(Fraction(OutputSize.Width() * 100, GraphicSize.Width())),
1344 tools::Long(Fraction(OutputSize.Height() * 100, GraphicSize.Height()))));
1345 nZ -= 10;
1346 Fraction aFraction (std::clamp(nZ, MINZOOM, sal_uInt16(100)));
1347
1348 OutputMapMode = MapMode(MapUnit::Map100thMM, Point(), aFraction, aFraction);
1349 }
1350 else
1351 OutputMapMode = MapMode(MapUnit::Map100thMM);
1352 break;
1353
1354 case PRINT_SIZE_ZOOMED:
1355 {
1356 Fraction aFraction( nZoomFactor, 100 );
1357
1358 OutputMapMode = MapMode(MapUnit::Map100thMM, Point(), aFraction, aFraction);
1359 break;
1360 }
1361 }
1362
1363 aSize = rOutDev.PixelToLogic(rOutDev.LogicToPixel(aSize, OutputMapMode),
1364 MapMode(MapUnit::Map100thMM));
1365
1366 Point aPos (aOutRect.Left() + (aOutRect.GetWidth() - aSize.Width()) / 2,
1367 aOutRect.Top() + (aOutRect.GetHeight() - aSize.Height()) / 2);
1368
1369 aPos = rOutDev.PixelToLogic(rOutDev.LogicToPixel(aPos, MapMode(MapUnit::Map100thMM)),
1370 OutputMapMode);
1371 aOutRect = rOutDev.PixelToLogic(rOutDev.LogicToPixel(aOutRect, MapMode(MapUnit::Map100thMM)),
1372 OutputMapMode);
1373
1374 rOutDev.SetMapMode(OutputMapMode);
1375 rOutDev.SetClipRegion(vcl::Region(aOutRect));
1376 GetDoc()->DrawFormula(rOutDev, aPos);
1377 rOutDev.SetClipRegion();
1378
1379 rOutDev.Pop();
1380 }
1381
GetPrinter(bool bCreate)1382 SfxPrinter* SmViewShell::GetPrinter(bool bCreate)
1383 {
1384 SmDocShell* pDoc = GetDoc();
1385 if (pDoc->HasPrinter() || bCreate)
1386 return pDoc->GetPrinter();
1387 return nullptr;
1388 }
1389
SetPrinter(SfxPrinter * pNewPrinter,SfxPrinterChangeFlags nDiffFlags)1390 sal_uInt16 SmViewShell::SetPrinter(SfxPrinter *pNewPrinter, SfxPrinterChangeFlags nDiffFlags )
1391 {
1392 SfxPrinter *pOld = GetDoc()->GetPrinter();
1393 if ( pOld && pOld->IsPrinting() )
1394 return SFX_PRINTERROR_BUSY;
1395
1396 if ((nDiffFlags & SfxPrinterChangeFlags::PRINTER) == SfxPrinterChangeFlags::PRINTER)
1397 GetDoc()->SetPrinter( pNewPrinter );
1398
1399 if ((nDiffFlags & SfxPrinterChangeFlags::OPTIONS) == SfxPrinterChangeFlags::OPTIONS)
1400 {
1401 SmModule *pp = SM_MOD();
1402 pp->GetConfig()->ItemSetToConfig(pNewPrinter->GetOptions());
1403 }
1404 return 0;
1405 }
1406
HasPrintOptionsPage() const1407 bool SmViewShell::HasPrintOptionsPage() const
1408 {
1409 return true;
1410 }
1411
CreatePrintOptionsPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rOptions)1412 std::unique_ptr<SfxTabPage> SmViewShell::CreatePrintOptionsPage(weld::Container* pPage, weld::DialogController* pController,
1413 const SfxItemSet &rOptions)
1414 {
1415 return SmPrintOptionsTabPage::Create(pPage, pController, rOptions);
1416 }
1417
GetEditWindow()1418 SmEditWindow *SmViewShell::GetEditWindow()
1419 {
1420 SmCmdBoxWrapper* pWrapper = static_cast<SmCmdBoxWrapper*>(
1421 GetViewFrame()->GetChildWindow(SmCmdBoxWrapper::GetChildWindowId()));
1422
1423 if (pWrapper != nullptr)
1424 {
1425 SmEditWindow& rEditWin = pWrapper->GetEditWindow();
1426 return &rEditWin;
1427 }
1428
1429 return nullptr;
1430 }
1431
GetDockingWindow()1432 SmElementsDockingWindow* SmViewShell::GetDockingWindow()
1433 {
1434 auto eldockwinwrap = GetViewFrame()->GetChildWindow(SmElementsDockingWindowWrapper::GetChildWindowId());
1435 if(eldockwinwrap)
1436 return dynamic_cast<SmElementsDockingWindow*>(eldockwinwrap->GetWindow());
1437 else
1438 return nullptr;
1439 }
1440
SetStatusText(const OUString & rText)1441 void SmViewShell::SetStatusText(const OUString& rText)
1442 {
1443 maStatusText = rText;
1444 GetViewFrame()->GetBindings().Invalidate(SID_TEXTSTATUS);
1445 }
1446
ShowError(const SmErrorDesc * pErrorDesc)1447 void SmViewShell::ShowError(const SmErrorDesc* pErrorDesc)
1448 {
1449 assert(GetDoc());
1450 if (pErrorDesc || nullptr != (pErrorDesc = GetDoc()->GetParser()->GetError()) )
1451 {
1452 SetStatusText( pErrorDesc->m_aText );
1453 GetEditWindow()->MarkError( Point( pErrorDesc->m_pNode->GetColumn(),
1454 pErrorDesc->m_pNode->GetRow()));
1455 }
1456 }
1457
NextError()1458 void SmViewShell::NextError()
1459 {
1460 assert(GetDoc());
1461 const SmErrorDesc *pErrorDesc = GetDoc()->GetParser()->NextError();
1462
1463 if (pErrorDesc)
1464 ShowError( pErrorDesc );
1465 }
1466
PrevError()1467 void SmViewShell::PrevError()
1468 {
1469 assert(GetDoc());
1470 const SmErrorDesc *pErrorDesc = GetDoc()->GetParser()->PrevError();
1471
1472 if (pErrorDesc)
1473 ShowError( pErrorDesc );
1474 }
1475
Insert(SfxMedium & rMedium)1476 void SmViewShell::Insert( SfxMedium& rMedium )
1477 {
1478 SmDocShell *pDoc = GetDoc();
1479 bool bRet = false;
1480
1481 uno::Reference <embed::XStorage> xStorage = rMedium.GetStorage();
1482 if (xStorage.is() && xStorage->getElementNames().hasElements())
1483 {
1484 if (xStorage->hasByName("content.xml"))
1485 {
1486 // is this a fabulous math package ?
1487 Reference<css::frame::XModel> xModel(pDoc->GetModel());
1488 SmXMLImportWrapper aEquation(xModel); //!! modifies the result of pDoc->GetText() !!
1489 bRet = ERRCODE_NONE == aEquation.Import(rMedium);
1490 }
1491 }
1492
1493 if (!bRet)
1494 return;
1495
1496 OUString aText = pDoc->GetText();
1497 SmEditWindow *pEditWin = GetEditWindow();
1498 if (pEditWin)
1499 pEditWin->InsertText( aText );
1500 else
1501 {
1502 SAL_WARN( "starmath", "EditWindow missing" );
1503 }
1504
1505 pDoc->Parse();
1506 pDoc->SetModified();
1507
1508 SfxBindings &rBnd = GetViewFrame()->GetBindings();
1509 rBnd.Invalidate(SID_GRAPHIC_SM);
1510 rBnd.Invalidate(SID_TEXT);
1511 }
1512
InsertFrom(SfxMedium & rMedium)1513 void SmViewShell::InsertFrom(SfxMedium &rMedium)
1514 {
1515 bool bSuccess = false;
1516 SmDocShell* pDoc = GetDoc();
1517 SvStream* pStream = rMedium.GetInStream();
1518
1519 if (pStream)
1520 {
1521 const OUString& rFltName = rMedium.GetFilter()->GetFilterName();
1522 if ( rFltName == MATHML_XML )
1523 {
1524 Reference<css::frame::XModel> xModel(pDoc->GetModel());
1525 SmXMLImportWrapper aEquation(xModel); //!! modifies the result of pDoc->GetText() !!
1526 bSuccess = ERRCODE_NONE == aEquation.Import(rMedium);
1527 }
1528 }
1529
1530 if (!bSuccess)
1531 return;
1532
1533 OUString aText = pDoc->GetText();
1534 SmEditWindow *pEditWin = GetEditWindow();
1535 if (pEditWin)
1536 pEditWin->InsertText(aText);
1537 else
1538 SAL_WARN( "starmath", "EditWindow missing" );
1539
1540 pDoc->Parse();
1541 pDoc->SetModified();
1542
1543 SfxBindings& rBnd = GetViewFrame()->GetBindings();
1544 rBnd.Invalidate(SID_GRAPHIC_SM);
1545 rBnd.Invalidate(SID_TEXT);
1546 }
1547
Execute(SfxRequest & rReq)1548 void SmViewShell::Execute(SfxRequest& rReq)
1549 {
1550 SmEditWindow *pWin = GetEditWindow();
1551
1552 switch (rReq.GetSlot())
1553 {
1554 case SID_FORMULACURSOR:
1555 {
1556 SmModule *pp = SM_MOD();
1557
1558 const SfxItemSet *pArgs = rReq.GetArgs();
1559 const SfxPoolItem *pItem;
1560
1561 bool bVal;
1562 if ( pArgs &&
1563 SfxItemState::SET == pArgs->GetItemState( SID_FORMULACURSOR, false, &pItem))
1564 bVal = static_cast<const SfxBoolItem *>(pItem)->GetValue();
1565 else
1566 bVal = !pp->GetConfig()->IsShowFormulaCursor();
1567
1568 pp->GetConfig()->SetShowFormulaCursor(bVal);
1569 if (!IsInlineEditEnabled())
1570 GetGraphicWidget().ShowCursor(bVal);
1571 break;
1572 }
1573 case SID_DRAW:
1574 if (pWin)
1575 {
1576 GetDoc()->SetText( pWin->GetText() );
1577 SetStatusText(OUString());
1578 ShowError( nullptr );
1579 GetDoc()->Repaint();
1580 }
1581 break;
1582
1583 case SID_ZOOM_OPTIMAL:
1584 mxGraphicWindow->ZoomToFitInWindow();
1585 break;
1586
1587 case SID_ZOOMIN:
1588 mxGraphicWindow->SetZoom(mxGraphicWindow->GetZoom() + 25);
1589 break;
1590
1591 case SID_ZOOMOUT:
1592 SAL_WARN_IF( mxGraphicWindow->GetZoom() < 25, "starmath", "incorrect sal_uInt16 argument" );
1593 mxGraphicWindow->SetZoom(mxGraphicWindow->GetZoom() - 25);
1594 break;
1595
1596 case SID_COPYOBJECT:
1597 {
1598 //TODO/LATER: does not work because of UNO Tunneling - will be fixed later
1599 Reference< datatransfer::XTransferable > xTrans( GetDoc()->GetModel(), uno::UNO_QUERY );
1600 if( xTrans.is() )
1601 {
1602 auto pTrans = comphelper::getUnoTunnelImplementation<TransferableHelper>(xTrans);
1603 if (pTrans)
1604 {
1605 SmEditWindow *pEditWin = GetEditWindow();
1606 pTrans->CopyToClipboard(pEditWin->GetClipboard());
1607 }
1608 }
1609 }
1610 break;
1611
1612 case SID_PASTEOBJECT:
1613 {
1614 SmEditWindow *pEditWin = GetEditWindow();
1615 TransferableDataHelper aData(TransferableDataHelper::CreateFromClipboard(pEditWin->GetClipboard()));
1616 uno::Reference < io::XInputStream > xStrm;
1617 SotClipboardFormatId nId;
1618 if( aData.GetTransferable().is() &&
1619 ( aData.HasFormat( nId = SotClipboardFormatId::EMBEDDED_OBJ ) ||
1620 (aData.HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ) &&
1621 aData.HasFormat( nId = SotClipboardFormatId::EMBED_SOURCE ))))
1622 xStrm = aData.GetInputStream(nId, OUString());
1623
1624 if (xStrm.is())
1625 {
1626 try
1627 {
1628 uno::Reference < embed::XStorage > xStorage =
1629 ::comphelper::OStorageHelper::GetStorageFromInputStream( xStrm, ::comphelper::getProcessComponentContext() );
1630 SfxMedium aMedium( xStorage, OUString() );
1631 Insert( aMedium );
1632 GetDoc()->UpdateText();
1633 }
1634 catch (uno::Exception &)
1635 {
1636 SAL_WARN( "starmath", "SmViewShell::Execute (SID_PASTEOBJECT): failed to get storage from input stream" );
1637 }
1638 }
1639 }
1640 break;
1641
1642
1643 case SID_CUT:
1644 if (pWin)
1645 pWin->Cut();
1646 break;
1647
1648 case SID_COPY:
1649 if (pWin)
1650 {
1651 if (pWin->IsAllSelected())
1652 {
1653 GetViewFrame()->GetDispatcher()->ExecuteList(
1654 SID_COPYOBJECT, SfxCallMode::RECORD,
1655 { new SfxVoidItem(SID_COPYOBJECT) });
1656 }
1657 else
1658 pWin->Copy();
1659 }
1660 break;
1661
1662 case SID_PASTE:
1663 {
1664 bool bCallExec = nullptr == pWin;
1665 if( !bCallExec )
1666 {
1667 SmEditWindow *pEditWin = GetEditWindow();
1668 TransferableDataHelper aDataHelper(
1669 TransferableDataHelper::CreateFromClipboard(
1670 pEditWin->GetClipboard()));
1671
1672 if( aDataHelper.GetTransferable().is() &&
1673 aDataHelper.HasFormat( SotClipboardFormatId::STRING ))
1674 pWin->Paste();
1675 else
1676 bCallExec = true;
1677 }
1678 if( bCallExec )
1679 {
1680 GetViewFrame()->GetDispatcher()->ExecuteList(
1681 SID_PASTEOBJECT, SfxCallMode::RECORD,
1682 { new SfxVoidItem(SID_PASTEOBJECT) });
1683 }
1684 }
1685 break;
1686
1687 case SID_DELETE:
1688 if (pWin)
1689 pWin->Delete();
1690 break;
1691
1692 case SID_SELECT:
1693 if (pWin)
1694 pWin->SelectAll();
1695 break;
1696
1697 case SID_INSERTCOMMANDTEXT:
1698 {
1699 const SfxStringItem& rItem = static_cast<const SfxStringItem&>(rReq.GetArgs()->Get(SID_INSERTCOMMANDTEXT));
1700
1701 if (pWin && (mbInsertIntoEditWindow || !IsInlineEditEnabled()))
1702 {
1703 pWin->InsertText(rItem.GetValue());
1704 }
1705 if (IsInlineEditEnabled() && (GetDoc() && !mbInsertIntoEditWindow))
1706 {
1707 GetDoc()->GetCursor().InsertCommandText(rItem.GetValue());
1708 GetGraphicWidget().GrabFocus();
1709 }
1710 break;
1711
1712 }
1713
1714 case SID_INSERTSPECIAL:
1715 {
1716 const SfxStringItem& rItem =
1717 static_cast<const SfxStringItem&>(rReq.GetArgs()->Get(SID_INSERTSPECIAL));
1718
1719 if (pWin && (mbInsertIntoEditWindow || !IsInlineEditEnabled()))
1720 pWin->InsertText(rItem.GetValue());
1721 if (IsInlineEditEnabled() && (GetDoc() && !mbInsertIntoEditWindow))
1722 GetDoc()->GetCursor().InsertSpecial(rItem.GetValue());
1723 break;
1724 }
1725
1726 case SID_IMPORT_FORMULA:
1727 {
1728 mpRequest.reset(new SfxRequest( rReq ));
1729 mpDocInserter.reset(new ::sfx2::DocumentInserter(pWin ? pWin->GetFrameWeld() : nullptr,
1730 GetDoc()->GetFactory().GetFactoryName()));
1731 mpDocInserter->StartExecuteModal( LINK( this, SmViewShell, DialogClosedHdl ) );
1732 break;
1733 }
1734
1735 case SID_IMPORT_MATHML_CLIPBOARD:
1736 {
1737 SmEditWindow *pEditWin = GetEditWindow();
1738 TransferableDataHelper aDataHelper(TransferableDataHelper::CreateFromClipboard(pEditWin->GetClipboard()));
1739 uno::Reference < io::XInputStream > xStrm;
1740 if ( aDataHelper.GetTransferable().is() )
1741 {
1742 SotClipboardFormatId nId = SotClipboardFormatId::MATHML;
1743 if (aDataHelper.HasFormat(nId))
1744 {
1745 xStrm = aDataHelper.GetInputStream(nId, "");
1746 if (xStrm.is())
1747 {
1748 SfxMedium aClipboardMedium;
1749 aClipboardMedium.GetItemSet(); //generate initial itemset, not sure if necessary
1750 std::shared_ptr<const SfxFilter> pMathFilter =
1751 SfxFilter::GetFilterByName(MATHML_XML);
1752 aClipboardMedium.SetFilter(pMathFilter);
1753 aClipboardMedium.setStreamToLoadFrom(xStrm, true /*bIsReadOnly*/);
1754 InsertFrom(aClipboardMedium);
1755 GetDoc()->UpdateText();
1756 }
1757 }
1758 else
1759 {
1760 nId = SotClipboardFormatId::STRING;
1761 if (aDataHelper.HasFormat(nId))
1762 {
1763 // In case of FORMAT_STRING no stream exists, need to generate one
1764 OUString aString;
1765 if (aDataHelper.GetString( nId, aString))
1766 {
1767 // tdf#117091 force xml declaration to exist
1768 if (!aString.startsWith("<?xml"))
1769 aString = "<?xml version=\"1.0\"?>\n" + aString;
1770
1771 SfxMedium aClipboardMedium;
1772 aClipboardMedium.GetItemSet(); //generates initial itemset, not sure if necessary
1773 std::shared_ptr<const SfxFilter> pMathFilter =
1774 SfxFilter::GetFilterByName(MATHML_XML);
1775 aClipboardMedium.SetFilter(pMathFilter);
1776
1777 std::unique_ptr<SvMemoryStream> pStrm;
1778 // The text to be imported might asserts encoding like 'encoding="utf-8"' but FORMAT_STRING is UTF-16.
1779 // Force encoding to UTF-16, if encoding exists.
1780 bool bForceUTF16 = false;
1781 sal_Int32 nPosL = aString.indexOf("encoding=\"");
1782 sal_Int32 nPosU = -1;
1783 if ( nPosL >= 0 && nPosL +10 < aString.getLength() )
1784 {
1785 nPosL += 10;
1786 nPosU = aString.indexOf( '"',nPosL);
1787 if (nPosU > nPosL)
1788 {
1789 bForceUTF16 = true;
1790 }
1791 }
1792 if ( bForceUTF16 )
1793 {
1794 OUString aNewString = aString.replaceAt( nPosL,nPosU-nPosL,"UTF-16");
1795 pStrm.reset(new SvMemoryStream( const_cast<sal_Unicode *>(aNewString.getStr()), aNewString.getLength() * sizeof(sal_Unicode), StreamMode::READ));
1796 }
1797 else
1798 {
1799 pStrm.reset(new SvMemoryStream( const_cast<sal_Unicode *>(aString.getStr()), aString.getLength() * sizeof(sal_Unicode), StreamMode::READ));
1800 }
1801 uno::Reference<io::XInputStream> xStrm2( new ::utl::OInputStreamWrapper(*pStrm) );
1802 aClipboardMedium.setStreamToLoadFrom(xStrm2, true /*bIsReadOnly*/);
1803 InsertFrom(aClipboardMedium);
1804 GetDoc()->UpdateText();
1805 }
1806 }
1807 }
1808 }
1809 break;
1810 }
1811
1812 case SID_NEXTERR:
1813 NextError();
1814 if (pWin)
1815 pWin->GrabFocus();
1816 break;
1817
1818 case SID_PREVERR:
1819 PrevError();
1820 if (pWin)
1821 pWin->GrabFocus();
1822 break;
1823
1824 case SID_NEXTMARK:
1825 if (pWin)
1826 {
1827 pWin->SelNextMark();
1828 pWin->GrabFocus();
1829 }
1830 break;
1831
1832 case SID_PREVMARK:
1833 if (pWin)
1834 {
1835 pWin->SelPrevMark();
1836 pWin->GrabFocus();
1837 }
1838 break;
1839
1840 case SID_TEXTSTATUS:
1841 {
1842 if (rReq.GetArgs() != nullptr)
1843 {
1844 const SfxStringItem& rItem =
1845 static_cast<const SfxStringItem&>(rReq.GetArgs()->Get(SID_TEXTSTATUS));
1846
1847 SetStatusText(rItem.GetValue());
1848 }
1849
1850 break;
1851 }
1852
1853 case SID_GETEDITTEXT:
1854 if (pWin && !pWin->GetText().isEmpty())
1855 GetDoc()->SetText( pWin->GetText() );
1856 break;
1857
1858 case SID_ATTR_ZOOM:
1859 {
1860 if ( !GetViewFrame()->GetFrame().IsInPlace() )
1861 {
1862 const SfxItemSet *pSet = rReq.GetArgs();
1863 if ( pSet )
1864 {
1865 ZoomByItemSet(pSet);
1866 }
1867 else
1868 {
1869 SfxItemSet aSet( SmDocShell::GetPool(), svl::Items<SID_ATTR_ZOOM, SID_ATTR_ZOOM>{});
1870 aSet.Put( SvxZoomItem( SvxZoomType::PERCENT, mxGraphicWindow->GetZoom()));
1871 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
1872 ScopedVclPtr<AbstractSvxZoomDialog> xDlg(pFact->CreateSvxZoomDialog(GetViewFrame()->GetWindow().GetFrameWeld(), aSet));
1873 xDlg->SetLimits( MINZOOM, MAXZOOM );
1874 if (xDlg->Execute() != RET_CANCEL)
1875 ZoomByItemSet(xDlg->GetOutputItemSet());
1876 }
1877 }
1878 }
1879 break;
1880
1881 case SID_ATTR_ZOOMSLIDER:
1882 {
1883 const SfxItemSet *pArgs = rReq.GetArgs();
1884 const SfxPoolItem* pItem;
1885
1886 if ( pArgs && SfxItemState::SET == pArgs->GetItemState(SID_ATTR_ZOOMSLIDER, true, &pItem ) )
1887 {
1888 const sal_uInt16 nCurrentZoom = static_cast<const SvxZoomSliderItem *>(pItem)->GetValue();
1889 mxGraphicWindow->SetZoom(nCurrentZoom);
1890 }
1891 }
1892 break;
1893
1894 case SID_ELEMENTSDOCKINGWINDOW:
1895 {
1896 GetViewFrame()->ToggleChildWindow( SmElementsDockingWindowWrapper::GetChildWindowId() );
1897 GetViewFrame()->GetBindings().Invalidate( SID_ELEMENTSDOCKINGWINDOW );
1898
1899 rReq.Ignore ();
1900 }
1901 break;
1902
1903 case SID_UNICODE_NOTATION_TOGGLE:
1904 {
1905 EditEngine* pEditEngine = nullptr;
1906 if( pWin )
1907 pEditEngine = pWin->GetEditEngine();
1908
1909 EditView* pEditView = nullptr;
1910 if( pEditEngine )
1911 pEditView = pEditEngine->GetView();
1912
1913 if( pEditView )
1914 {
1915 const OUString sInput = pEditView->GetSurroundingText();
1916 ESelection aSel( pWin->GetSelection() );
1917
1918 if ( aSel.nStartPos > aSel.nEndPos )
1919 aSel.nEndPos = aSel.nStartPos;
1920
1921 //calculate a valid end-position by reading logical characters
1922 sal_Int32 nUtf16Pos=0;
1923 while( (nUtf16Pos < sInput.getLength()) && (nUtf16Pos < aSel.nEndPos) )
1924 {
1925 sInput.iterateCodePoints(&nUtf16Pos);
1926 if( nUtf16Pos > aSel.nEndPos )
1927 aSel.nEndPos = nUtf16Pos;
1928 }
1929
1930 ToggleUnicodeCodepoint aToggle;
1931 while( nUtf16Pos && aToggle.AllowMoreInput( sInput[nUtf16Pos-1]) )
1932 --nUtf16Pos;
1933 const OUString sReplacement = aToggle.ReplacementString();
1934 if( !sReplacement.isEmpty() )
1935 {
1936 pEditView->SetSelection( aSel );
1937 pEditEngine->UndoActionStart(EDITUNDO_REPLACEALL);
1938 aSel.nStartPos = aSel.nEndPos - aToggle.StringToReplace().getLength();
1939 pWin->SetSelection( aSel );
1940 pEditView->InsertText( sReplacement, true );
1941 pEditEngine->UndoActionEnd();
1942 pWin->Flush();
1943 }
1944 }
1945 }
1946 break;
1947
1948 case SID_SYMBOLS_CATALOGUE:
1949 {
1950
1951 // get device used to retrieve the FontList
1952 SmDocShell *pDoc = GetDoc();
1953 OutputDevice *pDev = pDoc->GetPrinter();
1954 if (!pDev || pDev->GetDevFontCount() == 0)
1955 pDev = &SM_MOD()->GetDefaultVirtualDev();
1956 SAL_WARN_IF( !pDev, "starmath", "device for font list missing" );
1957
1958 SmModule *pp = SM_MOD();
1959 SmSymbolDialog aDialog(pWin ? pWin->GetFrameWeld() : nullptr, pDev, pp->GetSymbolManager(), *this);
1960 aDialog.run();
1961 }
1962 break;
1963 }
1964 rReq.Done();
1965 }
1966
1967
GetState(SfxItemSet & rSet)1968 void SmViewShell::GetState(SfxItemSet &rSet)
1969 {
1970 SfxWhichIter aIter(rSet);
1971
1972 SmEditWindow *pEditWin = GetEditWindow();
1973 for (sal_uInt16 nWh = aIter.FirstWhich(); nWh != 0; nWh = aIter.NextWhich())
1974 {
1975 switch (nWh)
1976 {
1977 case SID_CUT:
1978 case SID_COPY:
1979 case SID_DELETE:
1980 if (! pEditWin || ! pEditWin->IsSelected())
1981 rSet.DisableItem(nWh);
1982 break;
1983
1984 case SID_PASTE:
1985 if (pEditWin)
1986 {
1987 TransferableDataHelper aDataHelper(
1988 TransferableDataHelper::CreateFromClipboard(
1989 pEditWin->GetClipboard()) );
1990
1991 mbPasteState = aDataHelper.GetTransferable().is() &&
1992 ( aDataHelper.HasFormat( SotClipboardFormatId::STRING ) ||
1993 aDataHelper.HasFormat( SotClipboardFormatId::EMBEDDED_OBJ ) ||
1994 (aDataHelper.HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR )
1995 && aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE )));
1996 }
1997 if( !mbPasteState )
1998 rSet.DisableItem( nWh );
1999 break;
2000
2001 case SID_ATTR_ZOOM:
2002 rSet.Put(SvxZoomItem( SvxZoomType::PERCENT, mxGraphicWindow->GetZoom()));
2003 [[fallthrough]];
2004 case SID_ZOOMIN:
2005 case SID_ZOOMOUT:
2006 case SID_ZOOM_OPTIMAL:
2007 if ( GetViewFrame()->GetFrame().IsInPlace() )
2008 rSet.DisableItem( nWh );
2009 break;
2010
2011 case SID_ATTR_ZOOMSLIDER :
2012 {
2013 const sal_uInt16 nCurrentZoom = mxGraphicWindow->GetZoom();
2014 SvxZoomSliderItem aZoomSliderItem( nCurrentZoom, MINZOOM, MAXZOOM );
2015 aZoomSliderItem.AddSnappingPoint( 100 );
2016 rSet.Put( aZoomSliderItem );
2017 }
2018 break;
2019
2020 case SID_NEXTERR:
2021 case SID_PREVERR:
2022 case SID_NEXTMARK:
2023 case SID_PREVMARK:
2024 case SID_DRAW:
2025 case SID_SELECT:
2026 if (! pEditWin || pEditWin->IsEmpty())
2027 rSet.DisableItem(nWh);
2028 break;
2029
2030 case SID_TEXTSTATUS:
2031 {
2032 rSet.Put(SfxStringItem(nWh, maStatusText));
2033 }
2034 break;
2035
2036 case SID_FORMULACURSOR:
2037 {
2038 SmModule *pp = SM_MOD();
2039 rSet.Put(SfxBoolItem(nWh, pp->GetConfig()->IsShowFormulaCursor()));
2040 }
2041 break;
2042 case SID_ELEMENTSDOCKINGWINDOW:
2043 {
2044 bool bState = false;
2045 SfxChildWindow *pChildWnd = GetViewFrame()->
2046 GetChildWindow( SmElementsDockingWindowWrapper::GetChildWindowId() );
2047 if (pChildWnd && pChildWnd->GetWindow()->IsVisible())
2048 bState = true;
2049 rSet.Put(SfxBoolItem(SID_ELEMENTSDOCKINGWINDOW, bState));
2050 }
2051 break;
2052 }
2053 }
2054 }
2055
SmViewShell(SfxViewFrame * pFrame_,SfxViewShell *)2056 SmViewShell::SmViewShell(SfxViewFrame *pFrame_, SfxViewShell *)
2057 : SfxViewShell(pFrame_, SfxViewShellFlags::HAS_PRINTOPTIONS)
2058 , mxGraphicWindow(VclPtr<SmGraphicWindow>::Create(*this))
2059 , maGraphicController(mxGraphicWindow->GetGraphicWidget(), SID_GRAPHIC_SM, pFrame_->GetBindings())
2060 , mbPasteState(false)
2061 , mbInsertIntoEditWindow(false)
2062 {
2063 SetStatusText(OUString());
2064 SetWindow(mxGraphicWindow.get());
2065 SfxShell::SetName("SmView");
2066 SfxShell::SetUndoManager( &GetDoc()->GetEditEngine().GetUndoManager() );
2067 }
2068
~SmViewShell()2069 SmViewShell::~SmViewShell()
2070 {
2071 //!! this view shell is not active anymore !!
2072 // Thus 'SmGetActiveView' will give a 0 pointer.
2073 // Thus we need to supply this view as argument
2074 SmEditWindow *pEditWin = GetEditWindow();
2075 if (pEditWin)
2076 pEditWin->DeleteEditView();
2077 mxGraphicWindow.disposeAndClear();
2078 }
2079
Deactivate(bool bIsMDIActivate)2080 void SmViewShell::Deactivate( bool bIsMDIActivate )
2081 {
2082 SmEditWindow *pEdit = GetEditWindow();
2083 if ( pEdit )
2084 pEdit->Flush();
2085
2086 SfxViewShell::Deactivate( bIsMDIActivate );
2087 }
2088
Activate(bool bIsMDIActivate)2089 void SmViewShell::Activate( bool bIsMDIActivate )
2090 {
2091 SfxViewShell::Activate( bIsMDIActivate );
2092
2093 SmEditWindow *pEdit = GetEditWindow();
2094 if ( pEdit )
2095 {
2096 //! Since there is no way to be informed if a "drag and drop"
2097 //! event has taken place, we call SetText here in order to
2098 //! synchronize the GraphicWindow display with the text in the
2099 //! EditEngine.
2100 SmDocShell *pDoc = GetDoc();
2101 pDoc->SetText( pDoc->GetEditEngine().GetText() );
2102
2103 if ( bIsMDIActivate )
2104 pEdit->GrabFocus();
2105 }
2106 }
2107
IMPL_LINK(SmViewShell,DialogClosedHdl,sfx2::FileDialogHelper *,_pFileDlg,void)2108 IMPL_LINK( SmViewShell, DialogClosedHdl, sfx2::FileDialogHelper*, _pFileDlg, void )
2109 {
2110 assert(_pFileDlg && "SmViewShell::DialogClosedHdl(): no file dialog");
2111 assert(mpDocInserter && "ScDocShell::DialogClosedHdl(): no document inserter");
2112
2113 if ( ERRCODE_NONE == _pFileDlg->GetError() )
2114 {
2115 std::unique_ptr<SfxMedium> pMedium = mpDocInserter->CreateMedium();
2116
2117 if ( pMedium )
2118 {
2119 if ( pMedium->IsStorage() )
2120 Insert( *pMedium );
2121 else
2122 InsertFrom( *pMedium );
2123 pMedium.reset();
2124
2125 SmDocShell* pDoc = GetDoc();
2126 pDoc->UpdateText();
2127 pDoc->ArrangeFormula();
2128 pDoc->Repaint();
2129 // adjust window, repaint, increment ModifyCount,...
2130 GetViewFrame()->GetBindings().Invalidate(SID_GRAPHIC_SM);
2131 }
2132 }
2133
2134 mpRequest->SetReturnValue( SfxBoolItem( mpRequest->GetSlot(), true ) );
2135 mpRequest->Done();
2136 }
2137
Notify(SfxBroadcaster &,const SfxHint & rHint)2138 void SmViewShell::Notify( SfxBroadcaster& , const SfxHint& rHint )
2139 {
2140 switch( rHint.GetId() )
2141 {
2142 case SfxHintId::ModeChanged:
2143 case SfxHintId::DocChanged:
2144 GetViewFrame()->GetBindings().InvalidateAll(false);
2145 break;
2146 default:
2147 break;
2148 }
2149 }
2150
IsInlineEditEnabled()2151 bool SmViewShell::IsInlineEditEnabled()
2152 {
2153 return officecfg::Office::Common::Misc::ExperimentalMode::get();
2154 }
2155
ZoomByItemSet(const SfxItemSet * pSet)2156 void SmViewShell::ZoomByItemSet(const SfxItemSet *pSet)
2157 {
2158 assert(pSet);
2159 const SvxZoomItem &rZoom = pSet->Get(SID_ATTR_ZOOM);
2160 switch( rZoom.GetType() )
2161 {
2162 case SvxZoomType::PERCENT:
2163 mxGraphicWindow->SetZoom(sal::static_int_cast<sal_uInt16>(rZoom.GetValue ()));
2164 break;
2165
2166 case SvxZoomType::OPTIMAL:
2167 mxGraphicWindow->ZoomToFitInWindow();
2168 break;
2169
2170 case SvxZoomType::PAGEWIDTH:
2171 case SvxZoomType::WHOLEPAGE:
2172 {
2173 const MapMode aMap( MapUnit::Map100thMM );
2174 SfxPrinter *pPrinter = GetPrinter( true );
2175 tools::Rectangle OutputRect(Point(), pPrinter->GetOutputSize());
2176 Size OutputSize(pPrinter->LogicToPixel(Size(OutputRect.GetWidth(),
2177 OutputRect.GetHeight()), aMap));
2178 Size GraphicSize(pPrinter->LogicToPixel(GetDoc()->GetSize(), aMap));
2179 sal_uInt16 nZ = sal::static_int_cast<sal_uInt16>(std::min(tools::Long(Fraction(OutputSize.Width() * 100, GraphicSize.Width())),
2180 tools::Long(Fraction(OutputSize.Height() * 100, GraphicSize.Height()))));
2181 mxGraphicWindow->SetZoom(nZ);
2182 break;
2183 }
2184 default:
2185 break;
2186 }
2187 }
2188
2189 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2190