1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #include "precompiled_sw.hxx"
25
26 #include <AnnotationWin.hxx>
27
28 #include <AnnotationMenuButton.hxx>
29 #include <PostItMgr.hxx>
30
31 #include <annotation.hrc>
32 #include <popup.hrc>
33 #include <cmdid.h>
34
35 #include <vcl/menu.hxx>
36
37 #include <svl/undo.hxx>
38 #include <unotools/syslocale.hxx>
39 #include <svl/languageoptions.hxx>
40
41 #include <editeng/postitem.hxx>
42 #include <editeng/fhgtitem.hxx>
43 #include <editeng/langitem.hxx>
44
45 #include <editeng/editview.hxx>
46 #include <editeng/outliner.hxx>
47 #include <editeng/editeng.hxx>
48 #include <editeng/editobj.hxx>
49
50 #include <docufld.hxx> // SwPostItField
51 #include <txtfld.hxx>
52 #include <ndtxt.hxx>
53 #include <view.hxx>
54 #include <wrtsh.hxx>
55 #include <docsh.hxx>
56 #include <doc.hxx>
57 #include <IDocumentUndoRedo.hxx>
58 #include <SwUndoField.hxx>
59
60
61 namespace sw { namespace annotation {
62
SwAnnotationWin(SwEditWin & rEditWin,WinBits nBits,SwPostItMgr & aMgr,SwPostItBits aBits,SwSidebarItem & rSidebarItem,SwFmtFld * aField)63 SwAnnotationWin::SwAnnotationWin( SwEditWin& rEditWin,
64 WinBits nBits,
65 SwPostItMgr& aMgr,
66 SwPostItBits aBits,
67 SwSidebarItem& rSidebarItem,
68 SwFmtFld* aField )
69 : SwSidebarWin( rEditWin, nBits, aMgr, aBits, rSidebarItem )
70 , mpFmtFld(aField)
71 , mpFld( static_cast<SwPostItField*>(aField->GetField()))
72 , mpButtonPopup(0)
73 {
74 }
75
~SwAnnotationWin()76 SwAnnotationWin::~SwAnnotationWin()
77 {
78 delete mpButtonPopup;
79 }
80
SetPostItText()81 void SwAnnotationWin::SetPostItText()
82 {
83 // get text from SwPostItField and insert into our textview
84 Engine()->SetModifyHdl( Link() );
85 Engine()->EnableUndo( sal_False );
86 mpFld = static_cast<SwPostItField*>(mpFmtFld->GetField());
87 if( mpFld->GetTextObject() )
88 Engine()->SetText( *mpFld->GetTextObject() );
89 else
90 {
91 Engine()->Clear();
92 GetOutlinerView()->SetAttribs(DefaultItem());
93 GetOutlinerView()->InsertText(mpFld->GetPar2(),false);
94 }
95
96 Engine()->ClearModifyFlag();
97 Engine()->GetUndoManager().Clear();
98 Engine()->EnableUndo( sal_True );
99 Engine()->SetModifyHdl( LINK( this, SwAnnotationWin, ModifyHdl ) );
100 Invalidate();
101 }
102
UpdateData()103 void SwAnnotationWin::UpdateData()
104 {
105 if ( Engine()->IsModified() )
106 {
107 IDocumentUndoRedo & rUndoRedo(
108 DocView().GetDocShell()->GetDoc()->GetIDocumentUndoRedo());
109 ::std::auto_ptr<SwField> pOldField;
110 if (rUndoRedo.DoesUndo())
111 {
112 pOldField.reset(mpFld->Copy());
113 }
114 mpFld->SetPar2(Engine()->GetEditEngine().GetText());
115 mpFld->SetTextObject(Engine()->CreateParaObject());
116 if (rUndoRedo.DoesUndo())
117 {
118 SwTxtFld *const pTxtFld = mpFmtFld->GetTxtFld();
119 SwPosition aPosition( pTxtFld->GetTxtNode() );
120 aPosition.nContent = *pTxtFld->GetStart();
121 rUndoRedo.AppendUndo(
122 new SwUndoFieldFromDoc(aPosition, *pOldField, *mpFld, 0, true));
123 }
124 // so we get a new layout of notes (anchor position is still the same and we would otherwise not get one)
125 Mgr().SetLayout();
126 // #i98686# if we have several views, all notes should update their text
127 mpFmtFld->Broadcast(SwFmtFldHint( 0, SWFMTFLD_CHANGED));
128 DocView().GetDocShell()->SetModified();
129 }
130 Engine()->ClearModifyFlag();
131 Engine()->GetUndoManager().Clear();
132 }
133
Delete()134 void SwAnnotationWin::Delete()
135 {
136 SwSidebarWin::Delete();
137 // we delete the field directly, the Mgr cleans up the PostIt by listening
138 DocView().GetWrtShellPtr()->GotoField(*mpFmtFld);
139 GrabFocusToDocument();
140 DocView().GetWrtShellPtr()->DelRight();
141 }
142
GotoPos()143 void SwAnnotationWin::GotoPos()
144 {
145 DocView().GetDocShell()->GetWrtShell()->GotoField(*mpFmtFld);
146 }
147
MoveCaret()148 sal_uInt32 SwAnnotationWin::MoveCaret()
149 {
150 // if this is an answer, do not skip over all following ones, but insert directly behind the current one
151 // but when just leaving a note, skip all following ones as well to continue typing
152 return Mgr().IsAnswer()
153 ? 1
154 : 1 + CountFollowing();
155 }
156
157 //returns true, if there is another note right before this note
CalcFollow()158 bool SwAnnotationWin::CalcFollow()
159 {
160 SwTxtFld* pTxtFld = mpFmtFld->GetTxtFld();
161 SwPosition aPosition( pTxtFld->GetTxtNode() );
162 aPosition.nContent = *pTxtFld->GetStart();
163 SwTxtAttr * const pTxtAttr =
164 pTxtFld->GetTxtNode().GetTxtAttrForCharAt(
165 aPosition.nContent.GetIndex() - 1,
166 RES_TXTATR_ANNOTATION );
167 const SwField* pFld = pTxtAttr ? pTxtAttr->GetFmtFld().GetField() : 0;
168 return pFld && (pFld->Which()== RES_POSTITFLD);
169 }
170
171 // counts how many SwPostItField we have right after the current one
CountFollowing()172 sal_uInt32 SwAnnotationWin::CountFollowing()
173 {
174 sal_uInt32 aCount = 1; // we start with 1, so we have to subtract one at the end again
175 SwTxtFld* pTxtFld = mpFmtFld->GetTxtFld();
176 SwPosition aPosition( pTxtFld->GetTxtNode() );
177 aPosition.nContent = *pTxtFld->GetStart();
178
179 SwTxtAttr * pTxtAttr = pTxtFld->GetTxtNode().GetTxtAttrForCharAt(
180 aPosition.nContent.GetIndex() + 1,
181 RES_TXTATR_ANNOTATION );
182 SwField* pFld = pTxtAttr
183 ? const_cast<SwField*>(pTxtAttr->GetFmtFld().GetField())
184 : 0;
185 while ( pFld && ( pFld->Which()== RES_POSTITFLD ) )
186 {
187 aCount++;
188 pTxtAttr = pTxtFld->GetTxtNode().GetTxtAttrForCharAt(
189 aPosition.nContent.GetIndex() + aCount,
190 RES_TXTATR_ANNOTATION );
191 pFld = pTxtAttr
192 ? const_cast<SwField*>(pTxtAttr->GetFmtFld().GetField())
193 : 0;
194 }
195 return aCount - 1;
196 }
197
CreateMenuButton()198 MenuButton* SwAnnotationWin::CreateMenuButton()
199 {
200 mpButtonPopup = new PopupMenu(SW_RES(MN_ANNOTATION_BUTTON));
201 XubString aText = mpButtonPopup->GetItemText( FN_DELETE_NOTE_AUTHOR );
202 SwRewriter aRewriter;
203 aRewriter.AddRule(UNDO_ARG1,GetAuthor());
204 aText = aRewriter.Apply(aText);
205 mpButtonPopup->SetItemText(FN_DELETE_NOTE_AUTHOR,aText);
206 MenuButton* pMenuButton = new AnnotationMenuButton( *this );
207 pMenuButton->SetPopupMenu( mpButtonPopup );
208 pMenuButton->Show();
209 return pMenuButton;
210 }
211
InitAnswer(OutlinerParaObject * pText)212 void SwAnnotationWin::InitAnswer(OutlinerParaObject* pText)
213 {
214 //collect our old meta data
215 SwSidebarWin* pWin = Mgr().GetNextPostIt(KEY_PAGEUP, this);
216 const SvtSysLocale aSysLocale;
217 const LocaleDataWrapper& rLocalData = aSysLocale.GetLocaleData();
218 String aText = String(SW_RES(STR_REPLY));
219 SwRewriter aRewriter;
220 aRewriter.AddRule(UNDO_ARG1, pWin->GetAuthor());
221 aText = aRewriter.Apply(aText);
222 aText.Append(String(rtl::OUString::createFromAscii(" (") +
223 String(rLocalData.getDate( pWin->GetDate())) + rtl::OUString::createFromAscii(", ") +
224 String(rLocalData.getTime( pWin->GetTime(),false)) + rtl::OUString::createFromAscii("): \"")));
225 GetOutlinerView()->InsertText(aText,false);
226
227 // insert old, selected text or "..."
228 // TODO: iterate over all paragraphs, not only first one to find out if it is empty
229 if (pText->GetTextObject().GetText(0) != String(rtl::OUString::createFromAscii("")))
230 GetOutlinerView()->GetEditView().InsertText(pText->GetTextObject());
231 else
232 GetOutlinerView()->InsertText(rtl::OUString::createFromAscii("..."),false);
233 GetOutlinerView()->InsertText(rtl::OUString::createFromAscii("\"\n"),false);
234
235 GetOutlinerView()->SetSelection(ESelection(0, 0, EE_PARA_MAX, EE_INDEX_MAX));
236 SfxItemSet aAnswerSet( DocView().GetDocShell()->GetPool() );
237 aAnswerSet.Put(SvxFontHeightItem(200,80,EE_CHAR_FONTHEIGHT));
238 aAnswerSet.Put(SvxPostureItem(ITALIC_NORMAL,EE_CHAR_ITALIC));
239 GetOutlinerView()->SetAttribs(aAnswerSet);
240 GetOutlinerView()->SetSelection(ESelection(0, 0, EE_PARA_MAX, EE_INDEX_MAX));
241
242 //remove all attributes and reset our standard ones
243 GetOutlinerView()->GetEditView().RemoveAttribsKeepLanguages(true);
244 GetOutlinerView()->SetAttribs(DefaultItem());
245 // lets insert an undo step so the initial text can be easily deleted
246 // but do not use UpdateData() directly, would set modified state again and reentrance into Mgr
247 Engine()->SetModifyHdl( Link() );
248 IDocumentUndoRedo & rUndoRedo(
249 DocView().GetDocShell()->GetDoc()->GetIDocumentUndoRedo());
250 ::std::auto_ptr<SwField> pOldField;
251 if (rUndoRedo.DoesUndo())
252 {
253 pOldField.reset(mpFld->Copy());
254 }
255 mpFld->SetPar2(Engine()->GetEditEngine().GetText());
256 mpFld->SetTextObject(Engine()->CreateParaObject());
257 if (rUndoRedo.DoesUndo())
258 {
259 SwTxtFld *const pTxtFld = mpFmtFld->GetTxtFld();
260 SwPosition aPosition( pTxtFld->GetTxtNode() );
261 aPosition.nContent = *pTxtFld->GetStart();
262 rUndoRedo.AppendUndo(
263 new SwUndoFieldFromDoc(aPosition, *pOldField, *mpFld, 0, true));
264 }
265 Engine()->SetModifyHdl( LINK( this, SwAnnotationWin, ModifyHdl ) );
266 Engine()->ClearModifyFlag();
267 Engine()->GetUndoManager().Clear();
268 }
269
GetLanguage(void)270 SvxLanguageItem SwAnnotationWin::GetLanguage(void)
271 {
272 // set initial language for outliner
273 sal_uInt16 nScriptType = SvtLanguageOptions::GetScriptTypeOfLanguage( mpFld->GetLanguage() );
274 sal_uInt16 nLangWhichId = 0;
275 switch (nScriptType)
276 {
277 case SCRIPTTYPE_LATIN : nLangWhichId = EE_CHAR_LANGUAGE ; break;
278 case SCRIPTTYPE_ASIAN : nLangWhichId = EE_CHAR_LANGUAGE_CJK; break;
279 case SCRIPTTYPE_COMPLEX : nLangWhichId = EE_CHAR_LANGUAGE_CTL; break;
280 default: DBG_ERROR("GetLanguage: wrong script tye");
281 }
282 return SvxLanguageItem(mpFld->GetLanguage(),nLangWhichId);
283 }
284
IsProtected()285 bool SwAnnotationWin::IsProtected()
286 {
287 return SwSidebarWin::IsProtected() ||
288 GetLayoutStatus() == SwPostItHelper::DELETED ||
289 ( mpFmtFld ? mpFmtFld->IsProtect() : false );
290 }
291
GetAuthor()292 String SwAnnotationWin::GetAuthor()
293 {
294 return mpFld->GetPar1();
295 }
296
GetDate()297 Date SwAnnotationWin::GetDate()
298 {
299 return mpFld->GetDate();
300 }
301
GetTime()302 Time SwAnnotationWin::GetTime()
303 {
304 return mpFld->GetTime();
305 }
306
307 } } // end of namespace sw::annotation
308