1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 "sal/config.h"
22 #include <comphelper/string.hxx>
23 #include <officecfg/Office/Common.hxx>
24 #include <tools/gen.hxx>
25 #include <sfx2/imgmgr.hxx>
26 #include <sfx2/viewfrm.hxx>
27 #include <sfx2/dispatch.hxx>
28 #include <svx/ruler.hxx>
29 #include <svl/zforlist.hxx>
30 #include <svl/stritem.hxx>
32 #include "swtypes.hxx"
34 #include "swmodule.hxx"
38 #include "inputwin.hxx"
42 #include "cellatr.hxx"
46 // Only for the UpdateRange: Delete the box in which the stacked cursor is positioned.
51 #include "inputwin.hrc"
53 #include <IDocumentContentOperations.hxx>
55 SFX_IMPL_POS_CHILDWINDOW_WITHID( SwInputChild
, FN_EDIT_FORMULA
, SFX_OBJECTBAR_OBJECT
)
57 SwInputWindow::SwInputWindow( Window
* pParent
, SfxBindings
* pBind
)
58 : ToolBox( pParent
, SW_RES( RID_TBX_FORMULA
)),
59 aPos( this, SW_RES(ED_POS
)),
60 aEdit( this, WB_3DLOOK
|WB_TABSTOP
|WB_BORDER
|WB_NOHIDESELECTION
),
61 aPopMenu( SW_RES(MN_CALC_POPUP
)),
66 aAktTableName(aEmptyStr
)
72 bActive
= bIsTable
= bDelSel
= sal_False
;
76 aEdit
.SetSizePixel( aEdit
.CalcMinimumSize() );
78 SfxImageManager
* pManager
= SfxImageManager::GetImageManager( SW_MOD() );
79 pManager
->RegisterToolBox(this);
81 pView
= ::GetActiveView();
82 pWrtShell
= pView
? pView
->GetWrtShellPtr() : 0;
84 InsertWindow( ED_POS
, &aPos
, 0, 0);
85 InsertSeparator ( 1 );
87 InsertWindow( ED_FORMULA
, &aEdit
);
88 SetHelpId(ED_FORMULA
, HID_EDIT_FORMULA
);
90 SetItemImage( FN_FORMULA_CALC
, pManager
->GetImage(FN_FORMULA_CALC
));
91 SetItemImage( FN_FORMULA_CANCEL
, pManager
->GetImage(FN_FORMULA_CANCEL
));
92 SetItemImage( FN_FORMULA_APPLY
, pManager
->GetImage(FN_FORMULA_APPLY
));
94 SetItemBits( FN_FORMULA_CALC
, GetItemBits( FN_FORMULA_CALC
) | TIB_DROPDOWNONLY
);
95 SetDropdownClickHdl( LINK( this, SwInputWindow
, DropdownClickHdl
));
97 Size aSizeTbx
= CalcWindowSizePixel();
98 Size aEditSize
= aEdit
.GetSizePixel();
99 Rectangle
aItemRect( GetItemRect(FN_FORMULA_CALC
) );
100 long nMaxHeight
= (aEditSize
.Height() > aItemRect
.GetHeight()) ? aEditSize
.Height() : aItemRect
.GetHeight();
101 if( nMaxHeight
+2 > aSizeTbx
.Height() )
102 aSizeTbx
.Height() = nMaxHeight
+2;
103 Size aSize
= GetSizePixel();
104 aSize
.Height() = aSizeTbx
.Height();
105 SetSizePixel( aSize
);
107 // align edit and item vcentered
108 Size aPosSize
= aPos
.GetSizePixel();
109 aPosSize
.Height() = nMaxHeight
;
110 aEditSize
.Height() = nMaxHeight
;
111 Point aPosPos
= aPos
.GetPosPixel();
112 Point aEditPos
= aEdit
.GetPosPixel();
113 aPosPos
.Y() = (aSize
.Height() - nMaxHeight
)/2 + 1;
114 aEditPos
.Y() = (aSize
.Height() - nMaxHeight
)/2 + 1;
115 aPos
.SetPosSizePixel( aPosPos
, aPosSize
);
116 aEdit
.SetPosSizePixel( aEditPos
, aEditSize
);
118 aPopMenu
.SetSelectHdl(LINK( this, SwInputWindow
, MenuHdl
));
121 SwInputWindow::~SwInputWindow()
123 SfxImageManager::GetImageManager( SW_MOD() )->ReleaseToolBox(this);
128 pView
->GetHRuler().SetActive( sal_True
);
129 pView
->GetVRuler().SetActive( sal_True
);
133 pWrtShell
->EndSelTblCells();
135 CleanupUglyHackWithUndo();
138 void SwInputWindow::CleanupUglyHackWithUndo()
143 pWrtShell
->DoUndo(m_bDoesUndo
);
148 m_bResetUndo
= false; // #i117122# once is enough :)
152 void SwInputWindow::DataChanged( const DataChangedEvent
& rDCEvt
)
154 if ( rDCEvt
.GetType() == DATACHANGED_SETTINGS
&& (rDCEvt
.GetFlags() & SETTINGS_STYLE
) )
156 // update item images
157 SwModule
*pMod
= SW_MOD();
158 SfxImageManager
*pImgMgr
= SfxImageManager::GetImageManager( pMod
);
159 SetItemImage( FN_FORMULA_CALC
, pImgMgr
->GetImage(FN_FORMULA_CALC
));
160 SetItemImage( FN_FORMULA_CANCEL
, pImgMgr
->GetImage(FN_FORMULA_CANCEL
));
161 SetItemImage( FN_FORMULA_APPLY
, pImgMgr
->GetImage(FN_FORMULA_APPLY
));
164 ToolBox::DataChanged( rDCEvt
);
167 void SwInputWindow::Resize()
171 long nWidth
= GetSizePixel().Width();
172 long nLeft
= aEdit
.GetPosPixel().X();
173 Size aEditSize
= aEdit
.GetSizePixel();
175 aEditSize
.Width() = std::max( ((long)(nWidth
- nLeft
- 5)), (long)0 );
176 aEdit
.SetSizePixel( aEditSize
);
180 void SwInputWindow::ShowWin()
182 bIsTable
= sal_False
;
186 pView
->GetHRuler().SetActive( sal_False
);
187 pView
->GetVRuler().SetActive( sal_False
);
189 OSL_ENSURE(pWrtShell
, "no WrtShell!");
191 bIsTable
= pWrtShell
->IsCrsrInTbl() ? sal_True
: sal_False
;
194 pWrtShell
->SelTblCells( LINK( this, SwInputWindow
,
195 SelTblCellsNotify
) );
198 const String
& rPos
= pWrtShell
->GetBoxNms();
201 while( (nPos
= rPos
.Search( ':',nPos
+ 1 ) ) != STRING_NOTFOUND
)
202 nSrch
= (short) nPos
;
203 aPos
.SetText( rPos
.Copy( ++nSrch
) );
204 aAktTableName
= pWrtShell
->GetTableFmt()->GetName();
207 aPos
.SetText(SW_RESSTR(STR_TBL_FORMULA
));
209 // Edit current field
210 OSL_ENSURE(pMgr
== 0, "FieldManager not deleted");
213 // Formular should always begin with "=" , so set here
214 String sEdit
= OUString('=');
215 if( pMgr
->GetCurFld() && TYP_FORMELFLD
== pMgr
->GetCurTypeId() )
217 sEdit
+= pMgr
->GetCurFldPar2();
225 officecfg::Office::Common::Undo::Steps::get() <= 0,
226 "sw", "/org.openoffice.Office.Common/Undo/Steps <= 0");
228 m_bDoesUndo
= pWrtShell
->DoesUndo();
231 pWrtShell
->DoUndo( sal_True
);
234 if( !pWrtShell
->SwCrsrShell::HasSelection() )
236 pWrtShell
->MoveSection( fnSectionCurr
, fnSectionStart
);
237 pWrtShell
->SetMark();
238 pWrtShell
->MoveSection( fnSectionCurr
, fnSectionEnd
);
240 if( pWrtShell
->SwCrsrShell::HasSelection() )
242 pWrtShell
->StartUndo( UNDO_DELETE
);
244 if( 0 != pWrtShell
->EndUndo( UNDO_DELETE
))
249 pWrtShell
->DoUndo(false);
251 SfxItemSet
aSet( pWrtShell
->GetAttrPool(), RES_BOXATR_FORMULA
, RES_BOXATR_FORMULA
);
252 if( pWrtShell
->GetTblBoxFormulaAttrs( aSet
))
253 sEdit
+= ((SwTblBoxFormula
&)aSet
.Get( RES_BOXATR_FORMULA
)).GetFormula();
259 // Set WrtShell flags correctly
260 pWrtShell
->SttSelect();
261 pWrtShell
->EndSelect();
266 aEdit
.SetModifyHdl( LINK( this, SwInputWindow
, ModifyHdl
));
268 aEdit
.SetText( sEdit
);
269 aEdit
.SetSelection( Selection( sEdit
.Len(), sEdit
.Len() ) );
275 // For input cut the UserInterface
277 pView
->GetEditWin().LockKeyInput(sal_True
);
278 pView
->GetViewFrame()->GetDispatcher()->Lock(sal_True
);
284 IMPL_LINK( SwInputWindow
, MenuHdl
, Menu
*, pMenu
)
286 static const char * const aStrArr
[] = {
314 sal_uInt16 nId
= pMenu
->GetCurItemId();
315 if ( nId
<= MN_CALC_ROUND
)
317 String
aTmp( OUString::createFromAscii(aStrArr
[nId
- 1]) );
319 aEdit
.ReplaceSelected( aTmp
);
324 IMPL_LINK_NOARG(SwInputWindow
, DropdownClickHdl
)
326 sal_uInt16 nCurID
= GetCurItemId();
327 EndSelection(); // reset back CurItemId !
330 case FN_FORMULA_CALC
:
332 aPopMenu
.Execute( this, GetItemRect( FN_FORMULA_CALC
), POPUPMENU_NOMOUSEUPCLOSE
);
342 void SwInputWindow::Click( )
344 sal_uInt16 nCurID
= GetCurItemId();
345 EndSelection(); // reset back CurItemId !
348 case FN_FORMULA_CANCEL
:
353 case FN_FORMULA_APPLY
:
361 void SwInputWindow::ApplyFormula()
363 pView
->GetViewFrame()->GetDispatcher()->Lock(sal_False
);
364 pView
->GetEditWin().LockKeyInput(sal_False
);
365 CleanupUglyHackWithUndo();
366 pWrtShell
->Pop( sal_False
);
368 // Formular should always begin with "=", so remove it here again
369 String
sEdit(comphelper::string::strip(aEdit
.GetText(), ' '));
370 if( sEdit
.Len() && '=' == sEdit
.GetChar( 0 ) )
372 SfxStringItem
aParam(FN_EDIT_FORMULA
, sEdit
);
374 pWrtShell
->EndSelTblCells();
375 pView
->GetEditWin().GrabFocus();
376 const SfxPoolItem
* aArgs
[2];
379 pView
->GetViewFrame()->GetBindings().Execute( FN_EDIT_FORMULA
, aArgs
, 0, SFX_CALLMODE_ASYNCHRON
);
382 void SwInputWindow::CancelFormula()
386 pView
->GetViewFrame()->GetDispatcher()->Lock( sal_False
);
387 pView
->GetEditWin().LockKeyInput(sal_False
);
388 CleanupUglyHackWithUndo();
389 pWrtShell
->Pop( sal_False
);
392 pWrtShell
->EnterStdMode();
394 pWrtShell
->EndSelTblCells();
396 pView
->GetEditWin().GrabFocus();
398 pView
->GetViewFrame()->GetDispatcher()->Execute( FN_EDIT_FORMULA
, SFX_CALLMODE_ASYNCHRON
);
401 const sal_Unicode CH_LRE
= 0x202a;
402 const sal_Unicode CH_PDF
= 0x202c;
404 IMPL_LINK( SwInputWindow
, SelTblCellsNotify
, SwWrtShell
*, pCaller
)
408 SwFrmFmt
* pTblFmt
= pCaller
->GetTableFmt();
409 String
sBoxNms( pCaller
->GetBoxNms() );
411 if( pTblFmt
&& aAktTableName
!= pTblFmt
->GetName() )
412 sTblNm
= pTblFmt
->GetName();
414 aEdit
.UpdateRange( sBoxNms
, sTblNm
);
418 sNew
+= aEdit
.GetText();
421 if( sNew
!= sOldFml
)
423 // The WrtShell is in the table selection,
424 // then cancel the table selection otherwise, the cursor is
425 // positioned "in the forest" and the live update does not work!
426 pWrtShell
->StartAllAction();
428 SwPaM
aPam( *pWrtShell
->GetStkCrsr()->GetPoint() );
429 aPam
.Move( fnMoveBackward
, fnGoSection
);
431 aPam
.Move( fnMoveForward
, fnGoSection
);
433 IDocumentContentOperations
* pIDCO
= pWrtShell
->getIDocumentContentOperations();
434 pIDCO
->DeleteRange( aPam
);
435 pIDCO
->InsertString( aPam
, sNew
);
436 pWrtShell
->EndAllAction();
446 void SwInputWindow::SetFormula( const String
& rFormula
, sal_Bool bDelFlag
)
448 String sEdit
= OUString('=');
451 if( '=' == rFormula
.GetChar( 0 ) )
456 aEdit
.SetText( sEdit
);
457 aEdit
.SetSelection( Selection( sEdit
.Len(), sEdit
.Len() ) );
462 IMPL_LINK_NOARG(SwInputWindow
, ModifyHdl
)
464 if (bIsTable
&& m_bResetUndo
)
466 pWrtShell
->StartAllAction();
470 sNew
+= aEdit
.GetText();
472 pWrtShell
->SwEditShell::Insert2( sNew
);
473 pWrtShell
->EndAllAction();
480 void SwInputWindow::DelBoxCntnt()
484 pWrtShell
->StartAllAction();
485 pWrtShell
->ClearMark();
486 pWrtShell
->Pop( sal_False
);
488 pWrtShell
->MoveSection( fnSectionCurr
, fnSectionStart
);
489 pWrtShell
->SetMark();
490 pWrtShell
->MoveSection( fnSectionCurr
, fnSectionEnd
);
491 pWrtShell
->SwEditShell::Delete();
492 pWrtShell
->EndAllAction();
496 void InputEdit::KeyInput(const KeyEvent
& rEvent
)
498 const KeyCode aCode
= rEvent
.GetKeyCode();
499 if(aCode
== KEY_RETURN
|| aCode
== KEY_F2
)
500 ((SwInputWindow
*)GetParent())->ApplyFormula();
501 else if(aCode
== KEY_ESCAPE
)
502 ((SwInputWindow
*)GetParent())->CancelFormula();
504 Edit::KeyInput(rEvent
);
507 void InputEdit::UpdateRange(const String
& rBoxes
,
508 const String
& rName
)
515 const sal_Unicode cOpen
= '<', cClose
= '>',
517 String aPrefix
= rName
;
520 String aBoxes
= aPrefix
;
522 Selection
aSelection(GetSelection());
523 sal_uInt16 nSel
= (sal_uInt16
) aSelection
.Len();
524 // OS: The following expression ensures that in the overwrite mode,
525 // the selected closing parenthesis will be not deleted.
526 if( nSel
&& ( nSel
> 1 ||
527 GetText()[ (sal_uInt16
)aSelection
.Min() ] != cClose
))
530 aSelection
.Max() = aSelection
.Min();
531 String
aActText(GetText());
532 const sal_uInt16 nLen
= aActText
.Len();
535 String aStr
= OUStringBuffer().
536 append(cOpen
).append(aBoxes
).append(cClose
).
537 makeStringAndClear();
539 sal_uInt16 nPos
= aStr
.Search( cClose
);
540 OSL_ENSURE(nPos
< aStr
.Len(), "delimiter not found");
542 SetSelection( Selection( nPos
, nPos
));
548 sal_uInt16 nPos
, nEndPos
= 0, nStartPos
= (sal_uInt16
) aSelection
.Min();
552 if( cOpen
== (cCh
= aActText
.GetChar( nStartPos
) ) ||
553 cOpenBracket
== cCh
)
555 bFound
= cCh
== cOpen
;
558 } while( nStartPos
-- > 0 );
564 while( nEndPos
< nLen
)
566 if( cClose
== (cCh
= aActText
.GetChar( nEndPos
)))
573 // Only if the current position lies in the range or right behind.
574 if( bFound
&& !( nStartPos
< (sal_uInt16
)aSelection
.Max() &&
575 (sal_uInt16
)aSelection
.Max() <= nEndPos
+ 1 ))
580 nPos
= ++nStartPos
+ 1; // We want behind
581 aActText
.Erase( nStartPos
, nEndPos
- nStartPos
);
582 aActText
.Insert( aBoxes
, nStartPos
);
583 nPos
= nPos
+ aBoxes
.Len();
587 OUString aTmp
= OUStringBuffer().
588 append(cOpen
).append(aBoxes
).append(cClose
).
589 makeStringAndClear();
590 nPos
= (sal_uInt16
)aSelection
.Min();
591 aActText
.Insert( aTmp
, nPos
);
592 nPos
= nPos
+ aTmp
.getLength();
594 if( GetText() != OUString(aActText
) )
597 SetSelection( Selection( nPos
, nPos
) );
604 SwInputChild::SwInputChild(Window
* _pParent
,
606 SfxBindings
* pBindings
,
608 SfxChildWindow( _pParent
, nId
)
610 pDispatch
= pBindings
->GetDispatcher();
611 pWindow
= new SwInputWindow( _pParent
, pBindings
);
612 ((SwInputWindow
*)pWindow
)->ShowWin();
613 eChildAlignment
= SFX_ALIGN_LOWESTTOP
;
616 SwInputChild::~SwInputChild()
619 pDispatch
->Lock(sal_False
);
623 SfxChildWinInfo
SwInputChild::GetInfo() const
625 SfxChildWinInfo aInfo
= SfxChildWindow::GetInfo(); \
629 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */