Bump version to 5.0-14
[LibreOffice.git] / starmath / source / view.cxx
blob1250d3d6f864ecb205b03e033379df0f471a10e2
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
21 #include <com/sun/star/accessibility/AccessibleEventObject.hpp>
22 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
23 #include <com/sun/star/accessibility/XAccessible.hpp>
24 #include <com/sun/star/beans/XPropertySet.hpp>
25 #include <com/sun/star/frame/Desktop.hpp>
26 #include <com/sun/star/frame/XFramesSupplier.hpp>
27 #include <com/sun/star/container/XChild.hpp>
29 #include <comphelper/processfactory.hxx>
30 #include <comphelper/storagehelper.hxx>
31 #include <comphelper/string.hxx>
32 #include <sfx2/app.hxx>
33 #include <sfx2/dispatch.hxx>
34 #include <sfx2/docfile.hxx>
35 #include <sfx2/docfilt.hxx>
36 #include <sfx2/docinsert.hxx>
37 #include <sfx2/filedlghelper.hxx>
38 #include <sfx2/msg.hxx>
39 #include <sfx2/objface.hxx>
40 #include <sfx2/printer.hxx>
41 #include <sfx2/request.hxx>
42 #include <svl/eitem.hxx>
43 #include <svl/intitem.hxx>
44 #include <svl/itemset.hxx>
45 #include <svl/poolitem.hxx>
46 #include <svl/ptitem.hxx>
47 #include <svl/stritem.hxx>
48 #include <svtools/transfer.hxx>
49 #include <svtools/miscopt.hxx>
50 #include <svl/undo.hxx>
51 #include <svl/whiter.hxx>
52 #include <svx/dialogs.hrc>
53 #include <svx/zoomslideritem.hxx>
54 #include <editeng/editeng.hxx>
55 #include <svx/svxdlg.hxx>
56 #include <sfx2/zoomitem.hxx>
57 #include <vcl/decoview.hxx>
58 #include <vcl/menu.hxx>
59 #include <vcl/msgbox.hxx>
60 #include <vcl/wrkwin.hxx>
61 #include <vcl/settings.hxx>
63 #include <fstream>
65 #include "unomodel.hxx"
66 #include "view.hxx"
67 #include "config.hxx"
68 #include "dialog.hxx"
69 #include "document.hxx"
70 #include "starmath.hrc"
71 #include "mathmlimport.hxx"
72 #include "cursor.hxx"
73 #include "accessibility.hxx"
74 #include "ElementsDockingWindow.hxx"
75 #include <memory>
77 #define MINZOOM 25
78 #define MAXZOOM 800
80 // space around the edit window, in pixels
81 // fdo#69111: Increased border on the top so that the window is
82 // easier to tear off.
83 #define CMD_BOX_PADDING 4
84 #define CMD_BOX_PADDING_TOP 10
86 #define SmViewShell
87 #include "smslots.hxx"
89 using namespace css;
90 using namespace css::accessibility;
91 using namespace css::uno;
93 SmGraphicWindow::SmGraphicWindow(SmViewShell* pShell)
94 : ScrollableWindow(&pShell->GetViewFrame()->GetWindow(), 0)
95 , pAccessible(0)
96 , pViewShell(pShell)
97 , nZoom(100)
99 // docking windows are usually hidden (often already done in the
100 // resource) and will be shown by the sfx framework.
101 Hide();
103 const Fraction aFraction(1, 1);
104 SetMapMode(MapMode(MAP_100TH_MM, Point(), aFraction, aFraction));
106 SetTotalSize();
108 SetHelpId(HID_SMA_WIN_DOCUMENT);
109 SetUniqueId(HID_SMA_WIN_DOCUMENT);
111 ShowLine(false);
112 CaretBlinkInit();
115 SmGraphicWindow::~SmGraphicWindow()
117 disposeOnce();
120 void SmGraphicWindow::dispose()
122 if (pAccessible)
123 pAccessible->ClearWin(); // make Accessible defunctional
124 // Note: memory for pAccessible will be freed when the reference
125 // xAccessible is released.
126 CaretBlinkStop();
127 ScrollableWindow::dispose();
130 void SmGraphicWindow::StateChanged(StateChangedType eType)
132 if (eType == StateChangedType::InitShow)
133 Show();
134 ScrollableWindow::StateChanged(eType);
138 void SmGraphicWindow::ApplyColorConfigValues(const svtools::ColorConfig &rColorCfg)
140 // Note: SetTextColor not necessary since the nodes that
141 // get painted have the color information.
142 #if OSL_DEBUG_LEVEL > 1
143 // ColorData nVal = rColorCfg.GetColorValue(svtools::DOCCOLOR).nColor;
144 #endif
145 SetBackground(Color( (ColorData) rColorCfg.GetColorValue(svtools::DOCCOLOR).nColor));
149 void SmGraphicWindow::DataChanged( const DataChangedEvent& rEvt )
151 ScrollableWindow::DataChanged( rEvt );
155 void SmGraphicWindow::MouseButtonDown(const MouseEvent& rMEvt)
157 ScrollableWindow::MouseButtonDown(rMEvt);
159 GrabFocus();
161 // set formula-cursor and selection of edit window according to the
162 // position clicked at
164 SAL_WARN_IF( rMEvt.GetClicks() == 0, "starmath", "0 clicks" );
165 if ( rMEvt.IsLeft() )
167 // get click position relativ to formula
168 Point aPos (PixelToLogic(rMEvt.GetPosPixel())
169 - GetFormulaDrawPos());
171 const SmNode *pTree = pViewShell->GetDoc()->GetFormulaTree();
172 if (!pTree)
173 return;
175 if (IsInlineEditEnabled()) {
176 pViewShell->GetDoc()->GetCursor().MoveTo(this, aPos, !rMEvt.IsShift());
177 return;
179 const SmNode *pNode = 0;
180 // if it was clicked inside the formula then get the appropriate node
181 if (pTree->OrientedDist(aPos) <= 0)
182 pNode = pTree->FindRectClosestTo(aPos);
184 if (pNode)
185 { SmEditWindow *pEdit = pViewShell->GetEditWindow();
186 if (!pEdit)
187 return;
188 const SmToken aToken (pNode->GetToken());
190 // set selection to the beginning of the token
191 ESelection aSel (aToken.nRow - 1, aToken.nCol - 1);
193 if (rMEvt.GetClicks() != 1 || aToken.eType == TPLACE)
194 aSel.nEndPos = aSel.nEndPos + sal::static_int_cast< sal_uInt16 >(aToken.aText.getLength());
196 pEdit->SetSelection(aSel);
197 SetCursor(pNode);
199 // allow for immediate editing and
200 //! implicitly synchronize the cursor position mark in this window
201 pEdit->GrabFocus();
206 void SmGraphicWindow::MouseMove(const MouseEvent &rMEvt)
208 ScrollableWindow::MouseMove(rMEvt);
210 if (rMEvt.IsLeft() && IsInlineEditEnabled())
212 Point aPos(PixelToLogic(rMEvt.GetPosPixel()) - GetFormulaDrawPos());
213 pViewShell->GetDoc()->GetCursor().MoveTo(this, aPos, false);
215 CaretBlinkStop();
216 SetIsCursorVisible(true);
217 CaretBlinkStart();
218 RepaintViewShellDoc();
222 bool SmGraphicWindow::IsInlineEditEnabled() const
224 return pViewShell->IsInlineEditEnabled();
227 void SmGraphicWindow::GetFocus()
229 if (!IsInlineEditEnabled())
230 return;
231 if (pViewShell->GetEditWindow())
232 pViewShell->GetEditWindow()->Flush();
233 //Let view shell know what insertions should be done in visual editor
234 pViewShell->SetInsertIntoEditWindow(false);
235 SetIsCursorVisible(true);
236 ShowLine(true);
237 CaretBlinkStart();
238 RepaintViewShellDoc();
241 void SmGraphicWindow::LoseFocus()
243 ScrollableWindow::LoseFocus();
244 if (xAccessible.is())
246 uno::Any aOldValue, aNewValue;
247 aOldValue <<= AccessibleStateType::FOCUSED;
248 // aNewValue remains empty
249 pAccessible->LaunchEvent( AccessibleEventId::STATE_CHANGED,
250 aOldValue, aNewValue );
252 if (!IsInlineEditEnabled())
253 return;
254 SetIsCursorVisible(false);
255 ShowLine(false);
256 CaretBlinkStop();
257 RepaintViewShellDoc();
260 void SmGraphicWindow::RepaintViewShellDoc()
262 SmDocShell* pDoc = pViewShell->GetDoc();
263 if (pDoc)
264 pDoc->Repaint();
267 IMPL_LINK_NOARG_TYPED(SmGraphicWindow, CaretBlinkTimerHdl, Timer *, void)
269 if (IsCursorVisible())
270 SetIsCursorVisible(false);
271 else
272 SetIsCursorVisible(true);
274 RepaintViewShellDoc();
277 void SmGraphicWindow::CaretBlinkInit()
279 aCaretBlinkTimer.SetTimeoutHdl(LINK(this, SmGraphicWindow, CaretBlinkTimerHdl));
280 aCaretBlinkTimer.SetTimeout( ScrollableWindow::GetSettings().GetStyleSettings().GetCursorBlinkTime() );
283 void SmGraphicWindow::CaretBlinkStart()
285 if (!IsInlineEditEnabled())
286 return;
287 if (aCaretBlinkTimer.GetTimeout() != STYLE_CURSOR_NOBLINKTIME)
288 aCaretBlinkTimer.Start();
291 void SmGraphicWindow::CaretBlinkStop()
293 if (!IsInlineEditEnabled())
294 return;
295 aCaretBlinkTimer.Stop();
298 void SmGraphicWindow::ShowCursor(bool bShow)
299 // shows or hides the formula-cursor depending on 'bShow' is true or not
301 if (IsInlineEditEnabled())
302 return;
304 bool bInvert = bShow != IsCursorVisible();
306 if (bInvert)
307 InvertTracking(aCursorRect, SHOWTRACK_SMALL | SHOWTRACK_WINDOW);
309 SetIsCursorVisible(bShow);
312 void SmGraphicWindow::ShowLine(bool bShow)
314 if (!IsInlineEditEnabled())
315 return;
317 bIsLineVisible = bShow;
320 void SmGraphicWindow::SetCursor(const SmNode *pNode)
322 if (IsInlineEditEnabled())
323 return;
325 const SmNode *pTree = pViewShell->GetDoc()->GetFormulaTree();
327 // get appropriate rectangle
328 Point aOffset (pNode->GetTopLeft() - pTree->GetTopLeft()),
329 aTLPos (GetFormulaDrawPos() + aOffset);
330 aTLPos.X() -= pNode->GetItalicLeftSpace();
331 Size aSize (pNode->GetItalicSize());
333 SetCursor(Rectangle(aTLPos, aSize));
336 void SmGraphicWindow::SetCursor(const Rectangle &rRect)
337 // sets cursor to new position (rectangle) 'rRect'.
338 // The old cursor will be removed, and the new one will be shown if
339 // that is activated in the ConfigItem
341 if (IsInlineEditEnabled())
342 return;
344 SmModule *pp = SM_MOD();
346 if (IsCursorVisible())
347 ShowCursor(false); // clean up remainings of old cursor
348 aCursorRect = rRect;
349 if (pp->GetConfig()->IsShowFormulaCursor())
350 ShowCursor(true); // draw new cursor
353 const SmNode * SmGraphicWindow::SetCursorPos(sal_uInt16 nRow, sal_uInt16 nCol)
354 // looks for a VISIBLE node in the formula tree with it's token at
355 // (or around) the position 'nRow', 'nCol' in the edit window
356 // (row and column numbering starts with 1 there!).
357 // If there is such a node the formula-cursor is set to cover that nodes
358 // rectangle. If not the formula-cursor will be hidden.
359 // In any case the search result is being returned.
361 if (IsInlineEditEnabled())
362 return NULL;
364 // find visible node with token at nRow, nCol
365 const SmNode *pTree = pViewShell->GetDoc()->GetFormulaTree(),
366 *pNode = 0;
367 if (pTree)
368 pNode = pTree->FindTokenAt(nRow, nCol);
370 if (pNode)
371 SetCursor(pNode);
372 else
373 ShowCursor(false);
375 return pNode;
378 void SmGraphicWindow::Paint(vcl::RenderContext& rRenderContext, const Rectangle&)
380 SAL_WARN_IF(!pViewShell, "starmath", "view shell missing");
382 ApplyColorConfigValues(SM_MOD()->GetColorConfig());
384 SmDocShell& rDoc = *pViewShell->GetDoc();
385 Point aPoint;
387 rDoc.DrawFormula(rRenderContext, aPoint, true); //! modifies aPoint to be the topleft
388 //! corner of the formula
389 SetFormulaDrawPos(aPoint);
390 if (IsInlineEditEnabled())
392 //Draw cursor if any...
393 if (pViewShell->GetDoc()->HasCursor() && IsLineVisible())
394 pViewShell->GetDoc()->GetCursor().Draw(rRenderContext, aPoint, IsCursorVisible());
396 else
398 SetIsCursorVisible(false); // (old) cursor must be drawn again
400 const SmEditWindow* pEdit = pViewShell->GetEditWindow();
401 if (pEdit)
402 { // get new position for formula-cursor (for possible altered formula)
403 sal_Int32 nRow;
404 sal_uInt16 nCol;
405 SmGetLeftSelectionPart(pEdit->GetSelection(), nRow, nCol);
406 nRow++;
407 nCol++;
408 const SmNode *pFound = SetCursorPos(static_cast<sal_uInt16>(nRow), nCol);
410 SmModule *pp = SM_MOD();
411 if (pFound && pp->GetConfig()->IsShowFormulaCursor())
412 ShowCursor(true);
418 void SmGraphicWindow::SetTotalSize ()
420 SmDocShell &rDoc = *pViewShell->GetDoc();
421 const Size aTmp( PixelToLogic( LogicToPixel( rDoc.GetSize() )));
422 if ( aTmp != ScrollableWindow::GetTotalSize() )
423 ScrollableWindow::SetTotalSize( aTmp );
426 void SmGraphicWindow::KeyInput(const KeyEvent& rKEvt)
428 if (!IsInlineEditEnabled()) {
429 if (! (GetView() && GetView()->KeyInput(rKEvt)) )
430 ScrollableWindow::KeyInput(rKEvt);
431 return;
434 SmCursor& rCursor = pViewShell->GetDoc()->GetCursor();
435 KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction();
436 if (eFunc == KeyFuncType::COPY)
437 rCursor.Copy();
438 else if (eFunc == KeyFuncType::CUT)
439 rCursor.Cut();
440 else if (eFunc == KeyFuncType::PASTE)
441 rCursor.Paste();
442 else {
443 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
444 switch(nCode)
446 case KEY_LEFT:
448 rCursor.Move(this, MoveLeft, !rKEvt.GetKeyCode().IsShift());
449 }break;
450 case KEY_RIGHT:
452 rCursor.Move(this, MoveRight, !rKEvt.GetKeyCode().IsShift());
453 }break;
454 case KEY_UP:
456 rCursor.Move(this, MoveUp, !rKEvt.GetKeyCode().IsShift());
457 }break;
458 case KEY_DOWN:
460 rCursor.Move(this, MoveDown, !rKEvt.GetKeyCode().IsShift());
461 }break;
462 case KEY_RETURN:
464 if(!rKEvt.GetKeyCode().IsShift())
465 rCursor.InsertRow();
466 #ifdef DEBUG_ENABLE_DUMPASDOT
467 else {
468 SmNode *pTree = (SmNode*)pViewShell->GetDoc()->GetFormulaTree();
469 std::fstream file("/tmp/smath-dump.gv", std::fstream::out);
470 OUString label(pViewShell->GetDoc()->GetText());
471 pTree->DumpAsDot(file, &label);
472 file.close();
474 #endif /* DEBUG_ENABLE_DUMPASDOT */
475 }break;
476 case KEY_DELETE:
478 if(!rCursor.HasSelection()){
479 rCursor.Move(this, MoveRight, false);
480 if(rCursor.HasComplexSelection()) break;
482 rCursor.Delete();
483 }break;
484 case KEY_BACKSPACE:
486 rCursor.DeletePrev(this);
487 }break;
488 case KEY_ADD:
489 rCursor.InsertElement(PlusElement);
490 break;
491 case KEY_SUBTRACT:
492 if(rKEvt.GetKeyCode().IsShift())
493 rCursor.InsertSubSup(RSUB);
494 else
495 rCursor.InsertElement(MinusElement);
496 break;
497 case KEY_MULTIPLY:
498 rCursor.InsertElement(CDotElement);
499 break;
500 case KEY_DIVIDE:
501 rCursor.InsertFraction();
502 break;
503 case KEY_LESS:
504 rCursor.InsertElement(LessThanElement);
505 break;
506 case KEY_GREATER:
507 rCursor.InsertElement(GreaterThanElement);
508 break;
509 case KEY_EQUAL:
510 rCursor.InsertElement(EqualElement);
511 break;
512 default:
514 sal_Unicode code = rKEvt.GetCharCode();
515 SmBraceNode* pBraceNode = NULL;
517 if(code == ' ') {
518 rCursor.InsertElement(BlankElement);
519 }else if(code == '^') {
520 rCursor.InsertSubSup(RSUP);
521 }else if(code == '(') {
522 rCursor.InsertBrackets(RoundBrackets);
523 }else if(code == '[') {
524 rCursor.InsertBrackets(SquareBrackets);
525 }else if(code == '{') {
526 rCursor.InsertBrackets(CurlyBrackets);
527 }else if(code == '!') {
528 rCursor.InsertElement(FactorialElement);
529 }else if(code == '%') {
530 rCursor.InsertElement(PercentElement);
531 }else if(code == ')' && rCursor.IsAtTailOfBracket(RoundBrackets, &pBraceNode)) {
532 rCursor.MoveAfterBracket(pBraceNode);
533 }else if(code == ']' && rCursor.IsAtTailOfBracket(SquareBrackets, &pBraceNode)) {
534 rCursor.MoveAfterBracket(pBraceNode);
535 }else if(code == '}' && rCursor.IsAtTailOfBracket(CurlyBrackets, &pBraceNode)) {
536 rCursor.MoveAfterBracket(pBraceNode);
537 }else{
538 if(code != 0){
539 rCursor.InsertText(OUString(code));
540 }else if (! (GetView() && GetView()->KeyInput(rKEvt)) )
541 ScrollableWindow::KeyInput(rKEvt);
546 CaretBlinkStop();
547 CaretBlinkStart();
548 SetIsCursorVisible(true);
549 RepaintViewShellDoc();
553 void SmGraphicWindow::Command(const CommandEvent& rCEvt)
555 bool bCallBase = true;
556 if ( !pViewShell->GetViewFrame()->GetFrame().IsInPlace() )
558 switch ( rCEvt.GetCommand() )
560 case CommandEventId::ContextMenu:
562 GetParent()->ToTop();
563 SmResId aResId( RID_VIEWMENU );
564 std::unique_ptr<PopupMenu> xPopupMenu(new PopupMenu(aResId));
565 xPopupMenu->SetSelectHdl(LINK(this, SmGraphicWindow, MenuSelectHdl));
566 Point aPos(5, 5);
567 if (rCEvt.IsMouseEvent())
568 aPos = rCEvt.GetMousePosPixel();
569 SAL_WARN_IF( !pViewShell, "starmath", "view shell missing" );
571 // added for replaceability of context menus
572 pViewShell->GetViewFrame()->GetBindings().GetDispatcher()
573 ->ExecutePopup( aResId, this, &aPos );
575 bCallBase = false;
577 break;
579 case CommandEventId::Wheel:
581 const CommandWheelData* pWData = rCEvt.GetWheelData();
582 if ( pWData && CommandWheelMode::ZOOM == pWData->GetMode() )
584 sal_uInt16 nTmpZoom = GetZoom();
585 if( 0L > pWData->GetDelta() )
586 nTmpZoom -= 10;
587 else
588 nTmpZoom += 10;
589 SetZoom( nTmpZoom );
590 bCallBase = false;
593 break;
595 default: break;
598 if ( bCallBase )
599 ScrollableWindow::Command (rCEvt);
603 IMPL_LINK( SmGraphicWindow, MenuSelectHdl, Menu *, pMenu )
605 SmViewShell *pViewSh = GetView();
606 if (pViewSh)
607 pViewSh->GetViewFrame()->GetDispatcher()->Execute( pMenu->GetCurItemId() );
608 return 0;
611 void SmGraphicWindow::SetZoom(sal_uInt16 Factor)
613 nZoom = std::min(std::max((sal_uInt16) Factor, (sal_uInt16) MINZOOM), (sal_uInt16) MAXZOOM);
614 Fraction aFraction (nZoom, 100);
615 SetMapMode( MapMode(MAP_100TH_MM, Point(), aFraction, aFraction) );
616 SetTotalSize();
617 SmViewShell *pViewSh = GetView();
618 if (pViewSh)
620 pViewSh->GetViewFrame()->GetBindings().Invalidate(SID_ATTR_ZOOM);
621 pViewSh->GetViewFrame()->GetBindings().Invalidate(SID_ATTR_ZOOMSLIDER);
623 Invalidate();
627 void SmGraphicWindow::ZoomToFitInWindow()
629 SmDocShell &rDoc = *pViewShell->GetDoc();
631 // set defined mapmode before calling 'LogicToPixel' below
632 SetMapMode(MapMode(MAP_100TH_MM));
634 Size aSize (LogicToPixel(rDoc.GetSize()));
635 Size aWindowSize (GetSizePixel());
637 if (aSize.Width() > 0 && aSize.Height() > 0)
639 long nVal = std::min ((85 * aWindowSize.Width()) / aSize.Width(),
640 (85 * aWindowSize.Height()) / aSize.Height());
641 SetZoom ( sal::static_int_cast< sal_uInt16 >(nVal) );
645 uno::Reference< XAccessible > SmGraphicWindow::CreateAccessible()
647 if (!pAccessible)
649 pAccessible = new SmGraphicAccessible( this );
650 xAccessible = pAccessible;
652 return xAccessible;
655 /**************************************************************************/
658 SmGraphicController::SmGraphicController(SmGraphicWindow &rSmGraphic,
659 sal_uInt16 nId_,
660 SfxBindings &rBindings) :
661 SfxControllerItem(nId_, rBindings),
662 rGraphic(rSmGraphic)
667 void SmGraphicController::StateChanged(sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState)
669 rGraphic.SetTotalSize();
670 rGraphic.Invalidate();
671 SfxControllerItem::StateChanged (nSID, eState, pState);
675 /**************************************************************************/
678 SmEditController::SmEditController(SmEditWindow &rSmEdit,
679 sal_uInt16 nId_,
680 SfxBindings &rBindings) :
681 SfxControllerItem(nId_, rBindings),
682 rEdit(rSmEdit)
687 #if OSL_DEBUG_LEVEL > 1
688 SmEditController::~SmEditController()
691 #endif
694 void SmEditController::StateChanged(sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState)
696 const SfxStringItem *pItem = PTR_CAST(SfxStringItem, pState);
698 if ((pItem != NULL) && (rEdit.GetText() != OUString(pItem->GetValue())))
699 rEdit.SetText(pItem->GetValue());
700 SfxControllerItem::StateChanged (nSID, eState, pState);
703 /**************************************************************************/
704 SmCmdBoxWindow::SmCmdBoxWindow(SfxBindings *pBindings_, SfxChildWindow *pChildWindow,
705 vcl::Window *pParent) :
706 SfxDockingWindow(pBindings_, pChildWindow, pParent, WB_MOVEABLE|WB_CLOSEABLE|WB_SIZEABLE|WB_DOCKABLE),
707 aEdit (VclPtr<SmEditWindow>::Create(*this)),
708 aController (*(aEdit.get()), SID_TEXT, *pBindings_),
709 bExiting (false)
711 SetHelpId( HID_SMA_COMMAND_WIN );
712 SetSizePixel(LogicToPixel(Size(292 , 94), MapMode(MAP_APPFONT)));
713 SetText(SM_RESSTR(STR_CMDBOXWINDOW));
715 Hide();
717 aInitialFocusTimer.SetTimeoutHdl(LINK(this, SmCmdBoxWindow, InitialFocusTimerHdl));
718 aInitialFocusTimer.SetTimeout(100);
721 SmCmdBoxWindow::~SmCmdBoxWindow ()
723 disposeOnce();
726 void SmCmdBoxWindow::dispose()
728 aInitialFocusTimer.Stop();
729 bExiting = true;
730 aController.dispose();
731 aEdit.disposeAndClear();
732 SfxDockingWindow::dispose();
735 SmViewShell * SmCmdBoxWindow::GetView()
737 SfxDispatcher *pDispatcher = GetBindings().GetDispatcher();
738 SfxViewShell *pView = pDispatcher ? pDispatcher->GetFrame()->GetViewShell() : NULL;
739 return PTR_CAST(SmViewShell, pView);
742 void SmCmdBoxWindow::Resize()
744 Rectangle aRect(Point(0, 0), GetOutputSizePixel());
745 aRect.Left() += CMD_BOX_PADDING;
746 aRect.Top() += CMD_BOX_PADDING_TOP;
747 aRect.Right() -= CMD_BOX_PADDING;
748 aRect.Bottom() -= CMD_BOX_PADDING;
750 DecorationView aView(this);
751 aRect = aView.DrawFrame(aRect, DrawFrameStyle::In, DrawFrameFlags::NoDraw);
753 aEdit->SetPosSizePixel(aRect.TopLeft(), aRect.GetSize());
754 SfxDockingWindow::Resize();
755 Invalidate();
758 void SmCmdBoxWindow::Paint(vcl::RenderContext& rRenderContext, const Rectangle& /*rRect*/)
760 Rectangle aRect(Point(0, 0), GetOutputSizePixel());
761 aRect.Left() += CMD_BOX_PADDING;
762 aRect.Top() += CMD_BOX_PADDING_TOP;
763 aRect.Right() -= CMD_BOX_PADDING;
764 aRect.Bottom() -= CMD_BOX_PADDING;
766 aEdit->SetPosSizePixel(aRect.TopLeft(), aRect.GetSize());
768 DecorationView aView(&rRenderContext);
769 aView.DrawFrame( aRect, DrawFrameStyle::In );
772 Size SmCmdBoxWindow::CalcDockingSize(SfxChildAlignment eAlign)
774 switch (eAlign)
776 case SfxChildAlignment::LEFT:
777 case SfxChildAlignment::RIGHT:
778 return Size();
779 default:
780 break;
782 return SfxDockingWindow::CalcDockingSize(eAlign);
785 SfxChildAlignment SmCmdBoxWindow::CheckAlignment(SfxChildAlignment eActual,
786 SfxChildAlignment eWish)
788 switch (eWish)
790 case SfxChildAlignment::TOP:
791 case SfxChildAlignment::BOTTOM:
792 case SfxChildAlignment::NOALIGNMENT:
793 return eWish;
794 default:
795 break;
798 return eActual;
801 void SmCmdBoxWindow::StateChanged( StateChangedType nStateChange )
803 if (StateChangedType::InitShow == nStateChange)
805 Resize(); // avoid SmEditWindow not being painted correctly
807 // set initial position of window in floating mode
808 if (IsFloatingMode())
809 AdjustPosition(); //! don't change pos in docking-mode !
811 aInitialFocusTimer.Start();
814 SfxDockingWindow::StateChanged( nStateChange );
817 IMPL_LINK_NOARG_TYPED( SmCmdBoxWindow, InitialFocusTimerHdl, Timer *, void )
819 // We want to have the focus in the edit window once Math has been opened
820 // to allow for immediate typing.
821 // Problem: There is no proper way to do this
822 // Thus: this timer based solution has been implemented (see GrabFocus below)
824 // Follow-up problem (#i114910): grabing the focus may bust the help system since
825 // it relies on getting the current frame which conflicts with grabbing the focus.
826 // Thus aside from the 'GrabFocus' call everything else is to get the
827 // help reliably working despite using 'GrabFocus'.
831 uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create( comphelper::getProcessComponentContext() );
833 aEdit->GrabFocus();
835 bool bInPlace = GetView()->GetViewFrame()->GetFrame().IsInPlace();
836 uno::Reference< frame::XFrame > xFrame( GetBindings().GetDispatcher()->GetFrame()->GetFrame().GetFrameInterface());
837 if ( bInPlace )
839 uno::Reference< container::XChild > xModel( GetView()->GetDoc()->GetModel(), uno::UNO_QUERY_THROW );
840 uno::Reference< frame::XModel > xParent( xModel->getParent(), uno::UNO_QUERY_THROW );
841 uno::Reference< frame::XController > xParentCtrler( xParent->getCurrentController() );
842 uno::Reference< frame::XFramesSupplier > xParentFrame( xParentCtrler->getFrame(), uno::UNO_QUERY_THROW );
843 xParentFrame->setActiveFrame( xFrame );
845 else
847 xDesktop->setActiveFrame( xFrame );
850 catch (uno::Exception &)
852 SAL_WARN( "starmath", "failed to properly set initial focus to edit window" );
856 void SmCmdBoxWindow::AdjustPosition()
858 Point aPt;
859 const Rectangle aRect( aPt, GetParent()->GetOutputSizePixel() );
860 Point aTopLeft( Point( aRect.Left(),
861 aRect.Bottom() - GetSizePixel().Height() ) );
862 Point aPos( GetParent()->OutputToScreenPixel( aTopLeft ) );
863 if (aPos.X() < 0)
864 aPos.X() = 0;
865 if (aPos.Y() < 0)
866 aPos.Y() = 0;
867 SetPosPixel( aPos );
870 void SmCmdBoxWindow::ToggleFloatingMode()
872 SfxDockingWindow::ToggleFloatingMode();
874 if (GetFloatingWindow())
875 GetFloatingWindow()->SetMinOutputSizePixel(Size (200, 50));
878 void SmCmdBoxWindow::GetFocus()
880 if (!bExiting)
881 aEdit->GrabFocus();
884 SFX_IMPL_DOCKINGWINDOW_WITHID(SmCmdBoxWrapper, SID_CMDBOXWINDOW);
886 SmCmdBoxWrapper::SmCmdBoxWrapper(vcl::Window *pParentWindow, sal_uInt16 nId,
887 SfxBindings *pBindings,
888 SfxChildWinInfo *pInfo) :
889 SfxChildWindow(pParentWindow, nId)
891 pWindow.reset(VclPtr<SmCmdBoxWindow>::Create(pBindings, this, pParentWindow));
893 // make window docked to the bottom initially (after first start)
894 eChildAlignment = SfxChildAlignment::BOTTOM;
895 static_cast<SfxDockingWindow *>(pWindow.get())->Initialize(pInfo);
898 #if OSL_DEBUG_LEVEL > 1
899 SmCmdBoxWrapper::~SmCmdBoxWrapper()
902 #endif
904 struct SmViewShell_Impl
906 std::unique_ptr<sfx2::DocumentInserter> pDocInserter;
907 std::unique_ptr<SfxRequest> pRequest;
908 SvtMiscOptions aOpts;
911 TYPEINIT1(SmViewShell, SfxViewShell);
913 SFX_IMPL_SUPERCLASS_INTERFACE(SmViewShell, SfxViewShell)
915 void SmViewShell::InitInterface_Impl()
917 GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_TOOLS | SFX_VISIBILITY_STANDARD | SFX_VISIBILITY_FULLSCREEN | SFX_VISIBILITY_SERVER,
918 RID_MATH_TOOLBOX);
919 //Dummy-Objectbar, to avoid quiver while activating
921 GetStaticInterface()->RegisterChildWindow(SID_TASKPANE);
922 GetStaticInterface()->RegisterChildWindow(SmCmdBoxWrapper::GetChildWindowId());
923 GetStaticInterface()->RegisterChildWindow(SmElementsDockingWindowWrapper::GetChildWindowId());
926 SFX_IMPL_NAMED_VIEWFACTORY(SmViewShell, "Default")
928 SFX_VIEW_REGISTRATION(SmDocShell);
931 void SmViewShell::AdjustPosSizePixel(const Point &rPos, const Size &rSize)
933 aGraphic->SetPosSizePixel(rPos, rSize);
936 void SmViewShell::InnerResizePixel(const Point &rOfs, const Size &rSize)
938 Size aObjSize = GetObjectShell()->GetVisArea().GetSize();
939 if ( aObjSize.Width() > 0 && aObjSize.Height() > 0 )
941 Size aProvidedSize = GetWindow()->PixelToLogic( rSize, MAP_100TH_MM );
942 SfxViewShell::SetZoomFactor( Fraction( aProvidedSize.Width(), aObjSize.Width() ),
943 Fraction( aProvidedSize.Height(), aObjSize.Height() ) );
946 SetBorderPixel( SvBorder() );
947 GetGraphicWindow().SetPosSizePixel(rOfs, rSize);
948 GetGraphicWindow().SetTotalSize();
951 void SmViewShell::OuterResizePixel(const Point &rOfs, const Size &rSize)
953 SmGraphicWindow &rWin = GetGraphicWindow();
954 rWin.SetPosSizePixel(rOfs, rSize);
955 if (GetDoc()->IsPreview())
956 rWin.ZoomToFitInWindow();
957 rWin.Update();
960 void SmViewShell::QueryObjAreaPixel( Rectangle& rRect ) const
962 rRect.SetSize( GetGraphicWindow().GetSizePixel() );
965 void SmViewShell::SetZoomFactor( const Fraction &rX, const Fraction &rY )
967 const Fraction &rFrac = rX < rY ? rX : rY;
968 GetGraphicWindow().SetZoom( (sal_uInt16) long(rFrac * Fraction( 100, 1 )) );
970 //To avoid rounding errors base class regulates crooked values too
971 //if necessary
972 SfxViewShell::SetZoomFactor( rX, rY );
975 Size SmViewShell::GetTextLineSize(OutputDevice& rDevice, const OUString& rLine)
977 Size aSize(rDevice.GetTextWidth(rLine), rDevice.GetTextHeight());
978 sal_uInt16 nTabs = comphelper::string::getTokenCount(rLine, '\t');
979 long nTabPos = 0;
980 if (nTabs > 0)
981 nTabPos = rDevice.approximate_char_width() * 8;
983 if (nTabPos)
985 aSize.Width() = 0;
987 for (sal_uInt16 i = 0; i < nTabs; i++)
989 if (i > 0)
990 aSize.Width() = ((aSize.Width() / nTabPos) + 1) * nTabPos;
992 OUString aText = rLine.getToken(i, '\t');
993 aText = comphelper::string::stripStart(aText, '\t');
994 aText = comphelper::string::stripEnd(aText, '\t');
995 aSize.Width() += rDevice.GetTextWidth(aText);
999 return aSize;
1002 Size SmViewShell::GetTextSize(OutputDevice& rDevice, const OUString& rText, long MaxWidth)
1004 Size aSize;
1005 Size aTextSize;
1006 sal_uInt16 nLines = comphelper::string::getTokenCount(rText, '\n');
1008 for (sal_uInt16 i = 0; i < nLines; i++)
1010 OUString aLine = rText.getToken(i, '\n');
1011 aLine = comphelper::string::remove(aLine, '\r');
1012 aLine = comphelper::string::stripStart(aLine, '\n');
1013 aLine = comphelper::string::stripEnd(aLine, '\n');
1015 aSize = GetTextLineSize(rDevice, aLine);
1017 if (aSize.Width() > MaxWidth)
1021 OUString aText;
1022 sal_Int32 m = aLine.getLength();
1023 sal_Int32 nLen = m;
1025 for (sal_Int32 n = 0; n < nLen; n++)
1027 sal_Unicode cLineChar = aLine[n];
1028 if ((cLineChar == ' ') || (cLineChar == '\t'))
1030 aText = aLine.copy(0, n);
1031 if (GetTextLineSize(rDevice, aText).Width() < MaxWidth)
1032 m = n;
1033 else
1034 break;
1038 aText = aLine.copy(0, m);
1039 aLine = aLine.replaceAt(0, m, "");
1040 aSize = GetTextLineSize(rDevice, aText);
1041 aTextSize.Height() += aSize.Height();
1042 aTextSize.Width() = std::max(aTextSize.Width(), std::min(aSize.Width(), MaxWidth));
1044 aLine = comphelper::string::stripStart(aLine, ' ');
1045 aLine = comphelper::string::stripStart(aLine, '\t');
1046 aLine = comphelper::string::stripStart(aLine, ' ');
1048 while (!aLine.isEmpty());
1050 else
1052 aTextSize.Height() += aSize.Height();
1053 aTextSize.Width() = std::max(aTextSize.Width(), aSize.Width());
1057 return aTextSize;
1060 void SmViewShell::DrawTextLine(OutputDevice& rDevice, const Point& rPosition, const OUString& rLine)
1062 Point aPoint(rPosition);
1064 sal_uInt16 nTabs = comphelper::string::getTokenCount(rLine, '\t');
1065 long nTabPos = 0;
1066 if (nTabs > 0)
1067 nTabPos = rDevice.approximate_char_width() * 8;
1069 if (nTabPos)
1071 for (sal_uInt16 i = 0; i < nTabs; ++i)
1073 if (i > 0)
1074 aPoint.X() = ((aPoint.X() / nTabPos) + 1) * nTabPos;
1076 OUString aText = rLine.getToken(i, '\t');
1077 aText = comphelper::string::stripStart(aText, '\t');
1078 aText = comphelper::string::stripEnd(aText, '\t');
1079 rDevice.DrawText(aPoint, aText);
1080 aPoint.X() += rDevice.GetTextWidth(aText);
1083 else
1084 rDevice.DrawText(aPoint, rLine);
1088 void SmViewShell::DrawText(OutputDevice& rDevice, const Point& rPosition, const OUString& rText, sal_uInt16 MaxWidth)
1090 sal_uInt16 nLines = comphelper::string::getTokenCount(rText, '\n');
1091 Point aPoint(rPosition);
1092 Size aSize;
1094 for (sal_uInt16 i = 0; i < nLines; i++)
1096 OUString aLine = rText.getToken(i, '\n');
1097 aLine = comphelper::string::remove(aLine, '\r');
1098 aLine = comphelper::string::stripEnd(aLine, '\n');
1099 aLine = comphelper::string::stripEnd(aLine, '\n');
1100 aSize = GetTextLineSize(rDevice, aLine);
1101 if (aSize.Width() > MaxWidth)
1105 OUString aText;
1106 sal_Int32 m = aLine.getLength();
1107 sal_Int32 nLen = m;
1109 for (sal_Int32 n = 0; n < nLen; n++)
1111 sal_Unicode cLineChar = aLine[n];
1112 if ((cLineChar == ' ') || (cLineChar == '\t'))
1114 aText = aLine.copy(0, n);
1115 if (GetTextLineSize(rDevice, aText).Width() < MaxWidth)
1116 m = n;
1117 else
1118 break;
1121 aText = aLine.copy(0, m);
1122 aLine = aLine.replaceAt(0, m, "");
1124 DrawTextLine(rDevice, aPoint, aText);
1125 aPoint.Y() += aSize.Height();
1127 aLine = comphelper::string::stripStart(aLine, ' ');
1128 aLine = comphelper::string::stripStart(aLine, '\t');
1129 aLine = comphelper::string::stripStart(aLine, ' ');
1131 while (GetTextLineSize(rDevice, aLine).Width() > MaxWidth);
1133 // print the remaining text
1134 if (!aLine.isEmpty())
1136 DrawTextLine(rDevice, aPoint, aLine);
1137 aPoint.Y() += aSize.Height();
1140 else
1142 DrawTextLine(rDevice, aPoint, aLine);
1143 aPoint.Y() += aSize.Height();
1148 void SmViewShell::Impl_Print(OutputDevice &rOutDev, const SmPrintUIOptions &rPrintUIOptions, Rectangle aOutRect, Point aZeroPoint )
1150 const bool bIsPrintTitle = rPrintUIOptions.getBoolValue( PRTUIOPT_TITLE_ROW, true );
1151 const bool bIsPrintFrame = rPrintUIOptions.getBoolValue( PRTUIOPT_BORDER, true );
1152 const bool bIsPrintFormulaText = rPrintUIOptions.getBoolValue( PRTUIOPT_FORMULA_TEXT, true );
1153 SmPrintSize ePrintSize( static_cast< SmPrintSize >( rPrintUIOptions.getIntValue( PRTUIOPT_PRINT_FORMAT, PRINT_SIZE_NORMAL ) ));
1154 const sal_uInt16 nZoomFactor = static_cast< sal_uInt16 >(rPrintUIOptions.getIntValue( PRTUIOPT_PRINT_SCALE, 100 ));
1156 rOutDev.Push();
1157 rOutDev.SetLineColor( Color(COL_BLACK) );
1159 // output text on top
1160 if (bIsPrintTitle)
1162 Size aSize600 (0, 600);
1163 Size aSize650 (0, 650);
1164 vcl::Font aFont(FAMILY_DONTKNOW, aSize600);
1166 aFont.SetAlign(ALIGN_TOP);
1167 aFont.SetWeight(WEIGHT_BOLD);
1168 aFont.SetSize(aSize650);
1169 aFont.SetColor( Color(COL_BLACK) );
1170 rOutDev.SetFont(aFont);
1172 Size aTitleSize (GetTextSize(rOutDev, GetDoc()->GetTitle(), aOutRect.GetWidth() - 200));
1174 aFont.SetWeight(WEIGHT_NORMAL);
1175 aFont.SetSize(aSize600);
1176 rOutDev.SetFont(aFont);
1178 Size aDescSize (GetTextSize(rOutDev, GetDoc()->GetComment(), aOutRect.GetWidth() - 200));
1180 if (bIsPrintFrame)
1181 rOutDev.DrawRect(Rectangle(aOutRect.TopLeft(),
1182 Size(aOutRect.GetWidth(), 100 + aTitleSize.Height() + 200 + aDescSize.Height() + 100)));
1183 aOutRect.Top() += 200;
1185 // output title
1186 aFont.SetWeight(WEIGHT_BOLD);
1187 aFont.SetSize(aSize650);
1188 rOutDev.SetFont(aFont);
1189 Point aPoint(aOutRect.Left() + (aOutRect.GetWidth() - aTitleSize.Width()) / 2,
1190 aOutRect.Top());
1191 DrawText(rOutDev, aPoint, GetDoc()->GetTitle(),
1192 sal::static_int_cast< sal_uInt16 >(aOutRect.GetWidth() - 200));
1193 aOutRect.Top() += aTitleSize.Height() + 200;
1195 // output description
1196 aFont.SetWeight(WEIGHT_NORMAL);
1197 aFont.SetSize(aSize600);
1198 rOutDev.SetFont(aFont);
1199 aPoint.X() = aOutRect.Left() + (aOutRect.GetWidth() - aDescSize.Width()) / 2;
1200 aPoint.Y() = aOutRect.Top();
1201 DrawText(rOutDev, aPoint, GetDoc()->GetComment(),
1202 sal::static_int_cast< sal_uInt16 >(aOutRect.GetWidth() - 200));
1203 aOutRect.Top() += aDescSize.Height() + 300;
1206 // output text on bottom
1207 if (bIsPrintFormulaText)
1209 vcl::Font aFont(FAMILY_DONTKNOW, Size(0, 600));
1210 aFont.SetAlign(ALIGN_TOP);
1211 aFont.SetColor( Color(COL_BLACK) );
1213 // get size
1214 rOutDev.SetFont(aFont);
1216 Size aSize (GetTextSize(rOutDev, GetDoc()->GetText(), aOutRect.GetWidth() - 200));
1218 aOutRect.Bottom() -= aSize.Height() + 600;
1220 if (bIsPrintFrame)
1221 rOutDev.DrawRect(Rectangle(aOutRect.BottomLeft(),
1222 Size(aOutRect.GetWidth(), 200 + aSize.Height() + 200)));
1224 Point aPoint (aOutRect.Left() + (aOutRect.GetWidth() - aSize.Width()) / 2,
1225 aOutRect.Bottom() + 300);
1226 DrawText(rOutDev, aPoint, GetDoc()->GetText(),
1227 sal::static_int_cast< sal_uInt16 >(aOutRect.GetWidth() - 200));
1228 aOutRect.Bottom() -= 200;
1231 if (bIsPrintFrame)
1232 rOutDev.DrawRect(aOutRect);
1234 aOutRect.Top() += 100;
1235 aOutRect.Left() += 100;
1236 aOutRect.Bottom() -= 100;
1237 aOutRect.Right() -= 100;
1239 Size aSize (GetDoc()->GetSize());
1241 MapMode OutputMapMode;
1242 // PDF export should always use PRINT_SIZE_NORMAL ...
1243 if (!rPrintUIOptions.getBoolValue( "IsPrinter", false ) )
1244 ePrintSize = PRINT_SIZE_NORMAL;
1245 switch (ePrintSize)
1247 case PRINT_SIZE_NORMAL:
1248 OutputMapMode = MapMode(MAP_100TH_MM);
1249 break;
1251 case PRINT_SIZE_SCALED:
1252 if ((aSize.Width() > 0) && (aSize.Height() > 0))
1254 Size OutputSize (rOutDev.LogicToPixel(Size(aOutRect.GetWidth(),
1255 aOutRect.GetHeight()), MapMode(MAP_100TH_MM)));
1256 Size GraphicSize (rOutDev.LogicToPixel(aSize, MapMode(MAP_100TH_MM)));
1257 sal_uInt16 nZ = (sal_uInt16) std::min((long)Fraction(OutputSize.Width() * 100L, GraphicSize.Width()),
1258 (long)Fraction(OutputSize.Height() * 100L, GraphicSize.Height()));
1259 Fraction aFraction ((sal_uInt16) std::max ((sal_uInt16) MINZOOM, std::min((sal_uInt16) MAXZOOM, (sal_uInt16) (nZ - 10))), (sal_uInt16) 100);
1261 OutputMapMode = MapMode(MAP_100TH_MM, aZeroPoint, aFraction, aFraction);
1263 else
1264 OutputMapMode = MapMode(MAP_100TH_MM);
1265 break;
1267 case PRINT_SIZE_ZOOMED:
1269 Fraction aFraction( nZoomFactor, 100 );
1271 OutputMapMode = MapMode(MAP_100TH_MM, aZeroPoint, aFraction, aFraction);
1272 break;
1276 aSize = rOutDev.PixelToLogic(rOutDev.LogicToPixel(aSize, OutputMapMode),
1277 MapMode(MAP_100TH_MM));
1279 Point aPos (aOutRect.Left() + (aOutRect.GetWidth() - aSize.Width()) / 2,
1280 aOutRect.Top() + (aOutRect.GetHeight() - aSize.Height()) / 2);
1282 aPos = rOutDev.PixelToLogic(rOutDev.LogicToPixel(aPos, MapMode(MAP_100TH_MM)),
1283 OutputMapMode);
1284 aOutRect = rOutDev.PixelToLogic(rOutDev.LogicToPixel(aOutRect, MapMode(MAP_100TH_MM)),
1285 OutputMapMode);
1287 rOutDev.SetMapMode(OutputMapMode);
1288 rOutDev.SetClipRegion(vcl::Region(aOutRect));
1289 GetDoc()->DrawFormula(rOutDev, aPos, false);
1290 rOutDev.SetClipRegion();
1292 rOutDev.Pop();
1295 SfxPrinter* SmViewShell::GetPrinter(bool bCreate)
1297 SmDocShell* pDoc = GetDoc();
1298 if (pDoc->HasPrinter() || bCreate)
1299 return pDoc->GetPrinter();
1300 return 0;
1303 sal_uInt16 SmViewShell::SetPrinter(SfxPrinter *pNewPrinter, SfxPrinterChangeFlags nDiffFlags, bool )
1305 SfxPrinter *pOld = GetDoc()->GetPrinter();
1306 if ( pOld && pOld->IsPrinting() )
1307 return SFX_PRINTERROR_BUSY;
1309 if ((nDiffFlags & SfxPrinterChangeFlags::PRINTER) == SfxPrinterChangeFlags::PRINTER)
1310 GetDoc()->SetPrinter( pNewPrinter );
1312 if ((nDiffFlags & SfxPrinterChangeFlags::OPTIONS) == SfxPrinterChangeFlags::OPTIONS)
1314 SmModule *pp = SM_MOD();
1315 pp->GetConfig()->ItemSetToConfig(pNewPrinter->GetOptions());
1317 return 0;
1320 bool SmViewShell::HasPrintOptionsPage() const
1322 return true;
1325 VclPtr<SfxTabPage> SmViewShell::CreatePrintOptionsPage(vcl::Window *pParent,
1326 const SfxItemSet &rOptions)
1328 return SmPrintOptionsTabPage::Create(pParent, rOptions);
1331 SmEditWindow *SmViewShell::GetEditWindow()
1333 SmCmdBoxWrapper* pWrapper = static_cast<SmCmdBoxWrapper*>(
1334 GetViewFrame()->GetChildWindow(SmCmdBoxWrapper::GetChildWindowId()));
1336 if (pWrapper != nullptr)
1338 SmEditWindow& rEditWin = pWrapper->GetEditWindow();
1339 return &rEditWin;
1342 return nullptr;
1345 void SmViewShell::SetStatusText(const OUString& rText)
1347 aStatusText = rText;
1348 GetViewFrame()->GetBindings().Invalidate(SID_TEXTSTATUS);
1351 void SmViewShell::ShowError(const SmErrorDesc* pErrorDesc)
1353 SAL_WARN_IF( !GetDoc(), "starmath", "Document missing" );
1354 if (pErrorDesc || 0 != (pErrorDesc = GetDoc()->GetParser().GetError(0)) )
1356 SetStatusText( pErrorDesc->Text );
1357 GetEditWindow()->MarkError( Point( pErrorDesc->pNode->GetColumn(),
1358 pErrorDesc->pNode->GetRow()));
1362 void SmViewShell::NextError()
1364 SAL_WARN_IF( !GetDoc(), "starmath", "Document missing" );
1365 const SmErrorDesc *pErrorDesc = GetDoc()->GetParser().NextError();
1367 if (pErrorDesc)
1368 ShowError( pErrorDesc );
1371 void SmViewShell::PrevError()
1373 SAL_WARN_IF( !GetDoc(), "starmath", "Document missing" );
1374 const SmErrorDesc *pErrorDesc = GetDoc()->GetParser().PrevError();
1376 if (pErrorDesc)
1377 ShowError( pErrorDesc );
1380 void SmViewShell::Insert( SfxMedium& rMedium )
1382 SmDocShell *pDoc = GetDoc();
1383 bool bRet = false;
1385 uno::Reference <embed::XStorage> xStorage = rMedium.GetStorage();
1386 uno::Reference <container::XNameAccess> xNameAccess(xStorage, uno::UNO_QUERY);
1387 if (xNameAccess.is() && xNameAccess->getElementNames().getLength())
1389 if (xNameAccess->hasByName(OUString("content.xml")) || xNameAccess->hasByName(OUString("Content.xml")))
1391 // is this a fabulous math package ?
1392 Reference<com::sun::star::frame::XModel> xModel(pDoc->GetModel());
1393 SmXMLImportWrapper aEquation(xModel); //!! modifies the result of pDoc->GetText() !!
1394 bRet = 0 == aEquation.Import(rMedium);
1398 if (bRet)
1400 OUString aText = pDoc->GetText();
1401 SmEditWindow *pEditWin = GetEditWindow();
1402 if (pEditWin)
1403 pEditWin->InsertText( aText );
1404 else
1406 SAL_WARN( "starmath", "EditWindow missing" );
1409 pDoc->Parse();
1410 pDoc->SetModified(true);
1412 SfxBindings &rBnd = GetViewFrame()->GetBindings();
1413 rBnd.Invalidate(SID_GAPHIC_SM);
1414 rBnd.Invalidate(SID_TEXT);
1418 void SmViewShell::InsertFrom(SfxMedium &rMedium)
1420 bool bSuccess = false;
1421 SmDocShell* pDoc = GetDoc();
1422 SvStream* pStream = rMedium.GetInStream();
1424 if (pStream)
1426 const OUString& rFltName = rMedium.GetFilter()->GetFilterName();
1427 if ( rFltName == MATHML_XML )
1429 Reference<css::frame::XModel> xModel(pDoc->GetModel());
1430 SmXMLImportWrapper aEquation(xModel); //!! modifies the result of pDoc->GetText() !!
1431 bSuccess = 0 == aEquation.Import(rMedium);
1435 if (bSuccess)
1437 OUString aText = pDoc->GetText();
1438 SmEditWindow *pEditWin = GetEditWindow();
1439 if (pEditWin)
1440 pEditWin->InsertText(aText);
1441 else
1442 SAL_WARN( "starmath", "EditWindow missing" );
1444 pDoc->Parse();
1445 pDoc->SetModified(true);
1447 SfxBindings& rBnd = GetViewFrame()->GetBindings();
1448 rBnd.Invalidate(SID_GAPHIC_SM);
1449 rBnd.Invalidate(SID_TEXT);
1453 void SmViewShell::Execute(SfxRequest& rReq)
1455 SmEditWindow *pWin = GetEditWindow();
1457 switch (rReq.GetSlot())
1459 case SID_FORMULACURSOR:
1461 SmModule *pp = SM_MOD();
1463 const SfxItemSet *pArgs = rReq.GetArgs();
1464 const SfxPoolItem *pItem;
1466 bool bVal;
1467 if ( pArgs &&
1468 SfxItemState::SET == pArgs->GetItemState( SID_FORMULACURSOR, false, &pItem))
1469 bVal = static_cast<const SfxBoolItem *>(pItem)->GetValue();
1470 else
1471 bVal = !pp->GetConfig()->IsShowFormulaCursor();
1473 pp->GetConfig()->SetShowFormulaCursor(bVal);
1474 if (!IsInlineEditEnabled())
1475 GetGraphicWindow().ShowCursor(bVal);
1476 break;
1478 case SID_DRAW:
1479 if (pWin)
1481 GetDoc()->SetText( pWin->GetText() );
1482 SetStatusText(OUString());
1483 ShowError( 0 );
1484 GetDoc()->Repaint();
1486 break;
1488 case SID_ZOOM_OPTIMAL:
1489 aGraphic->ZoomToFitInWindow();
1490 break;
1492 case SID_ZOOMIN:
1493 aGraphic->SetZoom(aGraphic->GetZoom() + 25);
1494 break;
1496 case SID_ZOOMOUT:
1497 SAL_WARN_IF( aGraphic->GetZoom() < 25, "starmath", "incorrect sal_uInt16 argument" );
1498 aGraphic->SetZoom(aGraphic->GetZoom() - 25);
1499 break;
1501 case SID_COPYOBJECT:
1503 //TODO/LATER: does not work because of UNO Tunneling - will be fixed later
1504 Reference< datatransfer::XTransferable > xTrans( GetDoc()->GetModel(), uno::UNO_QUERY );
1505 if( xTrans.is() )
1507 Reference< lang::XUnoTunnel> xTnnl( xTrans, uno::UNO_QUERY);
1508 if( xTnnl.is() )
1510 TransferableHelper* pTrans = reinterpret_cast< TransferableHelper * >(
1511 sal::static_int_cast< sal_uIntPtr >(
1512 xTnnl->getSomething( TransferableHelper::getUnoTunnelId() )));
1513 if( pTrans )
1514 pTrans->CopyToClipboard(GetEditWindow());
1518 break;
1520 case SID_PASTEOBJECT:
1522 TransferableDataHelper aData( TransferableDataHelper::CreateFromSystemClipboard(GetEditWindow()) );
1523 uno::Reference < io::XInputStream > xStrm;
1524 SotClipboardFormatId nId;
1525 if( aData.GetTransferable().is() &&
1526 ( aData.HasFormat( nId = SotClipboardFormatId::EMBEDDED_OBJ ) ||
1527 (aData.HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ) &&
1528 aData.HasFormat( nId = SotClipboardFormatId::EMBED_SOURCE ))))
1529 xStrm = aData.GetInputStream(nId, OUString());
1531 if (xStrm.is())
1535 uno::Reference < embed::XStorage > xStorage =
1536 ::comphelper::OStorageHelper::GetStorageFromInputStream( xStrm, ::comphelper::getProcessComponentContext() );
1537 uno::Reference < beans::XPropertySet > xProps( xStorage, uno::UNO_QUERY );
1538 SfxMedium aMedium( xStorage, OUString() );
1539 Insert( aMedium );
1540 GetDoc()->UpdateText();
1542 catch (uno::Exception &)
1544 SAL_WARN( "starmath", "SmViewShell::Execute (SID_PASTEOBJECT): failed to get storage from input stream" );
1548 break;
1551 case SID_CUT:
1552 if (pWin)
1553 pWin->Cut();
1554 break;
1556 case SID_COPY:
1557 if (pWin)
1559 if (pWin->IsAllSelected())
1561 GetViewFrame()->GetDispatcher()->Execute(
1562 SID_COPYOBJECT, SfxCallMode::RECORD,
1563 new SfxVoidItem(SID_COPYOBJECT), 0L);
1565 else
1566 pWin->Copy();
1568 break;
1570 case SID_PASTE:
1572 bool bCallExec = 0 == pWin;
1573 if( !bCallExec )
1575 TransferableDataHelper aDataHelper(
1576 TransferableDataHelper::CreateFromSystemClipboard(
1577 GetEditWindow()) );
1579 if( aDataHelper.GetTransferable().is() &&
1580 aDataHelper.HasFormat( SotClipboardFormatId::STRING ))
1581 pWin->Paste();
1582 else
1583 bCallExec = true;
1585 if( bCallExec )
1587 GetViewFrame()->GetDispatcher()->Execute(
1588 SID_PASTEOBJECT, SfxCallMode::RECORD,
1589 new SfxVoidItem(SID_PASTEOBJECT), 0L);
1592 break;
1594 case SID_DELETE:
1595 if (pWin)
1596 pWin->Delete();
1597 break;
1599 case SID_SELECT:
1600 if (pWin)
1601 pWin->SelectAll();
1602 break;
1604 case SID_INSERTCOMMAND:
1606 const SfxInt16Item& rItem =
1607 static_cast<const SfxInt16Item&>(rReq.GetArgs()->Get(SID_INSERTCOMMAND));
1609 if (pWin && (bInsertIntoEditWindow || !IsInlineEditEnabled()))
1610 pWin->InsertCommand(rItem.GetValue());
1611 if (IsInlineEditEnabled() && (GetDoc() && !bInsertIntoEditWindow)) {
1612 GetDoc()->GetCursor().InsertCommand(rItem.GetValue());
1613 GetGraphicWindow().GrabFocus();
1615 break;
1618 case SID_INSERTCOMMANDTEXT:
1620 const SfxStringItem& rItem = static_cast<const SfxStringItem&>(rReq.GetArgs()->Get(SID_INSERTCOMMANDTEXT));
1622 if (pWin && (bInsertIntoEditWindow || !IsInlineEditEnabled()))
1624 pWin->InsertText(rItem.GetValue());
1626 if (IsInlineEditEnabled() && (GetDoc() && !bInsertIntoEditWindow))
1628 GetDoc()->GetCursor().InsertCommandText(rItem.GetValue());
1629 GetGraphicWindow().GrabFocus();
1631 break;
1635 case SID_INSERTSYMBOL:
1637 const SfxStringItem& rItem =
1638 static_cast<const SfxStringItem&>(rReq.GetArgs()->Get(SID_INSERTSYMBOL));
1640 if (pWin && (bInsertIntoEditWindow || !IsInlineEditEnabled()))
1641 pWin->InsertText(rItem.GetValue());
1642 if (IsInlineEditEnabled() && (GetDoc() && !bInsertIntoEditWindow))
1643 GetDoc()->GetCursor().InsertSpecial(rItem.GetValue());
1644 break;
1647 case SID_IMPORT_FORMULA:
1649 pImpl->pRequest.reset(new SfxRequest( rReq ));
1650 pImpl->pDocInserter.reset(new ::sfx2::DocumentInserter(
1651 GetDoc()->GetFactory().GetFactoryName(), false ));
1652 pImpl->pDocInserter->StartExecuteModal( LINK( this, SmViewShell, DialogClosedHdl ) );
1653 break;
1656 case SID_NEXTERR:
1657 NextError();
1658 if (pWin)
1659 pWin->GrabFocus();
1660 break;
1662 case SID_PREVERR:
1663 PrevError();
1664 if (pWin)
1665 pWin->GrabFocus();
1666 break;
1668 case SID_NEXTMARK:
1669 if (pWin)
1671 pWin->SelNextMark();
1672 pWin->GrabFocus();
1674 break;
1676 case SID_PREVMARK:
1677 if (pWin)
1679 pWin->SelPrevMark();
1680 pWin->GrabFocus();
1682 break;
1684 case SID_TEXTSTATUS:
1686 if (rReq.GetArgs() != NULL)
1688 const SfxStringItem& rItem =
1689 static_cast<const SfxStringItem&>(rReq.GetArgs()->Get(SID_TEXTSTATUS));
1691 SetStatusText(rItem.GetValue());
1694 break;
1697 case SID_GETEDITTEXT:
1698 if (pWin)
1699 if (!pWin->GetText().isEmpty()) GetDoc()->SetText( pWin->GetText() );
1700 break;
1702 case SID_ATTR_ZOOM:
1704 if ( !GetViewFrame()->GetFrame().IsInPlace() )
1706 std::unique_ptr<AbstractSvxZoomDialog> xDlg;
1707 const SfxItemSet *pSet = rReq.GetArgs();
1708 if ( !pSet )
1710 SfxItemSet aSet( SmDocShell::GetPool(), SID_ATTR_ZOOM, SID_ATTR_ZOOM);
1711 aSet.Put( SvxZoomItem( SvxZoomType::PERCENT, aGraphic->GetZoom()));
1712 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
1713 if(pFact)
1715 xDlg.reset(pFact->CreateSvxZoomDialog(&GetViewFrame()->GetWindow(), aSet));
1716 SAL_WARN_IF( !xDlg, "starmath", "Dialog creation failed!" );
1717 xDlg->SetLimits( MINZOOM, MAXZOOM );
1718 if (xDlg->Execute() != RET_CANCEL)
1719 pSet = xDlg->GetOutputItemSet();
1722 if ( pSet )
1724 const SvxZoomItem &rZoom = static_cast<const SvxZoomItem &>(pSet->Get(SID_ATTR_ZOOM));
1725 switch( rZoom.GetType() )
1727 case SvxZoomType::PERCENT:
1728 aGraphic->SetZoom((sal_uInt16)rZoom.GetValue ());
1729 break;
1731 case SvxZoomType::OPTIMAL:
1732 aGraphic->ZoomToFitInWindow();
1733 break;
1735 case SvxZoomType::PAGEWIDTH:
1736 case SvxZoomType::WHOLEPAGE:
1738 const MapMode aMap( MAP_100TH_MM );
1739 SfxPrinter *pPrinter = GetPrinter( true );
1740 Point aPoint;
1741 Rectangle OutputRect(aPoint, pPrinter->GetOutputSize());
1742 Size OutputSize(pPrinter->LogicToPixel(Size(OutputRect.GetWidth(),
1743 OutputRect.GetHeight()), aMap));
1744 Size GraphicSize(pPrinter->LogicToPixel(GetDoc()->GetSize(), aMap));
1745 sal_uInt16 nZ = (sal_uInt16) std::min((long)Fraction(OutputSize.Width() * 100L, GraphicSize.Width()),
1746 (long)Fraction(OutputSize.Height() * 100L, GraphicSize.Height()));
1747 aGraphic->SetZoom (nZ);
1748 break;
1750 default:
1751 break;
1756 break;
1758 case SID_ATTR_ZOOMSLIDER:
1760 const SfxItemSet *pArgs = rReq.GetArgs();
1761 const SfxPoolItem* pItem;
1763 if ( pArgs && SfxItemState::SET == pArgs->GetItemState(SID_ATTR_ZOOMSLIDER, true, &pItem ) )
1765 const sal_uInt16 nCurrentZoom = static_cast<const SvxZoomSliderItem *>(pItem)->GetValue();
1766 aGraphic->SetZoom( nCurrentZoom );
1769 break;
1771 case SID_ELEMENTSDOCKINGWINDOW:
1773 GetViewFrame()->ToggleChildWindow( SmElementsDockingWindowWrapper::GetChildWindowId() );
1774 GetViewFrame()->GetBindings().Invalidate( SID_ELEMENTSDOCKINGWINDOW );
1776 rReq.Ignore ();
1778 break;
1780 case SID_SYMBOLS_CATALOGUE:
1783 // get device used to retrieve the FontList
1784 SmDocShell *pDoc = GetDoc();
1785 OutputDevice *pDev = pDoc->GetPrinter();
1786 if (!pDev || pDev->GetDevFontCount() == 0)
1787 pDev = &SM_MOD()->GetDefaultVirtualDev();
1788 SAL_WARN_IF( !pDev, "starmath", "device for font list missing" );
1790 SmModule *pp = SM_MOD();
1791 ScopedVclPtrInstance<SmSymbolDialog>::Create( nullptr, pDev, pp->GetSymbolManager(), *this )->Execute();
1793 break;
1795 rReq.Done();
1799 void SmViewShell::GetState(SfxItemSet &rSet)
1801 SfxWhichIter aIter(rSet);
1803 SmEditWindow *pEditWin = GetEditWindow();
1804 for (sal_uInt16 nWh = aIter.FirstWhich(); nWh != 0; nWh = aIter.NextWhich())
1806 switch (nWh)
1808 case SID_CUT:
1809 case SID_COPY:
1810 case SID_DELETE:
1811 if (! pEditWin || ! pEditWin->IsSelected())
1812 rSet.DisableItem(nWh);
1813 break;
1815 case SID_PASTE:
1816 if (pEditWin)
1818 TransferableDataHelper aDataHelper(
1819 TransferableDataHelper::CreateFromSystemClipboard(
1820 pEditWin) );
1822 bPasteState = aDataHelper.GetTransferable().is() &&
1823 ( aDataHelper.HasFormat( SotClipboardFormatId::STRING ) ||
1824 aDataHelper.HasFormat( SotClipboardFormatId::EMBEDDED_OBJ ) ||
1825 (aDataHelper.HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR )
1826 && aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE )));
1828 if( !bPasteState )
1829 rSet.DisableItem( nWh );
1830 break;
1832 case SID_ATTR_ZOOM:
1833 rSet.Put(SvxZoomItem( SvxZoomType::PERCENT, aGraphic->GetZoom()));
1834 /* no break here */
1835 case SID_ZOOMIN:
1836 case SID_ZOOMOUT:
1837 case SID_ZOOM_OPTIMAL:
1838 if ( GetViewFrame()->GetFrame().IsInPlace() )
1839 rSet.DisableItem( nWh );
1840 break;
1842 case SID_ATTR_ZOOMSLIDER :
1844 const sal_uInt16 nCurrentZoom = aGraphic->GetZoom();
1845 SvxZoomSliderItem aZoomSliderItem( nCurrentZoom, MINZOOM, MAXZOOM );
1846 aZoomSliderItem.AddSnappingPoint( 100 );
1847 rSet.Put( aZoomSliderItem );
1849 break;
1851 case SID_NEXTERR:
1852 case SID_PREVERR:
1853 case SID_NEXTMARK:
1854 case SID_PREVMARK:
1855 case SID_DRAW:
1856 case SID_SELECT:
1857 if (! pEditWin || pEditWin->IsEmpty())
1858 rSet.DisableItem(nWh);
1859 break;
1861 case SID_TEXTSTATUS:
1863 rSet.Put(SfxStringItem(nWh, aStatusText));
1865 break;
1867 case SID_FORMULACURSOR:
1869 SmModule *pp = SM_MOD();
1870 rSet.Put(SfxBoolItem(nWh, pp->GetConfig()->IsShowFormulaCursor()));
1872 break;
1873 case SID_ELEMENTSDOCKINGWINDOW:
1875 bool bState = false;
1876 SfxChildWindow *pChildWnd = GetViewFrame()->
1877 GetChildWindow( SmElementsDockingWindowWrapper::GetChildWindowId() );
1878 if (pChildWnd && pChildWnd->GetWindow()->IsVisible())
1879 bState = true;
1880 rSet.Put(SfxBoolItem(SID_ELEMENTSDOCKINGWINDOW, bState));
1882 break;
1887 SmViewShell::SmViewShell(SfxViewFrame *pFrame_, SfxViewShell *)
1888 : SfxViewShell(pFrame_, SfxViewShellFlags::HAS_PRINTOPTIONS | SfxViewShellFlags::CAN_PRINT)
1889 , pImpl(new SmViewShell_Impl)
1890 , aGraphic(VclPtr<SmGraphicWindow>::Create(this))
1891 , aGraphicController(*aGraphic.get(), SID_GAPHIC_SM, pFrame_->GetBindings())
1892 , bPasteState(false)
1893 , bInsertIntoEditWindow(false)
1895 SetStatusText(OUString());
1896 SetWindow(aGraphic.get());
1897 SfxShell::SetName(OUString("SmView"));
1898 SfxShell::SetUndoManager( &GetDoc()->GetEditEngine().GetUndoManager() );
1899 SetHelpId( HID_SMA_VIEWSHELL_DOCUMENT );
1903 SmViewShell::~SmViewShell()
1905 //!! this view shell is not active anymore !!
1906 // Thus 'SmGetActiveView' will give a 0 pointer.
1907 // Thus we need to supply this view as argument
1908 SmEditWindow *pEditWin = GetEditWindow();
1909 if (pEditWin)
1910 pEditWin->DeleteEditView( *this );
1911 aGraphic.disposeAndClear();
1914 void SmViewShell::Deactivate( bool bIsMDIActivate )
1916 SmEditWindow *pEdit = GetEditWindow();
1917 if ( pEdit )
1918 pEdit->Flush();
1920 SfxViewShell::Deactivate( bIsMDIActivate );
1923 void SmViewShell::Activate( bool bIsMDIActivate )
1925 SfxViewShell::Activate( bIsMDIActivate );
1927 SmEditWindow *pEdit = GetEditWindow();
1928 if ( pEdit )
1930 //! Since there is no way to be informed if a "drag and drop"
1931 //! event has taken place, we call SetText here in order to
1932 //! synchronize the GraphicWindow display with the text in the
1933 //! EditEngine.
1934 SmDocShell *pDoc = GetDoc();
1935 pDoc->SetText( pDoc->GetEditEngine().GetText( LINEEND_LF ) );
1937 if ( bIsMDIActivate )
1938 pEdit->GrabFocus();
1942 IMPL_LINK( SmViewShell, DialogClosedHdl, sfx2::FileDialogHelper*, _pFileDlg )
1944 assert(_pFileDlg && "SmViewShell::DialogClosedHdl(): no file dialog");
1945 assert(pImpl->pDocInserter && "ScDocShell::DialogClosedHdl(): no document inserter");
1947 if ( ERRCODE_NONE == _pFileDlg->GetError() )
1949 SfxMedium* pMedium = pImpl->pDocInserter->CreateMedium();
1951 if ( pMedium != NULL )
1953 if ( pMedium->IsStorage() )
1954 Insert( *pMedium );
1955 else
1956 InsertFrom( *pMedium );
1957 delete pMedium;
1959 SmDocShell* pDoc = GetDoc();
1960 pDoc->UpdateText();
1961 pDoc->ArrangeFormula();
1962 pDoc->Repaint();
1963 // adjust window, repaint, increment ModifyCount,...
1964 GetViewFrame()->GetBindings().Invalidate(SID_GAPHIC_SM);
1968 pImpl->pRequest->SetReturnValue( SfxBoolItem( pImpl->pRequest->GetSlot(), true ) );
1969 pImpl->pRequest->Done();
1970 return 0;
1973 void SmViewShell::Notify( SfxBroadcaster& , const SfxHint& rHint )
1975 const SfxSimpleHint* pSimpleHint = dynamic_cast<const SfxSimpleHint*>(&rHint);
1976 if ( pSimpleHint )
1978 switch( pSimpleHint->GetId() )
1980 case SFX_HINT_MODECHANGED:
1981 case SFX_HINT_DOCCHANGED:
1982 GetViewFrame()->GetBindings().InvalidateAll(false);
1983 break;
1984 default:
1985 break;
1990 bool SmViewShell::IsInlineEditEnabled() const
1992 return pImpl->aOpts.IsExperimentalMode();
1995 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */