1 /* -*- mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: t -*- */
2 /* AbiWord
3 * Copyright (C) 1998-2000 AbiSource, Inc.
4 * Copyright (c) 2001,2002 Tomas Frydrych
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301 USA.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <ctype.h>
29 #include <string.h>
30 #include <glib.h>
31 #include "ut_locale.h"
32 #include "pf_Frag.h"
33 #include "pf_Frag_Strux.h"
34 #include "ut_assert.h"
35 #include "ut_debugmsg.h"
36 #include "ut_growbuf.h"
37 #include "ev_Mouse.h"
38 #include "ut_misc.h"
39 #include "ut_string.h"
40 #include "ut_std_string.h"
41 #include "ut_bytebuf.h"
42 #include "ut_timer.h"
43 #include "ie_imp_RTF.h"
44 #include "ie_exp_RTF.h"
45 #include "xav_View.h"
46 #include "fl_DocLayout.h"
47 #include "fl_BlockLayout.h"
48 #ifdef ENABLE_SPELL
49 #include "fl_Squiggles.h"
50 #endif
51 #include "fl_SectionLayout.h"
52 #include "fl_FootnoteLayout.h"
53 #include "fl_AutoNum.h"
54 #include "fp_Page.h"
55 #include "fp_PageSize.h"
56 #include "fp_Column.h"
57 #include "fp_Line.h"
58 #include "fp_Run.h"
59 #include "fp_TextRun.h"
60 #include "xap_Module.h"
61 #include "fg_Graphic.h"
62 #include "fg_GraphicRaster.h"
63 #include "pd_Document.h"
64 #include "pd_DocumentRDF.h"
65 #include "pd_Style.h"
66 #include "pp_Property.h"
67 #include "pp_AttrProp.h"
68 #include "gr_Graphics.h"
69 #include "gr_DrawArgs.h"
70 #include "ie_types.h"
71 #include "xap_App.h"
72 #include "xap_Frame.h"
73 #include "xap_Clipboard.h"
74 #include "ap_Features.h"
75 #include "ap_TopRuler.h"
76 #include "ap_LeftRuler.h"
77 #include "ap_Prefs.h"
78 #include "ap_Strings.h"
79 #include "fd_Field.h"
80 #ifdef ENABLE_SPELL
81 #include "spell_manager.h"
82 #endif
83 #include "ut_rand.h"
84 #include "fp_TableContainer.h"
85 #include "fl_TableLayout.h"
86 #include "xap_Dlg_Zoom.h"
87 #include "ap_Frame.h"
88 #include "ap_FrameData.h"
89 #include "fp_FrameContainer.h"
90 #include "xap_EncodingManager.h"
91 #include "gr_Painter.h"
92 #include "xap_DialogFactory.h"
93 #include "ap_Preview_Annotation.h"
94 #include "ap_Dialog_Id.h"
95 #include "fv_ViewDoubleBuffering.h"
96
97 #include "pp_Revision.h"
98
99 #include "fv_View.h"
100
101 // NB -- irrespective of this size, the piecetable will store
102 // at max BOOKMARK_NAME_LIMIT of chars as defined in pf_Frag_Bookmark.h
103 #define BOOKMARK_NAME_SIZE 30
104 #define CHECK_WINDOW_SIZE if(getWindowHeight() < m_pG->tlu(20)) return;
105
106 // add 0.1 inch for a left border to click in for showBorder
107
108 #define FRAME_MARGIN 144
109 /****************************************************************/
110
111 class ABI_EXPORT _fmtPair
112 {
113 public:
_fmtPair(const gchar * p,const PP_AttrProp * c,const PP_AttrProp * b,const PP_AttrProp * s,PD_Document * pDoc,bool bExpandStyles)114 _fmtPair(const gchar * p,
115 const PP_AttrProp * c, const PP_AttrProp * b, const PP_AttrProp * s,
116 PD_Document * pDoc, bool bExpandStyles)
117 {
118 m_prop = p;
119 m_val = PP_evalProperty(p,c,b,s, pDoc, bExpandStyles);
120 }
121
122 const gchar * m_prop;
123 const gchar * m_val;
124 };
125
126 class ABI_EXPORT FV_Caret_Listener : public AV_Listener
127 {
128 public:
FV_Caret_Listener(XAP_Frame * pFrame)129 FV_Caret_Listener(XAP_Frame * pFrame) : m_pFrame (pFrame) {}
~FV_Caret_Listener()130 virtual ~FV_Caret_Listener (){}
131
notify(AV_View * pView,const AV_ChangeMask mask)132 virtual bool notify(AV_View * pView, const AV_ChangeMask mask)
133 {
134 GR_Graphics *pG = static_cast<FV_View *>(pView)->getGraphics();
135
136 if (m_pFrame && (mask & (AV_CHG_INSERTMODE)))
137 {
138 AP_FrameData * pData = static_cast<AP_FrameData *>(m_pFrame->getFrameData());
139 if (pData)
140 {
141 pG->allCarets()->setInsertMode(pData->m_bInsertMode);
142 return true;
143 }
144 }
145
146 if (
147 // I hope I have all the signals here that makes sense for re-enabling the caret blink
148 // after it was stopped by a cursor blink timeout timer - MARCM
149 ((mask & AV_CHG_KEYPRESSED) ||
150 (mask & AV_CHG_TYPING) ||
151 (mask & AV_CHG_MOTION) ) && pG->allCarets()->getBaseCaret()
152 )
153 {
154 pG->allCarets()->getBaseCaret()->resetBlinkTimeout();
155 return true;
156 }
157
158 return false;
159 }
160
getType(void)161 virtual AV_ListenerType getType(void) {return AV_LISTENER_CARET;}
162
163 private:
164 XAP_Frame * m_pFrame;
165 GR_Graphics * m_pGraphics;
166 };
167
168
fv_CaretProps(FV_View * pView,PT_DocPosition InsPoint)169 fv_CaretProps::fv_CaretProps(FV_View * pView, PT_DocPosition InsPoint):
170 m_iInsPoint(InsPoint),
171 m_xPoint(0),
172 m_yPoint(0),
173 m_xPoint2(0),
174 m_yPoint2(0),
175 m_bPointDirection(false),
176 m_bDefaultDirectionRtl(false),
177 m_bUseHebrewContextGlyphs(false),
178 m_bPointEOL(false),
179 m_iPointHeight(0),
180 m_caretColor(0,0,0),
181 m_PropCaretListner(NULL),
182 m_pCaret(NULL),
183 m_ListenerID(0),
184 m_pView(pView),
185 m_iAuthorId(-1),
186 m_sCaretID("")
187 {
188 }
189
~fv_CaretProps(void)190 fv_CaretProps::~fv_CaretProps(void)
191 {
192 if(m_PropCaretListner != NULL)
193 {
194 DELETEP(m_PropCaretListner);
195 }
196 }
197
198 /****************************************************************/
199 #ifdef _MSC_VER // MSVC++ warns about using 'this' in initializer list.
200 #pragma warning(disable: 4355)
201 #endif
FV_View(XAP_App * pApp,void * pParentData,FL_DocLayout * pLayout)202 FV_View::FV_View(XAP_App * pApp, void* pParentData, FL_DocLayout* pLayout)
203 : AV_View(pApp, pParentData),
204 m_iNumHorizPages(1), /* This should probably be grabbed from a preference or something */
205 m_autoNumHorizPages(true), /* Same here */
206 m_horizPageSpacing(500),
207 m_iInsPoint(0),
208 m_xPoint(0),
209 m_yPoint(0),
210 m_xPoint2(0),
211 m_yPoint2(0),
212 m_bPointDirection(false) /* now what semantics is this? */,
213 m_bDefaultDirectionRtl(false),
214 m_bUseHebrewContextGlyphs(false),
215 m_iPointHeight(0),
216 m_xPointSticky(0),
217 m_bPointVisible(false),
218 m_bPointEOL(false),
219 m_pLayout(pLayout),
220 m_pDoc(pLayout->getDocument()),
221 m_pG(m_pLayout->getGraphics()),
222 m_pParentData(pParentData),
223 m_pAutoScrollTimer(0),
224 m_xLastMouse(0),
225 m_yLastMouse(0),
226 m_bCursorIsOn(false),
227 m_bEraseSaysStopBlinking(false),
228 m_wrappedEnd(false),
229 m_startPosition(0),
230 m_doneFind(false),
231 m_bEditHdrFtr(false),
232 m_pEditShadow(NULL),
233 m_iSavedPosition(0),
234 m_bNeedSavedPosition(false),
235 m_bReverseFind(false),
236 m_bWholeWord(false),
237 m_bMatchCase(false),
238 m_sFind(0),
239 m_sReplace(0),
240 m_bShowPara(false),
241 #ifdef EMBEDDED_TARGET
242 m_viewMode(VIEW_NORMAL),
243 #else
244 m_viewMode(VIEW_PRINT),
245 #endif
246 m_previewMode(PREVIEW_NONE),
247 m_bDontUpdateScreenOnGeneralUpdate(false),
248 m_iPieceTableState(0),
249 m_iMouseX(0),
250 m_iMouseY(0),
251 m_iViewRevision(0),
252 m_bWarnedThatRestartNeeded(false),
253 m_selImageRect(-1,-1,-1,-1),
254 m_imageSelCursor(GR_Graphics::GR_CURSOR_IBEAM),
255 m_ixResizeOrigin(0),
256 m_iyResizeOrigin(0),
257 m_bIsResizingImage(false),
258 m_curImageSel(-1,-1,-1,-1),
259 #if XAP_DONTUSE_XOR
260 m_curImageSelCache(NULL),
261 #endif
262 m_bIsDraggingImage(false),
263 m_pDraggedImageRun(NULL),
264 m_dragImageRect(-1,-1,-1,-1),
265 m_ixDragOrigin(0),
266 m_iyDragOrigin(0),
267 m_colorShowPara(127,127,127),
268 m_colorSpellSquiggle(255, 0, 0),
269 m_colorGrammarSquiggle(0, 192, 0),
270 m_colorMargin(127, 127, 127),
271 m_colorFieldOffset(10, 10, 10),
272 m_colorImage(0, 0, 255),
273 m_colorImageResize(0, 0, 0),
274 m_colorHyperLink(0, 0, 255),
275 m_colorHdrFtr(0, 0, 0),
276 m_colorColumnLine(0, 0, 0),
277 m_countDisable(0),
278 m_bDragTableLine(false),
279 m_prevMouseContext(EV_EMC_UNKNOWN),
280 m_pTopRuler(NULL),
281 m_pLeftRuler(NULL),
282 m_bInFootnote(false),
283 m_bgColorInitted(false),
284 m_iLowDrawPoint(0),
285 m_iHighDrawPoint(0),
286 m_CaretListID(0),
287 m_FrameEdit(this),
288 m_VisualDragText(this),
289 m_Selection(this),
290 m_bShowRevisions(true),
291 m_eBidiOrder(FV_Order_Visual),
292 m_iFreePass(0),
293 m_bDontNotifyListeners(false),
294 m_pLocalBuf(NULL),
295 m_iGrabCell(0),
296 m_InlineImage(this),
297 m_bInsertAtTablePending(false),
298 m_iPosAtTable(0),
299 m_bAnnotationPreviewActive(false),
300 m_bAllowSmartQuoteReplacement(true),
301 m_bubbleBlockerCount(0),
302 m_iOldPageCount(-1),
303 m_SelectionHandles(this, m_Selection),
304 m_pViewDoubleBufferingObject(NULL)
305 {
306 if(m_pDoc)
307 m_sDocUUID = m_pDoc->getMyUUIDString();
308 m_colorRevisions[0] = UT_RGBColor(171,4,254);
309 m_colorRevisions[1] = UT_RGBColor(171,20,119);
310 m_colorRevisions[2] = UT_RGBColor(255,151,8);
311 m_colorRevisions[3] = UT_RGBColor(158,179,69);
312 m_colorRevisions[4] = UT_RGBColor(15,179,5);
313 m_colorRevisions[5] = UT_RGBColor(8,179,248);
314 m_colorRevisions[6] = UT_RGBColor(4,206,195);
315 m_colorRevisions[7] = UT_RGBColor(4,133,195);
316 m_colorRevisions[8] = UT_RGBColor(7,18,195);
317 m_colorRevisions[9] = UT_RGBColor(255,0,0); // catch-all
318
319 //
320 m_colorAnnotations[0] = UT_RGBColor(171,4,254);
321 m_colorAnnotations[1] = UT_RGBColor(171,20,119);
322 m_colorAnnotations[2] = UT_RGBColor(255,151,8);
323 m_colorAnnotations[3] = UT_RGBColor(158,179,69);
324 m_colorAnnotations[4] = UT_RGBColor(15,179,5);
325 m_colorAnnotations[5] = UT_RGBColor(8,179,248);
326 m_colorAnnotations[6] = UT_RGBColor(4,206,195);
327 m_colorAnnotations[7] = UT_RGBColor(4,133,195);
328 m_colorAnnotations[8] = UT_RGBColor(7,18,195);
329 m_colorAnnotations[9] = UT_RGBColor(255,0,0); // catch-all
330
331 //
332 m_colorRDFAnchors[0] = UT_RGBColor(171,4,254);
333 m_colorRDFAnchors[1] = UT_RGBColor(171,20,119);
334 m_colorRDFAnchors[2] = UT_RGBColor(255,151,8);
335 m_colorRDFAnchors[3] = UT_RGBColor(158,179,69);
336 m_colorRDFAnchors[4] = UT_RGBColor(15,179,5);
337 m_colorRDFAnchors[5] = UT_RGBColor(8,179,248);
338 m_colorRDFAnchors[6] = UT_RGBColor(4,206,195);
339 m_colorRDFAnchors[7] = UT_RGBColor(4,133,195);
340 m_colorRDFAnchors[8] = UT_RGBColor(7,18,195);
341 m_colorRDFAnchors[9] = UT_RGBColor(255,0,0); // catch-all
342
343
344 // initialize prefs cache
345 pApp->getPrefsValueBool(AP_PREF_KEY_CursorBlink, &m_bCursorBlink);
346
347 const gchar * pszTmpColor = NULL;
348 if (pApp->getPrefsValue(static_cast<const gchar *>(XAP_PREF_KEY_ColorForShowPara), &pszTmpColor))
349 {
350 UT_parseColor(pszTmpColor, m_colorShowPara);
351 }
352 if (pApp->getPrefsValue(static_cast<const gchar *>(XAP_PREF_KEY_ColorForSquiggle), &pszTmpColor))
353 {
354 UT_parseColor(pszTmpColor, m_colorSpellSquiggle);
355 }
356 if (pApp->getPrefsValue(static_cast<const gchar *>(XAP_PREF_KEY_ColorForGrammarSquiggle), &pszTmpColor))
357 {
358 UT_parseColor(pszTmpColor, m_colorGrammarSquiggle);
359 }
360 if (pApp->getPrefsValue(static_cast<const gchar *>(XAP_PREF_KEY_ColorForMargin), &pszTmpColor))
361 {
362 UT_parseColor(pszTmpColor, m_colorMargin);
363 }
364 if (pApp->getPrefsValue(static_cast<const gchar *>(XAP_PREF_KEY_ColorForFieldOffset), &pszTmpColor))
365 {
366 UT_parseColor(pszTmpColor, m_colorFieldOffset);
367 }
368 if (pApp->getPrefsValue(static_cast<const gchar *>(XAP_PREF_KEY_ColorForImage), &pszTmpColor))
369 {
370 UT_parseColor(pszTmpColor, m_colorImage);
371 }
372 if (pApp->getPrefsValue(static_cast<const gchar *>(XAP_PREF_KEY_ColorForHyperLink), &pszTmpColor))
373 {
374 UT_parseColor(pszTmpColor, m_colorHyperLink);
375 }
376 if (pApp->getPrefsValue(static_cast<const gchar *>(XAP_PREF_KEY_ColorForHdrFtr), &pszTmpColor))
377 {
378 UT_parseColor(pszTmpColor, m_colorHdrFtr);
379 }
380 if (pApp->getPrefsValue(static_cast<const gchar *>(XAP_PREF_KEY_ColorForColumnLine), &pszTmpColor))
381 {
382 UT_parseColor(pszTmpColor, m_colorColumnLine);
383 }
384 if (pApp->getPrefsValue(static_cast<const gchar *>(XAP_PREF_KEY_ColorForRevision1), &pszTmpColor))
385 {
386 UT_parseColor(pszTmpColor, m_colorRevisions[0]);
387 }
388 if (pApp->getPrefsValue(static_cast<const gchar *>(XAP_PREF_KEY_ColorForRevision2), &pszTmpColor))
389 {
390 UT_parseColor(pszTmpColor, m_colorRevisions[1]);
391 }
392 if (pApp->getPrefsValue(static_cast<const gchar *>(XAP_PREF_KEY_ColorForRevision3), &pszTmpColor))
393 {
394 UT_parseColor(pszTmpColor, m_colorRevisions[2]);
395 }
396 if (pApp->getPrefsValue(static_cast<const gchar *>(XAP_PREF_KEY_ColorForRevision4), &pszTmpColor))
397 {
398 UT_parseColor(pszTmpColor, m_colorRevisions[3]);
399 }
400 if (pApp->getPrefsValue(static_cast<const gchar *>(XAP_PREF_KEY_ColorForRevision5), &pszTmpColor))
401 {
402 UT_parseColor(pszTmpColor, m_colorRevisions[4]);
403 }
404 if (pApp->getPrefsValue(static_cast<const gchar *>(XAP_PREF_KEY_ColorForRevision6), &pszTmpColor))
405 {
406 UT_parseColor(pszTmpColor, m_colorRevisions[5]);
407 }
408 if (pApp->getPrefsValue(static_cast<const gchar *>(XAP_PREF_KEY_ColorForRevision7), &pszTmpColor))
409 {
410 UT_parseColor(pszTmpColor, m_colorRevisions[6]);
411 }
412 if (pApp->getPrefsValue(static_cast<const gchar *>(XAP_PREF_KEY_ColorForRevision8), &pszTmpColor))
413 {
414 UT_parseColor(pszTmpColor, m_colorRevisions[7]);
415 }
416 if (pApp->getPrefsValue(static_cast<const gchar *>(XAP_PREF_KEY_ColorForRevision9), &pszTmpColor))
417 {
418 UT_parseColor(pszTmpColor, m_colorRevisions[8]);
419 }
420 if (pApp->getPrefsValue(static_cast<const gchar *>(XAP_PREF_KEY_ColorForRevision10), &pszTmpColor))
421 {
422 UT_parseColor(pszTmpColor, m_colorRevisions[9]);
423 }
424
425
426 if (pApp->getPrefsValue(static_cast<const gchar *>(AP_PREF_KEY_ColorForAnnotation1), &pszTmpColor))
427 {
428 UT_parseColor(pszTmpColor, m_colorAnnotations[0]);
429 }
430 if (pApp->getPrefsValue(static_cast<const gchar *>(AP_PREF_KEY_ColorForAnnotation2), &pszTmpColor))
431 {
432 UT_parseColor(pszTmpColor, m_colorAnnotations[1]);
433 }
434 if (pApp->getPrefsValue(static_cast<const gchar *>(AP_PREF_KEY_ColorForAnnotation3), &pszTmpColor))
435 {
436 UT_parseColor(pszTmpColor, m_colorAnnotations[2]);
437 }
438 if (pApp->getPrefsValue(static_cast<const gchar *>(AP_PREF_KEY_ColorForAnnotation4), &pszTmpColor))
439 {
440 UT_parseColor(pszTmpColor, m_colorAnnotations[3]);
441 }
442 if (pApp->getPrefsValue(static_cast<const gchar *>(AP_PREF_KEY_ColorForAnnotation5), &pszTmpColor))
443 {
444 UT_parseColor(pszTmpColor, m_colorAnnotations[4]);
445 }
446 if (pApp->getPrefsValue(static_cast<const gchar *>(AP_PREF_KEY_ColorForAnnotation6), &pszTmpColor))
447 {
448 UT_parseColor(pszTmpColor, m_colorAnnotations[5]);
449 }
450 if (pApp->getPrefsValue(static_cast<const gchar *>(AP_PREF_KEY_ColorForAnnotation7), &pszTmpColor))
451 {
452 UT_parseColor(pszTmpColor, m_colorAnnotations[6]);
453 }
454 if (pApp->getPrefsValue(static_cast<const gchar *>(AP_PREF_KEY_ColorForAnnotation8), &pszTmpColor))
455 {
456 UT_parseColor(pszTmpColor, m_colorAnnotations[7]);
457 }
458 if (pApp->getPrefsValue(static_cast<const gchar *>(AP_PREF_KEY_ColorForAnnotation9), &pszTmpColor))
459 {
460 UT_parseColor(pszTmpColor, m_colorAnnotations[8]);
461 }
462 if (pApp->getPrefsValue(static_cast<const gchar *>(AP_PREF_KEY_ColorForAnnotation10), &pszTmpColor))
463 {
464 UT_parseColor(pszTmpColor, m_colorAnnotations[9]);
465 }
466
467 ///////////////////
468 ///////////////////
469
470 if (pApp->getPrefsValue(static_cast<const gchar *>(AP_PREF_KEY_ColorForRDFAnchor1), &pszTmpColor))
471 {
472 UT_parseColor(pszTmpColor, m_colorRDFAnchors[0]);
473 }
474 if (pApp->getPrefsValue(static_cast<const gchar *>(AP_PREF_KEY_ColorForRDFAnchor2), &pszTmpColor))
475 {
476 UT_parseColor(pszTmpColor, m_colorRDFAnchors[1]);
477 }
478 if (pApp->getPrefsValue(static_cast<const gchar *>(AP_PREF_KEY_ColorForRDFAnchor3), &pszTmpColor))
479 {
480 UT_parseColor(pszTmpColor, m_colorRDFAnchors[2]);
481 }
482 if (pApp->getPrefsValue(static_cast<const gchar *>(AP_PREF_KEY_ColorForRDFAnchor4), &pszTmpColor))
483 {
484 UT_parseColor(pszTmpColor, m_colorRDFAnchors[3]);
485 }
486 if (pApp->getPrefsValue(static_cast<const gchar *>(AP_PREF_KEY_ColorForRDFAnchor5), &pszTmpColor))
487 {
488 UT_parseColor(pszTmpColor, m_colorRDFAnchors[4]);
489 }
490 if (pApp->getPrefsValue(static_cast<const gchar *>(AP_PREF_KEY_ColorForRDFAnchor6), &pszTmpColor))
491 {
492 UT_parseColor(pszTmpColor, m_colorRDFAnchors[5]);
493 }
494 if (pApp->getPrefsValue(static_cast<const gchar *>(AP_PREF_KEY_ColorForRDFAnchor7), &pszTmpColor))
495 {
496 UT_parseColor(pszTmpColor, m_colorRDFAnchors[6]);
497 }
498 if (pApp->getPrefsValue(static_cast<const gchar *>(AP_PREF_KEY_ColorForRDFAnchor8), &pszTmpColor))
499 {
500 UT_parseColor(pszTmpColor, m_colorRDFAnchors[7]);
501 }
502 if (pApp->getPrefsValue(static_cast<const gchar *>(AP_PREF_KEY_ColorForRDFAnchor9), &pszTmpColor))
503 {
504 UT_parseColor(pszTmpColor, m_colorRDFAnchors[8]);
505 }
506 if (pApp->getPrefsValue(static_cast<const gchar *>(AP_PREF_KEY_ColorForRDFAnchor10), &pszTmpColor))
507 {
508 UT_parseColor(pszTmpColor, m_colorRDFAnchors[9]);
509 }
510
511 ///////////////////
512 ///////////////////
513
514
515 // initialize prefs listener
516 pApp->getPrefs()->addListener( _prefsListener, this );
517
518 // Get View Mode
519 if(m_pG->queryProperties(GR_Graphics::DGP_SCREEN))
520 {
521 const char * szViewMode = NULL;
522 pApp->getPrefsValue(static_cast<const char *>(AP_PREF_KEY_LayoutMode),&szViewMode);
523 if(strcmp(szViewMode,"1") == 0)
524 {
525 setViewMode(VIEW_PRINT);
526 }
527 if(strcmp(szViewMode,"2") == 0)
528 {
529 setViewMode(VIEW_NORMAL);
530 }
531 if(strcmp(szViewMode,"3") == 0)
532 {
533 setViewMode(VIEW_WEB);
534 }
535 setCursorWait();
536 }
537
538 pApp->getPrefsValueBool(AP_PREF_KEY_DefaultDirectionRtl, &m_bDefaultDirectionRtl);
539 pApp->getPrefsValueBool(XAP_PREF_KEY_UseHebrewContextGlyphs, &m_bUseHebrewContextGlyphs);
540 /*
541 If the default direction indicated by the preferences is different
542 than the direction with which we were compiled, we need to modify
543 the default values stored in _props[] and also the direction
544 related properties of the Normal style (dir, dom-dir,
545 and text-align)
546 */
547
548 #ifndef BIDI_RTL_DOMINANT
549 if(m_bDefaultDirectionRtl)
550 {
551 //const gchar bidi_dir_name[] = "dir"; ###TF
552 const gchar bidi_dir_value[] = "rtl";
553 const gchar bidi_domdir_name[] = "dom-dir";
554 const gchar bidi_align_name[] = "text-align";
555 const gchar bidi_align_value[] = "right";
556
557 const gchar * bidi_props[5]= {/*bidi_dir_name, bidi_dir_value, */bidi_domdir_name, bidi_dir_value, bidi_align_name, bidi_align_value,0};
558
559 m_pDoc->addStyleProperties(static_cast<const gchar*>("Normal"), static_cast<const gchar**>(&bidi_props[0]));
560 PP_resetInitialBiDiValues("rtl");
561 }
562 #else
563 if(!m_bDefaultDirectionRtl)
564 {
565 //const gchar bidi_dir_name[] = "dir"; ###TF
566 const gchar bidi_dir_value[] = "ltr";
567 const gchar bidi_domdir_name[] = "dom-dir";
568 const gchar bidi_align_name[] = "text-align";
569 const gchar bidi_align_value[] = "left";
570
571 const gchar * bidi_props[5]= {/*bidi_dir_name, bidi_dir_value, */bidi_domdir_name, bidi_dir_value, bidi_align_name, bidi_align_value,0};
572
573 m_pDoc->addStyleProperties(static_cast<const gchar*>("Normal"), static_cast<const gchar**>(bidi_props));
574 PP_resetInitialBiDiValues("ltr");
575 }
576 #endif
577
578 UT_UTF8String s = XAP_EncodingManager::get_instance()->getLanguageISOName();
579
580 const char * pCountry
581 = XAP_EncodingManager::get_instance()->getLanguageISOTerritory();
582
583 if(pCountry)
584 {
585 s += "-";
586 s += pCountry;
587 }
588
589 // do a fuzzy match for Times New Roman
590 const char * pszFamily =
591 GR_Graphics::findNearestFont ("Times New Roman",
592 "normal", "normal",
593 "normal", "normal",
594 "12pt", s.utf8_str());
595
596 if (pszFamily)
597 PP_setDefaultFontFamily(pszFamily);
598
599 // should we display revisions?
600 m_bShowRevisions = m_pDoc->isShowRevisions();
601 m_iViewRevision = m_pDoc->getShowRevisionId();
602
603 // initialize change cache
604 m_chg.bUndo = false;
605 m_chg.bRedo = false;
606 m_chg.bDirty = false;
607 m_chg.bSelection = false;
608 m_chg.iColumn = 0; // current column number
609 m_chg.pCellLayout = NULL;
610 m_chg.propsChar = NULL;
611 m_chg.propsBlock = NULL;
612 m_chg.propsSection = NULL;
613
614 pLayout->setView(this);
615
616 //Test_Dump();
617
618 m_Selection.setSelectionAnchor(getPoint());
619 _resetSelection();
620 //
621 // Update the combo boxes on the frame with this documents info.
622 //
623 m_caretListener = NULL;
624 XAP_Frame * pFrame = static_cast<XAP_Frame*>(getParentData());
625 if( pFrame )
626 {
627 pFrame->repopulateCombos();
628 m_pG->createCaret();
629 m_pG->allCarets()->enable();
630 if(m_pG->queryProperties(GR_Graphics::DGP_SCREEN))
631 {
632 m_caretListener = new FV_Caret_Listener (pFrame);
633 addListener(m_caretListener, &m_CaretListID);
634 AP_FrameData *pFrameData = static_cast<AP_FrameData *>(pFrame->getFrameData());
635 if(pFrameData && pFrameData->m_bIsWidget)
636 {
637 setViewMode(VIEW_NORMAL);
638 //pFrame->toggleRuler(false);
639 //pFrame->toggleLeftRuler(false);
640 }
641 }
642 else
643 {
644 m_caretListener = NULL;
645 }
646 }
647
648 // see what the document value is for bidi ordering ...
649 const PP_AttrProp * pDocAP = m_pDoc->getAttrProp();
650 if(pDocAP)
651 {
652 const gchar * szValue;
653 pDocAP->getProperty("dom-dir",szValue);
654
655 if(szValue)
656 {
657 if(0 == strcmp(szValue, "logical-ltr"))
658 {
659 m_eBidiOrder = FV_Order_Logical_LTR;
660 }
661 else if(0 == strcmp(szValue, "logical-rtl"))
662 {
663 m_eBidiOrder = FV_Order_Logical_RTL;
664 }
665 }
666 }
667
668 }
669
~FV_View()670 FV_View::~FV_View()
671 {
672 // remove prefs listener
673 m_pApp->getPrefs()->removeListener( _prefsListener, this );
674
675 DELETEP(m_pAutoScrollTimer);
676 if(m_caretListener != NULL)
677 {
678 DELETEP(m_caretListener);
679 }
680
681 FREEP(m_sFind);
682 FREEP(m_sReplace);
683
684 FREEP(m_chg.propsChar);
685 FREEP(m_chg.propsBlock);
686 FREEP(m_chg.propsSection);
687 DELETEP(m_pLocalBuf);
688 UT_VECTOR_PURGEALL(fv_CaretProps *,m_vecCarets);
689 }
690
isActive(void) const691 bool FV_View::isActive(void) const
692 {
693 if(!couldBeActive())
694 return false;
695 const AV_View* pActiveView = NULL;
696 XAP_Frame* lff = getApp()->getLastFocussedFrame();
697 if(lff)
698 {
699 pActiveView = lff->getCurrentView();
700 }
701 else
702 {
703 pActiveView = this;
704 }
705
706 bool bAct = (pActiveView == this);
707 if(!bAct)
708 return false;
709 UT_UTF8String sUUID = m_pDoc->getMyUUIDString();
710 if(m_sDocUUID == sUUID)
711 return true;
712 return false;
713 }
714
setGraphics(GR_Graphics * pG)715 void FV_View::setGraphics(GR_Graphics * pG)
716 {
717 if(m_caretListener != NULL)
718 {
719 removeListener(m_CaretListID);
720 DELETEP(m_caretListener);
721 }
722 m_pG = pG;
723 if(m_pG->queryProperties(GR_Graphics::DGP_SCREEN))
724 {
725 m_pG->createCaret();
726 m_pG->allCarets()->enable();
727 XAP_Frame * pFrame = static_cast<XAP_Frame*>(getParentData());
728 m_caretListener = new FV_Caret_Listener (pFrame);
729 addListener(m_caretListener, &m_CaretListID);
730 }
731 else
732 {
733 m_caretListener = NULL;
734 }
735 }
736
registerDoubleBufferingObject(FV_ViewDoubleBuffering * obj)737 bool FV_View::registerDoubleBufferingObject(FV_ViewDoubleBuffering *obj)
738 {
739 if(m_pViewDoubleBufferingObject == NULL)
740 {
741 // ok, you're the top most one, I will register you
742 m_pViewDoubleBufferingObject = obj;
743 return true;
744 }
745 else return false;
746 }
747
unregisterDoubleBufferingObject(FV_ViewDoubleBuffering * obj)748 bool FV_View::unregisterDoubleBufferingObject(FV_ViewDoubleBuffering *obj)
749 {
750 if((void*)m_pViewDoubleBufferingObject == (void*)obj)
751 {
752 // you're the top most caller, I will unregister you
753 m_pViewDoubleBufferingObject = NULL;
754 return true;
755 }
756 else return false;
757 }
758
fixInsertionPointCoords(void)759 void FV_View:: fixInsertionPointCoords(void)
760 {
761 _fixInsertionPointCoords();
762 }
763
updateCarets(PT_DocPosition docPos,UT_sint32 iLen)764 void FV_View::updateCarets(PT_DocPosition docPos, UT_sint32 iLen)
765 {
766 fv_CaretProps * pCaretProps = NULL;
767 UT_sint32 iCount = m_vecCarets.getItemCount();
768 UT_UTF8String sUUID = m_pDoc->getMyUUIDString();
769 bool bLocal = (sUUID == m_sDocUUID);
770 UT_sint32 i = 0;
771 bool bFoundID = false;
772 for(i=0; i<iCount;i++)
773 {
774 pCaretProps = m_vecCarets.getNthItem(i);
775 pCaretProps->m_pCaret->resetBlinkTimeout();
776 if((pCaretProps->m_sCaretID == sUUID) && (iLen > 0))
777 {
778 _setPoint(pCaretProps,docPos,iLen);
779 bFoundID = true;
780 }
781 else if((docPos > 0) && (pCaretProps->m_iInsPoint >= docPos))
782 {
783 _setPoint(pCaretProps,pCaretProps->m_iInsPoint,iLen);
784 }
785 else if(docPos <= 0)
786 {
787 _setPoint(pCaretProps,pCaretProps->m_iInsPoint,iLen);
788 }
789 }
790 if((iLen > 0) && !bFoundID && !bLocal)
791 {
792 UT_DEBUGMSG(("Could find a caret to match UUID! Creating one now! \n"));
793 UT_sint32 iNewAuthor = m_pDoc->getLastAuthorInt();
794 UT_DEBUGMSG(("Creating Caret for author %d UUID %s \n",iNewAuthor,sUUID.utf8_str()));
795 addCaret(docPos, iNewAuthor);
796 }
797 }
798
removeCaret(const std::string & sUUID)799 void FV_View::removeCaret(const std::string& sUUID)
800 {
801 for (UT_sint32 i = 0; i < m_vecCarets.getItemCount(); i++)
802 {
803 fv_CaretProps* pCaretProps = m_vecCarets.getNthItem(i);
804 UT_continue_if_fail(pCaretProps);
805
806 if (pCaretProps->m_sCaretID == sUUID)
807 {
808 pCaretProps->m_pCaret->disable(false);
809 m_pG->removeCaret(pCaretProps->m_sCaretID);
810 removeListener(pCaretProps->m_ListenerID);
811 DELETEP(pCaretProps);
812 m_vecCarets.deleteNthItem(i);
813 break;
814 }
815 }
816 }
817
addCaret(PT_DocPosition docPos,UT_sint32 iAuthorId)818 void FV_View::addCaret(PT_DocPosition docPos,UT_sint32 iAuthorId)
819 {
820 //
821 // Don't add an extra caret for the local user
822 //
823 if(m_pDoc->getMyUUIDString() == m_sDocUUID)
824 return;
825 //
826 // Check we're not adding a duplicated caret
827 //
828 fv_CaretProps* pCaretProps = NULL;
829 UT_sint32 iCount = m_vecCarets.getItemCount();
830 for (UT_sint32 i = 0; i < iCount; i++)
831 {
832 pCaretProps = m_vecCarets.getNthItem(i);
833 if(pCaretProps->m_sCaretID == m_pDoc->getMyUUIDString())
834 {
835 return;
836 }
837 }
838 pCaretProps = new fv_CaretProps(this,docPos);
839 m_vecCarets.addItem(pCaretProps);
840 UT_DEBUGMSG((" add caret num %d id %d position %d \n",m_vecCarets.getItemCount(),iAuthorId,docPos));
841 pCaretProps->m_sCaretID = m_pDoc->getMyUUIDString().utf8_str();
842 pCaretProps->m_pCaret = m_pG->createCaret(pCaretProps->m_sCaretID );
843 UT_DEBUGMSG(("m_sCaretID %s OrigDocID %s \n",pCaretProps->m_sCaretID.c_str(),m_sDocUUID.utf8_str()));
844 XAP_Frame * pFrame = static_cast<XAP_Frame*>(getParentData());
845 pCaretProps->m_PropCaretListner = new FV_Caret_Listener (pFrame);
846 addListener(pCaretProps->m_PropCaretListner,&pCaretProps->m_ListenerID);
847 pCaretProps->m_pCaret->setBlink(true);
848 pCaretProps->m_pCaret->enable();
849 pCaretProps->m_iAuthorId = iAuthorId;
850 UT_sint32 icnt = iAuthorId;
851 pCaretProps->m_sCaretID = m_pDoc->getMyUUIDString().utf8_str();
852 icnt = icnt % 12;
853 if(m_pDoc->getMyAuthorInt() != iAuthorId)
854 {
855 pCaretProps->m_caretColor = getColorRevisions(icnt);
856 }
857 else
858 {
859 //
860 // Primary author carets are black
861 //
862 pCaretProps->m_caretColor = UT_RGBColor(0,0,0);
863 }
864 pCaretProps->m_pCaret->setRemoteColor(pCaretProps->m_caretColor);
865 _setPoint(pCaretProps,docPos,0);
866
867 }
868
869 #if ENABLE_SPELL
getColorSquiggle(FL_SQUIGGLE_TYPE iSquiggleType) const870 UT_RGBColor FV_View::getColorSquiggle(FL_SQUIGGLE_TYPE iSquiggleType) const
871 {
872 if(iSquiggleType == FL_SQUIGGLE_SPELL)
873 {
874 return m_colorSpellSquiggle;
875 }
876 return m_colorGrammarSquiggle;
877 }
878 #endif
879
getColorAnnotation(const fp_Run * pRun) const880 UT_RGBColor FV_View::getColorAnnotation(const fp_Run * pRun) const
881 {
882 fp_HyperlinkRun * pHRun = pRun->getHyperlink();
883 fp_AnnotationRun * pARun = NULL;
884 if(pHRun && pHRun->getHyperlinkType() == HYPERLINK_ANNOTATION)
885 {
886 pARun = static_cast<fp_AnnotationRun *>(pHRun);
887 }
888 else
889 {
890 return pRun->_getColorFG();
891 }
892 fp_Page * pPage = pARun->getLine()->getPage();
893 xxx_UT_DEBUGMSG(("getColorAnnotation() page:%p\n", pPage ));
894 if(!pPage)
895 return pRun->_getColorFG();
896 UT_uint32 pos = pPage->getAnnotationPos(pARun->getPID());
897 if(pos > 9)
898 pos = 9;
899 return m_colorAnnotations[pos];
900 }
901
902
getColorAnnotation(fp_Page * pPage,UT_uint32 pid) const903 UT_RGBColor FV_View::getColorAnnotation(fp_Page * pPage,UT_uint32 pid) const
904 {
905
906 UT_uint32 pos = pPage->getAnnotationPos(pid);
907 if(pos > 9)
908 pos = 9;
909 return m_colorAnnotations[pos];
910 }
911
912
getColorRDFAnchor(const fp_Run * pRun) const913 UT_RGBColor FV_View::getColorRDFAnchor(const fp_Run * pRun) const
914 {
915 fp_Page* pPage = pRun->getLine()->getPage();
916 xxx_UT_DEBUGMSG(("getColorRDFAnchor() page:%p\n", pPage ));
917 if(!pPage)
918 return pRun->_getColorFG();
919
920 fp_HyperlinkRun * pHRun = pRun->getHyperlink();
921 // fp_RDFAnchorRun * pARun = NULL;
922 if(pHRun && pHRun->getHyperlinkType() == HYPERLINK_RDFANCHOR)
923 {
924 // pARun = static_cast<fp_RDFAnchorRun*>(pHRun);
925 }
926 else
927 {
928 return pRun->_getColorFG();
929 }
930 // UT_uint32 pos = pPage->getRDFAnchorPos(pARun->getPID());
931 UT_uint32 pos = 1;
932 if(pos > 9)
933 pos = 9;
934 return m_colorRDFAnchors[pos];
935 }
936
937
938
replaceGraphics(GR_Graphics * pG)939 void FV_View::replaceGraphics(GR_Graphics * pG)
940 {
941 DELETEP(m_pG);
942 setGraphics(pG);
943 m_pLayout->setGraphics(pG);
944 XAP_Frame * pFrame = static_cast<XAP_Frame*>(getParentData());
945 if (pFrame && pFrame->getFrameData())
946 reinterpret_cast<AP_FrameData*>(pFrame->getFrameData())->m_pG = pG;
947 m_pLayout->rebuildFromHere(static_cast<fl_DocSectionLayout *>(m_pLayout->getFirstSection()));
948 }
949
950 //-------------------------
951 // Visual Drag stuff
952 //
cutVisualText(UT_sint32,UT_sint32)953 void FV_View::cutVisualText(UT_sint32 /*x*/, UT_sint32 /*y*/)
954 {
955 //
956 // Do nothing for now. Only cut on first drag event.
957 //
958 }
959
copyVisualText(UT_sint32 x,UT_sint32 y)960 void FV_View::copyVisualText(UT_sint32 x, UT_sint32 y)
961 {
962 m_VisualDragText.mouseCopy(x,y);
963
964 }
965
966
dragVisualText(UT_sint32 x,UT_sint32 y)967 void FV_View::dragVisualText(UT_sint32 x, UT_sint32 y)
968 {
969 m_VisualDragText.mouseDrag(x,y);
970 }
971
972
pasteVisualText(UT_sint32 x,UT_sint32 y)973 void FV_View::pasteVisualText(UT_sint32 x, UT_sint32 y)
974 {
975 m_VisualDragText.mouseRelease(x,y);
976 }
977
btn0VisualDrag(UT_sint32 x,UT_sint32 y)978 void FV_View::btn0VisualDrag(UT_sint32 x, UT_sint32 y)
979 {
980 m_xLastMouse = m_iMouseX;
981 m_iMouseX = x;
982 m_yLastMouse = m_iMouseY;
983 m_iMouseY = y;
984 setCursorToContext();
985 }
986
987 //
988 // Local copy stuff. This pastes from the local paste buffer into the document
989 //
_pasteFromLocalTo(PT_DocPosition pos)990 void FV_View::_pasteFromLocalTo(PT_DocPosition pos)
991 {
992 UT_return_if_fail(m_pLocalBuf);
993 PD_DocumentRange docRange(m_pDoc, pos,pos);
994 IE_Imp_RTF * pImpRTF = new IE_Imp_RTF(m_pDoc);
995 const unsigned char * pData = static_cast<const unsigned char *>(m_pLocalBuf->getPointer(0));
996 UT_uint32 iLen = m_pLocalBuf->getLength();
997
998 pImpRTF->pasteFromBuffer(&docRange,pData,iLen);
999
1000 delete pImpRTF;
1001 }
1002
pasteFromLocalTo(PT_DocPosition pos)1003 void FV_View::pasteFromLocalTo(PT_DocPosition pos)
1004 {
1005 UT_return_if_fail(m_pLocalBuf);
1006 // Signal PieceTable Change
1007 _saveAndNotifyPieceTableChange();
1008 m_pDoc->disableListUpdates();
1009 m_pDoc->beginUserAtomicGlob();
1010 m_pDoc->setDoingPaste();
1011 setCursorWait();
1012 m_pDoc->setDontImmediatelyLayout(true);
1013
1014 _pasteFromLocalTo(pos);
1015 clearCursorWait();
1016 m_pDoc->clearDoingPaste();
1017 m_pDoc->setDontImmediatelyLayout(false);
1018
1019 // restore updates and clean up dirty lists
1020 m_pDoc->enableListUpdates();
1021 m_pDoc->updateDirtyLists();
1022
1023
1024
1025 // Signal piceTable is stable again
1026 _restorePieceTableState();
1027 _generalUpdate();
1028 m_pDoc->endUserAtomicGlob();
1029 // Move insertion point out of field run if it is in one
1030 //
1031 _charMotion(true, 0);
1032 _fixInsertionPointCoords();
1033 if (isSelectionEmpty())
1034 {
1035 _ensureInsertionPointOnScreen();
1036 }
1037 notifyListeners(AV_CHG_MOTION | AV_CHG_HDRFTR);
1038 }
1039
getLocalBuf(void) const1040 const UT_ByteBuf * FV_View::getLocalBuf(void) const
1041 {
1042 return m_pLocalBuf;
1043 }
1044 //
1045 // This copies a range into a local buffer.
1046 //
copyToLocal(PT_DocPosition pos1,PT_DocPosition pos2)1047 void FV_View::copyToLocal(PT_DocPosition pos1, PT_DocPosition pos2)
1048 {
1049 DELETEP(m_pLocalBuf);
1050 m_pLocalBuf = new UT_ByteBuf;
1051 IE_Exp_RTF * pExpRtf = new IE_Exp_RTF(m_pDoc);
1052 PD_DocumentRange docRange(m_pDoc, pos1,pos2);
1053
1054 pExpRtf->copyToBuffer(&docRange,m_pLocalBuf);
1055 delete pExpRtf;
1056 }
1057
1058 //Creates a new document, inserts a string into it, selects all, and then copies it
1059 //onto the system clipboard
1060
copyTextToClipboard(const UT_UCS4String sIncoming,bool)1061 void FV_View::copyTextToClipboard(const UT_UCS4String sIncoming, bool /*useClipboard*/)
1062 {
1063 /* create a new hidden document */
1064 PD_Document * pDoc = new PD_Document();
1065 pDoc->newDocument();
1066 FL_DocLayout * pDocLayout = new FL_DocLayout(pDoc, m_pG);
1067 FV_View * pCopyLinkView = new FV_View(XAP_App::getApp(), 0, pDocLayout);
1068
1069 /* assign the view to the doclayout */
1070 pDocLayout->setView(pCopyLinkView);
1071
1072 /* fill its layout structures (which are quite empty, but still...) */
1073 pCopyLinkView->getLayout()->fillLayouts();
1074 pCopyLinkView->getLayout()->formatAll();
1075
1076 /* insert the string in the new document, select it, and copy it */
1077 pCopyLinkView->cmdCharInsert(sIncoming.ucs4_str(), sIncoming.length(),false);
1078 pCopyLinkView->cmdSelect(0,0,FV_DOCPOS_BOD,FV_DOCPOS_EOD);
1079 pCopyLinkView->cmdCopy();
1080
1081 /* we're done, release our resources */
1082 DELETEP(pCopyLinkView);
1083 DELETEP(pDocLayout);
1084 UNREFP(pDoc);
1085 }
1086
1087 /*!
1088 * Logic for determining what state the Image and cursor should be in.
1089 */
btn0InlineImage(UT_sint32 x,UT_sint32 y)1090 void FV_View::btn0InlineImage(UT_sint32 x, UT_sint32 y)
1091 {
1092 xxx_UT_DEBUGMSG(("btn0 called InlineImage mode %d \n",m_InlineImage.getInlineDragMode()));
1093 m_InlineImage.setDragType(x,y,false);
1094 setCursorToContext();
1095 }
1096
1097 /*!
1098 * Deal with a left -mouse click on a inline-image. It might be the
1099 * start of a drag or a resize.
1100 */
btn1InlineImage(UT_sint32 x,UT_sint32 y)1101 void FV_View::btn1InlineImage(UT_sint32 x, UT_sint32 y)
1102 {
1103 m_InlineImage.mouseLeftPress(x,y);
1104 }
1105
1106
1107 /*!
1108 * Complete the drag which either finishes the drag of the image or
1109 * completes the resize of the image.
1110 */
releaseInlineImage(UT_sint32 x,UT_sint32 y)1111 void FV_View::releaseInlineImage(UT_sint32 x, UT_sint32 y)
1112 {
1113 m_InlineImage.mouseRelease(x,y);
1114 }
1115
1116
1117
1118 /*!
1119 * Drag on an image. Either drag the whole image or do a resize.
1120 */
dragInlineImage(UT_sint32 x,UT_sint32 y)1121 void FV_View::dragInlineImage(UT_sint32 x, UT_sint32 y)
1122 {
1123 m_InlineImage.mouseDrag(x,y);
1124 }
1125
1126
1127 /*!
1128 * Make a copy of the inline image. This gets called with cntrl-left mouse
1129 * click.
1130 */
btn1CopyImage(UT_sint32 x,UT_sint32 y)1131 void FV_View::btn1CopyImage(UT_sint32 x, UT_sint32 y)
1132 {
1133 m_InlineImage.mouseCopy(x,y);
1134 }
1135
1136
1137
getFrameEdit(void)1138 FV_FrameEdit * FV_View::getFrameEdit(void)
1139 {
1140 return &m_FrameEdit;
1141 }
1142
1143 /*!
1144 * Logic for determining what state the frame and cursor should be in.
1145 */
btn0Frame(UT_sint32 x,UT_sint32 y)1146 void FV_View::btn0Frame(UT_sint32 x, UT_sint32 y)
1147 {
1148 xxx_UT_DEBUGMSG(("btn0 called frameEdit mode %d \n",m_FrameEdit.getFrameEditMode()));
1149 if(!m_FrameEdit.isActive())
1150 {
1151 getGraphics()->setCursor(GR_Graphics::GR_CURSOR_GRAB);
1152 return;
1153 }
1154 else if(m_FrameEdit.getFrameEditMode() == FV_FrameEdit_WAIT_FOR_FIRST_CLICK_INSERT)
1155 {
1156 getGraphics()->setCursor(GR_Graphics::GR_CURSOR_CROSSHAIR);
1157 }
1158 else if(m_FrameEdit.getFrameEditMode() == FV_FrameEdit_EXISTING_SELECTED)
1159 {
1160 m_FrameEdit.setDragType(x,y,false);
1161 setCursorToContext();
1162 }
1163 }
1164
1165
btn1Frame(UT_sint32 x,UT_sint32 y)1166 void FV_View::btn1Frame(UT_sint32 x, UT_sint32 y)
1167 {
1168 m_FrameEdit.mouseLeftPress(x,y);
1169 }
1170
setFrameFormat(const gchar * properties[])1171 void FV_View::setFrameFormat(const gchar * properties[])
1172 {
1173 std::string dataID;
1174 setFrameFormat(properties,NULL,dataID);
1175 }
1176
1177 /*!
1178 * This method converts a positioned object described by fp_FrameLayout * pFram
1179 * to an inline image. It then selects the inline image.
1180 */
convertPositionedToInLine(fl_FrameLayout * pFrame)1181 bool FV_View::convertPositionedToInLine(fl_FrameLayout * pFrame)
1182 {
1183 UT_GenericVector<fl_BlockLayout *> vecBlocks;
1184 fp_FrameContainer * pFC = static_cast<fp_FrameContainer *>(pFrame->getFirstContainer());
1185 pFC->getBlocksAroundFrame(vecBlocks);
1186 if(vecBlocks.getItemCount() == 0)
1187 {
1188 fp_Page * pPage = pFC->getPage();
1189 fp_Column * pCol = pPage->getNthColumnLeader(0);
1190 fp_Container * pCon = pCol->getFirstContainer();
1191 fl_BlockLayout * pB = NULL;
1192 if(pCon->getContainerType() == FP_CONTAINER_LINE)
1193 {
1194 pB = static_cast<fp_Line *>(pCon)->getBlock();
1195 }
1196 else
1197 {
1198 fl_ContainerLayout * pCL = static_cast<fl_ContainerLayout *>(pCon->getSectionLayout());
1199 pB = pCL->getNextBlockInDocument();
1200 }
1201 vecBlocks.addItem(pB);
1202 }
1203 UT_sint32 iBlk = 0;
1204 fl_BlockLayout * pBL = vecBlocks.getNthItem(iBlk);
1205 fp_Line * pLine = static_cast<fp_Line *>(pBL->getFirstContainer());
1206 bool bLoop = true;
1207 while((pLine != NULL) && bLoop)
1208 {
1209 UT_sint32 xoffLine, yoffLine;
1210 fp_VerticalContainer * pVCon= (static_cast<fp_VerticalContainer *>(pLine->getContainer()));
1211 pVCon->getScreenOffsets(pLine, xoffLine, yoffLine);
1212 if(yoffLine + pLine->getHeight() >= pFC->getFullY())
1213 {
1214 bLoop = false;
1215 break;
1216 }
1217 pLine = static_cast<fp_Line *>(pLine->getNext());
1218 if(pLine == NULL)
1219 {
1220 iBlk++;
1221 if(iBlk < vecBlocks.getItemCount())
1222 {
1223 pBL = vecBlocks.getNthItem(iBlk);
1224 pLine = static_cast<fp_Line *>(pBL->getFirstContainer());
1225 }
1226 }
1227 }
1228 if(pLine == NULL)
1229 {
1230 pBL = vecBlocks.getNthItem(vecBlocks.getItemCount()-1);
1231 pLine = static_cast<fp_Line *>(pBL->getLastContainer());
1232 if(pLine == NULL)
1233 return false;
1234 }
1235 fp_Run * pRun = pLine->getLastRun();
1236 PT_DocPosition pos = pBL->getPosition() + pRun->getBlockOffset() + pRun->getLength();
1237 const PP_AttrProp* pAP = NULL;
1238 pFrame->getAP(pAP);
1239 if(pAP == NULL)
1240 {
1241 return false;
1242 }
1243 const gchar* szDataID = 0;
1244 const gchar* szTitle = 0;
1245 const gchar* szDescription = 0;
1246 const gchar* szWidth = 0;
1247 const gchar * szHeight = 0;
1248 bool bFound = pAP->getAttribute(PT_STRUX_IMAGE_DATAID,szDataID);
1249 if(!bFound)
1250 {
1251 return false;
1252 }
1253 bFound = pAP->getProperty("frame-width",szWidth);
1254 if(!bFound)
1255 {
1256 return false;
1257 }
1258 bFound = pAP->getProperty("frame-height",szHeight);
1259 if(!bFound)
1260 {
1261 return false;
1262 }
1263 bFound = pAP->getAttribute("title",szTitle);
1264 bFound = pAP->getAttribute("alt",szDescription);
1265 UT_String sProps;
1266 sProps += "width:";
1267 sProps += szWidth;
1268 sProps += "; height:";
1269 sProps += szHeight;
1270 const gchar* attributes[] = {
1271 PT_IMAGE_DATAID, NULL,
1272 PT_IMAGE_TITLE,NULL,
1273 PT_IMAGE_DESCRIPTION,NULL,
1274 PT_PROPS_ATTRIBUTE_NAME, NULL,
1275 NULL, NULL};
1276 if(szTitle == 0)
1277 szTitle = "";
1278 if(szDescription == 0)
1279 szDescription = "";
1280 attributes[1] = szDataID;
1281 attributes[3] = szTitle;
1282 attributes[5] = szDescription;
1283 attributes[7] = sProps.c_str();
1284 if(pFrame->getPosition(true) < pos)
1285 {
1286 pos -= 2;
1287 }
1288 PT_DocPosition posEnd = 0;
1289 getEditableBounds(true,posEnd);
1290 while(!isPointLegal(pos) && pos <= posEnd)
1291 {
1292 pos++;
1293 }
1294 bool bMakeItLegal = false;
1295 if(pos > posEnd)
1296 {
1297 bMakeItLegal = true;
1298 }
1299 m_pDoc->beginUserAtomicGlob();
1300 m_FrameEdit.deleteFrame(pFrame);
1301 _saveAndNotifyPieceTableChange();
1302 if(bMakeItLegal)
1303 {
1304 setPoint(pos);
1305 pos = getPoint();
1306 }
1307 m_pDoc->insertObject(pos, PTO_Image, attributes, NULL);
1308 _restorePieceTableState();
1309 m_pDoc->endUserAtomicGlob();
1310 _updateInsertionPoint();
1311 _generalUpdate();
1312 cmdSelect(pos,pos+1);
1313 return true;
1314 }
1315
1316 /*!
1317 * This method converts an image located position pos to a positioned object.
1318 */
convertInLineToPositioned(PT_DocPosition pos,const gchar ** attributes)1319 void FV_View::convertInLineToPositioned(PT_DocPosition pos,const gchar ** attributes)
1320 {
1321
1322 fl_BlockLayout * pBlock = getBlockAtPosition(pos);
1323 fp_Run * pRun = NULL;
1324 bool bEOL,bDir;
1325 bEOL = false;
1326 UT_sint32 x1,y1,x2,y2,iHeight;
1327 if(pBlock)
1328 {
1329 pRun = pBlock->findPointCoords(pos,bEOL,x1,y1,x2,y2,iHeight,bDir);
1330 while(pRun && pRun->getType() != FPRUN_IMAGE)
1331 {
1332 pRun = pRun->getNextRun();
1333 }
1334 if(pRun && pRun->getType() == FPRUN_IMAGE)
1335 {
1336 UT_DEBUGMSG(("SEVIOR: Image run on pos \n"));
1337 }
1338 else
1339 {
1340 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
1341 return;
1342 }
1343 }
1344 //
1345 // Signal PieceTable Change
1346 _saveAndNotifyPieceTableChange();
1347 m_pDoc->beginUserAtomicGlob();
1348 _deleteSelection();
1349 pf_Frag_Strux * pfFrame = NULL;
1350 //
1351 // This should place the the frame strux immediately after the block containing
1352 // position posXY.
1353 // It returns the Frag_Strux of the new frame.
1354 //
1355 fl_BlockLayout * pBL = pBlock;
1356 if((pBL == NULL) || (pRun == NULL))
1357 {
1358 return;
1359 }
1360 fl_BlockLayout * pPrevBL = pBL;
1361 while(pBL && ((pBL->myContainingLayout()->getContainerType() == FL_CONTAINER_ENDNOTE) || (pBL->myContainingLayout()->getContainerType() == FL_CONTAINER_FOOTNOTE) || (pBL->myContainingLayout()->getContainerType() == FL_CONTAINER_ANNOTATION) || (pBL->myContainingLayout()->getContainerType() == FL_CONTAINER_TOC)|| (pBL->myContainingLayout()->getContainerType() == FL_CONTAINER_FRAME)))
1362 {
1363 UT_DEBUGMSG(("Skipping Block %p \n",pBL));
1364 pPrevBL = pBL;
1365 pBL = pBL->getPrevBlockInDocument();
1366 }
1367 if(pBL == NULL)
1368 {
1369 pBL = pPrevBL;
1370 }
1371 UT_ASSERT((pBL->myContainingLayout()->getContainerType() != FL_CONTAINER_HDRFTR)
1372 && (pBL->myContainingLayout()->getContainerType() != FL_CONTAINER_SHADOW));
1373 pos = pBL->getPosition();
1374 m_pDoc->insertStrux(pos,PTX_SectionFrame,attributes,NULL,&pfFrame);
1375 PT_DocPosition posFrame = pfFrame->getPos();
1376 m_pDoc->insertStrux(posFrame+1,PTX_EndFrame);
1377 insertParaBreakIfNeededAtPos(posFrame+2);
1378
1379 // Signal PieceTable Changes have finished
1380 _restorePieceTableState();
1381 m_pDoc->endUserAtomicGlob();
1382 _generalUpdate();
1383 setPoint(posFrame+2);
1384 if(!isPointLegal())
1385 {
1386 setPoint(posFrame);
1387 }
1388 _ensureInsertionPointOnScreen();
1389 notifyListeners(AV_CHG_MOTION | AV_CHG_ALL);
1390 }
1391
setFrameFormat(const gchar * properties[],FG_Graphic * pFG,const std::string & sDataID,fl_BlockLayout * pNewBL)1392 void FV_View::setFrameFormat(const gchar * properties[], FG_Graphic * pFG,
1393 const std::string & sDataID, fl_BlockLayout * pNewBL)
1394 {
1395 setCursorWait();
1396 //
1397 // Signal PieceTable Change
1398 _saveAndNotifyPieceTableChange();
1399
1400 fl_FrameLayout * pFrame = getFrameLayout();
1401 if(pFrame == NULL)
1402 {
1403 UT_DEBUGMSG(("No frame selected. Aborting! \n"));
1404 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
1405 return;
1406 }
1407
1408 if(isHdrFtrEdit())
1409 {
1410 clearHdrFtrEdit();
1411 warpInsPtToXY(0,0,false);
1412 }
1413
1414 PT_DocPosition posStart = getPoint();
1415 PT_DocPosition posEnd = posStart;
1416
1417 if (!isSelectionEmpty())
1418 {
1419 if (m_Selection.getSelectionAnchor() < posStart)
1420 posStart = m_Selection.getSelectionAnchor();
1421 else
1422 posEnd = m_Selection.getSelectionAnchor();
1423 if(posStart < 2)
1424 {
1425 posStart = 2;
1426 }
1427 }
1428 if(pFG != NULL)
1429 {
1430 pFG->insertAtStrux(m_pDoc,72,posStart,
1431 PTX_SectionFrame,sDataID.c_str());
1432 }
1433 else
1434 {
1435 const gchar * attributes[3] = {
1436 PT_STRUX_IMAGE_DATAID,NULL,NULL};
1437 UT_DebugOnly<bool> bRet = m_pDoc->changeStruxFmt(PTC_RemoveFmt,posStart,
1438 posStart,attributes,NULL,PTX_SectionFrame);
1439 UT_ASSERT(bRet);
1440 }
1441
1442 if(pNewBL && (pFrame->getParentContainer() != pNewBL))
1443 {
1444 UT_DEBUGMSG(("BEGIN RELOCATION\n"));
1445 getLayout()->relocateFrame(pFrame,pNewBL,NULL,properties);
1446 }
1447 else
1448 {
1449 UT_DEBUGMSG(("BEGIN CHANGE\n"));
1450 //posStart = pFrame->getPosition(true)+1;
1451 //PT_DocPosition posEnd = posStart;
1452 UT_DebugOnly<bool> bRet = m_pDoc->changeStruxFmt(PTC_AddFmt,posStart,posEnd,NULL,
1453 properties,PTX_SectionFrame);
1454 UT_ASSERT(bRet);
1455 }
1456
1457 // Signal PieceTable Changes have finished
1458 _restorePieceTableState();
1459 _generalUpdate();
1460
1461 _ensureInsertionPointOnScreen();
1462 clearCursorWait();
1463 notifyListeners(AV_CHG_MOTION);
1464 }
1465
getFrameStrings_view(UT_sint32 x,UT_sint32 y,fv_FrameStrings & FrameStrings,fl_BlockLayout ** pCloseBL,fp_Page ** ppPage)1466 bool FV_View::getFrameStrings_view(UT_sint32 x, UT_sint32 y,fv_FrameStrings & FrameStrings,
1467 fl_BlockLayout ** pCloseBL,fp_Page ** ppPage)
1468 {
1469 return (m_FrameEdit.getFrameStrings(x,y,FrameStrings,pCloseBL,ppPage));
1470 }
1471
1472
1473
setFrameFormat(const gchar * attribs[],const gchar * properties[],fl_BlockLayout * pNewBL)1474 void FV_View::setFrameFormat(const gchar * attribs[], const gchar * properties[], fl_BlockLayout *pNewBL)
1475 {
1476 setCursorWait();
1477 //
1478 // Signal PieceTable Change
1479 _saveAndNotifyPieceTableChange();
1480 if(isHdrFtrEdit())
1481 {
1482 clearHdrFtrEdit();
1483 warpInsPtToXY(0,0,false);
1484 }
1485 fl_FrameLayout * pFrame = getFrameLayout();
1486 if(pFrame == NULL)
1487 {
1488 UT_DEBUGMSG(("No frame selected. Aborting! \n"));
1489 // should we assert ?
1490 return;
1491 }
1492
1493 if(pNewBL && (pFrame->getParentContainer() != pNewBL))
1494 {
1495 getLayout()->relocateFrame(pFrame,pNewBL,attribs,properties);
1496 }
1497 else
1498 {
1499 PT_DocPosition posStart = pFrame->getPosition(true)+1;
1500 PT_DocPosition posEnd = posStart;
1501 UT_DebugOnly<bool> bRet = m_pDoc->changeStruxFmt(PTC_AddFmt,posStart,posEnd,
1502 attribs,properties,PTX_SectionFrame);
1503 UT_ASSERT(bRet);
1504 }
1505 // Signal PieceTable Changes have finished
1506 _restorePieceTableState();
1507 _generalUpdate();
1508
1509 _ensureInsertionPointOnScreen();
1510 clearCursorWait();
1511 notifyListeners(AV_CHG_MOTION);
1512 }
1513
dragFrame(UT_sint32 x,UT_sint32 y)1514 void FV_View::dragFrame(UT_sint32 x, UT_sint32 y)
1515 {
1516 m_FrameEdit.mouseDrag(x,y);
1517 }
1518
1519
releaseFrame(UT_sint32 x,UT_sint32 y)1520 void FV_View::releaseFrame(UT_sint32 x, UT_sint32 y)
1521 {
1522 m_FrameEdit.mouseRelease(x,y);
1523 }
1524
activateFrame(void)1525 void FV_View::activateFrame(void)
1526 {
1527 if(!m_FrameEdit.isActive())
1528 {
1529 m_FrameEdit.mouseLeftPress(m_iMouseX,m_iMouseY);
1530 }
1531 }
1532
copyFrame(bool b_keepFrame)1533 void FV_View::copyFrame(bool b_keepFrame)
1534 {
1535 if(!m_FrameEdit.isActive())
1536 {
1537 m_FrameEdit.mouseLeftPress(m_iMouseX,m_iMouseY);
1538 }
1539 fl_FrameLayout * pFL = getFrameLayout();
1540 if(pFL == NULL)
1541 {
1542 m_FrameEdit.setMode(FV_FrameEdit_NOT_ACTIVE);
1543 XAP_Frame * pFrame = static_cast<XAP_Frame*>(getParentData());
1544 if(pFrame)
1545 {
1546 EV_Mouse * pMouse = pFrame->getMouse();
1547 if(pMouse)
1548 {
1549 pMouse->clearMouseContext();
1550 }
1551 }
1552 m_prevMouseContext = EV_EMC_TEXT;
1553 setCursorToContext();
1554 return;
1555 }
1556 PT_DocPosition posLow = pFL->getPosition(true);
1557 PT_DocPosition posHigh = posLow + pFL->getLength();
1558 PD_DocumentRange dr(m_pDoc,posLow,posHigh);
1559 XAP_App::getApp()->copyToClipboard(&dr, true);
1560 if (!b_keepFrame)
1561 {
1562 m_FrameEdit.deleteFrame();
1563 }
1564 notifyListeners(AV_CHG_CLIPBOARD);
1565 }
1566
selectFrame(void)1567 void FV_View::selectFrame(void)
1568 {
1569 _clearSelection();
1570 if(!m_FrameEdit.isActive())
1571 {
1572 m_FrameEdit.mouseLeftPress(m_iMouseX,m_iMouseY);
1573 }
1574 fl_FrameLayout * pFL = getFrameLayout();
1575 if(pFL == NULL)
1576 {
1577 m_FrameEdit.setMode(FV_FrameEdit_NOT_ACTIVE);
1578 XAP_Frame * pFrame = static_cast<XAP_Frame*>(getParentData());
1579 if(pFrame)
1580 {
1581 EV_Mouse * pMouse = pFrame->getMouse();
1582 if(pMouse)
1583 {
1584 pMouse->clearMouseContext();
1585 }
1586 }
1587 m_prevMouseContext = EV_EMC_TEXT;
1588 setCursorToContext();
1589 return;
1590 }
1591 PT_DocPosition posLow = pFL->getPosition(true)+2;
1592 PT_DocPosition posHigh = pFL->getPosition(true) + pFL->getLength()-1;
1593 PD_DocumentRange dr(m_pDoc,posLow,posHigh);
1594 setPoint(posLow);
1595 _setSelectionAnchor();
1596 setPoint(posHigh);
1597 _drawSelection();
1598 }
1599
isFrameSelected(void) const1600 bool FV_View::isFrameSelected(void) const
1601 {
1602 return(m_FrameEdit.isActive());
1603 }
1604
deleteFrame(void)1605 void FV_View::deleteFrame(void)
1606 {
1607 if(!m_FrameEdit.isActive())
1608 {
1609 m_FrameEdit.mouseLeftPress(m_iMouseX,m_iMouseY);
1610 }
1611 if(getFrameLayout() == NULL)
1612 {
1613 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
1614 selectFrame(); // this will clear the frame context
1615 return;
1616 }
1617 UT_DEBUGMSG(("Doing Delete Frame \n"));
1618 m_FrameEdit.deleteFrame();
1619 XAP_Frame * pFrame = static_cast<XAP_Frame*>(getParentData());
1620 if(pFrame)
1621 {
1622 EV_Mouse * pMouse = pFrame->getMouse();
1623 if(pMouse)
1624 {
1625 pMouse->clearMouseContext();
1626 }
1627 }
1628 m_prevMouseContext = EV_EMC_TEXT;
1629 setCursorToContext();
1630 }
1631
getFrameLayout(void) const1632 fl_FrameLayout * FV_View::getFrameLayout(void) const
1633 {
1634 if(m_FrameEdit.isActive())
1635 {
1636 return m_FrameEdit.getFrameLayout();
1637 }
1638 return getFrameLayout(getPoint());
1639 }
1640
getFrameLayout(PT_DocPosition pos) const1641 fl_FrameLayout * FV_View::getFrameLayout(PT_DocPosition pos) const
1642 {
1643 if(m_pDoc->isFrameAtPos(pos))
1644 {
1645 fl_ContainerLayout* psfh = NULL;
1646 m_pDoc->getStruxOfTypeFromPosition(getLayout()->getLID(),pos+1,
1647 PTX_SectionFrame, &psfh);
1648 fl_FrameLayout * pFL = static_cast<fl_FrameLayout *>(psfh);
1649 UT_ASSERT(pFL->getContainerType() == FL_CONTAINER_FRAME);
1650 return pFL;
1651 }
1652 if(m_pDoc->isFrameAtPos(pos-1))
1653 {
1654 fl_ContainerLayout* psfh = NULL;
1655 m_pDoc->getStruxOfTypeFromPosition(getLayout()->getLID(),
1656 pos,
1657 PTX_SectionFrame, &psfh);
1658 fl_FrameLayout * pFL = static_cast<fl_FrameLayout *>(psfh);
1659 UT_ASSERT(pFL->getContainerType() == FL_CONTAINER_FRAME);
1660 return pFL;
1661 }
1662
1663 fl_BlockLayout* pBlock = _findBlockAtPosition(pos);
1664
1665 if(pBlock)
1666 {
1667 fl_ContainerLayout * pCL = pBlock->myContainingLayout();
1668 while(pCL && (pCL->getContainerType() != FL_CONTAINER_FRAME) && (pCL->getContainerType() != FL_CONTAINER_DOCSECTION))
1669 {
1670 if(pCL == pCL->myContainingLayout())
1671 break;
1672 pCL = pCL->myContainingLayout();
1673 }
1674 if(pCL && pCL->getContainerType() == FL_CONTAINER_FRAME)
1675 {
1676 return static_cast<fl_FrameLayout *>(pCL);
1677 }
1678 if((pBlock->getPosition(true) < pos) && (pBlock->getPosition(true) + pBlock->getLength() + 1 < pos))
1679 {
1680 pBlock = pBlock->getNextBlockInDocument();
1681 }
1682 if(pBlock == NULL)
1683 {
1684 return NULL;
1685 }
1686 if((pBlock->getPosition(true) < pos) && (pBlock->getPosition(true) + pBlock->getLength() +1 < pos))
1687 {
1688 return NULL;
1689 }
1690 pCL = pBlock->myContainingLayout();
1691 while(pCL && (pCL->getContainerType() != FL_CONTAINER_FRAME) && (pCL->getContainerType() != FL_CONTAINER_DOCSECTION))
1692 {
1693 pCL = pCL->myContainingLayout();
1694 }
1695 if(pCL == NULL)
1696 {
1697 return NULL;
1698 }
1699 if(pCL->getContainerType() != FL_CONTAINER_FRAME)
1700 {
1701 return NULL;
1702 }
1703 return static_cast<fl_FrameLayout *>(pCL);
1704 }
1705 return NULL;
1706 }
1707
1708 /*!
1709 * Returns true if the supplied Doc Position is inside a frame.
1710 */
isInFrame(PT_DocPosition pos) const1711 bool FV_View::isInFrame(PT_DocPosition pos) const
1712 {
1713 //
1714 // If at exactly the frame return true
1715 //
1716 if(m_pDoc->isFrameAtPos(pos))
1717 {
1718 return true;
1719 }
1720 if(m_pDoc->isFrameAtPos(pos-1) && !m_pDoc->isEndFrameAtPos(pos))
1721 {
1722 return true;
1723 }
1724 fl_BlockLayout* pBlock = _findBlockAtPosition(pos);
1725
1726 if(pBlock)
1727 {
1728 fl_ContainerLayout * pCL = pBlock->myContainingLayout();
1729 while(pCL && (pCL->getContainerType() != FL_CONTAINER_FRAME) && (pCL->getContainerType() != FL_CONTAINER_DOCSECTION))
1730 {
1731 pCL = pCL->myContainingLayout();
1732 }
1733 if(pCL == NULL)
1734 {
1735 return false;
1736 }
1737 if(pCL->getContainerType() != FL_CONTAINER_FRAME)
1738 {
1739 return false;
1740 }
1741 return true;
1742 }
1743 return false;
1744 }
1745
1746 /*!
1747 * Returns true if the suppiled position is not is a sepecial structure
1748 * like a frame or table or whatever.
1749 *
1750 * pos defaults to 0. Ifpos == 0, I assume you actually what the values of
1751 * getPoint()
1752 */
1753
isInDocSection(PT_DocPosition pos) const1754 bool FV_View::isInDocSection(PT_DocPosition pos) const
1755 {
1756 if(pos == 0)
1757 {
1758 pos = getPoint();
1759 }
1760 fl_BlockLayout * pBL = _findBlockAtPosition(pos);
1761 if(pBL && (pBL->myContainingLayout()->getContainerType() == FL_CONTAINER_DOCSECTION))
1762 {
1763 return true;
1764 }
1765 return false;
1766 }
1767
getColorSelBackground()1768 UT_RGBColor FV_View::getColorSelBackground ()
1769 {
1770 static UT_RGBColor bgcolor (192, 192, 192);
1771
1772 XAP_Frame * pFrame = 0;
1773
1774 if ((pFrame = static_cast<XAP_Frame*>(getParentData())) != NULL)
1775 return pFrame->getColorSelBackground ();
1776
1777 if (!m_bgColorInitted) {
1778 const gchar * pszTmpColor = NULL;
1779 if (XAP_App::getApp()->getPrefsValue(static_cast<const gchar *>(XAP_PREF_KEY_ColorForSelBackground), &pszTmpColor))
1780 {
1781 UT_parseColor(pszTmpColor, bgcolor);
1782 }
1783 m_bgColorInitted = true;
1784 }
1785
1786 return bgcolor;
1787 }
1788
getColorSelForeground() const1789 UT_RGBColor FV_View::getColorSelForeground () const
1790 {
1791 static UT_RGBColor fgcolor (255, 255, 255);
1792
1793 XAP_Frame * pFrame = 0;
1794
1795 if ((pFrame = static_cast<XAP_Frame*>(getParentData())) != NULL)
1796 return pFrame->getColorSelForeground ();
1797
1798 return fgcolor;
1799 }
1800
1801 // TODO i18n All of these case functions are too simplistic:
1802 // TODO i18n German single-letter "sharp s" uppercases to double-letter "SS"
1803 // TODO i18n Turkish "i" uppercases to capital "I" with dot
1804 // TODO i18n Turkish "I" lowercases to lower "i" without dot
1805 // TODO i18n Some ligatures have special versions with just the first letter
1806 // TODO i18n uppercase
1807
1808 #if 0
1809 // the code is not directly in the case function, as passing the
1810 // arguments is too awkward
1811 static void _toggleSentence (const UT_UCSChar * src,
1812 UT_UCSChar * dest, UT_uint32 len, const UT_UCSChar * prev)
1813 {
1814 if(!prev || (UT_UCS4_isSentenceSeparator(prev[0]) && UT_UCS4_isspace (prev[1])))
1815 {
1816 dest[0] = UT_UCS4_toupper (src[0]);
1817 dest[1] = src[1];
1818 }
1819 else
1820 {
1821 dest[0] = src[0];
1822 dest[1] = src[1];
1823 }
1824
1825 for (UT_uint32 i = 2; i < len; i++)
1826 {
1827 if(UT_UCS4_isSentenceSeparator(src[i-2]) && UT_UCS4_isspace (src[i-1]))
1828 dest[i] = UT_UCS4_toupper (src[i]);
1829 else
1830 dest[i] = src[i];
1831 }
1832 }
1833 #endif
1834
_toggleFirstCapital(const UT_UCSChar * src,UT_UCSChar * dest,UT_uint32 len,const UT_UCSChar * prev)1835 static void _toggleFirstCapital(const UT_UCSChar * src,
1836 UT_UCSChar * dest, UT_uint32 len, const UT_UCSChar * prev)
1837 {
1838 if(!prev || UT_UCS4_isspace(prev[0]))
1839 {
1840 dest[0] = UT_UCS4_toupper(src[0]);
1841 }
1842 else
1843 {
1844 dest[0] = UT_UCS4_tolower(src[0]);
1845 }
1846
1847 for (UT_uint32 i = 1; i < len; i++)
1848 {
1849 if(UT_UCS4_isspace(src[i-1]))
1850 dest[i] = UT_UCS4_toupper (src[i]);
1851 else
1852 dest[i] = UT_UCS4_tolower (src[i]);
1853 }
1854 }
1855
1856 // all gets set to lowercase
_toggleLower(const UT_UCSChar * src,UT_UCSChar * dest,UT_uint32 len)1857 static void _toggleLower (const UT_UCSChar * src,
1858 UT_UCSChar * dest, UT_uint32 len)
1859 {
1860 for (UT_uint32 i = 0; i < len; i++)
1861 {
1862 dest[i] = UT_UCS4_tolower (src[i]);
1863 }
1864 }
1865
1866 // all gets set to uppercase
_toggleUpper(const UT_UCSChar * src,UT_UCSChar * dest,UT_uint32 len)1867 static void _toggleUpper (const UT_UCSChar * src,
1868 UT_UCSChar * dest, UT_uint32 len)
1869 {
1870 for (UT_uint32 i = 0; i < len; i++)
1871 {
1872 dest[i] = UT_UCS4_toupper (src[i]);
1873 }
1874 }
1875
1876 // first character after each space gets capitalized
1877 // NB the title case algorithm here is too simplistic to
1878 // produce satisfactory results; basically we would need
1879 // language-dependent word lists to handle this correctly
1880 // and I see little need for it; so for now it is going to
1881 // be turned off
1882 #if 0
1883 static void _toggleTitle (const UT_UCSChar * src,
1884 UT_UCSChar * dest, UT_uint32 len,
1885 bool spaceBeforeFirstChar)
1886 {
1887 bool wasSpace = spaceBeforeFirstChar;
1888
1889 UT_UCSChar ch;
1890
1891 for (UT_uint32 i = 0; i < len; i++)
1892 {
1893 ch = src[i];
1894 if (wasSpace && !UT_UCS4_isspace (ch))
1895 {
1896 dest[i] = UT_UCS4_toupper (ch);
1897 wasSpace = false;
1898 }
1899 else if (UT_UCS4_isspace (ch))
1900 {
1901 dest[i] = ch;
1902 wasSpace = true;
1903 }
1904 else
1905 {
1906 dest[i] = ch;
1907 }
1908 }
1909 }
1910 #endif
1911
1912 // all gets set to its opposite
1913 // I have my doubts about usufulness of this, but the concensus on
1914 // the mailing list was to leave it, so it stays.
_toggleToggle(const UT_UCSChar * src,UT_UCSChar * dest,UT_uint32 len)1915 static void _toggleToggle (const UT_UCSChar * src,
1916 UT_UCSChar * dest, UT_uint32 len)
1917 {
1918 UT_UCSChar ch;
1919 for (UT_uint32 i = 0; i < len; i++)
1920 {
1921 ch = src[i];
1922
1923 if (UT_UCS4_islower (ch))
1924 dest[i] = UT_UCS4_toupper (ch);
1925 else
1926 dest[i] = UT_UCS4_tolower (src[i]);
1927 }
1928 }
1929
1930
toggleCase(ToggleCase c)1931 void FV_View::toggleCase (ToggleCase c)
1932 {
1933 // if there is no selection, apply to the current word
1934 PT_DocPosition origPos = 0;
1935 PT_DocPosition low, high;
1936
1937 if (isSelectionEmpty())
1938 {
1939 origPos = m_iInsPoint;
1940 low = _getDocPos(FV_DOCPOS_BOW, false);
1941 high = _getDocPos(FV_DOCPOS_EOW_SELECT, false);
1942 }
1943 else
1944 {
1945 if(m_iInsPoint < m_Selection.getSelectionAnchor())
1946 {
1947 low = m_iInsPoint;
1948 high = m_Selection.getSelectionAnchor();
1949 }
1950 else
1951 {
1952 high = m_iInsPoint;
1953 low = m_Selection.getSelectionAnchor();
1954 }
1955 }
1956
1957 if(low < 2)
1958 {
1959 // the initial block strux / section strux is also selected, for example when
1960 // using ctrl+a
1961 low = 2;
1962 }
1963
1964 // if this is an empty document, gracefully return
1965 if(low == high)
1966 return;
1967
1968 UT_DEBUGMSG(("fv_View::toggleCase: low %d, high %d\n", low, high));
1969
1970 fl_BlockLayout * pBL = m_pLayout->findBlockAtPosition(low);
1971 fp_Run * pRun;
1972 if(low < pBL->getPosition())
1973 {
1974 low = pBL->getPosition();
1975 }
1976 //
1977 // skip blank lines
1978 //
1979 while(pBL && (low == pBL->getPosition(true) + pBL->getLength()))
1980 {
1981 pBL = pBL->getNextBlockInDocument();
1982 if(pBL != NULL)
1983 {
1984 low = pBL->getPosition();
1985 }
1986 }
1987 if(pBL == NULL)
1988 {
1989 return;
1990 }
1991 // if this is an empty document, gracefully return
1992 if(low >= high)
1993 return;
1994
1995 // create a temp buffer of a reasonable size (will g_try_realloc if too small)
1996 UT_sint32 iTempLen = 150;
1997 UT_UCSChar * pTemp = new UT_UCSChar[iTempLen];
1998 UT_ASSERT(pTemp);
1999
2000 _saveAndNotifyPieceTableChange();
2001 m_pDoc->beginUserAtomicGlob();
2002
2003 UT_UCSChar * prev;
2004
2005 while(pBL && low < high)
2006 {
2007 UT_GrowBuf buffer;
2008 pBL->getBlockBuf(&buffer);
2009
2010 PT_DocPosition offset = low - pBL->getPosition(false);
2011
2012 if(offset == buffer.getLength())
2013 {
2014 // this is a special case when the selection starts at the very begining of a
2015 // block which is not the first block in the document -- the block that
2016 // findBlockAtPosition() returned to us is actually the block _before_ the one
2017 // we are interested in
2018 pBL = pBL->getNextBlockInDocument();
2019 UT_return_if_fail( pBL );
2020 buffer.truncate(0);
2021 pBL->getBlockBuf(&buffer);
2022
2023 // move past the block strux
2024 ++low;
2025 offset = 0;
2026 }
2027
2028 if(c == CASE_ROTATE)
2029 {
2030 // workout the current case
2031 UT_UCSChar * pT = reinterpret_cast<UT_UCSChar*>(buffer.getPointer(offset));
2032 xxx_UT_DEBUGMSG(("pT 0x%x, pT + 1 0x%x\n", *pT, *(pT+1)));
2033
2034 if(pT && UT_UCS4_islower(*pT) && buffer.getLength() > 1 && UT_UCS4_islower (*(pT+1)))
2035 {
2036 // lowercase, make first capital
2037 xxx_UT_DEBUGMSG(("case 1\n"));
2038 c = CASE_FIRST_CAPITAL;
2039 }
2040 else if(pT && !UT_UCS4_islower (*pT) && buffer.getLength() > 1 && UT_UCS4_islower (*(pT+1)))
2041 {
2042 // first capital, make upper
2043 xxx_UT_DEBUGMSG(("case 2\n"));
2044 c = CASE_UPPER;
2045 }
2046 else if(pT && buffer.getLength() == 1 && UT_UCS4_islower (*pT))
2047 {
2048 // single lowercase letter
2049 xxx_UT_DEBUGMSG(("case 3\n"));
2050 c = CASE_UPPER;
2051 }
2052 else
2053 {
2054 UT_DEBUGMSG(("case 4\n"));
2055 c = CASE_LOWER;
2056 }
2057
2058 xxx_UT_DEBUGMSG(("CASE_ROTATE translated to %d\n", c));
2059
2060 }
2061 if(pBL == NULL)
2062 {
2063 return;
2064 }
2065 if(pBL->getContainerType() != FL_CONTAINER_BLOCK)
2066 {
2067 pBL = static_cast<fl_ContainerLayout *>(pBL)->getNextBlockInDocument();
2068 }
2069
2070 const PP_AttrProp * pSpanAPAfter = NULL;
2071 pBL->getSpanAP(offset,false,pSpanAPAfter);
2072 PP_AttrProp * pSpanAPNow = const_cast<PP_AttrProp *>(pSpanAPAfter);
2073
2074 xxx_UT_DEBUGMSG(("fv_View::toggleCase: pBL 0x%x, offset %d, pSpanAPAfter 0x%x\n", pBL, offset, pSpanAPAfter));
2075
2076 pRun = pBL->findRunAtOffset(offset);
2077
2078 xxx_UT_DEBUGMSG(("fv_View::toggleCase: block offset %d, low %d, high %d, lastPos %%d\n", offset, low, high/*, lastPos*/));
2079
2080 bool bBlockDone = false;
2081 while(!bBlockDone && (low < high) /*&& (low < lastPos)*/)
2082 {
2083 UT_sint32 iLenToCopy = UT_MIN(high - low, buffer.getLength() - offset);
2084
2085 xxx_UT_DEBUGMSG(("fv_View::toggleCase: iLenToCopy %d, low %d\n", iLenToCopy, low));
2086
2087 if(!pRun || pRun->getType() == FPRUN_ENDOFPARAGRAPH || iLenToCopy == 0)
2088 break;
2089
2090 if(iLenToCopy > iTempLen)
2091 {
2092 delete[] pTemp;
2093 pTemp = new UT_UCSChar[iLenToCopy];
2094 iTempLen = iLenToCopy;
2095 UT_ASSERT(pTemp);
2096 }
2097
2098 while(pRun && iLenToCopy > 0)
2099 {
2100 UT_uint32 iLen = 0;
2101
2102 UT_ASSERT(pRun);
2103
2104 while( pRun
2105 && pRun->getType() != FPRUN_TEXT)
2106 {
2107 offset += pRun->getLength();
2108 low += pRun->getLength();
2109 iLenToCopy -= pRun->getLength();
2110 pRun = pRun->getNextRun();
2111 }
2112
2113 if(pRun && pRun->getBlockOffset() > offset)
2114 {
2115 // we skipped over an embeded section
2116 iLenToCopy -= pRun->getBlockOffset() - offset;
2117
2118 offset = pRun->getBlockOffset();
2119 low = pBL->getPosition(false) + offset;
2120 }
2121
2122
2123 fp_TextRun * pPrevTR = NULL;
2124
2125 while(pRun
2126 && iLenToCopy > 0
2127 && pRun->getType() == FPRUN_TEXT)
2128 {
2129 // in order not to loose formating, we will only replace
2130 // runs that can be merged in a single go
2131 if(pPrevTR && !pPrevTR->canMergeWithNext())
2132 break;
2133
2134 if(pRun->getBlockOffset() > offset + iLen)
2135 {
2136 // we skipped over an embeded section
2137 // i.e., there is a discontinuity in the block buffer
2138 break;
2139 }
2140
2141 UT_sint32 iDiff = UT_MIN((UT_sint32)pRun->getLength(), iLenToCopy);
2142 iLen += iDiff;
2143 iLenToCopy -= iDiff;
2144 pPrevTR = static_cast<fp_TextRun*>(pRun);
2145 pRun = pRun->getNextRun();
2146 }
2147
2148 if(!iLen) // sequence of 0-len runs only
2149 {
2150 UT_DEBUGMSG(("fv_View::toggleCase: sequence of 0-width runs only, next run type %d\n", pRun ? pRun->getType():-1));
2151 continue;
2152 }
2153
2154 UT_ASSERT(iLen + offset + pBL->getPosition(false) <= high);
2155
2156 memmove(pTemp, buffer.getPointer(offset), iLen * sizeof(UT_UCSChar));
2157
2158 switch (c)
2159 {
2160 case CASE_FIRST_CAPITAL:
2161 if(offset == 0)
2162 prev = NULL;
2163 else
2164 prev = reinterpret_cast<UT_UCSChar*>(buffer.getPointer(offset - 1));
2165 _toggleFirstCapital(pTemp,pTemp, iLen, prev);
2166 break;
2167
2168 case CASE_SENTENCE:
2169 #if 0
2170 if(offset < 2)
2171 prev = NULL;
2172 else
2173 prev = buffer.getPointer(offset - 2);
2174 _toggleSentence (pTemp, pTemp, iLen, prev);
2175 #endif
2176 {
2177 UT_uint32 iOffset = offset;
2178 UT_UCSChar * text = reinterpret_cast<UT_UCSChar*>(buffer.getPointer(0));
2179 UT_uint32 i = 1;
2180
2181 // examine what preceedes this chunk of text
2182 if(iOffset)
2183 iOffset--;
2184
2185 while(iOffset && UT_UCS4_isspace(text[iOffset]))
2186 {
2187 iOffset--;
2188 }
2189
2190 bool bStartOfSentence = !iOffset;
2191
2192 if(iOffset)
2193 {
2194 bStartOfSentence = UT_UCS4_isSentenceSeparator(text[iOffset]) && UT_UCS4_isalpha(text[iOffset-1]);
2195 }
2196
2197 if(bStartOfSentence)
2198 {
2199 i = 0;
2200 while( i < iLen && UT_UCS4_isspace(pTemp[i]))
2201 i++;
2202
2203 if(i < iLen)
2204 {
2205 pTemp[i] = UT_UCS4_toupper (pTemp[i]);
2206 i++;
2207 }
2208 }
2209
2210 for(; i < iLen; i++)
2211 {
2212 UT_ASSERT(i > 0);
2213 while(i < iLen && !UT_UCS4_isSentenceSeparator(pTemp[i]))
2214 i++;
2215
2216 // now i is either out of bounds, or points to the separator
2217 // if it points to the separator, check that the character before it
2218 // is a letter if not, start all over again
2219 if(i < iLen && !UT_UCS4_isalpha(pTemp[i-1]))
2220 continue;
2221
2222 // move past the separator
2223 i++;
2224
2225 if(i < iLen)
2226 {
2227 while( i < iLen && UT_UCS4_isspace(pTemp[i]))
2228 i++;
2229
2230 if(i < iLen)
2231 pTemp[i] = UT_UCS4_toupper(pTemp[i]);
2232 }
2233 }
2234 }
2235 break;
2236
2237 case CASE_LOWER:
2238 _toggleLower (pTemp, pTemp, iLen);
2239 break;
2240
2241 case CASE_UPPER:
2242 _toggleUpper (pTemp, pTemp, iLen);
2243 break;
2244 #if 0
2245 // see comments before _toggleTitle()
2246 case CASE_TITLE:
2247 _toggleTitle (pTemp, pTemp, iLen, _isSpaceBefore(low));
2248 break;
2249 #endif
2250 case CASE_TOGGLE:
2251 _toggleToggle (pTemp, pTemp, iLen);
2252 break;
2253
2254 default:
2255 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
2256 }
2257
2258 // get the props after our segment
2259 pBL->getSpanAP(offset+iLen,false,pSpanAPAfter);
2260 xxx_UT_DEBUGMSG(("fv_View::toggleCase: delete/insert: low %d, iLen %d, pSpanAPAfter 0x%x, pSpanAPNow 0x%x\n", low, iLen,pSpanAPAfter,pSpanAPNow));
2261
2262 #if 0
2263 UT_DEBUGMSG(("AP Now\n"));
2264 pSpanAPNow->miniDump(getDocument());
2265 UT_DEBUGMSG(("---------------------------------- \nAP After\n"));
2266 pSpanAPAfter->miniDump(getDocument());
2267 #endif
2268 UT_uint32 iRealDeleteCount;
2269 m_pDoc->tellPTDoNotTweakPosition(true); // stop surrounding hyperlinks,
2270 // bookmarks, etc. getting deleted
2271 bool bResult = m_pDoc->deleteSpan(low, low + iLen,NULL,iRealDeleteCount);
2272 m_pDoc->tellPTDoNotTweakPosition(false);
2273 UT_ASSERT(bResult);
2274
2275 //special handling is required for delete in revisions mode
2276 //where we have to move the insertion point
2277 if(isMarkRevisions())
2278 {
2279 UT_ASSERT( iRealDeleteCount <= iLen );
2280 _charMotion(true,iLen - iRealDeleteCount);
2281 }
2282 bResult = m_pDoc->insertSpan(low, pTemp, iLen, pSpanAPNow);
2283 UT_ASSERT_HARMLESS( bResult );
2284
2285 if(pSpanAPNow->getAttributes() || pSpanAPNow->getProperties())
2286 {
2287 bResult &= m_pDoc->changeSpanFmt(PTC_SetFmt,low,low+iLen,
2288 pSpanAPNow->getAttributes(),pSpanAPNow->getProperties());
2289 }
2290
2291 // now remember the props for the next round
2292 pSpanAPNow = const_cast<PP_AttrProp*>(pSpanAPAfter);
2293
2294 UT_ASSERT_HARMLESS(bResult);
2295 low += iLen;
2296 offset += iLen;
2297
2298 // the piecetable operations might have invalidated the pRun pointer,
2299 // need to get it afresh
2300
2301 pRun = pBL->findRunAtOffset(offset);
2302 if(!pRun && iLenToCopy && offset > 0)
2303 {
2304 // see if no run is not because of an embeded section
2305 // get a pointer to the run that holds the last
2306 // character we just changed, and from that get the next run
2307 pRun = pBL->findRunAtOffset(offset-1);
2308 if(pRun)
2309 {
2310 pRun = pRun->getNextRun();
2311 }
2312
2313 if(pRun)
2314 {
2315 // so there are still runs in this block; readjust the offsets
2316 iLenToCopy -= (pRun->getBlockOffset() - offset);
2317 offset = pRun->getBlockOffset();
2318 low = offset + pBL->getPosition(false);
2319 }
2320 }
2321 }
2322 }
2323 pBL = pBL->getNextBlockInDocument();
2324 if ( pBL )
2325 low = pBL->getPosition(false);
2326 else
2327 break;
2328 }
2329
2330 delete[] pTemp;
2331 _restorePieceTableState();
2332 _generalUpdate();
2333 m_pDoc->endUserAtomicGlob();
2334 if(origPos)
2335 _setPoint(origPos);
2336 }
2337
2338 /*!
2339 * This method appends all the text in the current Block to the supplied
2340 * Growbuf.
2341 */
getTextInCurrentBlock(UT_GrowBuf & buf) const2342 void FV_View::getTextInCurrentBlock(UT_GrowBuf & buf) const
2343 {
2344 fl_BlockLayout * pBlock = getCurrentBlock();
2345 pBlock->appendTextToBuf(buf);
2346 }
2347
2348
2349 /*!
2350 * This method appends all the text in the current DocSection to the supplied
2351 * Growbuf.
2352 */
getTextInCurrentSection(UT_GrowBuf & buf) const2353 void FV_View:: getTextInCurrentSection(UT_GrowBuf & buf) const
2354 {
2355 fl_BlockLayout * pBlock = getCurrentBlock();
2356 fl_DocSectionLayout * pDSL = pBlock->getDocSectionLayout();
2357 pDSL->appendTextToBuf(buf);
2358 }
2359
2360
2361 /*!
2362 * This method appends all the text in the Document to the supplied
2363 * Growbuf.
2364 */
getTextInDocument(UT_GrowBuf & buf) const2365 void FV_View:: getTextInDocument(UT_GrowBuf & buf) const
2366 {
2367 fl_ContainerLayout * pDSL = static_cast<fl_ContainerLayout *>(m_pLayout->getFirstSection());
2368 while(pDSL)
2369 {
2370 pDSL->appendTextToBuf(buf);
2371 pDSL = pDSL->getNext();
2372 }
2373 }
2374
2375 /*!
2376 * This method returns the bounds of a line, given an offset.
2377 */
getLineBounds(PT_DocPosition pos,PT_DocPosition * start,PT_DocPosition * end)2378 bool FV_View::getLineBounds(PT_DocPosition pos, PT_DocPosition *start, PT_DocPosition *end)
2379 {
2380 fl_BlockLayout *pBlock = NULL;
2381 fp_Run *pRun = NULL;
2382 UT_sint32 x, y;
2383 UT_uint32 height;
2384 UT_sint32 x2, y2;
2385 bool bDirection;
2386 _findPositionCoords(pos, FALSE, x, y, x2, y2, height, bDirection, &pBlock, &pRun);
2387 if (!pRun) return FALSE;
2388 fp_Line *line = pRun->getLine();
2389 PT_DocPosition blockpos = pBlock->getPosition();
2390 if (start)
2391 {
2392 *start = blockpos + line->getFirstRun()->getBlockOffset();
2393 }
2394 if (end)
2395 {
2396 fp_Run *lastrun = line->getLastRun();
2397 *end = blockpos + lastrun->getBlockOffset() + lastrun->getLength();
2398 }
2399 return TRUE;
2400 }
2401
getChar(PT_DocPosition pos,UT_sint32 * x,UT_sint32 * y,UT_uint32 * width,UT_uint32 * height)2402 UT_UCSChar FV_View::getChar(PT_DocPosition pos, UT_sint32 *x, UT_sint32 *y, UT_uint32 *width, UT_uint32 *height)
2403 {
2404 if (x || y || height)
2405 {
2406 UT_sint32 fp_x, fp_y;
2407 UT_uint32 fp_height;
2408 UT_sint32 x2, y2;
2409 bool bDirection;
2410 _findPositionCoords(pos, FALSE, fp_x, fp_y, x2, y2, fp_height, bDirection, NULL, NULL);
2411 if (x) *x = fp_x;
2412 if (y) *y = fp_y;
2413 if (height) *height = fp_height;
2414 }
2415
2416 pt_PieceTable *piece = getDocument()->getPieceTable();
2417 pf_Frag *p;
2418 PT_BlockOffset offset;
2419 UT_UCSChar ret = 0;
2420 if (piece->getFragFromPosition(pos, &p, &offset))
2421 {
2422 if (p->getType() == 0) // PFT_Text)
2423 {
2424 pf_Frag_Text *pt = reinterpret_cast<pf_Frag_Text *>(p);
2425 PT_BufIndex bi = pt->getBufIndex();
2426 const UT_UCSChar *c = piece->getPointer(bi);
2427 ret = c[offset];
2428 }
2429 }
2430 if (ret && width) *width = getGraphics()->measureUnRemappedChar(ret);
2431 return ret;
2432 }
2433
2434 /*!
2435 * Goes through the document and reformats any paragraphs that need this.
2436 */
updateLayout(void)2437 void FV_View::updateLayout(void)
2438 {
2439 m_pLayout->updateLayout();
2440 }
2441
setPaperColor(const gchar * clr)2442 void FV_View::setPaperColor(const gchar* clr)
2443 {
2444 UT_DEBUGMSG(("DOM: color is: %s\n", clr));
2445
2446 const gchar * props[3];
2447 props[0] = "background-color";
2448 props[1] = clr;
2449 props[2] = 0;
2450
2451 setSectionFormat(props);
2452 // update the screen
2453 _draw(0, 0, getWindowWidth(), getWindowHeight(), false, false);
2454 }
2455
killBlink(void)2456 void FV_View::killBlink(void)
2457 {
2458 m_pG->allCarets()->setBlink(false);
2459 }
2460
focusChange(AV_Focus focus)2461 void FV_View::focusChange(AV_Focus focus)
2462 {
2463 m_focus=focus;
2464 xxx_UT_DEBUGMSG(("fv_View:: Focus change focus = %d selection %d \n",focus,isSelectionEmpty()));
2465 switch(focus)
2466 {
2467 case AV_FOCUS_HERE:
2468 if(getPoint() > 0 && isSelectionEmpty())
2469 {
2470 if(m_FrameEdit.getFrameEditMode() != FV_FrameEdit_WAIT_FOR_FIRST_CLICK_INSERT)
2471 {
2472 m_pG->allCarets()->enable();
2473 }
2474 else
2475 {
2476 break;
2477 }
2478 }
2479 if (isSelectionEmpty() && (getPoint() > 0))
2480 {
2481 m_pG->allCarets()->setBlink(m_bCursorBlink);
2482 _setPoint(getPoint());
2483 }
2484 m_pApp->rememberFocussedFrame(m_pParentData);
2485 _updateSelectionHandles();
2486 break;
2487 case AV_FOCUS_NEARBY:
2488 if (isSelectionEmpty() && (getPoint() > 0))
2489 {
2490 m_pG->allCarets()->disable(true);
2491 m_countDisable++;
2492 }
2493 break;
2494 case AV_FOCUS_MODELESS:
2495 if (isSelectionEmpty() && (getPoint() > 0))
2496 {
2497 m_pG->allCarets()->setBlink(false);
2498 _setPoint(getPoint());
2499 }
2500 break;
2501 case AV_FOCUS_NONE:
2502 m_SelectionHandles.hide();
2503 if (isSelectionEmpty() && (getPoint() > 0))
2504 {
2505 m_pG->allCarets()->disable(true);
2506 m_countDisable++;
2507 }
2508 break;
2509 }
2510 AV_View::notifyListeners(AV_CHG_FOCUS);
2511 }
2512
getLayout() const2513 FL_DocLayout* FV_View::getLayout() const
2514 {
2515 return m_pLayout;
2516 }
2517
notifyListeners(const AV_ChangeMask hint)2518 bool FV_View::notifyListeners(const AV_ChangeMask hint)
2519 {
2520 //
2521 // No need to update stuff if we're in preview mode
2522 //
2523 if(isPreview()|| m_bDontNotifyListeners)
2524 return true;
2525 //
2526 // Sevior check if we need this?
2527 // For some complex operations we can't update stuff in the middle.
2528 // In particular insert headers/footers
2529 //
2530 // if(!_shouldScreenUpdateOnGeneralUpdate())
2531 // return false;
2532 /*
2533 IDEA: The view caches its change state as of the last notification,
2534 to minimize noise from duplicate notifications.
2535 */
2536 UT_ASSERT(hint != AV_CHG_NONE);
2537 AV_ChangeMask mask = hint;
2538
2539 //
2540 // Since we short circuit some operations we need to give some operations
2541 // a "freepass"
2542 //
2543 if(mask & m_iFreePass)
2544 {
2545 m_iFreePass = 0;
2546 return AV_View::notifyListeners(mask);
2547 }
2548
2549 if (mask & AV_CHG_DO)
2550 {
2551 bool bUndo = canDo(true);
2552 bool bRedo = canDo(false);
2553
2554 if ((m_chg.bUndo == bUndo) && (m_chg.bRedo == bRedo))
2555 {
2556 mask ^= AV_CHG_DO;
2557 }
2558 else
2559 {
2560 if (m_chg.bUndo != bUndo)
2561 m_chg.bUndo = bUndo;
2562 if (m_chg.bRedo != bRedo)
2563 m_chg.bRedo = bRedo;
2564 }
2565 }
2566
2567 if (mask & AV_CHG_DIRTY)
2568 {
2569 bool bDirty = m_pDoc->isDirty();
2570
2571 if (m_chg.bDirty != bDirty)
2572 {
2573 m_chg.bDirty = bDirty;
2574 }
2575 else
2576 {
2577 mask ^= AV_CHG_DIRTY;
2578 }
2579 }
2580
2581 if (mask & AV_CHG_EMPTYSEL)
2582 {
2583 bool bSel = !isSelectionEmpty();
2584
2585 if (m_chg.bSelection != bSel)
2586 m_chg.bSelection = bSel;
2587 else
2588 mask ^= AV_CHG_EMPTYSEL;
2589 }
2590
2591 if (mask & AV_CHG_FILENAME)
2592 {
2593 // NOTE: we don't attempt to filter this
2594 }
2595
2596 if (mask & AV_CHG_FMTBLOCK)
2597 {
2598 /*
2599 The following brute-force solution works, but is atrociously
2600 expensive, so we should avoid using it whenever feasible.
2601 */
2602 const gchar ** propsBlock = NULL;
2603 getBlockFormat(&propsBlock);
2604
2605 bool bMatch = false;
2606
2607 if (propsBlock && m_chg.propsBlock)
2608 {
2609 bMatch = true;
2610
2611 int i=0;
2612
2613 while (bMatch)
2614 {
2615 if (!propsBlock[i] || !m_chg.propsBlock[i])
2616 {
2617 bMatch = (propsBlock[i] == m_chg.propsBlock[i]);
2618 break;
2619 }
2620
2621 if (strcmp(propsBlock[i], m_chg.propsBlock[i]))
2622 {
2623 bMatch = false;
2624 break;
2625 }
2626
2627 i++;
2628 }
2629 }
2630
2631 if (!bMatch)
2632 {
2633 FREEP(m_chg.propsBlock);
2634 m_chg.propsBlock = propsBlock;
2635 }
2636 else
2637 {
2638 FREEP(propsBlock);
2639 mask ^= AV_CHG_FMTBLOCK;
2640 }
2641 }
2642
2643 if (mask & AV_CHG_FMTCHAR)
2644 {
2645 /*
2646 The following brute-force solution works, but is atrociously
2647 expensive, so we should avoid using it whenever feasible.
2648
2649 TODO: devise special case logic for (at minimum) char motion
2650 */
2651 const gchar ** propsChar = NULL;
2652 getCharFormat(&propsChar);
2653
2654 bool bMatch = false;
2655
2656 if (propsChar && m_chg.propsChar)
2657 {
2658 bMatch = true;
2659
2660 int i=0;
2661
2662 while (bMatch)
2663 {
2664 if (!propsChar[i] || !m_chg.propsChar[i])
2665 {
2666 bMatch = (propsChar[i] == m_chg.propsChar[i]);
2667 break;
2668 }
2669
2670 if (strcmp(propsChar[i], m_chg.propsChar[i]))
2671 {
2672 bMatch = false;
2673 break;
2674 }
2675
2676 i++;
2677 }
2678 }
2679
2680 if (!bMatch)
2681 {
2682 FREEP(m_chg.propsChar);
2683 m_chg.propsChar = propsChar;
2684 }
2685 else
2686 {
2687 FREEP(propsChar);
2688 mask ^= AV_CHG_FMTCHAR;
2689 }
2690 }
2691
2692 if (mask & AV_CHG_FMTSECTION)
2693 {
2694 /*
2695 The following brute-force solution works, but is atrociously
2696 expensive, so we should avoid using it whenever feasible.
2697 */
2698 const gchar ** propsSection = NULL;
2699 getSectionFormat(&propsSection);
2700
2701 bool bMatch = false;
2702
2703 if (propsSection && m_chg.propsSection)
2704 {
2705 bMatch = true;
2706
2707 int i=0;
2708
2709 while (bMatch)
2710 {
2711 if (!propsSection[i] || !m_chg.propsSection[i])
2712 {
2713 bMatch = (propsSection[i] == m_chg.propsSection[i]);
2714 break;
2715 }
2716
2717 if (strcmp(propsSection[i], m_chg.propsSection[i]))
2718 {
2719 bMatch = false;
2720 break;
2721 }
2722
2723 i++;
2724 }
2725 }
2726
2727 if (!bMatch)
2728 {
2729 FREEP(m_chg.propsSection);
2730 m_chg.propsSection = propsSection;
2731 }
2732 else
2733 {
2734 FREEP(propsSection);
2735 mask ^= AV_CHG_FMTSECTION;
2736 }
2737 }
2738
2739 if (mask & AV_CHG_FMTSTYLE)
2740 {
2741 // NOTE: we don't attempt to filter this
2742 // TODO: we probably should
2743 }
2744
2745 if (mask & AV_CHG_PAGECOUNT)
2746 {
2747 // We keep track of the number of page in the document in order
2748 // to recalculate the vertical scrollbar only when needed
2749 // (this prevents bug #13355 (comment #17))
2750
2751 UT_sint32 iNbPages = getLayout()->countPages();
2752 if (m_iOldPageCount == iNbPages)
2753 {
2754 mask ^= AV_CHG_PAGECOUNT;
2755 }
2756 else
2757 {
2758 m_iOldPageCount = iNbPages;
2759 }
2760 }
2761
2762 if (mask & AV_CHG_COLUMN)
2763 {
2764 // computing which column the cursor is in is rather expensive,
2765 // i'm not sure it's worth the effort here...
2766
2767 fp_Run * pRun = NULL;
2768 UT_sint32 xCaret, yCaret;
2769 UT_uint32 heightCaret;
2770 UT_sint32 xCaret2, yCaret2;
2771 bool bDirection;
2772 _findPositionCoords(getPoint(), m_bPointEOL, xCaret, yCaret, xCaret2, yCaret2, heightCaret, bDirection, NULL, &pRun);
2773
2774 //
2775 // Handle Headers/Footers This is a kludge for now
2776 //
2777 fp_Container * pContainer = NULL;
2778 if(pRun == NULL)
2779 {
2780 return false; // bail out
2781 }
2782 fl_BlockLayout * pBlock = pRun->getBlock();
2783 if(pBlock->getSectionLayout()->getType() == FL_SECTION_HDRFTR)
2784 {
2785 // General question for msevior: When is this triggered?
2786 // Usually we have an FL_SECTION_SHADOW. - PL
2787 // The answer:
2788
2789 // That if was put in to guard against an extremely
2790 // convoluted crasher that occured once. I forget the
2791 // details and you really don't want to know. Something
2792 // like calling a _generalUpdate() from an insertStrux
2793 // while editting the first header and it had been
2794 // modified or something...
2795
2796 if(m_bEditHdrFtr)
2797 {
2798 pContainer = m_pEditShadow->getFirstContainer();
2799 }
2800 else
2801 pContainer = pBlock->getSectionLayout()->getFirstContainer();
2802 }
2803 else
2804 {
2805 pContainer = pRun->getLine()->getColumn();
2806 if(pContainer == NULL)
2807 {
2808 pBlock->needsReformat();
2809 return false;
2810 }
2811 }
2812
2813 UT_ASSERT(pContainer);
2814 if (pContainer && pContainer->getContainerType() == FP_CONTAINER_COLUMN)
2815 {
2816 fp_Column* pColumn = static_cast<fp_Column*>(pContainer);
2817
2818 UT_uint32 nCol=0;
2819 fp_Column * pNthColumn = pColumn->getLeader();
2820 while (pNthColumn && (pNthColumn != pColumn))
2821 {
2822 nCol++;
2823 pNthColumn = pNthColumn->getFollower();
2824 }
2825
2826 if (nCol != m_chg.iColumn)
2827 {
2828 m_chg.iColumn = nCol;
2829 }
2830 else
2831 {
2832 mask ^= AV_CHG_COLUMN;
2833 }
2834 }
2835 else if (pContainer && pContainer->getContainerType() == FP_CONTAINER_COLUMN_SHADOW)
2836 {
2837 // Hack the kludge:
2838 // Clearly you can't change columns while editing a header. -PL
2839 mask ^= AV_CHG_COLUMN;
2840 }
2841 else if(pContainer == NULL)
2842 {
2843 return false;
2844 }
2845 }
2846
2847 if (mask & AV_CHG_CELL)
2848 {
2849 fl_BlockLayout * pBlock = _findBlockAtPosition(getPoint());
2850 fl_ContainerLayout * pCL = pBlock->myContainingLayout();
2851 if (pCL && (pCL->getContainerType() == FL_CONTAINER_CELL))
2852 {
2853 if (pCL != m_chg.pCellLayout)
2854 {
2855 m_chg.pCellLayout = static_cast<fl_CellLayout*>(pCL);
2856 }
2857 else
2858 {
2859 mask ^= AV_CHG_CELL;
2860 }
2861 }
2862 else if (m_chg.pCellLayout)
2863 {
2864 // Caret just moved out of a table
2865 m_chg.pCellLayout = NULL;
2866 }
2867 else
2868 {
2869 mask ^= AV_CHG_CELL;
2870 }
2871 }
2872
2873 if (mask & AV_CHG_WINDOWSIZE)
2874 m_pG->allCarets()->setWindowSize(getWindowWidth(), getWindowHeight());
2875
2876 // base class does the rest
2877 xxx_UT_DEBUGMSG(("FV_View: notifyListeners: this %x \n",this));
2878 return AV_View::notifyListeners(mask);
2879 }
2880
2881
saveSelectedImage(const char * toFile)2882 PT_DocPosition FV_View::saveSelectedImage (const char * toFile)
2883 {
2884 const UT_ByteBuf * pBytes = NULL ;
2885
2886 PT_DocPosition dPos = saveSelectedImage ( &pBytes ) ;
2887
2888 if ( pBytes )
2889 {
2890 pBytes->writeToURI ( toFile ) ;
2891 }
2892
2893 return dPos ;
2894 }
2895
mapDocPos(FV_DocPos dp)2896 PT_DocPosition FV_View::mapDocPos( FV_DocPos dp ) {
2897 return ( _getDocPos( dp ));
2898 }
2899
mapDocPosSimple(FV_DocPos dp)2900 PT_DocPosition FV_View::mapDocPosSimple( FV_DocPos dp ) {
2901 return ( _getDocPos( dp, false ));
2902 }
2903
saveSelectedImage(const UT_ByteBuf ** pBytes)2904 PT_DocPosition FV_View::saveSelectedImage (const UT_ByteBuf ** pBytes)
2905 {
2906 const char * dataId;
2907 PT_DocPosition pos = 0;
2908 if(m_prevMouseContext == EV_EMC_POSOBJECT)
2909 {
2910 fl_FrameLayout * pFrame = getFrameLayout();
2911 const PP_AttrProp* pAP = NULL;
2912 UT_return_val_if_fail(pFrame, 0);
2913 pFrame->getAP(pAP);
2914 if(pAP == NULL)
2915 {
2916 return 0;
2917 }
2918 pAP->getAttribute(PT_STRUX_IMAGE_DATAID, dataId);
2919 pos = pFrame->getPosition();
2920 }
2921 else
2922 {
2923 pos = getSelectedImage(&dataId);
2924
2925 // if nothing selected or selection not an image
2926 if (pos == 0) return 0;
2927 }
2928 if ( m_pDoc->getDataItemDataByName ( dataId, pBytes, NULL, NULL ) )
2929 {
2930 return pos ;
2931 }
2932 return 0 ;
2933 }
2934
2935 /* If no image is selected returns 0
2936 * and if dataId is not NULL will set value to NULL
2937 * Otherwise returns a nonzero value indicating the position of the image
2938 * and if dataId is not NULL will set value to the image's data ID
2939 */
2940
getSelectedImage(const char ** dataId) const2941 PT_DocPosition FV_View::getSelectedImage(const char **dataId) const
2942 {
2943 const fp_Run * pRun = NULL;
2944 return getSelectedImage(dataId,&pRun);
2945 }
2946
getSelectedImage(const char ** dataId,const fp_Run ** pImRun) const2947 PT_DocPosition FV_View::getSelectedImage(const char **dataId, const fp_Run **pImRun) const
2948 {
2949 // if nothing selected, then an image can't be
2950 if (!isSelectionEmpty())
2951 {
2952 PT_DocPosition pos = m_Selection.getSelectionAnchor();
2953 fp_Run* pRun = NULL;
2954
2955 UT_GenericVector<fl_BlockLayout *> vBlock;
2956 getBlocksInSelection( &vBlock);
2957 UT_uint32 count = vBlock.getItemCount();
2958 fl_BlockLayout * pBlock = NULL;
2959 for(UT_uint32 i=0; (i< count); i++)
2960 {
2961 if(i==0)
2962 {
2963 if(getPoint() < m_Selection.getSelectionAnchor())
2964 {
2965 pos = getPoint();
2966 }
2967 UT_sint32 x,y,x2,y2;
2968 UT_uint32 height;
2969
2970 bool bEOL = false;
2971 bool bDirection;
2972 _findPositionCoords(pos,bEOL,x,y,x2,y2,height,bDirection,&pBlock,&pRun);
2973 }
2974 else
2975 {
2976 pBlock = vBlock.getNthItem(i);
2977 pRun = pBlock->getFirstRun();
2978 }
2979
2980 while(pRun && pRun->getType() != FPRUN_IMAGE)
2981 {
2982 pRun = pRun->getNextRun();
2983 }
2984 if(pRun && pRun->getType() == FPRUN_IMAGE)
2985 {
2986 pos = pBlock->getPosition() + pRun->getBlockOffset();
2987 if (dataId != NULL)
2988 {
2989 *dataId = static_cast<fp_ImageRun *>(pRun)->getDataId();
2990 }
2991 *pImRun = pRun;
2992 return pos;
2993 }
2994 }
2995 }
2996
2997 // if we made it here, then run type is not an image
2998 if (dataId != NULL) {
2999 *dataId = NULL;
3000 }
3001 pImRun = NULL;
3002
3003 return 0;
3004 }
3005
3006 /* If no object is selected returns NULL
3007 * Otherwise returns a nonzero value indicating the position of the object
3008 * and if dataId is not NULL will set value to the object's data ID
3009 */
getSelectedObject() const3010 fp_Run *FV_View::getSelectedObject() const
3011 {
3012 // if nothing selected, then an image can't be
3013 if (!isSelectionEmpty())
3014 {
3015 PT_DocPosition pos = m_Selection.getSelectionAnchor();
3016 fp_Run* pRun = NULL;
3017
3018 UT_GenericVector<fl_BlockLayout *> vBlock;
3019 getBlocksInSelection( &vBlock);
3020 UT_uint32 count = vBlock.getItemCount();
3021 fl_BlockLayout * pBlock = NULL;
3022 for(UT_uint32 i=0; (i< count); i++)
3023 {
3024 if(i==0)
3025 {
3026 if(getPoint() < m_Selection.getSelectionAnchor())
3027 {
3028 pos = getPoint();
3029 }
3030 UT_sint32 x,y,x2,y2;
3031 UT_uint32 height;
3032
3033 bool bEOL = false;
3034 bool bDirection;
3035 _findPositionCoords(pos,bEOL,x,y,x2,y2,height,bDirection,&pBlock,&pRun);
3036 }
3037 else
3038 {
3039 pBlock = vBlock.getNthItem(i);
3040 pRun = pBlock->getFirstRun();
3041 }
3042
3043 while(pRun && pRun->getType() != FPRUN_EMBED)
3044 {
3045 pRun = pRun->getNextRun();
3046 }
3047 if(pRun && pRun->getType() == FPRUN_EMBED)
3048 {
3049 return pRun;
3050 }
3051 }
3052 }
3053
3054 return NULL;
3055 }
3056
getSelectionAnchor(void) const3057 PT_DocPosition FV_View::getSelectionAnchor(void) const
3058 {
3059 if(m_Selection.isSelected())
3060 {
3061 return m_Selection.getSelectionAnchor();
3062 }
3063 return m_iInsPoint;
3064 }
3065
getSelectionLeftAnchor(void) const3066 PT_DocPosition FV_View::getSelectionLeftAnchor(void) const
3067 {
3068 return m_Selection.getSelectionLeftAnchor();
3069 }
3070
getSelectionRightAnchor(void) const3071 PT_DocPosition FV_View::getSelectionRightAnchor(void) const
3072 {
3073 return m_Selection.getSelectionRightAnchor();
3074 }
3075
3076 /*!
3077 * Returns true if a TOC is selected.
3078 */
isTOCSelected(void) const3079 bool FV_View::isTOCSelected(void) const
3080 {
3081 return (m_Selection.getSelectionMode() == FV_SelectionMode_TOC);
3082 }
3083
3084 /*!
3085 * This method assumes that pos points to exactly the location of
3086 * PTX_SectionTOC. It should only really be called if the TOC is selected.
3087 */
setTOCProps(PT_DocPosition pos,const char * szProps)3088 bool FV_View::setTOCProps(PT_DocPosition pos, const char * szProps)
3089 {
3090 bool bRet;
3091
3092 // Signal PieceTable Change
3093 _saveAndNotifyPieceTableChange();
3094 const gchar * atts[3] ={"props",NULL,NULL};
3095 atts[1] = szProps;
3096 bRet = m_pDoc->changeStruxFmt(PTC_AddFmt,pos,pos,atts,NULL,PTX_SectionTOC);
3097
3098 // Signal piceTable is stable again
3099 _restorePieceTableState();
3100 _generalUpdate();
3101 return bRet;
3102 }
3103
isSelectionEmpty(void) const3104 bool FV_View::isSelectionEmpty(void) const
3105 {
3106 if(m_FrameEdit.isActive() && m_FrameEdit.isImageWrapper() )
3107 {
3108 if (m_pG)
3109 m_pG->allCarets()->disable(true);
3110 return false;
3111 }
3112 if(m_FrameEdit.isActive() && (m_FrameEdit. getFrameEditMode() >= FV_FrameEdit_RESIZE_INSERT))
3113 {
3114 if (m_pG)
3115 m_pG->allCarets()->disable(true);
3116 return false;
3117 }
3118 if (!m_Selection.isSelected())
3119 {
3120 return true;
3121 }
3122 if((m_Selection.getSelectionMode() != FV_SelectionMode_Single) &&
3123 (m_Selection.getSelectionMode() != FV_SelectionMode_NONE))
3124 {
3125 if((m_Selection.getSelectionMode() == FV_SelectionMode_TableRow) &&
3126 (getPoint() == getSelectionAnchor()) && (m_Selection.getSelectionLeftAnchor() ==
3127 m_Selection.getSelectionLeftAnchor()))
3128 {
3129 return true;
3130 }
3131 if (m_pG)
3132 m_pG->allCarets()->disable(true);
3133 return false;
3134 }
3135 PT_DocPosition curPos = getPoint();
3136 if (curPos == m_Selection.getSelectionAnchor())
3137 {
3138 return true;
3139 }
3140 if (m_pG)
3141 m_pG->allCarets()->disable(true);
3142 return false;
3143 }
3144
3145
moveInsPtTo(FV_DocPos dp,bool bClearSelection)3146 void FV_View::moveInsPtTo(FV_DocPos dp, bool bClearSelection)
3147 {
3148 if(bClearSelection)
3149 {
3150 if (!isSelectionEmpty())
3151 _clearSelection();
3152 }
3153
3154
3155 PT_DocPosition iPos = _getDocPos(dp);
3156 if((dp == FV_DOCPOS_EOD) && m_pDoc->isHdrFtrAtPos(iPos) &&
3157 m_pDoc->isEndFrameAtPos(iPos-1))
3158 {
3159 iPos--;
3160 while(!isPointLegal(iPos))
3161 {
3162 iPos--;
3163 }
3164 }
3165 else if((dp == FV_DOCPOS_EOD) && m_pDoc->isEndFrameAtPos(iPos))
3166 {
3167 iPos--;
3168 while(!isPointLegal(iPos))
3169 {
3170 iPos--;
3171 }
3172 }
3173 if (iPos != getPoint())
3174 {
3175 bool bPointIsValid = (getPoint() >= _getDocPos(FV_DOCPOS_BOD));
3176 if (bPointIsValid)
3177 _clearIfAtFmtMark(getPoint());
3178 }
3179
3180 _setPoint(iPos, (dp == FV_DOCPOS_EOL));
3181 _makePointLegal();
3182 //
3183 // Check we have a layout defined first. On startup we don't
3184 //
3185 if(getLayout()->getFirstSection())
3186 {
3187 _ensureInsertionPointOnScreen();
3188 notifyListeners(AV_CHG_MOTION);
3189 }
3190 }
3191
moveInsPtTo(PT_DocPosition dp)3192 void FV_View::moveInsPtTo(PT_DocPosition dp)
3193 {
3194 if (dp != getPoint())
3195 _clearIfAtFmtMark(getPoint());
3196
3197 _setPoint(dp, /* (dp == FV_DOCPOS_EOL) */ false); // is this bool correct?
3198 _makePointLegal();
3199 /*TF CHANGE: Why do we automatically scroll? We should only scroll the window
3200 if the point to be displayed is not already on the screen. If it
3201 is already on the screen then we should just leave it in place and
3202 not do any scrolling. Instead of the code below, we use the code which
3203 is already in the _ensureInsertionPointOnScreen() function.
3204 _fixInsertionPointCoords();
3205 cmdScroll(AV_SCROLLCMD_LINEDOWN, static_cast<UT_uint32>(m_yPoint + m_iPointHeight/2 - getWindowHeight()/2));
3206 cmdScroll(AV_SCROLLCMD_LINERIGHT, static_cast<UT_uint32>(m_xPoint - getWindowWidth()/2));
3207 notifyListeners(AV_CHG_MOTION);
3208 */
3209 _ensureInsertionPointOnScreen();
3210 }
3211
3212
getCurrentPageNumber(void) const3213 UT_uint32 FV_View::getCurrentPageNumber(void) const
3214 {
3215 UT_sint32 iPageNum = 0;
3216 PT_DocPosition pos = getPoint();
3217 fl_BlockLayout * pBlock;
3218 UT_sint32 xPoint, yPoint, xPoint2, yPoint2;
3219 UT_uint32 iPointHeight;
3220 bool bDirection;
3221 fp_Run* pRun;
3222 _findPositionCoords(pos, m_bPointEOL, xPoint, yPoint, xPoint2, yPoint2, iPointHeight, bDirection,&pBlock, &pRun);
3223 if(!pRun)
3224 {
3225 return 1;
3226 }
3227 fp_Line * pLine = pRun->getLine();
3228 if (pLine && pLine->getContainer() && pLine->getContainer()->getPage())
3229 {
3230 fp_Page* pPage = pLine->getContainer()->getPage();
3231 FL_DocLayout* pDL = pPage->getDocLayout();
3232
3233 UT_uint32 iNumPages = pDL->countPages();
3234 for (UT_uint32 i=0; i<iNumPages; i++)
3235 {
3236 fp_Page* pPg = pDL->getNthPage(i);
3237
3238 if (pPg == pPage)
3239 {
3240 iPageNum = i + 1;
3241 break;
3242 }
3243 }
3244 }
3245 else
3246 {
3247 iPageNum = 0;
3248 }
3249 return iPageNum;
3250 }
3251
3252
insertSectionBreak(BreakSectionType type)3253 void FV_View::insertSectionBreak(BreakSectionType type)
3254 {
3255 // if Type = 0 "continuous" section break
3256 // if Type = 1 "next page" section break
3257 // if Type = 2 "even page" section break
3258 // if Type = 3 "odd page" section break
3259
3260
3261 // Signal PieceTable Changes have Started
3262 m_pDoc->notifyPieceTableChangeStart();
3263
3264 UT_UCSChar c = UCS_FF;
3265 UT_uint32 iPageNum = 0;
3266 switch(type)
3267 {
3268 case BreakSectionContinuous:
3269 m_pDoc->beginUserAtomicGlob();
3270 _insertSectionBreak();
3271 m_pDoc->endUserAtomicGlob();
3272 break;
3273 case BreakSectionNextPage:
3274 m_pDoc->beginUserAtomicGlob();
3275 _insertSectionBreak();
3276 cmdCharInsert(&c,1);
3277 m_pDoc->endUserAtomicGlob();
3278 break;
3279 case BreakSectionEvenPage:
3280 m_pDoc->beginUserAtomicGlob();
3281 cmdCharInsert(&c,1);
3282 iPageNum = getCurrentPageNumber();
3283 if( (iPageNum & 1) == 1)
3284 {
3285 _insertSectionBreak();
3286 cmdCharInsert(&c,1);
3287 }
3288 else
3289 {
3290 _insertSectionBreak();
3291 }
3292 m_pDoc->endUserAtomicGlob();
3293 break;
3294 case BreakSectionOddPage:
3295 m_pDoc->beginUserAtomicGlob();
3296 cmdCharInsert(&c,1);
3297 iPageNum = getCurrentPageNumber();
3298 if( (iPageNum & 1) == 0)
3299 {
3300 _insertSectionBreak();
3301 cmdCharInsert(&c,1);
3302 }
3303 else
3304 {
3305 _insertSectionBreak();
3306 }
3307 m_pDoc->endUserAtomicGlob();
3308 break;
3309 default:
3310 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
3311 }
3312
3313 // Signal PieceTable Changes have ended
3314 m_pDoc->notifyPieceTableChangeEnd();
3315 m_iPieceTableState = 0;
3316 notifyListeners(AV_CHG_ALL);
3317 }
3318
insertSectionBreak(void)3319 void FV_View::insertSectionBreak(void)
3320 {
3321 m_pDoc->beginUserAtomicGlob();
3322
3323 // Signal PieceTable Changes have Started
3324 m_pDoc->notifyPieceTableChangeStart();
3325
3326 _insertSectionBreak();
3327
3328 // Signal PieceTable Changes have ended
3329 m_pDoc->notifyPieceTableChangeEnd();
3330 m_iPieceTableState = 0;
3331 m_pDoc->endUserAtomicGlob();
3332 }
3333
3334
3335
isCurrentListBlockEmpty(void) const3336 bool FV_View::isCurrentListBlockEmpty(void) const
3337 {
3338 //
3339 // If the current block is a list and is otherwise empty return true
3340 //
3341 fl_BlockLayout * pBlock = getCurrentBlock();
3342 fl_BlockLayout * nBlock = static_cast<fl_BlockLayout *>(pBlock->getNext());
3343 bool bEmpty = true;
3344 if(pBlock->isListItem() == false || (nBlock!= NULL && nBlock->isListItem()==true))
3345 {
3346 return false;
3347 }
3348
3349 //
3350 // Now look to see if the current block is otherwise empty
3351 //
3352 fp_Run * pRun = pBlock->getFirstRun();
3353 UT_uint32 ifield =0;
3354 UT_uint32 iTab = 0;
3355 while((bEmpty == true) && (pRun != NULL))
3356 {
3357 FP_RUN_TYPE runtype = static_cast<FP_RUN_TYPE>(pRun->getType());
3358 if((runtype == FPRUN_TAB) ||
3359 ( runtype == FPRUN_FIELD) ||
3360 (runtype == FPRUN_FMTMARK) ||
3361 (runtype == FPRUN_ENDOFPARAGRAPH))
3362 {
3363 if(runtype == FPRUN_FIELD)
3364 {
3365 ifield++;
3366 if(ifield > 1)
3367 {
3368 bEmpty = false;
3369 break;
3370 }
3371 }
3372 else if(runtype == FPRUN_TAB)
3373 {
3374 iTab++;
3375 if(iTab > 1)
3376 {
3377 bEmpty = false;
3378 break;
3379 }
3380 }
3381 pRun = pRun->getNextRun();
3382 }
3383 else
3384 {
3385 bEmpty = false;
3386 }
3387 }
3388 return bEmpty;
3389 }
3390
isPointBeforeListLabel(void) const3391 bool FV_View::isPointBeforeListLabel(void) const
3392 {
3393 //
3394 // If the current point is in a list block and the point is before the list label
3395 // return true
3396 //
3397 fl_BlockLayout * pBlock = getCurrentBlock();
3398 bool bBefore = true;
3399 if(pBlock->isListItem() == false)
3400 {
3401 return false;
3402 }
3403
3404 //
3405 // Now look to see if the point is before the list label
3406 //
3407 PT_DocPosition pos = getPoint();
3408 UT_sint32 xPoint;
3409 UT_sint32 yPoint;
3410 UT_sint32 iPointHeight;
3411 UT_sint32 xPoint2;
3412 UT_sint32 yPoint2;
3413 bool bDirection;
3414
3415 fp_Run* pRun = pBlock->findPointCoords(pos, m_bPointEOL, xPoint, yPoint, xPoint2, yPoint2, iPointHeight, bDirection);
3416 pRun = pRun->getPrevRun();
3417 while(pRun != NULL && bBefore == true)
3418 {
3419 if(pRun->getType()== FPRUN_FIELD)
3420 {
3421 fp_FieldRun * pFRun = static_cast<fp_FieldRun *>(pRun);
3422 if (pFRun->getFieldType() == FPFIELD_list_label)
3423 {
3424 bBefore = false;
3425 }
3426 }
3427 pRun = pRun->getPrevRun();
3428 }
3429 return bBefore;
3430 }
3431
3432 /*!
3433 * This method returns true if the block presented has a numbered heading
3434 * defined or in it's ancestray.
3435 */
isNumberedHeadingHere(fl_BlockLayout * pBlock) const3436 bool FV_View::isNumberedHeadingHere(fl_BlockLayout * pBlock) const
3437 {
3438 bool bHasNumberedHeading = false;
3439 if(pBlock == NULL)
3440 {
3441 return bHasNumberedHeading;
3442 }
3443 const PP_AttrProp * pBlockAP = NULL;
3444 pBlock->getAP(pBlockAP);
3445 const gchar* pszCurStyle = NULL;
3446 pBlockAP->getAttribute(PT_STYLE_ATTRIBUTE_NAME, pszCurStyle);
3447 if(pszCurStyle == NULL)
3448 {
3449 return false;
3450 }
3451 PD_Style * pCurStyle = NULL;
3452 m_pDoc->getStyle(static_cast<const char*>(pszCurStyle), &pCurStyle);
3453 UT_uint32 depth = 0;
3454 while(pCurStyle && !bHasNumberedHeading && depth < 10)
3455 {
3456 bHasNumberedHeading = (strstr(pszCurStyle,"Numbered Heading") != NULL);
3457 if(!bHasNumberedHeading)
3458 {
3459 pCurStyle = pCurStyle->getBasedOn();
3460 if(pCurStyle)
3461 pszCurStyle = pCurStyle->getName();
3462 depth++;
3463 }
3464 }
3465 return bHasNumberedHeading;
3466 }
3467
processSelectedBlocks(FL_ListType listType)3468 void FV_View::processSelectedBlocks(FL_ListType listType)
3469 {
3470 //
3471 // Update Lists in the selected region
3472 //
3473
3474 // Signal PieceTable Change
3475 _saveAndNotifyPieceTableChange();
3476
3477 UT_GenericVector<fl_BlockLayout *> vBlock;
3478 getBlocksInSelection( &vBlock);
3479
3480 PT_DocPosition posStart = getPoint();
3481 PT_DocPosition posEnd = m_Selection.getSelectionAnchor();
3482 if(posEnd < posStart)
3483 {
3484 PT_DocPosition swap = posStart;
3485 posStart = posEnd;
3486 posEnd = swap;
3487 }
3488 UT_sint32 diff =0;
3489 bool bNoSelection = true;
3490 //
3491 // Turn off cursor
3492 //
3493 if(!isSelectionEmpty())
3494 {
3495 bNoSelection = false;
3496 _clearSelection();
3497 }
3498 UT_sint32 i;
3499 m_pDoc->disableListUpdates();
3500
3501 m_pDoc->beginUserAtomicGlob();
3502
3503 char margin_left [] = "margin-left";
3504 char margin_right[] = "margin-right";
3505 UT_GenericVector<fl_BlockLayout *> vListBlocks;
3506 UT_GenericVector<fl_BlockLayout *> vNoListBlocks;
3507
3508 for(i=0; i< vBlock.getItemCount(); i++)
3509 {
3510 fl_BlockLayout * pBlock = vBlock.getNthItem(i);
3511 if(pBlock->isListItem())
3512 {
3513 vListBlocks.addItem(pBlock);
3514 diff -= 2;
3515 }
3516 else
3517 {
3518 vNoListBlocks.addItem(pBlock);
3519 diff += 2;
3520 }
3521 }
3522 //
3523 // Have to stop lists in reverse order so undo works!
3524 //
3525 for(i = vListBlocks.getItemCount() -1; i>=0; i--)
3526 {
3527 UT_DEBUGMSG(("SEVIOR: Processing block %d \n",i));
3528 fl_BlockLayout * pBlock = vListBlocks.getNthItem(i);
3529 PT_DocPosition posBlock = pBlock->getPosition();
3530
3531 const gchar * pListAttrs[10];
3532 pListAttrs[0] = "listid";
3533 pListAttrs[1] = NULL;
3534 pListAttrs[2] = "parentid";
3535 pListAttrs[3] = NULL;
3536 pListAttrs[4] = "level";
3537 pListAttrs[5] = NULL;
3538 pListAttrs[6] = NULL;
3539 pListAttrs[7] = NULL;
3540 pListAttrs[8] = NULL;
3541 pListAttrs[9] = NULL;
3542
3543 // we also need to explicitely clear the list formating
3544 // properties, since their values are not necessarily part
3545 // of the style definition, so that cloneWithEliminationIfEqual
3546 // which we call later will not get rid off them
3547 const gchar * pListProps[20];
3548 pListProps[0] = "start-value";
3549 pListProps[1] = NULL;
3550 pListProps[2] = "list-style";
3551 pListProps[3] = NULL;
3552
3553 if(pBlock->getDominantDirection() == UT_BIDI_RTL)
3554 pListProps[4] = "margin-right";
3555 else
3556 pListProps[4] = "margin-left";
3557
3558 pListProps[5] = NULL;
3559 pListProps[6] = "text-indent";
3560 pListProps[7] = NULL;
3561 pListProps[8] = "field-color";
3562 pListProps[9] = NULL;
3563 pListProps[10]= "list-delim";
3564 pListProps[11] = NULL;
3565 pListProps[12]= "field-font";
3566 pListProps[13] = NULL;
3567 pListProps[14]= "list-decimal";
3568 pListProps[15] = NULL;
3569 pListProps[16] = "list-tag";
3570 pListProps[17] = NULL;
3571 pListProps[18] = NULL;
3572 pListProps[19] = NULL;
3573 //
3574 // Remove all the list related properties
3575 //
3576 UT_DebugOnly<bool> bRet = m_pDoc->changeStruxFmt(PTC_RemoveFmt, posBlock,
3577 posBlock, pListAttrs, pListProps, PTX_Block);
3578 UT_ASSERT(bRet);
3579 fp_Run * pRun = pBlock->getFirstRun();
3580 while(pRun->getNextRun())
3581 {
3582 pRun = pRun->getNextRun();
3583 }
3584 PT_DocPosition lastPos = posBlock + pRun->getBlockOffset();
3585 bRet = m_pDoc->changeSpanFmt(PTC_RemoveFmt, posBlock, lastPos, pListAttrs, pListProps);
3586 UT_ASSERT(bRet);
3587 }
3588 //
3589 // Have to start lists in order so undo works!
3590 //
3591 for(i=0; i<vNoListBlocks.getItemCount(); i++)
3592 {
3593 UT_DEBUGMSG(("Doing Block %d of %d \n",i,vNoListBlocks.getItemCount()));
3594 fl_BlockLayout * pBlock = vNoListBlocks.getNthItem(i);
3595 fl_BlockLayout * pPrev = static_cast<fl_BlockLayout *>(pBlock->getPrev());
3596 while(pPrev && (pPrev->getContainerType() != FL_CONTAINER_BLOCK))
3597 {
3598 pPrev = static_cast<fl_BlockLayout *>(pPrev->getPrev());
3599 }
3600 //
3601 // Only attach block to previous list if the margin of the current block < the
3602 // previous block.
3603 //
3604 double prevLeft = 0.0;
3605 double blockLeft = 0.0;
3606 if(pPrev != NULL)
3607 {
3608 prevLeft = pPrev->getDominantDirection() == UT_BIDI_LTR
3609 ? UT_convertToInches(pPrev->getProperty(margin_left,true))
3610 : UT_convertToInches(pPrev->getProperty(margin_right,true));
3611
3612 blockLeft = pBlock->getDominantDirection() == UT_BIDI_LTR
3613 ? UT_convertToInches(pBlock->getProperty(margin_left,true))
3614 : UT_convertToInches(pBlock->getProperty(margin_right,true));
3615 }
3616 //
3617 // Look for Numbered Heading in the prev block style or it's ancestry.
3618 // If there is one there we don't attach this block to it.
3619 //
3620 bool bHasNumberedHeading = false;
3621 if(pPrev != NULL)
3622 {
3623 bHasNumberedHeading = isNumberedHeadingHere(pPrev);
3624 }
3625 //
3626 // Don't resume if the previous block has a Numbered Heading Style
3627 //
3628 if(!bHasNumberedHeading && (pBlock->isListItem()== false) && (pPrev != NULL) && (pPrev->isListItem()== true) && (pPrev->getAutoNum()->getType() == listType) && (blockLeft <= (prevLeft - 0.00001)))
3629 {
3630 pBlock->resumeList(pPrev);
3631 }
3632 else if(!pBlock->isListItem())
3633 {
3634 gchar* cType = pBlock->getListStyleString(listType);
3635 pBlock->StartList(cType);
3636 }
3637 }
3638
3639 // closes bug # 1255 - unselect a list after creation
3640 //cmdUnselectSelection();
3641
3642 // restore updates and clean up dirty lists
3643 m_pDoc->enableListUpdates();
3644 m_pDoc->updateDirtyLists();
3645
3646
3647
3648 // Signal piceTable is stable again
3649 _restorePieceTableState();
3650 _generalUpdate();
3651 m_pDoc->endUserAtomicGlob();
3652 if(!bNoSelection)
3653 {
3654 posEnd += diff;
3655 setPoint(posStart);
3656 _setSelectionAnchor();
3657 setPoint(posEnd);
3658 _drawSelection();
3659 }
3660 _fixInsertionPointCoords();
3661 if (isSelectionEmpty())
3662 {
3663 _ensureInsertionPointOnScreen();
3664 }
3665 notifyListeners(AV_CHG_MOTION | AV_CHG_HDRFTR);
3666 UT_DEBUGMSG(("Point %d anchor %d \n",getPoint(),m_Selection.getSelectionAnchor()));
3667 }
3668
3669 /*!
3670 * This returns the number of distinct columns in a selection. If part of the
3671 * the selection is outside a table, it returns 0.
3672 */
getNumColumnsInSelection(void) const3673 UT_sint32 FV_View::getNumColumnsInSelection(void) const
3674 {
3675 UT_GenericVector<fl_BlockLayout *> vecBlocks;
3676 getBlocksInSelection(&vecBlocks);
3677 UT_sint32 i =0;
3678 UT_sint32 iNumCols = 0;
3679 UT_sint32 iCurCol = -1;
3680 fl_BlockLayout * pBlock = NULL;
3681 fl_CellLayout * pCell = NULL;
3682 fp_CellContainer * pCellCon = NULL;
3683 for(i=0; i< vecBlocks.getItemCount();i++)
3684 {
3685 pBlock = vecBlocks.getNthItem(i);
3686 if(pBlock->myContainingLayout()->getContainerType() != FL_CONTAINER_CELL)
3687 {
3688 return 0;
3689 }
3690 pCell = static_cast<fl_CellLayout *>(pBlock->myContainingLayout());
3691 pCellCon = static_cast<fp_CellContainer *>(pCell->getFirstContainer());
3692 if(pCellCon == NULL)
3693 {
3694 return 0;
3695 }
3696 if(pCellCon->getLeftAttach() > iCurCol)
3697 {
3698 iNumCols++;
3699 iCurCol = pCellCon->getLeftAttach();
3700 }
3701 }
3702 return iNumCols;
3703 }
3704
3705 /*!
3706 * This returns the number of distinct rows in a selection. If part of the
3707 * the selection is outside a table, it returns 0.
3708 */
getNumRowsInSelection(void) const3709 UT_sint32 FV_View::getNumRowsInSelection(void) const
3710 {
3711 UT_GenericVector<fl_BlockLayout *> vecBlocks;
3712 getBlocksInSelection(&vecBlocks);
3713 UT_sint32 i =0;
3714 UT_sint32 iNumRows = 0;
3715 UT_sint32 iCurRow = -1;
3716 fl_BlockLayout * pBlock = NULL;
3717 fl_CellLayout * pCell = NULL;
3718 fp_CellContainer * pCellCon = NULL;
3719 PT_DocPosition startpos = getPoint();
3720 PT_DocPosition endpos = startpos;
3721 if(!isSelectionEmpty())
3722 {
3723 if (m_Selection.getSelectionAnchor() > startpos)
3724 {
3725 endpos = m_Selection.getSelectionAnchor();
3726 }
3727 else
3728 {
3729 startpos = m_Selection.getSelectionAnchor();
3730 }
3731 }
3732 for(i=0; i< vecBlocks.getItemCount();i++)
3733 {
3734 pBlock = vecBlocks.getNthItem(i);
3735 if((getNumSelections() == 0) && ((pBlock->getPosition() + pBlock->getLength() - 1) <= startpos))
3736 {
3737 if((startpos == endpos) && ((pBlock->getPosition() <= startpos)))
3738 {
3739 pCell = static_cast<fl_CellLayout *>(pBlock->myContainingLayout());
3740 pCellCon = static_cast<fp_CellContainer *>(pCell->getFirstContainer());
3741 if(pCellCon == NULL)
3742 {
3743 return 0;
3744 }
3745 return 1;
3746
3747 }
3748 else
3749 {
3750 continue;
3751 }
3752 }
3753 if(pBlock->getPosition() > endpos)
3754 {
3755 break;
3756 }
3757 if(pBlock->myContainingLayout()->getContainerType() != FL_CONTAINER_CELL)
3758 {
3759 return 0;
3760 }
3761 pCell = static_cast<fl_CellLayout *>(pBlock->myContainingLayout());
3762 pCellCon = static_cast<fp_CellContainer *>(pCell->getFirstContainer());
3763 if(pCellCon == NULL)
3764 {
3765 return 0;
3766 }
3767 if(pCellCon->getTopAttach() > iCurRow)
3768 {
3769 iNumRows++;
3770 iCurRow = pCellCon->getTopAttach();
3771 }
3772 }
3773 return iNumRows;
3774 }
3775
3776 /*
3777 * Create a vector of all blocks within the selection.
3778 * If bAllBlocks is false, the last block is not included if the selection stops right at the beginning
3779 * of the block.
3780 */
3781
getBlocksInSelection(UT_GenericVector<fl_BlockLayout * > * vBlock,bool bAllBlocks) const3782 void FV_View::getBlocksInSelection( UT_GenericVector<fl_BlockLayout*>* vBlock, bool bAllBlocks) const
3783 {
3784 PT_DocPosition startpos = getPoint();
3785 PT_DocPosition endpos = startpos;
3786 if(isSelectionEmpty())
3787 {
3788 vBlock->addItem(getCurrentBlock());
3789 return;
3790 }
3791 if (m_Selection.getSelectionAnchor() > startpos)
3792 {
3793 endpos = m_Selection.getSelectionAnchor();
3794 }
3795 else
3796 {
3797 startpos = m_Selection.getSelectionAnchor();
3798 }
3799 bool bStop = false;
3800 //
3801 // tweak the start point of the selection if it is just before the current block
3802 // strux. Clicking in the left margin moves the start point here but usually the
3803 // user wants block after this.
3804 //
3805 UT_sint32 iNumSelections = getNumSelections();
3806 UT_sint32 iSel =0;
3807 if(iNumSelections > 0)
3808 {
3809 PD_DocumentRange * pRange = getNthSelection(iSel);
3810 startpos = pRange->m_pos1;
3811 endpos = pRange->m_pos2;
3812 iNumSelections--;
3813 }
3814 while(!bStop)
3815 {
3816 fl_BlockLayout * pBlock = _findBlockAtPosition(startpos);
3817 fl_BlockLayout * pBlNext = NULL;
3818 PT_DocPosition posEOD = 0;
3819 getEditableBounds(true, posEOD);
3820
3821 if(startpos < posEOD)
3822 {
3823 pBlNext = _findBlockAtPosition(startpos+1);
3824 }
3825 if((pBlNext != NULL) && (pBlNext != pBlock))
3826 {
3827 pBlock = pBlNext;
3828 }
3829 while( pBlock != NULL && pBlock->getPosition(true) <= endpos)
3830 {
3831 if(pBlock->getContainerType()== FL_CONTAINER_BLOCK)
3832 {
3833 if (bAllBlocks || pBlock->getPosition(true) < endpos - 1)
3834 {
3835 vBlock->addItem(pBlock);
3836 }
3837 }
3838 pBlock = static_cast<fl_BlockLayout *>(pBlock->getNextBlockInDocument());
3839 }
3840 if(iNumSelections == 0)
3841 {
3842 bStop = true;
3843 }
3844 else
3845 {
3846 iNumSelections--;
3847 iSel++;
3848 PD_DocumentRange * pRange = getNthSelection(iSel);
3849 startpos = pRange->m_pos1;
3850 endpos = pRange->m_pos2;
3851 }
3852 }
3853 return;
3854 }
3855
insertParagraphBreak(void)3856 void FV_View::insertParagraphBreak(void)
3857 {
3858 STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
3859
3860 bool bBefore = false;
3861 bool bStopList = false;
3862
3863 m_pDoc->beginUserAtomicGlob();
3864
3865 // Prevent access to Piecetable for things like spellchecks until
3866 // paragraphs have stablized
3867 //
3868 _saveAndNotifyPieceTableChange();
3869
3870 if (!isSelectionEmpty() && !m_FrameEdit.isActive())
3871 {
3872 // m_pDoc->beginUserAtomicGlob();
3873 _deleteSelection();
3874 }
3875 else if(m_FrameEdit.isActive())
3876 {
3877 m_FrameEdit.setPointInside();
3878 }
3879 if(m_bInsertAtTablePending)
3880 {
3881 m_pDoc->disableListUpdates();
3882 PT_DocPosition pos = m_iPosAtTable;
3883 m_pDoc->insertStrux( m_iPosAtTable,PTX_Block);
3884 m_bInsertAtTablePending = false;
3885 // Signal piceTable is stable again
3886 _restorePieceTableState();
3887
3888 // Signal piceTable is stable again
3889 // Signal PieceTable Changes have finished
3890 _generalUpdate();
3891 // restore updates and clean up dirty lists
3892 m_pDoc->enableListUpdates();
3893 m_pDoc->updateDirtyLists();
3894 setPoint(pos+1);
3895 m_iPosAtTable = 0;
3896 _generalUpdate();
3897 m_pDoc->endUserAtomicGlob();
3898 return;
3899 }
3900 // insert a new paragraph with the same attributes/properties
3901 // as the previous (or none if the first paragraph in the section).
3902 //
3903 // But first check to see if we're in a list and the current block is
3904 // otherwise blank.
3905 //
3906 m_pDoc->disableListUpdates();
3907 fl_BlockLayout * pBlock = getCurrentBlock();
3908 pf_Frag_Strux* sdh = pBlock->getStruxDocHandle();
3909 //
3910 // If we're at the end of the block set new style to followed-by. Look for this
3911 // condition before we do insertStrux
3912 //
3913 bool bAtEnd = false;
3914 PT_DocPosition posEOD = 0;
3915 getEditableBounds(true, posEOD);
3916 if(getPoint() != posEOD)
3917 {
3918 bAtEnd = _findBlockAtPosition(getPoint()+1) != _findBlockAtPosition(getPoint());
3919 }
3920 else
3921 {
3922 bAtEnd = true;
3923 }
3924 if(isCurrentListBlockEmpty() == true)
3925 {
3926 m_pDoc->StopList(sdh);
3927 bStopList = true;
3928 }
3929 else if(isPointBeforeListLabel() == true)
3930 {
3931 //
3932 // Now deal with the case of entering a line before a list label
3933 // We flag were entering a new line and delete the current list label. After the we
3934 // insert the line break (which automatically write a new list label) we stop the list
3935 // in preceding block.
3936 //
3937 bBefore = true;
3938 pBlock->deleteListLabel();
3939 }
3940 if(bStopList == false)
3941 m_pDoc->insertStrux(getPoint(), PTX_Block);
3942 if(bBefore == true)
3943 {
3944 fl_BlockLayout * pPrev = static_cast<fl_BlockLayout *>(getCurrentBlock()->getPrev());
3945 sdh = pPrev->getStruxDocHandle();
3946 m_pDoc->StopList(sdh);
3947 _setPoint(getCurrentBlock()->getPosition());
3948 }
3949
3950 const gchar* style = NULL;
3951 PD_Style* pStyle = NULL;
3952 if(getStyle(&style) && bAtEnd)
3953 {
3954 m_pDoc->getStyle(static_cast<const char*>(style), &pStyle);
3955 if(pStyle != NULL && !bBefore)
3956 {
3957 const gchar* szFollow = NULL;
3958 pStyle->getAttribute("followedby",szFollow);
3959 if(szFollow && strcmp(szFollow,"Current Settings")!=0)
3960 {
3961 if(pStyle->getFollowedBy())
3962 pStyle = pStyle->getFollowedBy();
3963
3964 const gchar* szValue = NULL;
3965 //
3966 // The name of the style is stored in the PT_NAME_ATTRIBUTE_NAME attribute within the
3967 // style
3968 //
3969 pStyle->getAttribute(PT_NAME_ATTRIBUTE_NAME, szValue);
3970
3971 UT_ASSERT((szValue));
3972 getEditableBounds(true, posEOD);
3973
3974 if ((getPoint() <= posEOD) && (strcmp(static_cast<const char *>(szValue), static_cast<const char *>(style)) != 0))
3975 {
3976 setStyle(szValue,true);
3977 //
3978 // Stop a List if "followed-by" is not a list style
3979 //
3980 const gchar * szListType = NULL;
3981 pStyle->getProperty("list-style",szListType);
3982 bool bisListStyle = false;
3983 if(szListType)
3984 {
3985 bisListStyle = (NOT_A_LIST != getCurrentBlock()->getListTypeFromStyle( szListType));
3986 }
3987 sdh = getCurrentBlock()->getStruxDocHandle();
3988 while(!bisListStyle && getCurrentBlock()->isListItem())
3989 {
3990 m_pDoc->StopList(sdh);
3991 }
3992 }
3993 }
3994 }
3995 }
3996
3997
3998 // Signal piceTable is stable again
3999 _restorePieceTableState();
4000
4001 // Signal piceTable is stable again
4002 // Signal PieceTable Changes have finished
4003
4004 _generalUpdate();
4005 // restore updates and clean up dirty lists
4006 m_pDoc->enableListUpdates();
4007 m_pDoc->updateDirtyLists();
4008 _generalUpdate();
4009
4010 m_pDoc->endUserAtomicGlob();
4011 _fixInsertionPointCoords();
4012 _ensureInsertionPointOnScreen();
4013 notifyListeners(AV_CHG_MOTION | AV_CHG_ALL);
4014 m_pLayout->considerPendingSmartQuoteCandidate();
4015 }
4016
4017
insertParagraphBreaknoListUpdate(void)4018 void FV_View::insertParagraphBreaknoListUpdate(void)
4019 {
4020 bool bDidGlob = false;
4021
4022 if (!isSelectionEmpty())
4023 {
4024 bDidGlob = true;
4025 m_pDoc->beginUserAtomicGlob();
4026 _deleteSelection();
4027 }
4028
4029 // insert a new paragraph with the same attributes/properties
4030 // as the previous (or none if the first paragraph in the section).
4031
4032 m_pDoc->insertStrux(getPoint(), PTX_Block);
4033
4034 _generalUpdate();
4035
4036 if (bDidGlob)
4037 m_pDoc->endUserAtomicGlob();
4038 _ensureInsertionPointOnScreen();
4039 }
4040
appendStyle(const gchar ** style)4041 bool FV_View::appendStyle(const gchar ** style)
4042 {
4043 return m_pDoc->appendStyle(style);
4044 }
4045
setStyle(const gchar * style,bool bDontGeneralUpdate)4046 bool FV_View::setStyle(const gchar * style, bool bDontGeneralUpdate)
4047 {
4048 PT_DocPosition posStart = getPoint();
4049 PT_DocPosition posEnd = posStart;
4050 return setStyleAtPos(style, posStart, posEnd, bDontGeneralUpdate);
4051 }
4052
setStyleAtPos(const gchar * style,PT_DocPosition posStart1,PT_DocPosition posEnd1,bool bDontGeneralUpdate)4053 bool FV_View::setStyleAtPos(const gchar * style, PT_DocPosition posStart1, PT_DocPosition posEnd1, bool bDontGeneralUpdate)
4054 {
4055 bool bRet;
4056
4057 PT_DocPosition posStart = posStart1;
4058 PT_DocPosition posEnd = posEnd1;
4059
4060 // Signal PieceTable Change
4061 _saveAndNotifyPieceTableChange();
4062
4063 // Turn off list updates
4064 m_pDoc->disableListUpdates();
4065 //
4066 // FIXME Handle table columns here
4067 //
4068 if (!isSelectionEmpty())
4069 {
4070 if (m_Selection.getSelectionAnchor() < posStart)
4071 {
4072 posStart = m_Selection.getSelectionAnchor();
4073 }
4074 else
4075 {
4076 posEnd = m_Selection.getSelectionAnchor();
4077 }
4078 if(posStart < 2)
4079 {
4080 posStart = 2;
4081 }
4082 }
4083
4084 // lookup the current style
4085 PD_Style * pStyle = NULL;
4086 m_pDoc->getStyle(static_cast<const char*>(style), &pStyle);
4087 if (!pStyle)
4088 {
4089 m_pDoc->enableListUpdates();
4090 UT_DEBUGMSG(("restoring PieceTable state (2)\n"));
4091 _restorePieceTableState();
4092 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
4093 return false;
4094 }
4095 if(strcmp(style,"None") == 0)
4096 {
4097 m_pDoc->enableListUpdates();
4098 UT_DEBUGMSG(("restoring PieceTable state (2)\n"));
4099 _restorePieceTableState();
4100 return true; // do nothing.
4101 }
4102 pStyle->used (1);
4103 //
4104 // Get This info before it's lost from the following processing
4105 //
4106 fl_BlockLayout * pBL = getCurrentBlock();
4107 const gchar * pszStyle = NULL;
4108 pStyle->getProperty("list-style",pszStyle);
4109 bool bisListStyle = false;
4110 if(pszStyle)
4111 bisListStyle = (NOT_A_LIST != pBL->getListTypeFromStyle( pszStyle));
4112 //
4113 // Can't handle lists inside header/Footers. Bail out
4114 //
4115 if(bisListStyle && isHdrFtrEdit())
4116 {
4117 m_pDoc->enableListUpdates();
4118 UT_DEBUGMSG(("restoring PieceTable state (2)\n"));
4119 _restorePieceTableState();
4120 return false;
4121 }
4122 pBL = _findBlockAtPosition(posStart+2);
4123 if(pBL == NULL)
4124 {
4125 m_pDoc->enableListUpdates();
4126 UT_DEBUGMSG(("restoring PieceTable state (3)\n"));
4127 _restorePieceTableState();
4128 return false;
4129 }
4130 if(bisListStyle)
4131 {
4132 if(pBL->isHdrFtr())
4133 {
4134 m_pDoc->enableListUpdates();
4135 UT_DEBUGMSG(("restoring PieceTable state (4)\n"));
4136 _restorePieceTableState();
4137 return false;
4138 }
4139 fl_ContainerLayout * pCL = pBL->myContainingLayout();
4140 while(pCL && (pCL->getContainerType() != FL_CONTAINER_DOCSECTION))
4141 {
4142 if((pCL->getContainerType() == FL_CONTAINER_HDRFTR) ||
4143 (pCL->getContainerType() == FL_CONTAINER_SHADOW) ||
4144 (pCL->getContainerType() == FL_CONTAINER_FOOTNOTE) ||
4145 (pCL->getContainerType() == FL_CONTAINER_ANNOTATION) ||
4146 (pCL->getContainerType() == FL_CONTAINER_ENDNOTE))
4147 {
4148 m_pDoc->enableListUpdates();
4149 UT_DEBUGMSG(("restoring PieceTable state (5)\n"));
4150 _restorePieceTableState();
4151 return false;
4152 }
4153 pCL = pCL->myContainingLayout();
4154 }
4155 if(pCL == NULL)
4156 {
4157 return false;
4158 }
4159 }
4160 if((posStart == pBL->getPosition(true)) && (posEnd > posStart))
4161 {
4162 posStart++;
4163 if(posStart > posEnd)
4164 {
4165 posEnd=posStart;
4166 }
4167 }
4168 //
4169 // Glob piecetable changes together.
4170 //
4171 m_pDoc->beginUserAtomicGlob();
4172 UT_GenericVector<fl_BlockLayout *> vBlock;
4173 getBlocksInSelection( &vBlock);
4174 setScreenUpdateOnGeneralUpdate( false);
4175 bool bCharStyle = pStyle->isCharStyle();
4176 const gchar * attribs[] = { PT_STYLE_ATTRIBUTE_NAME, 0, 0 };
4177 attribs[1] = style;
4178 //
4179 // Need this to adjust the start and end positions of the style change.
4180 //
4181 PT_DocPosition curPos=0;
4182 PT_DocPosition posNewStart = posStart;
4183 PT_DocPosition posNewEnd = posEnd;
4184 if(bisListStyle && !bCharStyle)
4185 {
4186 //
4187 // Stop the Lists contained in the current selection.
4188 //
4189 //
4190 // Adjust region of style for the deletion of the Field/Tab required for each list
4191 // element.
4192 //
4193 UT_sint32 i;
4194
4195 for(i=0; i< vBlock.getItemCount(); i++)
4196 {
4197 pBL = vBlock.getNthItem(i);
4198 curPos = pBL->getPosition();
4199 if(pBL->isListItem())
4200 {
4201 if(curPos < posStart)
4202 {
4203 posStart -=2;
4204 }
4205 if(curPos < posEnd)
4206 {
4207 posEnd -= 2;
4208 }
4209 }
4210 else
4211 {
4212 if(curPos < posStart)
4213 {
4214 posNewStart += 2;
4215 }
4216 if(curPos < posEnd)
4217 {
4218 posNewEnd += 2;
4219 }
4220 }
4221 while(pBL->isListItem())
4222 {
4223 m_pDoc->StopList(pBL->getStruxDocHandle());
4224 }
4225 }
4226 }
4227 else if(!bCharStyle)
4228 {
4229 UT_sint32 i;
4230
4231 for(i=0; i< vBlock.getItemCount(); i++)
4232 {
4233 pBL = vBlock.getNthItem(i);
4234 curPos = pBL->getPosition();
4235 if(pBL->isListItem())
4236 {
4237 if(curPos < posStart)
4238 {
4239 posNewStart -=2;
4240 }
4241 if(curPos < posEnd)
4242 {
4243 posNewEnd -= 2;
4244 }
4245 }
4246 }
4247 }
4248 bool bHasNumberedHeading = false;
4249 const gchar * pszCurStyle = style;
4250 PD_Style * pCurStyle = pStyle;
4251 UT_uint32 depth = 0;
4252 if (bCharStyle)
4253 {
4254 _clearIfAtFmtMark(getPoint()); // TODO is this correct ?
4255 _eraseSelection();
4256 UT_DEBUGMSG(("Applying Character style: start %d, end %d\n", posStart, posEnd));
4257 bRet = m_pDoc->changeSpanFmt(PTC_AddStyle,posStart,posEnd,attribs,NULL);
4258 goto finish_up;
4259 }
4260 else
4261 {
4262 // set block-level style
4263 UT_DEBUGMSG(("Applying Block style: start %d, end %d\n", posStart, posEnd));
4264
4265 _clearIfAtFmtMark(getPoint()); // TODO is this correct ?
4266 UT_DEBUGMSG(("Applying Paragraph style: start %d, end %d\n", posStart, posEnd));
4267
4268 // PLAM this is the only place that PTC_AddStyle is used.
4269 // NB: clear explicit props at both block and char levels
4270 bRet = m_pDoc->changeStruxFmt(PTC_AddStyle,posStart,posEnd,attribs,NULL,PTX_Block);
4271 }
4272 //
4273 // Do the list elements processing
4274 //
4275 //
4276 // Look for Numbered Heading in the style or it's ancestry.
4277 //
4278 while(bisListStyle && pCurStyle && !bHasNumberedHeading && depth < 10)
4279 {
4280 bHasNumberedHeading = (strstr(pszCurStyle,"Numbered Heading") != NULL);
4281 if(!bHasNumberedHeading)
4282 {
4283 pCurStyle = pCurStyle->getBasedOn();
4284 if(pCurStyle)
4285 pszCurStyle = pCurStyle->getName();
4286 depth++;
4287 }
4288 }
4289
4290 if(bisListStyle && !bHasNumberedHeading)
4291 {
4292 UT_sint32 i;
4293 for(i=0; i< vBlock.getItemCount(); i++)
4294 {
4295 pBL = vBlock.getNthItem(i);
4296 curPos = pBL->getPosition();
4297 if(i == 0)
4298 pBL->StartList(style);
4299 else
4300 {
4301 fl_BlockLayout * pPrevBL = pBL->getPrevBlockInDocument();
4302 if(pPrevBL)
4303 {
4304 pBL->resumeList(pPrevBL);
4305
4306 }
4307 }
4308 }
4309 }
4310 //
4311 // Code to handle Numbered Heading styles...
4312 //
4313 else if(bHasNumberedHeading)
4314 {
4315 fl_BlockLayout* currBlock = vBlock.getNthItem(0);
4316 PT_DocPosition pos = currBlock->getPosition(true) -1;
4317 pf_Frag_Strux* curSdh = currBlock->getStruxDocHandle();
4318 if(pos < 2 )
4319 pos = 2;
4320 //
4321 // First look to see if this numbered heading style is embedded in a previous
4322 // Numbered Heading piece of text.
4323 //
4324 bool bAttach = false;
4325 pf_Frag_Strux* prevSDH = m_pDoc->getPrevNumberedHeadingStyle(curSdh);
4326 if(prevSDH != NULL)
4327 {
4328 PD_Style * pPrevStyle = m_pDoc->getStyleFromSDH(prevSDH);
4329 if(pPrevStyle != NULL)
4330 {
4331 //
4332 // See if it's of shallower depth then current numbered Heading.
4333 //
4334 UT_uint32 icurDepth = UT_HeadingDepth(style);
4335 UT_uint32 iprevDepth = UT_HeadingDepth(pPrevStyle->getName());
4336 //
4337 // Start a sublist with the previous heading as the parent.
4338 //
4339 if(iprevDepth < icurDepth)
4340 {
4341 //
4342 // Now look to see if the proposed parent item is already a list parent. In which
4343 // case we just add this iem to the already existing list. The list class will get
4344 // the order correct.
4345 //
4346 UT_sint32 count = m_pDoc->getListsCount();
4347 UT_sint32 i =0;
4348 const fl_AutoNum * pAuto = NULL;
4349 bool bFoundPrevList = false;
4350 for(i=0; (i< count) && !bFoundPrevList; i++)
4351 {
4352 pAuto = m_pDoc->getNthList(i);
4353 bFoundPrevList = (pAuto->getParentItem() == prevSDH);
4354 }
4355 if(bFoundPrevList && pAuto->getFirstItem())
4356 {
4357 pf_Frag_Strux* subSDH = pAuto->getFirstItem();
4358 fl_BlockLayout * pSubBlock = getBlockFromSDH(subSDH);
4359 UT_ASSERT(pSubBlock);
4360 if(pSubBlock == NULL)
4361 goto finish_up;
4362
4363 for(i=0; i< vBlock.getItemCount(); i++)
4364 {
4365 pBL = vBlock.getNthItem(i);
4366 pBL->prependList(pSubBlock);
4367 }
4368 }
4369 //
4370 // OK the previously found item with a numbered list is not a parent item
4371 // even though this style is at a higher level of nesting than the previous
4372 // style. Instead we have to start a new sublist with the previous item as
4373 // the parent.
4374 //
4375 else
4376 {
4377 for(i=0; i< vBlock.getItemCount(); i++)
4378 {
4379 pBL = vBlock.getNthItem(i);
4380 if(i == 0)
4381 pBL->StartList(style,prevSDH);
4382 else
4383 pBL->resumeList(static_cast<fl_BlockLayout *>(pBL->getPrev()));
4384 }
4385 }
4386 bAttach = true;
4387 }
4388 }
4389 }
4390 if(!bAttach)
4391 {
4392 //
4393 // Look backwards to see if there is a heading before here.
4394 //
4395 bool bFoundPrevHeadingBackwards = false;
4396 pf_Frag_Strux* sdh = m_pDoc->findPreviousStyleStrux(style, pos);
4397 bFoundPrevHeadingBackwards = (sdh != NULL);
4398 //
4399 // If not, Look forward to see if there one ahead of this block
4400 //
4401 if(!bFoundPrevHeadingBackwards || (curSdh == sdh))
4402 {
4403 //
4404 // Start looking from the block following and skip through to end of Doc.
4405 //
4406 fl_BlockLayout * pNext = vBlock.getLastItem();
4407 pNext = static_cast<fl_BlockLayout *>(pNext->getNext());
4408 if(pNext)
4409 {
4410 PT_DocPosition nextPos = pNext->getPosition(false)+1;
4411 sdh = m_pDoc->findForwardStyleStrux(style, nextPos);
4412 }
4413 }
4414 //
4415 // OK put this heading style into any pre-exsiting Numbering Headings
4416 //
4417 if(sdh == NULL || (sdh == curSdh))
4418 {
4419 for(UT_sint32 i=0; i< vBlock.getItemCount(); i++)
4420 {
4421 pBL = vBlock.getNthItem(i);
4422 if(i == 0)
4423 pBL->StartList(style);
4424 else
4425 {
4426 fl_ContainerLayout * pPrevL = pBL->getPrev();
4427 if(pPrevL && pPrevL->getContainerType() == FL_CONTAINER_BLOCK)
4428 {
4429 pBL->resumeList(static_cast<fl_BlockLayout *>(pPrevL));
4430 }
4431 }
4432 }
4433 }
4434 //
4435 // Insert into pre-existing List.
4436 //
4437 else if(bFoundPrevHeadingBackwards)
4438 {
4439 fl_BlockLayout * pBlock = getBlockFromSDH(sdh);
4440 UT_ASSERT(pBlock);
4441 if(pBlock == NULL)
4442 goto finish_up;
4443
4444 for(UT_sint32 j = 0; j < vBlock.getItemCount(); ++j)
4445 {
4446 pBL = vBlock.getNthItem(j);
4447 if(j == 0)
4448 pBL->resumeList(pBlock);
4449 else if(pBL->getPrev())
4450 {
4451 pBL->resumeList(static_cast<fl_BlockLayout *>(pBL->getPrev()));
4452 }
4453 }
4454 }
4455 //
4456 // Prepend onto a pre-existing List.
4457 //
4458 else
4459 {
4460 fl_BlockLayout * pBlock = getBlockFromSDH(sdh);
4461 UT_ASSERT(pBlock);
4462 if(pBlock == NULL)
4463 goto finish_up;
4464 for(UT_sint32 j = 0; j < vBlock.getItemCount(); j++)
4465 {
4466 pBL = vBlock.getNthItem(j);
4467 if (j == 0)
4468 pBL->prependList(pBlock);
4469 else if(pBL->getPrev())
4470 {
4471 pBL->resumeList(static_cast<fl_BlockLayout *>(pBL->getPrev()));
4472 }
4473 }
4474 }
4475 }
4476 }
4477 finish_up:
4478 setScreenUpdateOnGeneralUpdate( true);
4479 // Signal piceTable is stable again
4480 UT_DEBUGMSG(("restoring PieceTable state GeneralUpdate %d \n",bDontGeneralUpdate));
4481 _restorePieceTableState();
4482 if(!bDontGeneralUpdate)
4483 {
4484 _generalUpdate();
4485 // restore updates and clean up dirty lists
4486 m_pDoc->enableListUpdates();
4487 m_pDoc->updateDirtyLists();
4488 }
4489 UT_DEBUGMSG(("SEVIOR: posNewStart %d posNewEnd %d at end \n",posStart,posEnd));
4490
4491 m_pDoc->endUserAtomicGlob();
4492 if (posEnd != posStart)
4493 {
4494 _clearSelection();
4495 _setPoint(posNewStart);
4496 _setSelectionAnchor();
4497 _setPoint(posNewEnd);
4498 _drawSelection();
4499 }
4500 return bRet;
4501 }
4502
4503 /*!
4504 * This method finds the appropiate matching block in the current view
4505 * for the StruxDocHandle (actually a pointer to a pf_frag_strux)
4506 */
getBlockFromSDH(pf_Frag_Strux * sdh)4507 fl_BlockLayout * FV_View::getBlockFromSDH(pf_Frag_Strux* sdh)
4508 {
4509 fl_ContainerLayout* sfh = NULL;
4510 fl_BlockLayout * pBlock = NULL;
4511 //
4512 // Cast it into a fl_BlockLayout and we're done!
4513 //
4514 sfh = m_pDoc->getNthFmtHandle(sdh, m_pLayout->getLID());
4515 if(sfh != NULL)
4516 {
4517 pBlock = static_cast<fl_BlockLayout *>(sfh);
4518 if(pBlock->getDocLayout() != m_pLayout)
4519 {
4520 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
4521 pBlock = NULL;
4522 }
4523 }
4524 return pBlock;
4525 }
4526
4527
x_getStyle(const PP_AttrProp * pAP,bool bBlock)4528 static const gchar * x_getStyle(const PP_AttrProp * pAP, bool bBlock)
4529 {
4530 UT_return_val_if_fail(pAP, NULL);
4531 const gchar* sz = NULL;
4532
4533 pAP->getAttribute(PT_STYLE_ATTRIBUTE_NAME, sz);
4534
4535 // TODO: should we have an explicit default for char styles?
4536 if (!sz && bBlock)
4537 {
4538 sz = "None";
4539 }
4540 return sz;
4541 }
4542
getStyle(const gchar ** style) const4543 bool FV_View::getStyle(const gchar ** style) const
4544 {
4545 bool bCharStyle = false;
4546 const gchar * szChar = NULL;
4547 const gchar * szBlock = NULL;
4548
4549 const PP_AttrProp * pBlockAP = NULL;
4550
4551 /*
4552 IDEA: We want to know the style, if it's constant across the
4553 entire selection. Usually, this will be a block-level style.
4554 However, if the entire span has the same char-level style,
4555 we'll report that instead. */
4556
4557 //
4558 // Check we have a layout defined first. On start up we don't
4559 //
4560 if(getLayout()->getFirstSection() == NULL)
4561 {
4562 return false;
4563 }
4564 PT_DocPosition posStart = getPoint();
4565 PT_DocPosition posEnd = posStart;
4566 bool bSelEmpty = isSelectionEmpty();
4567
4568 if (!bSelEmpty)
4569 {
4570 if (m_Selection.getSelectionAnchor() < posStart)
4571 posStart = m_Selection.getSelectionAnchor();
4572 else
4573 posEnd = m_Selection.getSelectionAnchor();
4574 }
4575
4576 // 1. get block style at insertion point
4577 fl_BlockLayout* pBlock2 = _findBlockAtPosition(posStart);
4578 if(pBlock2 == NULL)
4579 {
4580 return false;
4581 }
4582 pBlock2->getAP(pBlockAP);
4583
4584 szBlock = x_getStyle(pBlockAP, true);
4585
4586 // 2. prune if block style varies across selection
4587 if (!bSelEmpty)
4588 {
4589 fl_BlockLayout* pBlockEnd = _findBlockAtPosition(posEnd);
4590
4591 while (pBlock2 && (pBlock2 != pBlockEnd))
4592 {
4593 const PP_AttrProp * pAP;
4594 bool bCheck = false;
4595
4596 pBlock2 = pBlock2->getNextBlockInDocument();
4597
4598 if (!pBlock2)
4599 {
4600 // at EOD, so just bail
4601 break;
4602 }
4603
4604 // did block format change?
4605 pBlock2->getAP(pAP);
4606 if (pBlockAP != pAP)
4607 {
4608 pBlockAP = pAP;
4609 bCheck = true;
4610 }
4611
4612 if (bCheck)
4613 {
4614 const gchar* sz = x_getStyle(pBlockAP, true);
4615
4616 if (strcmp(sz, szBlock))
4617 {
4618 // doesn't match, so stop looking
4619 szBlock = NULL;
4620 pBlock2 = NULL;
4621 break;
4622 }
4623 }
4624 }
4625 }
4626
4627 // NOTE: if block style varies, no need to check char style
4628
4629 if (szBlock && szBlock[0])
4630 {
4631 const PP_AttrProp * pSpanAP = NULL;
4632
4633 // 3. locate char style at insertion point
4634 UT_sint32 xPoint, yPoint, xPoint2, yPoint2;
4635 UT_uint32 iPointHeight;
4636 bool bDirection;
4637
4638 fl_BlockLayout* pBlock;
4639 fp_Run* pRun;
4640
4641 _findPositionCoords(posStart, false, xPoint, yPoint, xPoint2, yPoint2, iPointHeight, bDirection, &pBlock, &pRun);
4642 if(pBlock == NULL)
4643 {
4644 return false;
4645 }
4646 UT_uint32 blockPosition = pBlock->getPosition();
4647 bool bLeftSide = true;
4648
4649 // TODO consider adding indexAP from change record to the
4650 // TODO runs so that we can just use it here.
4651
4652 if (!bSelEmpty)
4653 {
4654 // we want the interior of the selection -- and not the
4655 // format to the left of the start of the selection.
4656 bLeftSide = false;
4657
4658 /*
4659 Likewise, findPointCoords will return the run to the right
4660 of the specified position, so we need to stop looking one
4661 position to the left.
4662 */
4663 posEnd--;
4664 }
4665
4666 pBlock->getSpanAP( (posStart - blockPosition), bLeftSide, pSpanAP);
4667
4668 if (pSpanAP)
4669 {
4670 szChar = x_getStyle(pSpanAP, false);
4671 bCharStyle = (szChar && szChar[0]);
4672 }
4673
4674 // 4. prune if char style varies across selection
4675 if (!bSelEmpty)
4676 {
4677 fl_BlockLayout* pBlockEnd;
4678 fp_Run* pRunEnd;
4679 _findPositionCoords(posEnd, false, xPoint, yPoint, xPoint2, yPoint2, iPointHeight, bDirection, &pBlockEnd, &pRunEnd);
4680
4681 while (pRun && (pRun != pRunEnd))
4682 {
4683 const PP_AttrProp * pAP;
4684 bool bCheck = false;
4685
4686 pRun = pRun->getNextRun();
4687 if (!pRun)
4688 {
4689 // go to first run of next block
4690 pBlock = pBlock->getNextBlockInDocument();
4691 if (!pBlock) // at EOD, so just bail
4692 break;
4693 pRun = pBlock->getFirstRun();
4694 }
4695
4696 // did span format change?
4697
4698 pAP = NULL;
4699 pBlock->getSpanAP(pRun->getBlockOffset()+pRun->getLength(),true,pAP);
4700 if (pAP && (pSpanAP != pAP))
4701 {
4702 pSpanAP = pAP;
4703 bCheck = true;
4704 }
4705
4706 if (bCheck)
4707 {
4708 const gchar* sz = x_getStyle(pSpanAP, true);
4709 bool bHere = (sz && sz[0]);
4710
4711 if ((bCharStyle != bHere) || ((sz && szChar && strcmp(sz, szChar))))
4712 {
4713 // doesn't match, so stop looking
4714 bCharStyle = false;
4715 szChar = NULL;
4716 pRun = NULL;
4717 break;
4718 }
4719 }
4720 }
4721 }
4722 }
4723
4724 *style = (bCharStyle ? szChar : szBlock);
4725
4726 return true;
4727 }
4728
4729 // TODO: merge this the and other override to not iterate twice.
setCharFormat(const std::vector<std::string> & properties)4730 bool FV_View::setCharFormat(const std::vector<std::string>& properties)
4731 {
4732 size_t len = properties.size();
4733 const gchar** props = (const gchar**)calloc(len + 1, sizeof (gchar*));
4734 const gchar** current = props;
4735 for(std::vector<std::string>::const_iterator iter = properties.begin();
4736 iter != properties.end(); ++iter) {
4737 *current = iter->c_str();
4738 current++;
4739 }
4740 props[len] = NULL;
4741 bool ret = setCharFormat(props, NULL);
4742 free(props);
4743 return ret;
4744 }
4745
setCharFormat(const gchar * properties[],const gchar * attribs[])4746 bool FV_View::setCharFormat(const gchar * properties[], const gchar * attribs[])
4747 {
4748 bool bRet = false;
4749
4750 // Signal PieceTable Change
4751 _saveAndNotifyPieceTableChange();
4752
4753 PT_DocPosition posStart = getPoint();
4754 PT_DocPosition posEnd = posStart;
4755
4756 if (!isSelectionEmpty())
4757 {
4758 if(1 < getNumSelections())
4759 {
4760
4761 m_pDoc->beginUserAtomicGlob();
4762 UT_sint32 i = 0;
4763 PD_DocumentRange * pRange = NULL;
4764 for(i=0; i < getNumSelections(); i++)
4765 {
4766 pRange = getNthSelection(i); // don't delete!
4767 posStart = pRange->m_pos1;
4768 posEnd = pRange->m_pos2;
4769 while(!isPointLegal(posStart))
4770 {
4771 posStart++;
4772 }
4773 while(!isPointLegal(posEnd) && (posEnd > posStart) )
4774 {
4775 posEnd--;
4776 }
4777 posEnd++;
4778 if(posEnd < posStart)
4779 {
4780 posEnd= posStart;
4781 }
4782 bRet = m_pDoc->changeSpanFmt(PTC_AddFmt,posStart,posEnd,attribs,properties);
4783 }
4784
4785 // Signal piceTable is stable again
4786 _restorePieceTableState();
4787 _generalUpdate();
4788
4789 m_pDoc->endUserAtomicGlob();
4790 return bRet;
4791 }
4792 if (m_Selection.getSelectionAnchor() < posStart)
4793 {
4794 posStart = m_Selection.getSelectionAnchor();
4795 }
4796 else
4797 {
4798 posEnd = m_Selection.getSelectionAnchor();
4799 }
4800 if(m_pDoc->isEndFootnoteAtPos(posEnd))
4801 {
4802 posEnd++;
4803 }
4804 }
4805
4806 m_pDoc->beginUserAtomicGlob();
4807 if(m_bInsertAtTablePending)
4808 {
4809 PT_DocPosition pos = m_iPosAtTable;
4810 m_pDoc->insertStrux( m_iPosAtTable,PTX_Block);
4811 m_bInsertAtTablePending = false;
4812 posStart = pos+1;
4813 posEnd = posStart;
4814 m_iPosAtTable = 0;
4815 }
4816 if((posStart == posEnd) && !isPointLegal(posStart))
4817 {
4818 _makePointLegal();
4819 posStart = getPoint();
4820 posEnd = posStart;
4821 }
4822 // Here the selection used to be cleared, but that prevented users
4823 // from making multiple changes to the same region.
4824
4825 bRet = m_pDoc->changeSpanFmt(PTC_AddFmt,posStart,posEnd,attribs,properties);
4826
4827 // Signal pieceTable is stable again
4828 _restorePieceTableState();
4829 _generalUpdate();
4830
4831 m_pDoc->endUserAtomicGlob();
4832 _fixInsertionPointCoords();
4833
4834 return bRet;
4835 }
4836
4837 /*!
4838 clears props and attribs
4839 bAll specifies that everything is to go; if !bAll some selected props will be preserved
4840
4841 Notes: This function is to be called in response to reset fmt command
4842 (ctrl+space). The idea is this: we use props and attributes to store things that are
4843 not strictly speaking text fmt. For example, spellchecker language is a property, but
4844 not strictly text fmt; when pressing ctrl+space, more often than not the user wants to
4845 get rid of bold, italics, etc., but not of the langauge markup. So we exercise a
4846 degree of discretion.
4847 */
resetCharFormat(bool bAll)4848 bool FV_View::resetCharFormat(bool bAll)
4849 {
4850 PP_AttrProp AP;
4851
4852 if(!bAll)
4853 {
4854 const PP_AttrProp * pAP = getAttrPropForPoint();
4855
4856 if(pAP)
4857 {
4858 UT_uint32 i = 0;
4859 const gchar * szName, *szValue;
4860 while(pAP->getNthProperty(i++,szName,szValue))
4861 {
4862 // add other props as required ...
4863 if(!strcmp(szName,"lang"))
4864 AP.setProperty(szName,szValue);
4865 }
4866
4867 }
4868 }
4869
4870 m_pDoc->beginUserAtomicGlob();
4871
4872 // first we reset everything ...
4873 // we have to do this, because setCharFormat() calls are cumulative (it uses
4874 // PTC_AddFmt)
4875 const gchar * attrs_out[5] = {"props","","style","",NULL};
4876 bool bRet = setCharFormat(NULL,attrs_out);
4877
4878 // now if we have something to set, we do so ...
4879 if(AP.hasAttributes() || AP.hasProperties())
4880 bRet &= setCharFormat(AP.getProperties(), AP.getAttributes());
4881
4882 m_pDoc->endUserAtomicGlob();
4883 return bRet;
4884 }
4885
getAttrPropForPoint() const4886 const PP_AttrProp * FV_View::getAttrPropForPoint() const
4887 {
4888 const fl_BlockLayout * pBL = getCurrentBlock();
4889 UT_return_val_if_fail( pBL, NULL);
4890
4891 UT_uint32 blockOffset = getPoint() - pBL->getPosition();
4892 fp_Run * pRun = pBL->findRunAtOffset(blockOffset);
4893
4894 UT_return_val_if_fail( pRun, NULL );
4895 bool bLeftSide = true;
4896
4897 if(/*(pRun->getType() == FPRUN_TEXT || pRun->getType() == FPRUN_ENDOFPARAGRAPH) &&*/
4898 pRun->getBlockOffset() == blockOffset &&
4899 pRun->getPrevRun()
4900 && pRun->getPrevRun()->getType() == FPRUN_TEXT)
4901 {
4902 // between two text frags, use the one on the left
4903 pRun = pRun->getPrevRun();
4904
4905 blockOffset = pRun->getBlockOffset();
4906 bLeftSide = false;
4907 }
4908
4909 const PP_AttrProp * pAP = NULL;
4910 getDocument()->getSpanAttrProp(pBL->getStruxDocHandle(), blockOffset, bLeftSide, &pAP);
4911 #if 0
4912 if(pAP) pAP->miniDump(getDocument());
4913 #endif
4914 return pAP;
4915 }
4916
4917
getAttributes(const PP_AttrProp ** ppSpanAP,const PP_AttrProp ** ppBlockAP,PT_DocPosition posStart) const4918 bool FV_View::getAttributes(const PP_AttrProp ** ppSpanAP, const PP_AttrProp ** ppBlockAP, PT_DocPosition posStart) const
4919 {
4920 if(getLayout()->getFirstSection() == NULL)
4921 return false;
4922
4923 PT_DocPosition posEnd = posStart;
4924 bool bSelEmpty = true;
4925 if(posStart == 0)
4926 {
4927 posStart = getPoint();
4928 posEnd = posStart;
4929 bSelEmpty = isSelectionEmpty();
4930
4931 if (!bSelEmpty)
4932 {
4933 if (m_Selection.getSelectionAnchor() < posStart)
4934 posStart = m_Selection.getSelectionAnchor();
4935 else
4936 posEnd = m_Selection.getSelectionAnchor();
4937 }
4938 }
4939 if(posStart < 2)
4940 {
4941 posStart = 2;
4942 }
4943 // 1. assemble complete set at insertion point
4944 UT_sint32 xPoint, yPoint, xPoint2, yPoint2;
4945 UT_uint32 iPointHeight;
4946 bool bDirection;
4947
4948 fl_BlockLayout* pBlock;
4949 fl_BlockLayout* pNBlock = NULL;
4950 fp_Run* pRun;
4951
4952 _findPositionCoords(posStart, false, xPoint, yPoint, xPoint2, yPoint2, iPointHeight, bDirection, &pBlock, &pRun);
4953
4954 //
4955 // Look if our selection starts just before a paragraph break
4956 //
4957 if(posStart < posEnd)
4958 {
4959 pNBlock = _findBlockAtPosition(posStart+1);
4960 if(pNBlock != pBlock)
4961 {
4962 _findPositionCoords(posStart + 1,
4963 false,
4964 xPoint,
4965 yPoint,
4966 xPoint2,
4967 yPoint2,
4968 iPointHeight,
4969 bDirection,
4970 &pBlock,
4971 &pRun);
4972 }
4973 }
4974
4975 UT_uint32 blockPosition = pBlock->getPosition();
4976 if(blockPosition > posStart)
4977 {
4978 posStart = blockPosition;
4979 if(posEnd < posStart)
4980 posEnd = posStart;
4981 }
4982 bool bLeftSide = true;
4983
4984 // TODO consider adding indexAP from change record to the
4985 // TODO runs so that we can just use it here.
4986
4987 if (!bSelEmpty)
4988 {
4989 // we want the interior of the selection -- and not the
4990 // format to the left of the start of the selection.
4991 bLeftSide = false;
4992
4993 /*
4994 Likewise, findPointCoords will return the run to the right
4995 of the specified position, so we need to stop looking one
4996 position to the left.
4997 */
4998 posEnd--;
4999 }
5000
5001 if (ppSpanAP)
5002 pBlock->getSpanAP( (posStart - blockPosition), bLeftSide, *ppSpanAP);
5003 if (ppBlockAP)
5004 pBlock->getAP(*ppBlockAP);
5005
5006 return true;
5007 }
5008
5009 /* Get complete(?) set of properties for current position, or for the start of current
5010 * selection.
5011 */
getAllAttrProp(const PP_AttrProp * & pSpanAP,const PP_AttrProp * & pBlockAP,const PP_AttrProp * & pSectionAP,const PP_AttrProp * & pDocAP) const5012 bool FV_View::getAllAttrProp(const PP_AttrProp *& pSpanAP, const PP_AttrProp *& pBlockAP, const PP_AttrProp *& pSectionAP, const PP_AttrProp *& pDocAP) const
5013 {
5014 pDocAP = m_pDoc->getAttrProp();
5015 pSectionAP = 0;
5016 pBlockAP = 0;
5017 pSpanAP = 0;
5018
5019 if(getLayout()->getFirstSection() == NULL)
5020 {
5021 UT_DEBUGMSG(("FV_View::getAllAttrProp: no first section!\n"));
5022 return false;
5023 }
5024
5025 PT_DocPosition posStart = getPoint();
5026
5027 if (!isSelectionEmpty())
5028 {
5029 if (m_Selection.getSelectionAnchor() < posStart)
5030 posStart = m_Selection.getSelectionAnchor();
5031 }
5032 if (posStart < 2)
5033 posStart = 2;
5034
5035 if (fl_BlockLayout * pBlock = getBlockAtPosition(posStart))
5036 {
5037 bool bLeftSide = true; // looking to the left of the cursor, I think... does this work with bidi? [TODO: ??]
5038
5039 pBlock->getAP(pBlockAP);
5040
5041 if (fl_DocSectionLayout * pSection = pBlock->getDocSectionLayout())
5042 pSection->getAP(pSectionAP);
5043
5044 pBlock->getSpanAP(posStart - pBlock->getPosition(), bLeftSide, pSpanAP);
5045 }
5046 else
5047 {
5048 UT_DEBUGMSG(("WARNING: FV_View::getAllAttrProp: No block at start of selection!\n"));
5049 }
5050 return true;
5051 }
5052
5053 /* Find out whether a property has been defined explicitly for a given span, or for spans
5054 * within the current selection, rather than just in the document style or as a default;
5055 * either way, get the resultant value - and, if a selection, say whether spans differ
5056 * in value or explicitness.
5057 *
5058 * NOTES:
5059 * 1. If a property is specified explicitly at block level, then we consider it to be
5060 * explicit also at span level.
5061 * 2. In the case of a mixed selection, it returns szValue and bExplicitlyDefined for the
5062 * start of the selection.
5063 *
5064 * [Question: How does, e.g., paragraph background color export to other formats?]
5065 */
queryCharFormat(const gchar * szProperty,UT_UTF8String & szValue,bool & bExplicitlyDefined,bool & bMixedSelection) const5066 bool FV_View::queryCharFormat(const gchar * szProperty, UT_UTF8String & szValue, bool & bExplicitlyDefined, bool & bMixedSelection) const
5067 {
5068 UT_return_val_if_fail(szProperty,false);
5069
5070 bMixedSelection = false;
5071
5072 if (isSelectionEmpty())
5073 return queryCharFormat(szProperty, szValue, bExplicitlyDefined, getPoint());
5074
5075 PT_DocPosition posStart = getPoint();
5076 PT_DocPosition posEnd = posStart;
5077
5078 if (m_Selection.getSelectionAnchor() < posStart)
5079 posStart = m_Selection.getSelectionAnchor();
5080 else
5081 posEnd = m_Selection.getSelectionAnchor();
5082
5083 if (posStart < 2)
5084 posStart = 2;
5085
5086 PT_DocPosition position = posStart;
5087
5088 bool okay = true;
5089 bool first = true;
5090
5091 bool bLeftSide = true; // looking to the left of the cursor, I think... does this work with bidi? [TODO: ??]
5092
5093 bool bExplicitlyDefined_current;
5094
5095 UT_UTF8String szValue_current;
5096
5097 const PP_AttrProp * pSpanAP = 0;
5098 const PP_AttrProp * prev_pSpanAP = 0;
5099
5100 while (position < posEnd)
5101 {
5102 fl_BlockLayout * pBlock = getBlockAtPosition(position);
5103 if (!pBlock)
5104 {
5105 UT_DEBUGMSG(("FV_View::queryCharFormat(bool): no block at position!\n"));
5106 okay = false;
5107 break;
5108 }
5109 pBlock->getSpanAP(position - pBlock->getPosition(), bLeftSide, pSpanAP);
5110
5111 if (first || (pSpanAP != prev_pSpanAP))
5112 {
5113 okay = queryCharFormat(szProperty, szValue_current, bExplicitlyDefined_current, position);
5114 if (!okay)
5115 break;
5116
5117 if (first)
5118 {
5119 bExplicitlyDefined = bExplicitlyDefined_current;
5120 szValue = szValue_current;
5121 }
5122 else if (!bMixedSelection)
5123 {
5124 if ((bExplicitlyDefined_current != bExplicitlyDefined) || (szValue_current != szValue))
5125 bMixedSelection = true;
5126 }
5127 first = false;
5128 prev_pSpanAP = pSpanAP;
5129 }
5130 ++position; // ??
5131 }
5132 return okay;
5133 }
5134
5135
5136 /*!
5137 * Returns true if the abigrammar plugin is loaded
5138 */
isGrammarLoaded(void) const5139 bool FV_View::isGrammarLoaded(void) const
5140 {
5141 XAP_Module * pGrammar = m_pApp->getPlugin("abigrammar");
5142 if(pGrammar == NULL)
5143 {
5144 return false;
5145 }
5146 return true;
5147 }
5148
5149 /*!
5150 * Returns true if the abimathview plugin is loaded
5151 */
isMathLoaded(void) const5152 bool FV_View::isMathLoaded(void) const
5153 {
5154 XAP_Module * pMath = m_pApp->getPlugin("abimathview");
5155 if(pMath == NULL)
5156 {
5157 return false;
5158 }
5159 return true;
5160 }
5161
queryCharFormat(const gchar * szProperty,UT_UTF8String & szValue,bool & bExplicitlyDefined,PT_DocPosition position) const5162 bool FV_View::queryCharFormat(const gchar * szProperty, UT_UTF8String & szValue, bool & bExplicitlyDefined, PT_DocPosition position) const
5163 {
5164 UT_return_val_if_fail(szProperty,false);
5165
5166 fl_BlockLayout * pBlock = getBlockAtPosition(position);
5167 if (!pBlock)
5168 {
5169 UT_DEBUGMSG(("FV_View::queryCharFormat(PT_DocPosition): no block at position!\n"));
5170 return false;
5171 }
5172
5173 bool bLeftSide = true; // looking to the left of the cursor, I think... does this work with bidi? [TODO: ??]
5174
5175 const PP_AttrProp * pSectionAP = 0;
5176 const PP_AttrProp * pBlockAP = 0;
5177 const PP_AttrProp * pSpanAP = 0;
5178
5179 pBlock->getAP(pBlockAP);
5180
5181 if (fl_DocSectionLayout * pSection = pBlock->getDocSectionLayout())
5182 pSection->getAP(pSectionAP);
5183
5184 pBlock->getSpanAP(position - pBlock->getPosition(), bLeftSide, pSpanAP);
5185
5186 bExplicitlyDefined = false;
5187
5188 const gchar * szPropValue = 0;
5189
5190 if (pSpanAP)
5191 {
5192 if (pSpanAP->getProperty(szProperty, szPropValue))
5193 {
5194 UT_DEBUGMSG(("Property \"%s\" defined at span level as \"%s\"\n",szProperty,szPropValue));
5195 szValue = szPropValue;
5196 bExplicitlyDefined = true;
5197 }
5198 }
5199 if (pBlockAP && !bExplicitlyDefined)
5200 {
5201 if (pBlockAP->getProperty(szProperty, szPropValue))
5202 {
5203 xxx_UT_DEBUGMSG(("Property \"%s\" defined at block level as \"%s\"\n",szProperty,szPropValue));
5204 szValue = szPropValue;
5205 bExplicitlyDefined = true;
5206 }
5207 }
5208
5209 bool okay = true;
5210
5211 if (!bExplicitlyDefined)
5212 {
5213 szPropValue = PP_evalProperty(szProperty, pSpanAP, pBlockAP, pSectionAP, m_pDoc, true);
5214 if (szPropValue != NULL)
5215 {
5216 xxx_UT_DEBUGMSG(("Property \"%s\" defined at style/document level as \"%s\"\n",szProperty,szPropValue));
5217 szValue = szPropValue;
5218 }
5219 else
5220 {
5221 /* PP_evalProperty returns NULL only if something is very wrong...
5222 */
5223 szValue = "";
5224 okay = false;
5225 }
5226 }
5227 return okay;
5228 }
5229
getCharFormat(const gchar *** pProps,bool bExpandStyles) const5230 bool FV_View::getCharFormat(const gchar *** pProps, bool bExpandStyles) const
5231 {
5232 return getCharFormat(pProps,bExpandStyles,0);
5233 }
5234
getCharFormat(const gchar *** pProps,bool bExpandStyles,PT_DocPosition posStart) const5235 bool FV_View::getCharFormat(const gchar *** pProps, bool bExpandStyles, PT_DocPosition posStart) const
5236 {
5237 const PP_AttrProp * pSpanAP = NULL;
5238 const PP_AttrProp * pBlockAP = NULL;
5239 const PP_AttrProp * pSectionAP = NULL; // TODO do we care about section-level inheritance
5240 UT_GenericVector<_fmtPair *> v;
5241 UT_uint32 i;
5242 _fmtPair * f;
5243
5244 //
5245 // Check we have a layout defined first. On start up we don't
5246 //
5247
5248 if(getLayout()->getFirstSection() == NULL)
5249 {
5250 return false;
5251 }
5252 //
5253 // fixme
5254 #if 0
5255 // NOTE: caller must g_free this, but not the referenced contents
5256 const gchar ** tprops = static_cast<const gchar **>(UT_calloc(3, sizeof(gchar *)));
5257 UT_DEBUGMSG(("charFormat \n"));
5258 tprops[0] = "fred";
5259 tprops[1] = "1";
5260 tprops[2] = NULL;
5261 *pProps = tprops;
5262 #endif
5263 if((AV_View::getTick() == m_CharProps.getTick()) && m_CharProps.isValid())
5264 {
5265 *pProps = m_CharProps.getCopyOfProps();
5266 return true;
5267 }
5268 m_CharProps.clearProps();
5269 m_CharProps.setTick(AV_View::getTick());
5270 /*
5271 IDEA: We want to know character-level formatting properties, if
5272 they're constant across the entire selection. To do so, we start
5273 at the beginning of the selection, load 'em all into a vector, and
5274 then prune any property that collides.
5275 */
5276 PT_DocPosition posEnd = posStart;
5277 bool bSelEmpty = true;
5278 if(posStart == 0)
5279 {
5280 posStart = getPoint();
5281 posEnd = posStart;
5282 bSelEmpty = isSelectionEmpty();
5283
5284 if (!bSelEmpty)
5285 {
5286 if (m_Selection.getSelectionAnchor() < posStart)
5287 posStart = m_Selection.getSelectionAnchor();
5288 else
5289 posEnd = m_Selection.getSelectionAnchor();
5290 }
5291 }
5292 if(posStart < 2)
5293 {
5294 posStart = 2;
5295 }
5296 // 1. assemble complete set at insertion point
5297 UT_sint32 xPoint, yPoint, xPoint2, yPoint2;
5298 UT_uint32 iPointHeight;
5299 bool bDirection;
5300
5301 fl_BlockLayout* pBlock;
5302 fl_BlockLayout* pNBlock = NULL;
5303 fp_Run* pRun;
5304
5305 _findPositionCoords(posStart, false, xPoint, yPoint, xPoint2, yPoint2, iPointHeight, bDirection, &pBlock, &pRun);
5306
5307 //
5308 // Look if our selection starts just before a paragraph break
5309 //
5310 if(posStart < posEnd)
5311 {
5312 pNBlock = _findBlockAtPosition(posStart+1);
5313 if(pNBlock != pBlock)
5314 {
5315 _findPositionCoords(posStart + 1,
5316 false,
5317 xPoint,
5318 yPoint,
5319 xPoint2,
5320 yPoint2,
5321 iPointHeight,
5322 bDirection,
5323 &pBlock,
5324 &pRun);
5325 }
5326 }
5327 if(pBlock == NULL)
5328 {
5329 // We want to return NULL here, because that makes it clear to the caller that the props are
5330 // not valid; in any case to return sometimes a dynamically allocated array and sometimes a
5331 // statically allocated one is not a good idea
5332 //
5333 // static const char * pszTmp[2] = {NULL,NULL};
5334
5335 *pProps = NULL;
5336 return false;
5337 }
5338 UT_uint32 blockPosition = pBlock->getPosition();
5339 if(blockPosition > posStart)
5340 {
5341 posStart = blockPosition;
5342 if(posEnd < posStart)
5343 posEnd = posStart;
5344 }
5345 bool bLeftSide = true;
5346
5347 // TODO consider adding indexAP from change record to the
5348 // TODO runs so that we can just use it here.
5349
5350 if (!bSelEmpty)
5351 {
5352 // we want the interior of the selection -- and not the
5353 // format to the left of the start of the selection.
5354 bLeftSide = false;
5355
5356 /*
5357 Likewise, findPointCoords will return the run to the right
5358 of the specified position, so we need to stop looking one
5359 position to the left.
5360 */
5361 posEnd--;
5362 }
5363
5364 pBlock->getSpanAP( (posStart - blockPosition), bLeftSide, pSpanAP);
5365
5366 pBlock->getAP(pBlockAP);
5367
5368 UT_uint32 iPropsCount = PP_getPropertyCount();
5369
5370 for(UT_uint32 n = 0; n < iPropsCount; n++)
5371 {
5372 if((PP_getNthPropertyLevel(n) & PP_LEVEL_CHAR))
5373 {
5374 f = new _fmtPair(PP_getNthPropertyName(n),pSpanAP,pBlockAP,pSectionAP,m_pDoc,bExpandStyles);
5375 if(f->m_val != NULL)
5376 v.addItem(f);
5377 else
5378 delete f;
5379 }
5380 }
5381
5382 // 2. prune 'em as they vary across selection
5383 if (!bSelEmpty)
5384 {
5385 fl_BlockLayout* pBlockEnd;
5386 fp_Run* pRunEnd;
5387 _findPositionCoords(posEnd, false, xPoint, yPoint, xPoint2, yPoint2, iPointHeight, bDirection, &pBlockEnd, &pRunEnd);
5388
5389 while (pRun && (pRun != pRunEnd))
5390 {
5391 const PP_AttrProp * pAP;
5392 bool bCheck = false;
5393
5394 pRun = pRun->getNextRun();
5395
5396
5397 if (!pRun)
5398 {
5399 // go to first run of next block
5400 pBlock = pBlock->getNextBlockInDocument();
5401
5402 if (!pBlock) // at EOD, so just bail
5403 break;
5404
5405 // did block format change?
5406 pBlock->getAP(pAP);
5407 if (pBlockAP != pAP)
5408 {
5409 pBlockAP = pAP;
5410 bCheck = true;
5411 }
5412
5413 pRun = pBlock->getFirstRun();
5414 }
5415
5416 // FIXME: Don't look in EOP Runs. This is because they are
5417 // not represented in the PT, so when the PT is asked for
5418 // the properties of the EOP's position, it returns the
5419 // default properties. What it should return is the
5420 // properties of the previous Run. But just skipping the
5421 // check altogether is easier (and faster).
5422 if (pRun->getType() == FPRUN_ENDOFPARAGRAPH)
5423 continue;
5424
5425 // did span format change?
5426
5427 pAP = NULL;
5428 pBlock->getSpanAP(pRun->getBlockOffset()+pRun->getLength(),true,pAP);
5429 if (pSpanAP != pAP)
5430 {
5431 pSpanAP = pAP;
5432 bCheck = true;
5433 }
5434
5435 if (bCheck)
5436 {
5437 i = v.getItemCount();
5438
5439 while (i > 0)
5440 {
5441 f = v.getNthItem(i-1);
5442
5443 const gchar * value = PP_evalProperty(f->m_prop,pSpanAP,pBlockAP,pSectionAP,m_pDoc,bExpandStyles);
5444
5445 // prune anything that doesn't match
5446 if (value && strcmp(f->m_val, value))
5447 {
5448 DELETEP(f);
5449 v.deleteNthItem(i-1);
5450 }
5451
5452 i--;
5453 }
5454
5455 // when vector is empty, stop looking
5456 if (0 == v.getItemCount())
5457 {
5458 pRun = NULL;
5459 break;
5460 }
5461 }
5462 }
5463 }
5464
5465 // 3. export whatever's left
5466 UT_uint32 count = v.getItemCount()*2 + 1;
5467
5468 // NOTE: caller must g_free this, but not the referenced contents
5469 const gchar ** props = static_cast<const gchar **>(UT_calloc(count, sizeof(gchar *)));
5470 if (!props)
5471 return false;
5472
5473 const gchar ** p = props;
5474 i = v.getItemCount();
5475 UT_uint32 numProps = count;
5476 while (i > 0)
5477 {
5478 f = v.getNthItem(i-1);
5479 i--;
5480
5481 p[0] = f->m_prop;
5482 p[1] = f->m_val;
5483 p += 2;
5484
5485 }
5486 p[0] = NULL;
5487
5488 UT_VECTOR_PURGEALL(_fmtPair *,v);
5489
5490 *pProps = props;
5491 m_CharProps.fillProps(numProps,props);
5492 return true;
5493 }
5494
5495
5496 /*!
5497 This method fills a vector with all the blocks contained between the
5498 first and last blocks of a list structure.
5499 \param v Pointer to Vector of all the blocks found
5500 */
5501
getAllBlocksInList(UT_GenericVector<fl_BlockLayout * > * v) const5502 void FV_View::getAllBlocksInList(UT_GenericVector<fl_BlockLayout *> * v) const
5503 {
5504 //
5505 // get all the blocks in the list
5506 //
5507 fl_BlockLayout * pBlock;
5508 fl_AutoNum * pAuto = getCurrentBlock()->getAutoNum();
5509 if(pAuto == NULL)
5510 {
5511 pBlock = getCurrentBlock();
5512 v->addItem(pBlock);
5513 return;
5514 }
5515 pf_Frag_Strux* pFirstSdh = pAuto->getFirstItem();
5516 pf_Frag_Strux* pLastSdh = pAuto->getNthBlock(pAuto->getNumLabels()-1);
5517 fl_SectionLayout * pSl = getCurrentBlock()->getSectionLayout();
5518 pBlock = pSl->getNextBlockInDocument();
5519 bool foundLast = false;
5520 bool foundFirst = false;
5521
5522 //
5523 // Now collect all all the blocks between the first and last list elements
5524 // in a vector
5525 //
5526 while (pBlock != NULL && foundLast == false)
5527 {
5528 if(pBlock->getStruxDocHandle() == pFirstSdh)
5529 {
5530 foundFirst = true;
5531 }
5532 if(foundFirst == true && (pBlock->getContainerType() == FL_CONTAINER_BLOCK))
5533 v->addItem(pBlock);
5534 if(pBlock->getStruxDocHandle() == pLastSdh)
5535 foundLast = true;
5536 pBlock = static_cast<fl_BlockLayout *>(pBlock->getNextBlockInDocument());
5537 }
5538 }
5539
5540 /*!
5541
5542 This method increases or decreases the indents of a range of blocks.
5543 The blocks can be either all those contained by a list structure or
5544 just those in a selection.
5545
5546 \param doList true if you want to indents all the blocks in the list
5547 of which the current block is a member. If false just those
5548 blocks within the current selected range.
5549 \param indentChange +-ve value by which the block will be indented.
5550 \param page_size width of the page in inches.
5551 */
5552
setBlockIndents(bool doLists,double indentChange,double page_size)5553 bool FV_View::setBlockIndents(bool doLists, double indentChange, double page_size)
5554 {
5555 //
5556 // indentChange is the increment to the current alignment.
5557 //
5558 UT_GenericVector<fl_BlockLayout *> v;
5559 UT_String szAlign;
5560 UT_String szIndent;
5561 double fIndent;
5562 bool bRet = true;
5563 UT_Dimension dim;
5564 double fAlign;
5565 fl_BlockLayout * pBlock;
5566 UT_sint32 i;
5567 //
5568 // Signal PieceTable Change
5569 //
5570 _saveAndNotifyPieceTableChange();
5571
5572 m_pDoc->beginUserAtomicGlob();
5573 //
5574 // OK now change the alignements of the blocks.
5575 //
5576 if(doLists)
5577 getAllBlocksInList(&v);
5578 else
5579 getBlocksInSelection(&v);
5580 const gchar * props[] = {NULL,"0.0in",NULL,NULL};
5581 const gchar ind_left [] = "margin-left";
5582 const gchar ind_right[] = "margin-right";
5583 const gchar * indent;
5584
5585 for(i = 0; i<v.getItemCount();i++)
5586 {
5587 pBlock = v.getNthItem(i);
5588 if(pBlock->getDominantDirection() == UT_BIDI_RTL)
5589 indent = ind_right;
5590 else
5591 indent = ind_left;
5592
5593 szAlign = pBlock->getProperty(indent);
5594 dim = UT_determineDimension(szAlign.c_str());
5595 fAlign = static_cast<double>(UT_convertToInches(szAlign.c_str()));
5596 szIndent = pBlock->getProperty("text-indent");
5597 fIndent = static_cast<double>(UT_convertToInches(szIndent.c_str()));
5598 if(fAlign + fIndent + indentChange < 0.0)
5599 {
5600 fAlign = -fIndent + 0.0001;
5601 }
5602 else if( fAlign + indentChange + fIndent > page_size)
5603 {
5604 fAlign = page_size - fIndent;
5605 }
5606 else
5607 {
5608 fAlign = fAlign + indentChange;
5609 }
5610 UT_String szNewAlign = UT_convertInchesToDimensionString (dim, fAlign);
5611 pf_Frag_Strux* sdh = pBlock->getStruxDocHandle();
5612 PT_DocPosition iPos = m_pDoc->getStruxPosition(sdh)+fl_BLOCK_STRUX_OFFSET;
5613 props[0] = indent;
5614 props[1] = static_cast<const gchar *>(szNewAlign.c_str());
5615 bRet = m_pDoc->changeStruxFmt(PTC_AddFmt, iPos, iPos, NULL, props, PTX_Block);
5616 }
5617 //
5618 // Moved outside the loop. Speeds things up and seems OK.
5619 //
5620
5621 // Signal PieceTable Changes have finished
5622 _restorePieceTableState();
5623 _generalUpdate();
5624
5625 m_pDoc->endUserAtomicGlob();
5626 _fixInsertionPointCoords();
5627 notifyListeners(AV_CHG_MOTION | AV_CHG_HDRFTR);
5628 return bRet;
5629 }
5630
removeStruxAttrProps(PT_DocPosition ipos1,PT_DocPosition ipos2,PTStruxType iStrux,const gchar * attributes[],const gchar * properties[])5631 bool FV_View::removeStruxAttrProps(PT_DocPosition ipos1,
5632 PT_DocPosition ipos2,
5633 PTStruxType iStrux,
5634 const gchar * attributes[] ,
5635 const gchar * properties[])
5636 {
5637 bool bRet;
5638
5639 // Signal PieceTable Change
5640 _saveAndNotifyPieceTableChange();
5641
5642 _clearIfAtFmtMark(getPoint());
5643 bRet = m_pDoc->changeStruxFmt(PTC_RemoveFmt,ipos1,ipos2,attributes,properties,iStrux);
5644
5645 // Signal PieceTable Changes have finished
5646 _restorePieceTableState();
5647 _generalUpdate();
5648 _fixInsertionPointCoords();
5649
5650 return bRet;
5651 }
5652
isImageAtStrux(PT_DocPosition ipos1,PTStruxType iStrux)5653 bool FV_View::isImageAtStrux(PT_DocPosition ipos1, PTStruxType iStrux)
5654 {
5655 pf_Frag_Strux* sdh = NULL;
5656 bool bret = m_pDoc->getStruxOfTypeFromPosition(ipos1, iStrux, &sdh);
5657 if(!bret)
5658 {
5659 return false;
5660 }
5661 const gchar * pszDataID = NULL;
5662 bret = m_pDoc->getAttributeFromSDH(sdh, isShowRevisions(), getRevisionLevel(), PT_STRUX_IMAGE_DATAID,&pszDataID);
5663 if(!bret)
5664 {
5665 return false;
5666 }
5667 if(pszDataID == NULL)
5668 {
5669 return false;
5670 }
5671 return true;
5672 }
5673
setBlockFormat(const gchar * properties[])5674 bool FV_View::setBlockFormat(const gchar * properties[])
5675 {
5676 bool bRet;
5677
5678 // Signal PieceTable Change
5679 _saveAndNotifyPieceTableChange();
5680
5681 _clearIfAtFmtMark(getPoint());
5682
5683 PT_DocPosition posStart = getPoint();
5684 PT_DocPosition posEnd = posStart;
5685 if (!isSelectionEmpty())
5686 {
5687 if (m_Selection.getSelectionAnchor() < posStart)
5688 {
5689 posStart = m_Selection.getSelectionAnchor();
5690 }
5691 else
5692 {
5693 posEnd = m_Selection.getSelectionAnchor();
5694 }
5695 }
5696 if(posStart < 2)
5697 {
5698 posStart = 2;
5699 }
5700
5701
5702 // if the format change includes dom-dir, we need to force change
5703 // of direction for the last run in the block, the EndOfParagraph
5704 // run. (This should really not be necessary, the EndOfParagraph
5705 // run should lookup its properties)
5706
5707 bool bDomDirChange = false;
5708 UT_BidiCharType iDomDir = UT_BIDI_LTR;
5709
5710 const gchar ** p = properties;
5711
5712 while(*p)
5713 {
5714 if(!strcmp(*p,"dom-dir"))
5715 {
5716 bDomDirChange = true;
5717 if(!strcmp(*(p+1), "rtl"))
5718 {
5719 iDomDir = UT_BIDI_RTL;
5720 }
5721 break;
5722 }
5723 p += 2;
5724 }
5725
5726 if(bDomDirChange)
5727 {
5728
5729 fl_BlockLayout * pBl = _findBlockAtPosition(posStart);
5730 fl_BlockLayout * pBl2 = _findBlockAtPosition(posEnd);
5731
5732 if(pBl2)
5733 pBl2 = static_cast<fl_BlockLayout *>(pBl2->getNextBlockInDocument());
5734
5735 while(pBl)
5736 {
5737
5738 if(iDomDir == UT_BIDI_RTL)
5739 {
5740 static_cast<fp_Line *>(static_cast<fl_BlockLayout *>(pBl)->getLastContainer())->getLastRun()->setDirection(UT_BIDI_LTR);
5741 }
5742 else
5743 {
5744 static_cast<fp_Line *>(static_cast<fl_BlockLayout *>(pBl)->getLastContainer())->getLastRun()->setDirection(UT_BIDI_RTL);
5745 }
5746
5747 pBl = static_cast<fl_BlockLayout *>(pBl->getNextBlockInDocument());
5748 if(pBl == pBl2)
5749 break;
5750 }
5751 }
5752
5753
5754 // We need to know if the selection is inside a table, because in that
5755 // case, not all blocks can be selected
5756 pf_Frag_Strux *tstart, *tend;
5757 if (m_pDoc->getStruxOfTypeFromPosition(posStart,PTX_SectionTable,&tstart)
5758 && m_pDoc->getStruxOfTypeFromPosition(posEnd,PTX_SectionTable,&tend)
5759 && tstart == tend)
5760 {
5761 bRet = false;
5762 UT_GenericVector<fl_BlockLayout*> vBlock;
5763 getBlocksInSelection(&vBlock);
5764 fl_ContainerLayout * pCL = NULL;
5765 UT_sint32 i =0;
5766 for(i=0; i<vBlock.getItemCount();i++)
5767 {
5768 fl_BlockLayout * pBL = vBlock.getNthItem(i);
5769 pCL = pBL->myContainingLayout();
5770 if(pCL->getContainerType() == FL_CONTAINER_CELL)
5771 {
5772 PT_DocPosition pos = pBL->getPosition();
5773 bRet = m_pDoc->changeStruxFmt(PTC_AddFmt,pos,pos,NULL,properties,PTX_Block);
5774 }
5775 }
5776 }
5777 else
5778 bRet = m_pDoc->changeStruxFmt(PTC_AddFmt,posStart,posEnd,NULL,properties,PTX_Block);
5779
5780 // Signal PieceTable Changes have finished
5781 _restorePieceTableState();
5782
5783 _generalUpdate();
5784
5785 notifyListeners(AV_CHG_MOTION | AV_CHG_ALL);
5786
5787 _fixInsertionPointCoords();
5788
5789 return bRet;
5790 }
5791
5792
5793 /*!
5794 * Collapse text to the level specified over the range of text given.
5795 */
setCollapsedRange(PT_DocPosition posLow,PT_DocPosition posHigh,const gchar * properties[])5796 bool FV_View::setCollapsedRange(PT_DocPosition posLow,
5797 PT_DocPosition posHigh,
5798 const gchar * properties[])
5799 {
5800 bool bRet;
5801
5802 // Signal PieceTable Change
5803 _saveAndNotifyPieceTableChange();
5804
5805 _clearIfAtFmtMark(getPoint());
5806
5807 bRet = m_pDoc->changeStruxFmt(PTC_AddFmt,posLow,posHigh,NULL,properties);
5808
5809
5810 // Signal PieceTable Changes have finished
5811 _restorePieceTableState();
5812 _generalUpdate();
5813 _fixInsertionPointCoords();
5814
5815 return bRet;
5816 }
5817
5818 /*!
5819 * This method does the insert Page Number logic.
5820 * It inserts with this logic. For the sake of not writing header/footer every
5821 * time I will just write "footer"
5822 * 1. If no footer exists one will be created and a page number inserted.
5823 * 2. If a footer with a page number exists the paragraph containing the footer
5824 * will be right center or left justified as requested by the user.
5825 * 3. If a footer with no page number exists a new paragraph containg the
5826 * page number will be inserted at the top of the container.
5827 *
5828 \param bIsFooter true if the user wants a pagenumber in a footer.
5829 \param const gchar ** atts const string describing left , center or right
5830 * justification.
5831 */
5832
processPageNumber(HdrFtrType hfType,const gchar ** atts)5833 bool FV_View::processPageNumber(HdrFtrType hfType, const gchar ** atts)
5834 {
5835 //
5836 // Quick hack to stop a segfault if a user tries to insert a header from
5837 // within a header/footer.
5838 //
5839 bool bInsertFromHdrFtr = false;
5840 PT_DocPosition oldpos = getPoint();
5841 fl_HdrFtrShadow * pShadow = NULL;
5842 if(isHdrFtrEdit())
5843 {
5844 bInsertFromHdrFtr = true;
5845 pShadow = m_pEditShadow;
5846 clearHdrFtrEdit();
5847 warpInsPtToXY(0,0,false);
5848 }
5849 //
5850 // Handle simple cases of inserting into non-existing header/footers.
5851 //
5852 fl_DocSectionLayout * pDSL = getCurrentPage()->getOwningSection();
5853 if(hfType == FL_HDRFTR_FOOTER && pDSL->getFooter() == NULL)
5854 {
5855 insertPageNum(atts, hfType);
5856 setPoint(oldpos);
5857 if(m_pDoc->isEndFrameAtPos(oldpos-1))
5858 {
5859 setPoint(oldpos-1);
5860 }
5861 return true;
5862 }
5863 else if(hfType == FL_HDRFTR_HEADER && pDSL->getHeader() == NULL)
5864 {
5865 insertPageNum(atts, hfType);
5866 setPoint(oldpos);
5867 if(m_pDoc->isEndFrameAtPos(oldpos-1))
5868 {
5869 setPoint(oldpos-1);
5870 }
5871 return true;
5872 }
5873 //
5874 // OK we're here if we want to insert a page number into a pre-existing
5875 // header/footer. Let's get the header/footer now.
5876 //
5877 fl_HdrFtrSectionLayout * pHFSL = NULL;
5878 if(hfType >= FL_HDRFTR_FOOTER)
5879 pHFSL = pDSL->getFooter();
5880 else
5881 pHFSL = pDSL->getHeader();
5882 //
5883 // Scan the layout for a pre-existing page number.
5884 //
5885 fl_BlockLayout * pBL = pHFSL->getNextBlockInDocument();
5886 bool bFoundPageNumber = false;
5887 while(pBL != NULL && !bFoundPageNumber)
5888 {
5889 fp_Run * pRun = pBL->getFirstRun();
5890 while(pRun != NULL && !bFoundPageNumber)
5891 {
5892 if(pRun->getType() == FPRUN_FIELD)
5893 {
5894 fp_FieldRun * pFRun = static_cast<fp_FieldRun *>(pRun);
5895 bFoundPageNumber = (pFRun->getFieldType() == FPFIELD_page_number);
5896 }
5897 pRun = pRun->getNextRun();
5898 }
5899 if(!bFoundPageNumber)
5900 pBL = static_cast<fl_BlockLayout *>(pBL->getNext());
5901 }
5902
5903 // Signal PieceTable Change
5904
5905 _saveAndNotifyPieceTableChange();
5906 //
5907 // Just set the format of the Block if a PageNumber has been found.
5908 //
5909 bool bRet;
5910 PT_DocPosition pos;
5911 if(bFoundPageNumber)
5912 {
5913 pos = pBL->getPosition();
5914
5915 bRet = m_pDoc->changeStruxFmt(PTC_AddFmt,pos,pos,NULL,atts,PTX_Block);
5916
5917 if(bInsertFromHdrFtr)
5918 {
5919 _setPoint(oldpos);
5920 setHdrFtrEdit(pShadow);
5921 }
5922
5923 // Signal PieceTable Changes have finished
5924 _restorePieceTableState();
5925 _generalUpdate();
5926 return bRet;
5927 }
5928 //
5929 // We're here if there's a header/footer with no page number
5930 // Insert a page number with the correct formatting.
5931 //
5932
5933 const gchar* f_attributes[] = {
5934 "type", "page_number",
5935 NULL, NULL
5936 };
5937 pBL = pHFSL->getNextBlockInDocument();
5938 pos = pBL->getPosition();
5939
5940 //Glob it all together so it can be undone with one
5941 // click
5942
5943 m_pDoc->beginUserAtomicGlob();
5944
5945 //
5946 // Insert a blank paragraph at the beginning of the Section
5947 //
5948
5949 m_pDoc->insertStrux(pos, PTX_Block);
5950
5951 //
5952 // Set the formatting of the paragraph to the Users request
5953 //
5954 bRet = m_pDoc->changeStruxFmt(PTC_AddFmt,pos,pos,NULL,atts,PTX_Block);
5955
5956 // Insert the page_number field with the requested attributes at the top
5957 // of the header/footer.
5958
5959 bRet = m_pDoc->insertObject(pos, PTO_Field, f_attributes, NULL);
5960 m_pDoc->endUserAtomicGlob();
5961
5962 if(bInsertFromHdrFtr)
5963 {
5964 _setPoint(oldpos);
5965 setHdrFtrEdit(pShadow);
5966 }
5967
5968 // Signal PieceTable Changes have finished
5969 _restorePieceTableState();
5970
5971 _generalUpdate();
5972 return bRet;
5973 }
5974
5975
changeListStyle(fl_AutoNum * pAuto,FL_ListType lType,UT_uint32 startv,const gchar * pszDelim,const gchar * pszDecimal,const gchar * pszFont,float Align,float Indent)5976 void FV_View::changeListStyle( fl_AutoNum* pAuto,
5977 FL_ListType lType,
5978 UT_uint32 startv,
5979 const gchar* pszDelim,
5980 const gchar* pszDecimal,
5981 const gchar* pszFont,
5982 float Align,
5983 float Indent)
5984 {
5985 UT_sint32 i=0;
5986 gchar pszStart[80],pszAlign[20],pszIndent[20];
5987 UT_GenericVector<const gchar*> va,vp;
5988 UT_GenericVector<pf_Frag_Strux*> vb;
5989 pf_Frag_Strux* sdh2 = pAuto->getNthBlock(i);
5990 m_pDoc->beginUserAtomicGlob();
5991
5992 // Signal PieceTable Change
5993 _saveAndNotifyPieceTableChange();
5994
5995 m_pDoc->disableListUpdates();
5996
5997 if(lType == NOT_A_LIST)
5998 {
5999 // Stop lists in all elements
6000 i = 0;
6001 sdh2 = pAuto->getNthBlock(i);
6002 while(sdh2 != NULL)
6003 {
6004 vb.addItem(sdh2);
6005 i++;
6006 sdh2 = pAuto->getNthBlock(i);
6007 }
6008 for(i=0; i< vb.getItemCount(); ++i)
6009 {
6010 pf_Frag_Strux* sdh = vb.getNthItem(i);
6011 m_pDoc->listUpdate(sdh);
6012 m_pDoc->StopList(sdh);
6013 }
6014
6015 m_pDoc->enableListUpdates();
6016 m_pDoc->updateDirtyLists();
6017
6018 // Signal PieceTable Changes have finished
6019 _restorePieceTableState();
6020 _generalUpdate();
6021 m_pDoc->endUserAtomicGlob();
6022
6023 return;
6024 }
6025
6026 gchar * style = getCurrentBlock()->getListStyleString(lType);
6027 //
6028 // This is depeciated..
6029 va.addItem( PT_STYLE_ATTRIBUTE_NAME); va.addItem( style);
6030
6031 pAuto->setListType(lType);
6032 sprintf(pszStart, "%i" , startv);
6033 strncpy( pszAlign,
6034 UT_convertInchesToDimensionString(DIM_IN, Align, 0),
6035 sizeof(pszAlign));
6036
6037 strncpy( pszIndent,
6038 UT_convertInchesToDimensionString(DIM_IN, Indent, 0),
6039 sizeof(pszIndent));
6040
6041 vp.addItem( "start-value"); vp.addItem( pszStart);
6042 vp.addItem( "margin-left"); vp.addItem( pszAlign);
6043 vp.addItem( "text-indent"); vp.addItem( pszIndent);
6044 vp.addItem( "list-style"); vp.addItem( style);
6045 pAuto->setStartValue(startv);
6046 if(pszDelim != NULL)
6047 {
6048 vp.addItem( "list-delim"); vp.addItem( pszDelim);
6049 pAuto->setDelim(pszDelim);
6050 }
6051 if(pszDecimal != NULL)
6052 {
6053 vp.addItem( "list-decimal"); vp.addItem( pszDecimal);
6054 pAuto->setDecimal(pszDecimal);
6055 }
6056 if(pszFont != NULL)
6057 {
6058 vp.addItem( "field-font"); vp.addItem( pszFont);
6059 }
6060 //
6061 // Assemble the List attributes
6062 //
6063 UT_uint32 counta = va.getItemCount() + 1;
6064 const gchar ** attribs = static_cast<const gchar **>(UT_calloc(counta, sizeof(gchar *)));
6065 for(i=0; i<va.getItemCount();i++)
6066 {
6067 attribs[i] = va.getNthItem(i);
6068 }
6069 attribs[i] = static_cast<gchar *>(NULL);
6070 //
6071 // Now assemble the list properties
6072 //
6073 UT_uint32 countp = vp.getItemCount() + 1;
6074 const gchar ** props = static_cast<const gchar **>(UT_calloc(countp, sizeof(gchar *)));
6075 for(i=0; i<vp.getItemCount();i++)
6076 {
6077 props[i] = vp.getNthItem(i);
6078 }
6079 props[i] = static_cast<gchar *>(NULL);
6080
6081 i = 0;
6082 sdh2 = pAuto->getNthBlock(i);
6083 while(sdh2 != NULL)
6084 {
6085 PT_DocPosition iPos = m_pDoc->getStruxPosition(sdh2)+fl_BLOCK_STRUX_OFFSET;
6086 UT_DebugOnly<bool> bRet;
6087 // bRet = m_pDoc->changeStruxFmt(PTC_AddFmt, iPos, iPos, attribs, props, PTX_Block);
6088 bRet = m_pDoc->changeStruxFmt(PTC_AddFmt, iPos, iPos, NULL, props, PTX_Block);
6089 UT_ASSERT(bRet);
6090 i++;
6091 sdh2 = pAuto->getNthBlock(i);
6092 _generalUpdate();
6093 }
6094
6095 // Signal PieceTable Changes have finished
6096 _restorePieceTableState();
6097
6098 _generalUpdate();
6099 m_pDoc->enableListUpdates();
6100 m_pDoc->updateDirtyLists();
6101 m_pDoc->endUserAtomicGlob();
6102 _ensureInsertionPointOnScreen();
6103 FREEP(attribs);
6104 FREEP(props);
6105 }
6106
6107
getSectionFormat(const gchar *** pProps) const6108 bool FV_View::getSectionFormat(const gchar ***pProps) const
6109 {
6110 const PP_AttrProp * pBlockAP = NULL;
6111 const PP_AttrProp * pSectionAP = NULL;
6112 UT_GenericVector<_fmtPair *> v;
6113 UT_uint32 i;
6114 _fmtPair * f;
6115
6116 /*
6117 IDEA: We want to know block-level formatting properties, if
6118 they're constant across the entire selection. To do so, we start
6119 at the beginning of the selection, load 'em all into a vector, and
6120 then prune any property that collides.
6121 */
6122 PT_DocPosition posStart = getPoint();
6123 PT_DocPosition posEnd = posStart;
6124
6125 //
6126 // Check we have a layout defined first. On start up we don't
6127 //
6128 bool b = m_SecProps.isValid();
6129 if((AV_View::getTick() == m_SecProps.getTick()) && b)
6130 {
6131 xxx_UT_DEBUGMSG(("GOt a valid cache for section props \n"));
6132 *pProps = m_SecProps.getCopyOfProps();
6133 return true;
6134 }
6135 m_SecProps.clearProps();
6136 m_SecProps.setTick(AV_View::getTick());
6137 b = m_SecProps.isValid();
6138
6139 if(getLayout()->getFirstSection() == NULL)
6140 {
6141 return false;
6142 }
6143
6144 if (!isSelectionEmpty())
6145 {
6146 if (m_Selection.getSelectionAnchor() < posStart)
6147 posStart = m_Selection.getSelectionAnchor();
6148 else
6149 posEnd = m_Selection.getSelectionAnchor();
6150 }
6151
6152 // 1. assemble complete set at insertion point
6153 fl_BlockLayout* pBlock = _findBlockAtPosition(posStart);
6154 UT_return_val_if_fail(pBlock,false);
6155 fl_DocSectionLayout* pSection = pBlock->getDocSectionLayout();
6156 pSection->getAP(pSectionAP);
6157
6158 UT_uint32 iPropsCount = PP_getPropertyCount();
6159 for(UT_uint32 n = 0; n < iPropsCount; n++)
6160 {
6161 if((PP_getNthPropertyLevel(n) & PP_LEVEL_SECT))
6162 {
6163 f = new _fmtPair(PP_getNthPropertyName(n),NULL,pBlockAP,pSectionAP,m_pDoc,false);
6164 if(f->m_val != NULL)
6165 v.addItem(f);
6166 else
6167 delete f;
6168 }
6169 }
6170
6171 // 2. prune 'em as they vary across selection
6172 if (!isSelectionEmpty())
6173 {
6174 fl_BlockLayout* pBlockEnd = _findBlockAtPosition(posEnd);
6175 UT_ASSERT_HARMLESS( pBlockEnd );
6176 if(!pBlockEnd)
6177 {
6178 UT_VECTOR_PURGEALL(_fmtPair *,v);
6179 return false;
6180 }
6181
6182 fl_DocSectionLayout *pSectionEnd = pBlockEnd->getDocSectionLayout();
6183
6184 while (pSection && (pSection != pSectionEnd))
6185 {
6186 const PP_AttrProp * pAP;
6187 bool bCheck = false;
6188
6189 pSection = pSection->getNextDocSection();
6190 if (!pSection) // at EOD, so just bail
6191 break;
6192
6193 // did block format change?
6194 pSection->getAP(pAP);
6195 if (pSectionAP != pAP)
6196 {
6197 pSectionAP = pAP;
6198 bCheck = true;
6199 }
6200
6201 if (bCheck)
6202 {
6203 i = v.getItemCount();
6204
6205 while (i > 0)
6206 {
6207 f = v.getNthItem(i-1);
6208
6209 const gchar * value = PP_evalProperty(f->m_prop,NULL,pBlockAP,pSectionAP,m_pDoc,false);
6210
6211 // prune anything that doesn't match
6212 if(f->m_val == NULL || value == NULL)
6213 {
6214 DELETEP(f);
6215 v.deleteNthItem(i-1);
6216 }
6217 else if (strcmp(f->m_val, value))
6218 {
6219 DELETEP(f);
6220 v.deleteNthItem(i-1);
6221 }
6222
6223 i--;
6224 }
6225
6226 // when vector is empty, stop looking
6227 if (0 == v.getItemCount())
6228 {
6229 pSection = NULL;
6230 break;
6231 }
6232 }
6233 }
6234 }
6235
6236 // 3. export whatever's left
6237 UT_uint32 count = v.getItemCount()*2 + 1;
6238
6239 // NOTE: caller must g_free this, but not the referenced contents
6240 const gchar ** props = static_cast<const gchar **>(UT_calloc(count, sizeof(gchar *)));
6241 if (!props)
6242 return false;
6243
6244 const gchar ** p = props;
6245
6246 i = v.getItemCount();
6247 UT_uint32 numProps = count;
6248 while (i > 0)
6249 {
6250 f = v.getNthItem(i-1);
6251 i--;
6252
6253 p[0] = f->m_prop;
6254 p[1] = f->m_val;
6255 p += 2;
6256 }
6257 p[0] = NULL;
6258 UT_VECTOR_PURGEALL(_fmtPair *,v);
6259
6260 *pProps = props;
6261 m_SecProps.fillProps(numProps,props);
6262 b = m_SecProps.isValid();
6263 UT_ASSERT(b);
6264
6265 return true;
6266 }
6267
6268 /*!
6269 * Set a string with the cell properties of the cell located at position pos
6270 */
getCellFormat(PT_DocPosition pos,UT_String & sCellProps) const6271 bool FV_View::getCellFormat(PT_DocPosition pos, UT_String & sCellProps) const
6272 {
6273 sCellProps.clear();
6274 if(!isInTable(pos))
6275 {
6276 return false;
6277 }
6278 const PP_AttrProp * pCellAP = NULL;
6279 fl_BlockLayout * pBL = _findBlockAtPosition(pos);
6280 if(!pBL)
6281 {
6282 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
6283 return false;
6284 }
6285 fl_SectionLayout * pCell = static_cast<fl_CellLayout *>(pBL->myContainingLayout());
6286 if(!pCell)
6287 {
6288 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
6289 return false;
6290 }
6291 pCell->getAP(pCellAP);
6292
6293 UT_sint32 iPropsCount = PP_getPropertyCount();
6294 UT_sint32 n = 0;
6295 UT_String sPropName;
6296 UT_String sPropVal;
6297 const gchar * pszPropVal;
6298 for(n = 0; n < iPropsCount; n++)
6299 {
6300 if((PP_getNthPropertyLevel(n) & PP_LEVEL_TABLE))
6301 {
6302 sPropName = PP_getNthPropertyName(n);
6303 sPropVal.clear();
6304 bool bFound = pCellAP->getProperty(sPropName.c_str(),pszPropVal);
6305 if(bFound)
6306 {
6307 sPropVal = pszPropVal;
6308 UT_String_setProperty(sCellProps,sPropName,sPropVal);
6309 }
6310 }
6311 }
6312 return true;
6313 }
6314
getBlockFormat(const gchar *** pProps,bool bExpandStyles) const6315 bool FV_View::getBlockFormat(const gchar *** pProps,bool bExpandStyles) const
6316 {
6317 const PP_AttrProp * pBlockAP = NULL;
6318 const PP_AttrProp * pSectionAP = NULL; // TODO do we care about section-level inheritance?
6319 // we do in the bidi version
6320
6321 //
6322 // Check we have a layout defined first. On startup we don't
6323 //
6324 // fixme
6325
6326 *pProps = NULL;
6327
6328 if(getLayout()->getFirstSection() == NULL)
6329 {
6330 return false;
6331 }
6332
6333 // currently there are 69 block level properties
6334 UT_GenericVector<_fmtPair *> v(69,4,true);
6335 UT_sint32 i;
6336 _fmtPair * f = NULL;
6337
6338 /*
6339 IDEA: We want to know block-level formatting properties, if
6340 they're constant across the entire selection. To do so, we start
6341 at the beginning of the selection, load 'em all into a vector, and
6342 then prune any property that collides.
6343 */
6344 fl_BlockLayout * pBlock = _findBlockAtPosition(getPoint());
6345 if((AV_View::getTick() == m_BlockProps.getTick()) && m_BlockProps.isValid() &&
6346 (pBlock == m_BlockProps.getCurrentCL()))
6347 {
6348 *pProps = m_BlockProps.getCopyOfProps();
6349 return true;
6350 }
6351 m_BlockProps.clearProps();
6352 m_BlockProps.setTick(AV_View::getTick());
6353 m_BlockProps.setCurrentCL(pBlock);
6354
6355 PT_DocPosition posStart = getPoint();
6356 PT_DocPosition posEnd = posStart;
6357
6358 if (!isSelectionEmpty())
6359 {
6360 if (m_Selection.getSelectionAnchor() < posStart)
6361 posStart = m_Selection.getSelectionAnchor();
6362 else
6363 posEnd = m_Selection.getSelectionAnchor();
6364 }
6365
6366 // 1. assemble complete set at insertion point
6367 pBlock = _findBlockAtPosition(posStart);
6368 if(pBlock == NULL)
6369 {
6370 return false;
6371 }
6372 pBlock->getAP(pBlockAP);
6373
6374 fl_SectionLayout* pSection = pBlock->getSectionLayout();
6375 pSection->getAP(pSectionAP);
6376
6377
6378 UT_uint32 iPropsCount = PP_getPropertyCount();
6379 for(UT_uint32 n = 0; n < iPropsCount; n++)
6380 {
6381 if((PP_getNthPropertyLevel(n) & PP_LEVEL_BLOCK))
6382 {
6383 f = new _fmtPair(PP_getNthPropertyName(n),NULL,pBlockAP,pSectionAP,m_pDoc,bExpandStyles);
6384 if(f->m_val != NULL)
6385 v.addItem(f);
6386 else
6387 delete f;
6388 }
6389 }
6390
6391 // 2. prune 'em as they vary across selection
6392 if (!isSelectionEmpty())
6393 {
6394 fl_BlockLayout* pBlockEnd = _findBlockAtPosition(posEnd);
6395
6396 while (pBlock && (pBlock != pBlockEnd))
6397 {
6398 const PP_AttrProp * pAP;
6399 bool bCheck = false;
6400
6401 pBlock = static_cast<fl_BlockLayout *>(pBlock->getNextBlockInDocument());
6402 if (!pBlock) // at EOD, so just bail
6403 break;
6404
6405 // did block format change?
6406 pBlock->getAP(pAP);
6407 if (pBlockAP != pAP)
6408 {
6409 pBlockAP = pAP;
6410 bCheck = true;
6411 }
6412
6413 if (bCheck)
6414 {
6415 i = v.getItemCount();
6416
6417 while (i > 0)
6418 {
6419 f = v.getNthItem(i-1);
6420
6421 const gchar * value = PP_evalProperty(f->m_prop,NULL,pBlockAP,pSectionAP,m_pDoc,bExpandStyles);
6422 UT_ASSERT(value);
6423
6424 // prune anything that doesn't match
6425 if (strcmp(f->m_val, value))
6426 {
6427 DELETEP(f);
6428 v.deleteNthItem(i-1);
6429 }
6430
6431 i--;
6432 }
6433
6434 // when vector is empty, stop looking
6435 if (0 == v.getItemCount())
6436 {
6437 pBlock = NULL;
6438 break;
6439 }
6440 }
6441 }
6442 }
6443
6444 // 3. export whatever's left
6445 UT_sint32 count = v.getItemCount()*2 + 1;
6446
6447 // NOTE: caller must g_free this, but not the referenced contents
6448 const gchar ** props = static_cast<const gchar **>(UT_calloc(count, sizeof(gchar *)));
6449 if (!props)
6450 return false;
6451
6452 const gchar ** p = props;
6453
6454 i = v.getItemCount();
6455 UT_sint32 numProps = count;
6456 while (i > 0)
6457 {
6458 f = v.getNthItem(i-1);
6459 i--;
6460
6461 p[0] = f->m_prop;
6462 p[1] = f->m_val;
6463 p += 2;
6464 }
6465 p[0] = NULL;
6466 UT_VECTOR_PURGEALL(_fmtPair *,v);
6467
6468 *pProps = props;
6469 m_BlockProps.fillProps(numProps,props);
6470
6471 return true;
6472 }
6473
delTo(FV_DocPos dp)6474 void FV_View::delTo(FV_DocPos dp)
6475 {
6476 PT_DocPosition iPos = _getDocPos(dp);
6477 PT_DocPosition iPoint = getPoint();
6478
6479 if (iPos == iPoint)
6480 {
6481 return;
6482 }
6483
6484 // Signal PieceTable Change
6485 _saveAndNotifyPieceTableChange();
6486
6487 _extSelToPos(iPos);
6488
6489 bool bCaretLeft = false;
6490 if(isMarkRevisions() && iPos < iPoint)
6491 {
6492 // move to the start of the original selection
6493 bCaretLeft = true;
6494 }
6495
6496 _deleteSelection(NULL, false, bCaretLeft);
6497
6498
6499 // Signal PieceTable Changes have finished
6500 _restorePieceTableState();
6501
6502 _generalUpdate();
6503 _fixInsertionPointCoords();
6504
6505 }
6506
getSelectionLength(void) const6507 UT_uint32 FV_View::getSelectionLength(void) const
6508 {
6509 return static_cast<UT_uint32>(labs(m_iInsPoint - m_Selection.getSelectionAnchor()));
6510 }
6511
6512 /*
6513 This function is somewhat of a compromise. It will return a new
6514 range of memory (destroy with g_free()) full of what's in the selection,
6515 but it will not cross block boundaries. This is for convenience
6516 in implementation, but could probably be accomplished without
6517 too much more effort. However, since an edit entry in a dialog
6518 box (1) only allows a bit of text and (2) has no concept of a
6519 block break anyway, I don't see a reason to make this behave
6520 differently.
6521
6522 The caller must g_free the returned pointer !!!
6523 */
getSelectionText(UT_UCS4Char * & pText) const6524 void FV_View::getSelectionText(UT_UCS4Char * & pText) const
6525 {
6526 UT_ASSERT(!isSelectionEmpty());
6527
6528 UT_GrowBuf buffer;
6529
6530 UT_sint32 selLength = getSelectionLength();
6531
6532 PT_DocPosition low;
6533 const fl_BlockLayout * block; // the current block the insertion point is in
6534 if (m_iInsPoint > m_Selection.getSelectionAnchor())
6535 {
6536 low = m_Selection.getSelectionAnchor();
6537 block = m_pLayout->findBlockAtPosition(low+1);
6538 }
6539 else
6540 {
6541 low = m_iInsPoint;
6542 block = m_pLayout->findBlockAtPosition(low);
6543 }
6544
6545 if (block)
6546 {
6547 block->getBlockBuf(&buffer);
6548
6549 UT_UCSChar * bufferSegment = NULL;
6550
6551 PT_DocPosition offset = 0;
6552 if( low >= block->getPosition(false) )
6553 {
6554 offset = low - block->getPosition(false);
6555 }
6556 if( buffer.getLength() <= 0)
6557 {
6558 pText = NULL;
6559 return;
6560 }
6561 // allow no more than the rest of the block
6562 if (offset + static_cast<UT_uint32>(selLength) > buffer.getLength())
6563 {
6564 selLength = static_cast<UT_sint32>(buffer.getLength()) - static_cast<UT_sint32>(offset);
6565 }
6566 // give us space for our new chunk of selected text, add 1 so it
6567 // terminates itself
6568 if(selLength < 0)
6569 {
6570 selLength = 0;
6571 }
6572 bufferSegment = static_cast<UT_UCSChar *>(UT_calloc(selLength + 1, sizeof(UT_UCSChar)));
6573
6574 if(!bufferSegment)
6575 {
6576 pText = NULL;
6577 return;
6578 }
6579
6580 // copy it out
6581 memmove(bufferSegment, buffer.getPointer(offset), selLength * sizeof(UT_UCSChar));
6582
6583 pText = bufferSegment;
6584 return;
6585 }
6586
6587 pText = NULL;
6588 }
6589
6590 /* this function has not been debugged
6591
6592 The caller must delete [] the returned pointer !!!
6593 */
getTextBetweenPos(PT_DocPosition pos1,PT_DocPosition pos2) const6594 UT_UCSChar * FV_View::getTextBetweenPos(PT_DocPosition pos1, PT_DocPosition pos2) const
6595 {
6596 UT_return_val_if_fail(pos2 > pos1, NULL);
6597
6598 UT_GrowBuf buffer;
6599
6600 UT_uint32 iLength = pos2 - pos1;
6601
6602 PT_DocPosition curPos = pos1;
6603
6604 // get the current block the insertion point is in
6605 const fl_BlockLayout * pBlock = m_pLayout->findBlockAtPosition(curPos);
6606
6607 UT_UCSChar * bufferRet = new UT_UCSChar[iLength+1];
6608
6609 UT_ASSERT(bufferRet);
6610 if(!bufferRet)
6611 return NULL;
6612
6613 UT_UCSChar * buff_ptr = bufferRet;
6614
6615 while(pBlock && curPos < pos2)
6616 {
6617 buffer.truncate(0);
6618 pBlock->getBlockBuf(&buffer);
6619
6620 if (curPos < pBlock->getPosition(FALSE)) {
6621 curPos = pBlock->getPosition(FALSE);
6622 }
6623 PT_DocPosition offset = curPos - pBlock->getPosition(false);
6624 UT_uint32 iLenToCopy = UT_MIN(pos2 - curPos, buffer.getLength() - offset);
6625 if(curPos < pos2 && (curPos < pBlock->getPosition(false) + pBlock->getLength()))
6626 {
6627 memmove(buff_ptr, buffer.getPointer(offset), iLenToCopy * sizeof(UT_UCSChar));
6628 offset += iLenToCopy;
6629 buff_ptr += iLenToCopy;
6630 curPos += iLenToCopy;
6631 if (curPos < pos2)
6632 {
6633 *buff_ptr++ = '\n';
6634 curPos++;
6635 }
6636 }
6637
6638 pBlock = static_cast<fl_BlockLayout *>(pBlock->getNextBlockInDocument());
6639 }
6640
6641 UT_ASSERT(curPos == pos2);
6642 *buff_ptr = 0;
6643 return bufferRet;
6644 }
6645
isTabListBehindPoint(UT_sint32 & iNumToDelete) const6646 bool FV_View::isTabListBehindPoint(UT_sint32 & iNumToDelete) const
6647 {
6648 PT_DocPosition cpos = getPoint();
6649 PT_DocPosition ppos = cpos - 1;
6650 PT_DocPosition posBOD;
6651 bool bEOL = false;
6652 UT_uint32 iPointHeight;
6653 UT_sint32 xPoint, yPoint, xPoint2, yPoint2;
6654 bool bDirection;
6655 iNumToDelete = 0;
6656 UT_DebugOnly<bool> bRes;
6657 bRes = getEditableBounds(false, posBOD);
6658 UT_ASSERT(bRes);
6659 if (cpos <= posBOD - 1)
6660 {
6661 return false;
6662 }
6663
6664 fl_BlockLayout* pBlock;
6665 fp_Run * pRun;
6666 _findPositionCoords(cpos, bEOL, xPoint, yPoint, xPoint2, yPoint2, iPointHeight, bDirection, &pBlock, &pRun);
6667
6668 if (!pBlock)
6669 return false;
6670 if(pBlock->isListItem() == false)
6671 return false;
6672
6673 fl_BlockLayout* ppBlock;
6674 _findPositionCoords(ppos, bEOL, xPoint, yPoint, xPoint2, yPoint2, iPointHeight, bDirection, &ppBlock, &pRun);
6675
6676 if (!ppBlock || pBlock != ppBlock)
6677 {
6678 return false;
6679 }
6680 while(pRun && pRun->getLength() == 0)
6681 {
6682 pRun = pRun->getPrevRun();
6683 }
6684 if(pRun == NULL)
6685 {
6686 return false;
6687 }
6688 if(pRun->getType() == FPRUN_FIELD)
6689 {
6690 const fp_FieldRun * pFRun = static_cast<const fp_FieldRun *>(pRun);
6691 if (pFRun->getFieldType() != FPFIELD_list_label)
6692 {
6693 return false;
6694 }
6695 iNumToDelete = 1;
6696 return true;
6697 }
6698 if(pRun->getType() != FPRUN_TAB)
6699 {
6700 return false;
6701 }
6702 pRun = pRun->getPrevRun();
6703 while((pRun != NULL) && (pRun->getType()== FPRUN_FMTMARK))
6704 {
6705 pRun = pRun->getPrevRun();
6706 }
6707 if (!pRun || pRun->getType() != FPRUN_FIELD)
6708 {
6709 return false;
6710 }
6711 else
6712 {
6713 const fp_FieldRun * pFRun = static_cast<const fp_FieldRun *>(pRun);
6714 if (pFRun->getFieldType() != FPFIELD_list_label)
6715 {
6716 return false;
6717 }
6718 iNumToDelete = 2;
6719 return true;
6720 }
6721 }
6722
6723
isTabListAheadPoint(void) const6724 bool FV_View::isTabListAheadPoint(void) const
6725 {
6726 //
6727 // Return TRUE if the point is immediately ahead of a list label - TAB combination
6728 //
6729
6730 PT_DocPosition cpos = getPoint();
6731
6732 bool bEOL = false;
6733 UT_uint32 iPointHeight;
6734 UT_sint32 xPoint, yPoint, xPoint2, yPoint2;
6735 bool bDirection;
6736
6737 fl_BlockLayout* pBlock;
6738 fp_Run* pRun;
6739 _findPositionCoords(cpos, bEOL, xPoint, yPoint, xPoint2, yPoint2, iPointHeight, bDirection, &pBlock, &pRun);
6740
6741 if (!pBlock)
6742 {
6743 return false;
6744 }
6745
6746 // Find first run that is not an FPRUN_FMTMARK
6747 while (pRun && (pRun->getType() == FPRUN_FMTMARK))
6748 {
6749 pRun = pRun->getNextRun();
6750 }
6751
6752 if (!pRun || pRun->getType() != FPRUN_FIELD)
6753 {
6754 return false;
6755 }
6756
6757 const fp_FieldRun * pFRun = static_cast<const fp_FieldRun *>(pRun);
6758 if(pFRun->getFieldType() != FPFIELD_list_label)
6759 {
6760 return false;
6761 }
6762
6763 pRun = pRun->getNextRun();
6764 while (pRun && (pRun->getType()== FPRUN_FMTMARK))
6765 {
6766 pRun = pRun->getNextRun();
6767 }
6768 if (!pRun || pRun->getType() != FPRUN_TAB)
6769 {
6770 return false;
6771 }
6772
6773 return true;
6774 }
6775
6776
6777 /*!
6778 Move point by one screen
6779 \param bNext True if moving to next screen
6780 */
warpInsPtNextPrevScreen(bool bNext)6781 void FV_View::warpInsPtNextPrevScreen(bool bNext)
6782 {
6783 if (!isSelectionEmpty())
6784 {
6785 _moveToSelectionEnd(bNext);
6786 return;
6787 }
6788
6789 _resetSelection();
6790 _clearIfAtFmtMark(getPoint());
6791 _moveInsPtNextPrevScreen(bNext,true);
6792
6793 notifyListeners(AV_CHG_MOTION | AV_CHG_ALL);
6794 }
6795
6796 /*!
6797 Move point to next or previous page
6798 \param bNext True if moving to next page
6799
6800 \note Cursor movement while there's a selection has the effect of
6801 clearing the selection. And only that. See bug 993.
6802 */
warpInsPtNextPrevPage(bool bNext)6803 void FV_View::warpInsPtNextPrevPage(bool bNext)
6804 {
6805 if (!isSelectionEmpty())
6806 {
6807 _moveToSelectionEnd(bNext);
6808 return;
6809 }
6810
6811 _resetSelection();
6812 _clearIfAtFmtMark(getPoint());
6813 _moveInsPtNextPrevPage(bNext);
6814
6815 notifyListeners(AV_CHG_MOTION | AV_CHG_ALL);
6816 }
6817
6818 /*!
6819 Move point to next or previous line
6820 \param bNext True if moving to next line
6821
6822 \note Cursor movement while there's a selection has the effect of
6823 clearing the selection. And only that. See bug 993.
6824 */
warpInsPtNextPrevLine(bool bNext)6825 void FV_View::warpInsPtNextPrevLine(bool bNext)
6826 {
6827 if (!isSelectionEmpty())
6828 {
6829 _moveToSelectionEnd(bNext);
6830 return;
6831 }
6832
6833 _resetSelection();
6834 _clearIfAtFmtMark(getPoint());
6835 fp_Page * pPage = getCurrentPage();
6836 _moveInsPtNextPrevLine(bNext);
6837 if(getCurrentPage() != pPage)
6838 {
6839 notifyListeners(AV_CHG_MOTION | AV_CHG_ALL);
6840 }
6841 else
6842 {
6843 notifyListeners(AV_CHG_MOTION);
6844 }
6845 }
6846
extSelNextPrevLine(bool bNext)6847 void FV_View::extSelNextPrevLine(bool bNext)
6848 {
6849 if (isSelectionEmpty())
6850 {
6851 _setSelectionAnchor();
6852 _clearIfAtFmtMark(getPoint());
6853 _moveInsPtNextPrevLine(bNext);
6854 if (isSelectionEmpty())
6855 {
6856 _fixInsertionPointCoords();
6857 }
6858 else
6859 {
6860 _drawSelection();
6861 }
6862 }
6863 else
6864 {
6865 PT_DocPosition iOldPoint = getPoint();
6866 _moveInsPtNextPrevLine(bNext);
6867 PT_DocPosition iNewPoint = getPoint();
6868
6869 // top/bottom of doc - nowhere to go
6870 if (iOldPoint == iNewPoint)
6871 return;
6872
6873 _extSel(iOldPoint);
6874
6875 if (isSelectionEmpty())
6876 {
6877 _resetSelection();
6878 }
6879 }
6880
6881 notifyListeners(AV_CHG_MOTION);
6882 }
6883
6884 // TODO preferably we should implement a new function for the simple
6885 // page Up/Down that actually moves the insertion point (currently
6886 // the PgUp and PgDown keys are bound to scrolling the window, but
6887 // they do not move the insertion point, which is a real nuisance)
6888 // once we fix that, we can use it in the function bellow to get
6889 // a consistent behaviour
6890 //
6891 // the number 100 is heuristic, it is to get the end of the selection
6892 // on screen, but it does not work well with large gaps in the text
6893 // and on page boundaries
6894 #define TOP_OF_PAGE_OFFSET 100
6895
extSelNextPrevScreen(bool bNext)6896 void FV_View::extSelNextPrevScreen(bool bNext)
6897 {
6898 if (isSelectionEmpty())
6899 {
6900 _setSelectionAnchor();
6901 _clearIfAtFmtMark(getPoint());
6902 _moveInsPtNextPrevScreen(bNext,false);
6903
6904 if (isSelectionEmpty())
6905 {
6906 _fixInsertionPointCoords();
6907 }
6908 else
6909 {
6910 _drawSelection();
6911 }
6912 }
6913 else
6914 {
6915 PT_DocPosition iOldPoint = getPoint();
6916 _moveInsPtNextPrevScreen(bNext,false);
6917
6918 // top/bottom of doc - nowhere to go
6919 if (iOldPoint == getPoint())
6920 return;
6921
6922 _extSel(iOldPoint);
6923
6924 if (isSelectionEmpty())
6925 {
6926 _resetSelection();
6927 }
6928 }
6929
6930 notifyListeners(AV_CHG_MOTION| AV_CHG_ALL);
6931 }
6932
extSelNextPrevPage(bool bNext)6933 void FV_View::extSelNextPrevPage(bool bNext)
6934 {
6935 if (isSelectionEmpty())
6936 {
6937 _setSelectionAnchor();
6938 _clearIfAtFmtMark(getPoint());
6939 _moveInsPtNextPrevPage(bNext);
6940
6941 if (isSelectionEmpty())
6942 {
6943 _fixInsertionPointCoords();
6944 }
6945 else
6946 {
6947 _drawSelection();
6948 }
6949 }
6950 else
6951 {
6952 PT_DocPosition iOldPoint = getPoint();
6953 _moveInsPtNextPrevPage(bNext);
6954
6955 // top/bottom of doc - nowhere to go
6956 if (iOldPoint == getPoint())
6957 return;
6958
6959 _extSel(iOldPoint);
6960
6961 if (isSelectionEmpty())
6962 {
6963 _resetSelection();
6964 }
6965 }
6966
6967 notifyListeners(AV_CHG_MOTION | AV_CHG_ALL);
6968 }
6969
extSelHorizontal(bool bForward,UT_uint32 count)6970 void FV_View::extSelHorizontal(bool bForward, UT_uint32 count)
6971 {
6972 if (isSelectionEmpty())
6973 {
6974 _setSelectionAnchor();
6975 _charMotion(bForward, count);
6976 }
6977 else
6978 {
6979 PT_DocPosition iOldPoint = getPoint();
6980
6981 if (_charMotion(bForward, count) == false)
6982 {
6983 _setPoint(iOldPoint);
6984 return;
6985 }
6986
6987 _extSel(iOldPoint);
6988 }
6989
6990 _ensureInsertionPointOnScreen();
6991
6992 // It IS possible for the selection to be empty, even
6993 // after extending it. If the charMotion fails, for example,
6994 // because we are at the end of a document, then the selection
6995 // will end up empty once again.
6996
6997 if (isSelectionEmpty())
6998 {
6999 _resetSelection();
7000 }
7001 else
7002 {
7003 _drawSelection();
7004 }
7005
7006 notifyListeners(AV_CHG_MOTION);
7007 }
7008
endDragSelection(UT_sint32 xpos,UT_sint32 ypos)7009 void FV_View::endDragSelection(UT_sint32 xpos, UT_sint32 ypos)
7010 {
7011 //
7012 // Signal PieceTable Change
7013 _saveAndNotifyPieceTableChange();
7014
7015 // Turn off list updates
7016
7017 m_pDoc->disableListUpdates();
7018
7019 // turn off immediate layout of table
7020
7021 m_pDoc->setDontImmediatelyLayout(true);
7022
7023
7024 m_pDoc->beginUserAtomicGlob();
7025
7026 PT_DocPosition pos = getDocPositionFromXY(xpos, ypos);
7027
7028 cmdCut();
7029 moveInsPtTo(pos);
7030 cmdPaste();
7031
7032 // Allow updates
7033
7034 m_pDoc->setDontImmediatelyLayout(false);
7035
7036
7037 // Signal PieceTable Changes have finished
7038 _restorePieceTableState();
7039 _generalUpdate();
7040
7041 // restore updates and clean up dirty lists
7042 m_pDoc->enableListUpdates();
7043 m_pDoc->updateDirtyLists();
7044
7045 m_pDoc->endUserAtomicGlob();
7046 }
7047
extSelTo(FV_DocPos dp)7048 void FV_View::extSelTo(FV_DocPos dp)
7049 {
7050 PT_DocPosition iPos = _getDocPos(dp);
7051
7052 _extSelToPos(iPos);
7053
7054 if (!_ensureInsertionPointOnScreen())
7055 {
7056 if (isSelectionEmpty())
7057 {
7058 _fixInsertionPointCoords();
7059 }
7060 }
7061
7062 notifyListeners(AV_CHG_MOTION);
7063 }
7064
7065
7066 /*!
7067 * This method returns the document position at xpos,ypos on the screen.
7068 */
getDocPositionFromXY(UT_sint32 xpos,UT_sint32 ypos,bool bNotFrames)7069 PT_DocPosition FV_View::getDocPositionFromXY(UT_sint32 xpos, UT_sint32 ypos, bool bNotFrames)
7070 {
7071 // Figure out which page we clicked on.
7072 // Pass the click down to that page.
7073 UT_sint32 xClick, yClick;
7074 fp_Page* pPage = _getPageForXY(xpos, ypos, xClick, yClick);
7075
7076 PT_DocPosition iNewPoint;
7077 bool bBOL = false;
7078 bool bEOL = false;
7079 bool isTOC = false;
7080 bool bUseHdrFtr = true;
7081 if(bNotFrames)
7082 {
7083 bUseHdrFtr = false;
7084 }
7085 pPage->mapXYToPosition(bNotFrames,xClick, yClick, iNewPoint, bBOL, bEOL,isTOC, bUseHdrFtr,NULL);
7086 xxx_UT_DEBUGMSG((" point at (%d,%d) is docpos %d \n",xpos,ypos,iNewPoint));
7087 return iNewPoint;
7088 }
7089
setVisualSelectionEnabled(bool bActive)7090 void FV_View::setVisualSelectionEnabled(bool bActive)
7091 {
7092 if (!bActive)
7093 m_SelectionHandles.hide();
7094 m_VisualSelectionActive=bActive;
7095 }
7096
extSelToXY(UT_sint32 xPos,UT_sint32 yPos,bool bDrag)7097 void FV_View::extSelToXY(UT_sint32 xPos, UT_sint32 yPos, bool bDrag)
7098 {
7099 // Figure out which page we clicked on.
7100 // Pass the click down to that page.
7101 UT_sint32 xClick, yClick;
7102 fp_Page* pPage = _getPageForXY(xPos, yPos, xClick, yClick);
7103 xxx_UT_DEBUGMSG((" Selected to x %d \n",xPos));
7104
7105 PT_DocPosition iNewPoint;
7106 bool bBOL = false;
7107 bool bEOL = false;
7108 bool isTOC = false;
7109 pPage->mapXYToPosition(xClick, yClick, iNewPoint, bBOL, bEOL,isTOC, true);
7110
7111 bool bPostpone = false;
7112
7113 if (bDrag)
7114 {
7115 // figure out whether we're still on screen
7116 bool bOnScreen = true;
7117
7118 if ((xPos < 0 || xPos > getWindowWidth()) ||
7119 (yPos < 0 || yPos > getWindowHeight()))
7120 bOnScreen = false;
7121 // is autoscroll timer set properly?
7122 if (bOnScreen)
7123 {
7124 if (m_pAutoScrollTimer)
7125 {
7126 // timer not needed any more, so stop it
7127 m_pAutoScrollTimer->stop();
7128 }
7129 }
7130 else
7131 {
7132 // remember where mouse is
7133 m_xLastMouse = xPos;
7134 m_yLastMouse = yPos;
7135 // offscreen ==> make sure it's set
7136 if (!m_pAutoScrollTimer)
7137 {
7138 m_pAutoScrollTimer = UT_Timer::static_constructor(_autoScroll, this);
7139 if (m_pAutoScrollTimer)
7140 {
7141 m_pAutoScrollTimer->set(AUTO_SCROLL_MSECS);
7142 }
7143 }
7144 else
7145 {
7146 m_pAutoScrollTimer->start();
7147 }
7148
7149 // postpone selection until timer fires
7150 bPostpone = true;
7151 }
7152 }
7153 if (!bPostpone)
7154 {
7155 _extSelToPos(iNewPoint);
7156 notifyListeners(AV_CHG_MOTION);
7157 _updateSelectionHandles();
7158 }
7159 }
7160
extSelToXYword(UT_sint32 xPos,UT_sint32 yPos,bool bDrag)7161 void FV_View::extSelToXYword(UT_sint32 xPos, UT_sint32 yPos, bool bDrag)
7162 {
7163 // extend the current selection to
7164 // include the WORD at the given XY.
7165 // this should behave just like extSelToXY()
7166 // but with WORD-level granularity.
7167
7168 // Figure out which page we clicked on.
7169 // Pass the click down to that page.
7170 UT_sint32 xClick, yClick;
7171 fp_Page* pPage = _getPageForXY(xPos, yPos, xClick, yClick);
7172
7173 PT_DocPosition iNewPoint;
7174 bool bBOL, bEOL;
7175
7176 bBOL = bEOL = false;
7177 bool isTOC = false;
7178 pPage->mapXYToPosition(xClick, yClick, iNewPoint, bBOL, bEOL, isTOC,true);
7179
7180 //UT_ASSERT(!isSelectionEmpty());
7181
7182 xxx_UT_DEBUGMSG(("left anchor %d right %d \n",m_Selection.getSelectionLeftAnchor(),m_Selection.getSelectionRightAnchor()));
7183
7184 PT_DocPosition iNewPointWord = 0;
7185 PT_DocPosition iTmpPointWord = 0;
7186 /*
7187 Here is the Logic.
7188 If No selection present:
7189
7190 If iNewPoint > getSelectionAnchor()
7191 then:
7192 1. Make sure selection anchor is at nearest Beginning of Word (BOW)
7193 2. Make iNewPoint go to nearest End of Word (EOW)
7194 else
7195 1. Make selection anchor go to nearest End of Word (EOW)
7196 2. Make iNewPoint go to nearest BOW
7197 endif
7198
7199 else selection is present:
7200
7201 if oldpoint >= anchor and iNewPoint >= anchor then
7202 iNewPoint goes to nearest BOW
7203 else if oldpoint > anchor and (iNewPoint < anchor) then
7204
7205 clear selection
7206 iNewPoint goes to nearest BOW before anchor
7207 anchor goes to nearest EOW to iNewPoint
7208
7209 else if oldpoint < anchor and iNewPoint < anchor then
7210
7211 iNewPoint goes to nears BOW
7212
7213 else if oldpoint < anchor and iNewPoint >= anchor then
7214
7215 clear selection
7216 anchor goes to nearest BOW > iNewPoint
7217 iNewPoint goes to nearest EOW > anchor
7218
7219 endif
7220 */
7221 if(isSelectionEmpty())
7222 {
7223 if(iNewPoint > getPoint())
7224 {
7225 iNewPointWord = getPoint();
7226 if(!m_pDoc->isBlockAtPos(iNewPointWord) &&
7227 !m_pDoc->isTableAtPos(iNewPointWord) &&
7228 !m_pDoc->isCellAtPos(iNewPointWord) &&
7229 !m_pDoc->isEndTableAtPos(iNewPointWord))
7230 {
7231 iNewPointWord = _getDocPosFromPoint(getPoint(), FV_DOCPOS_BOW, false);
7232 }
7233 m_Selection.setSelectionAnchor(iNewPointWord);
7234 iNewPointWord = iNewPoint;
7235 if(!m_pDoc->isBlockAtPos(iNewPointWord) &&
7236 !m_pDoc->isTableAtPos(iNewPointWord) &&
7237 !m_pDoc->isCellAtPos(iNewPointWord) &&
7238 !m_pDoc->isEndTableAtPos(iNewPointWord))
7239 {
7240
7241 iNewPointWord = _getDocPosFromPoint(iNewPoint, FV_DOCPOS_EOW_SELECT, false);
7242 }
7243 }
7244 else
7245 {
7246 iNewPointWord = getPoint();
7247 if(!m_pDoc->isBlockAtPos(iNewPointWord) &&
7248 !m_pDoc->isTableAtPos(iNewPointWord) &&
7249 !m_pDoc->isCellAtPos(iNewPointWord) &&
7250 !m_pDoc->isEndTableAtPos(iNewPointWord))
7251 {
7252 iNewPointWord = _getDocPosFromPoint(getPoint(), FV_DOCPOS_EOW_SELECT, false);
7253 }
7254
7255 m_Selection.setSelectionAnchor(iNewPointWord);
7256 iNewPointWord = iNewPoint;
7257 if(!m_pDoc->isBlockAtPos(iNewPointWord) &&
7258 !m_pDoc->isTableAtPos(iNewPointWord) &&
7259 !m_pDoc->isCellAtPos(iNewPointWord) &&
7260 !m_pDoc->isEndTableAtPos(iNewPointWord))
7261 {
7262 iNewPointWord = _getDocPosFromPoint(iNewPoint, FV_DOCPOS_BOW, false);
7263 }
7264 }
7265 }
7266 else
7267 {
7268 if((getPoint() > m_Selection.getSelectionAnchor()) && (iNewPoint >= m_Selection.getSelectionAnchor()))
7269 {
7270 iNewPointWord = iNewPoint;
7271 if(!m_pDoc->isBlockAtPos(iNewPointWord) &&
7272 !m_pDoc->isTableAtPos(iNewPointWord) &&
7273 !m_pDoc->isCellAtPos(iNewPointWord) &&
7274 !m_pDoc->isEndTableAtPos(iNewPointWord))
7275 {
7276 iNewPointWord = _getDocPosFromPoint(iNewPoint, FV_DOCPOS_EOW_SELECT, false);
7277 }
7278 iTmpPointWord = getSelectionAnchor();
7279 if(!m_pDoc->isBlockAtPos(iTmpPointWord) &&
7280 !m_pDoc->isTableAtPos(iTmpPointWord) &&
7281 !m_pDoc->isCellAtPos(iTmpPointWord) &&
7282 !m_pDoc->isEndTableAtPos(iTmpPointWord))
7283 {
7284 iTmpPointWord = _getDocPosFromPoint(iTmpPointWord, FV_DOCPOS_BOW, false);
7285 }
7286 if(iTmpPointWord != getSelectionAnchor())
7287 {
7288 _clearSelection();
7289 m_Selection.setSelectionAnchor(iTmpPointWord);
7290 }
7291 }
7292 else if ((getPoint() > m_Selection.getSelectionAnchor()) && (iNewPoint < m_Selection.getSelectionAnchor()))
7293 {
7294 iNewPointWord = _getDocPosFromPoint(m_Selection.getSelectionAnchor(), FV_DOCPOS_BOW, false);
7295 _clearSelection();
7296 iNewPointWord = _getDocPosFromPoint(iNewPointWord, FV_DOCPOS_EOW_SELECT, false);
7297 m_Selection.setSelectionAnchor(iNewPointWord);
7298 iNewPointWord = _getDocPosFromPoint(iNewPointWord, FV_DOCPOS_BOW, false);
7299 }
7300 else if ((getPoint() <= m_Selection.getSelectionAnchor()) && (iNewPoint < m_Selection.getSelectionAnchor()))
7301 {
7302 iNewPointWord = iNewPoint;
7303 if(!m_pDoc->isBlockAtPos(iNewPointWord) &&
7304 !m_pDoc->isTableAtPos(iNewPointWord) &&
7305 !m_pDoc->isCellAtPos(iNewPointWord) &&
7306 !m_pDoc->isEndTableAtPos(iNewPointWord))
7307 {
7308 iNewPointWord = _getDocPosFromPoint(iNewPoint, FV_DOCPOS_BOW, false);
7309 }
7310 iTmpPointWord = getSelectionAnchor();
7311 if(!m_pDoc->isBlockAtPos(iTmpPointWord) &&
7312 !m_pDoc->isTableAtPos(iTmpPointWord) &&
7313 !m_pDoc->isCellAtPos(iTmpPointWord) &&
7314 !m_pDoc->isEndTableAtPos(iTmpPointWord))
7315 {
7316 iTmpPointWord = _getDocPosFromPoint(iTmpPointWord, FV_DOCPOS_EOW_SELECT, false);
7317 }
7318 if(iTmpPointWord != getSelectionAnchor())
7319 {
7320 _clearSelection();
7321 m_Selection.setSelectionAnchor(iTmpPointWord);
7322 }
7323 }
7324 else
7325 {
7326 iNewPointWord = iNewPoint;
7327 if(!m_pDoc->isBlockAtPos(iNewPointWord) &&
7328 !m_pDoc->isTableAtPos(iNewPointWord) &&
7329 !m_pDoc->isCellAtPos(iNewPointWord) &&
7330 !m_pDoc->isEndTableAtPos(iNewPointWord))
7331 {
7332 iNewPointWord = _getDocPosFromPoint(iNewPoint, FV_DOCPOS_BOW, false);
7333 }
7334 _clearSelection();
7335 m_Selection.setSelectionAnchor(iNewPointWord);
7336 iNewPointWord = _getDocPosFromPoint(iNewPointWord, FV_DOCPOS_EOW_SELECT, false);
7337 }
7338 }
7339
7340 bool bPostpone = false;
7341
7342 if (bDrag)
7343 {
7344 // figure out whether we're still on screen
7345 bool bOnScreen = true;
7346
7347 if ((xPos < 0 || xPos > getWindowWidth()) ||
7348 (yPos < 0 || yPos > getWindowHeight()))
7349 bOnScreen = false;
7350
7351 // is autoscroll timer set properly?
7352 if (bOnScreen)
7353 {
7354 if (m_pAutoScrollTimer)
7355 {
7356 // timer not needed any more, so stop it
7357 m_pAutoScrollTimer->stop();
7358 }
7359 }
7360 else
7361 {
7362 // remember where mouse is
7363 m_xLastMouse = xPos;
7364 m_yLastMouse = yPos;
7365
7366 // offscreen ==> make sure it's set
7367 if (!m_pAutoScrollTimer)
7368 {
7369 m_pAutoScrollTimer = UT_Timer::static_constructor(_autoScroll, this);
7370 if (m_pAutoScrollTimer)
7371 {
7372 m_pAutoScrollTimer->set(AUTO_SCROLL_MSECS);
7373 }
7374 }
7375 else
7376 {
7377 m_pAutoScrollTimer->start();
7378 }
7379
7380 // postpone selection until timer fires
7381 bPostpone = true;
7382 }
7383 }
7384 xxx_UT_DEBUGMSG(("anchor %d extend to point %d \n",getSelectionAnchor(), iNewPointWord));
7385 if (!bPostpone)
7386 {
7387 _extSelToPos(iNewPointWord);
7388 notifyListeners(AV_CHG_MOTION);
7389 }
7390 if(getPoint() > getSelectionAnchor())
7391 {
7392 m_Selection.setSelectionLeftAnchor(getSelectionAnchor());
7393 m_Selection.setSelectionRightAnchor(getPoint());
7394 }
7395 else
7396 {
7397 m_Selection.setSelectionRightAnchor(m_Selection.getSelectionAnchor());
7398 m_Selection.setSelectionLeftAnchor(getPoint());
7399 }
7400 xxx_UT_DEBUGMSG(("final selection anchor %d extend to point %d \n",getSelectionAnchor(), iNewPointWord));
7401 }
7402
endDrag(UT_sint32 xPos,UT_sint32 yPos)7403 void FV_View::endDrag(UT_sint32 xPos, UT_sint32 yPos)
7404 {
7405 if (!m_pAutoScrollTimer)
7406 return;
7407
7408 // figure out whether we're still on screen
7409 bool bOnScreen = true;
7410
7411 if ((xPos < 0 || xPos > getWindowWidth()) ||
7412 (yPos < 0 || yPos > getWindowHeight()))
7413 bOnScreen = false;
7414
7415 if (!bOnScreen)
7416 {
7417 // remember where mouse is
7418 m_xLastMouse = xPos;
7419 m_yLastMouse = yPos;
7420
7421 // finish pending autoscroll
7422 m_pAutoScrollTimer->fire();
7423 }
7424
7425 // timer not needed any more, so stop it
7426 m_pAutoScrollTimer->stop();
7427 }
7428
7429 // ---------------- start goto ---------------
gotoTarget(AP_JumpTarget type,const UT_UCSChar * data)7430 bool FV_View::gotoTarget(AP_JumpTarget type, const UT_UCSChar *data)
7431 {
7432 char * numberString = static_cast<char *>(UT_calloc(UT_UCS4_strlen(data)*6 + 1, sizeof(char)));
7433 UT_return_val_if_fail(numberString, false);
7434 UT_UCS4String s(data,0);
7435 strcpy(numberString,s.utf8_str());
7436
7437 bool result = gotoTarget(type, numberString);
7438 FREEP(numberString);
7439 return result;
7440 }
7441
7442
gotoTarget(AP_JumpTarget type,const char * numberString)7443 bool FV_View::gotoTarget(AP_JumpTarget type, const char *numberString)
7444 {
7445 UT_ASSERT(m_pLayout);
7446 bool inc = false;
7447 bool dec = false;
7448
7449 if (!isSelectionEmpty())
7450 {
7451 _clearSelection();
7452 }
7453
7454 switch (numberString[0])
7455 {
7456 case '+':
7457 inc = true;
7458 numberString++;
7459 break;
7460 case '-':
7461 dec = true;
7462 numberString++;
7463 break;
7464 }
7465
7466 UT_uint32 number = 0;
7467 if(type != AP_JUMPTARGET_BOOKMARK && type != AP_JUMPTARGET_XMLID)
7468 number = atol(numberString);
7469
7470 if (dec || inc)
7471 numberString--;
7472
7473 // check for range
7474 // if (number < 0 || number > static_cast<UT_uint32>(m_pLayout->countPages()))
7475 // return false;
7476
7477 switch (type)
7478 {
7479 case AP_JUMPTARGET_PAGE:
7480 {
7481 if (!inc && !dec)
7482 _moveInsPtNthPage (number);
7483 else
7484 {
7485 fp_Page* pOldPage = _getCurrentPage();
7486 fp_Page* pPage = pOldPage;
7487 fp_Page* pTmpPage = pOldPage;
7488
7489 if (inc) // TODO: What if number passes the number of pages?
7490 for (UT_uint32 i = 0; i < number; i++)
7491 {
7492 if ((pTmpPage = pPage->getNext ()) != NULL)
7493 pPage = pTmpPage;
7494 else
7495 break;
7496 }
7497 else
7498 for (UT_uint32 i = 0; i < number; i++)
7499 {
7500 if ((pTmpPage = pPage->getPrev ()) != NULL)
7501 pPage = pTmpPage;
7502 else
7503 break;
7504 }
7505
7506 if (!pPage)
7507 pPage = pOldPage;
7508
7509 _moveInsPtToPage (pPage);
7510 }
7511
7512 notifyListeners(AV_CHG_MOTION | AV_CHG_HDRFTR);
7513
7514 break;
7515 }
7516 case AP_JUMPTARGET_LINE:
7517 if (inc || dec)
7518 {
7519 bool bNext;
7520 bNext = inc;
7521
7522 for (UT_uint32 i = 0; i < number; i++)
7523 {
7524 _moveInsPtNextPrevLine (bNext); // HACK: A like the quick hacks... :)
7525 }
7526 }
7527 else
7528 {
7529 //UT_uint32 line = 0;
7530 fl_SectionLayout * pSL = m_pLayout->getFirstSection();
7531 fl_BlockLayout * pBL = pSL->getNextBlockInDocument();
7532 if(pBL == NULL)
7533 {
7534 return false;
7535 }
7536 fp_Line* pLine = static_cast<fp_Line *>(pBL->getFirstContainer());
7537 fp_Line * pOldLine = pLine;
7538 for (UT_uint32 i = 1; i < number; i++)
7539 {
7540 if(pLine == NULL)
7541 {
7542 pLine = pOldLine;
7543 break;
7544 }
7545 pOldLine = pLine;
7546 pLine = static_cast<fp_Line *>(pLine->getNext ());
7547 if (pLine == NULL)
7548 {
7549 pBL = pBL->getNextBlockInDocument();
7550 if (pBL == NULL)
7551 {
7552 return false;
7553 }
7554 else
7555 {
7556 pLine = static_cast<fp_Line *>(pBL->getFirstContainer());
7557 }
7558 }
7559 }
7560 if(pLine == NULL)
7561 {
7562 return false;
7563 }
7564 fp_Run* frun = pLine->getFirstRun ();
7565 fl_BlockLayout* fblock = pLine->getBlock ();
7566 PT_DocPosition dp = frun->getBlockOffset () + fblock->getPosition ();
7567 moveInsPtTo (dp);
7568 }
7569
7570 notifyListeners(AV_CHG_MOTION | AV_CHG_HDRFTR);
7571
7572 break;
7573 /* case AP_JUMPTARGET_PICTURE:
7574 // TODO
7575 break; */
7576 case AP_JUMPTARGET_XMLID:
7577 {
7578 std::string xmlid = numberString;
7579 PD_Document* doc = getDocument();
7580 if( PD_DocumentRDFHandle rdf = doc->getDocumentRDF() )
7581 {
7582 std::pair< PT_DocPosition, PT_DocPosition > range = rdf->getIDRange( xmlid );
7583 UT_DEBUGMSG(("jump xmlid:%s gives range:%d to %d\n",
7584 xmlid.c_str(), range.first, range.second ));
7585 moveInsPtTo(range.second);
7586 selectRange( range.first, range.second );
7587 }
7588 break;
7589 }
7590 case AP_JUMPTARGET_ANNOTATION:
7591 {
7592 UT_uint32 iAnnotation = number;
7593 fl_AnnotationLayout* l = getAnnotationLayout( iAnnotation );
7594 selectAnnotation( l );
7595 break;
7596 }
7597 case AP_JUMPTARGET_BOOKMARK:
7598 {
7599 fl_SectionLayout * pSL = m_pLayout->getFirstSection();
7600 fl_BlockLayout * pBL;
7601 fp_Run* pRun;
7602 fp_BookmarkRun * pB[2] = {NULL,NULL};
7603
7604 UT_uint32 i = 0;
7605 bool bFound = false;
7606
7607 UT_DEBUGMSG(("fv_View::gotoTarget: bookmark [%s]\n",numberString));
7608 if(UT_go_path_is_uri(numberString))
7609 {
7610 XAP_App::getApp()->openURL(numberString);
7611 return false;
7612 }
7613 if(m_pDoc->isBookmarkUnique(static_cast<const gchar *>(numberString)))
7614 goto book_mark_not_found; //bookmark does not exist
7615
7616 // TODO: Make this work inside tables
7617 while(pSL)
7618 {
7619 pBL = pSL->getNextBlockInDocument();
7620
7621 while(pBL)
7622 {
7623 pRun = pBL->getFirstRun();
7624
7625 while(pRun)
7626 {
7627 if(pRun->getType()== FPRUN_BOOKMARK)
7628 {
7629 fp_BookmarkRun * pBR = static_cast<fp_BookmarkRun*>(pRun);
7630 if(!strcmp(pBR->getName(),numberString))
7631 {
7632 pB[i] = pBR;
7633 i++;
7634 if(i>1)
7635 {
7636 bFound = true;
7637 break;
7638 }
7639 }
7640 }
7641 if(bFound)
7642 break;
7643 pRun = pRun->getNextRun();
7644 }
7645 if(bFound)
7646 break;
7647 pBL = static_cast<fl_BlockLayout *>(pBL->getNext());
7648 }
7649 if(bFound)
7650 break;
7651 pSL = static_cast<fl_SectionLayout *>(pSL->getNext());
7652 }
7653
7654 if(pB[0] && pB[1])
7655 {
7656 _clearSelection();
7657 PT_DocPosition dp1 = pB[0]->getBookmarkedDocPosition(true);
7658 PT_DocPosition dp2 = pB[1]->getBookmarkedDocPosition(false);
7659
7660 if(dp2 - dp1 == 1)
7661 moveInsPtTo (dp2);
7662 else
7663 {
7664 moveInsPtTo(dp1);
7665 selectRange( dp2, dp1 );
7666
7667 //make a selection
7668 // _setPoint(dp2);
7669 // _setSelectionAnchor();
7670 // setPoint(dp1);
7671 // _drawSelection();
7672 }
7673
7674 }
7675 else
7676
7677 book_mark_not_found:
7678 {
7679 //bookmark not found
7680 XAP_Frame * pFrame = static_cast<XAP_Frame *>(getParentData());
7681 UT_return_val_if_fail(pFrame, false);
7682
7683 pFrame->showMessageBox(AP_STRING_ID_MSG_BookmarkNotFound,
7684 XAP_Dialog_MessageBox::b_O,
7685 XAP_Dialog_MessageBox::a_OK,
7686 numberString);
7687
7688 return true;
7689 }
7690
7691 }
7692
7693 notifyListeners(AV_CHG_MOTION);
7694 break;
7695 default:
7696 // TODO
7697 ;
7698 }
7699 _ensureInsertionPointOnScreen();
7700
7701 return false;
7702 }
7703
7704 // ---------------- start find and replace ---------------
7705
7706 /*!
7707 Find next occurrence of string
7708 \param pFind String to find
7709 \param bMatchCase True to match case, false to ignore case
7710 \result bDoneEntireDocument True if entire document searched,
7711 false otherwise
7712 \return True if string was found, false otherwise
7713 */
7714 bool
findNext(const UT_UCSChar * pFind,bool & bDoneEntireDocument)7715 FV_View::findNext(const UT_UCSChar* pFind, bool& bDoneEntireDocument)
7716
7717 {
7718 findSetFindString(pFind);
7719 return findNext(bDoneEntireDocument);
7720 }
7721
7722 bool
findNext(bool & bDoneEntireDocument)7723 FV_View::findNext(bool& bDoneEntireDocument)
7724 {
7725 if (m_startPosition <2) {
7726 m_startPosition = 2;
7727 setPoint(m_startPosition);
7728 }
7729
7730 if (!isSelectionEmpty())
7731 {
7732 _clearSelection();
7733 }
7734
7735 UT_uint32* pPrefix = _computeFindPrefix(m_sFind);
7736 bool bRes = _findNext(pPrefix, bDoneEntireDocument);
7737 FREEP(pPrefix);
7738
7739 if (isSelectionEmpty())
7740 {
7741 _updateInsertionPoint();
7742 }
7743 else
7744 {
7745 _ensureInsertionPointOnScreen();
7746 _drawSelection();
7747 }
7748
7749 // TODO do we need to do a notifyListeners(AV_CHG_MOTION) -- yes
7750 notifyListeners(AV_CHG_MOTION);
7751 return bRes;
7752 }
7753
7754
7755 bool
findPrev(const UT_UCSChar * pFind,bool & bDoneEntireDocument)7756 FV_View::findPrev(const UT_UCSChar* pFind, bool& bDoneEntireDocument)
7757 {
7758 findSetFindString(pFind);
7759 return findPrev(bDoneEntireDocument);
7760 }
7761
7762 bool
findPrev(bool & bDoneEntireDocument)7763 FV_View::findPrev(bool& bDoneEntireDocument)
7764 {
7765 if (!isSelectionEmpty())
7766 {
7767 _clearSelection();
7768 }
7769
7770 UT_uint32* pPrefix = _computeFindPrefix(m_sFind);
7771 bool bRes = _findPrev(pPrefix, bDoneEntireDocument);
7772 FREEP(pPrefix);
7773
7774 if (isSelectionEmpty())
7775 {
7776 _updateInsertionPoint();
7777 }
7778 else
7779 {
7780 _ensureInsertionPointOnScreen();
7781 _drawSelection();
7782 }
7783
7784 notifyListeners(AV_CHG_MOTION);
7785 return bRes;
7786 }
7787
7788 void
findSetStartAt(PT_DocPosition pos)7789 FV_View::findSetStartAt(PT_DocPosition pos)
7790 {
7791 PT_DocPosition posEnd;
7792 m_pDoc->getBounds(true, posEnd);
7793 UT_return_if_fail(pos <= posEnd);
7794
7795 m_startPosition = pos;
7796 m_wrappedEnd = false;
7797 m_doneFind = false;
7798 }
7799
7800 /*!
7801 Find operation reset
7802
7803 This function is called at the start of a new find operation to reset
7804 the search location parameters.
7805 */
7806 void
findSetStartAtInsPoint(void)7807 FV_View::findSetStartAtInsPoint(void)
7808 {
7809 m_startPosition = m_iInsPoint;
7810 m_wrappedEnd = false;
7811 m_doneFind = false;
7812 }
7813
7814
7815
7816 void
findSetFindString(const UT_UCSChar * pFind)7817 FV_View::findSetFindString(const UT_UCSChar* pFind)
7818 {
7819 FREEP(m_sFind);
7820 UT_UCS4_cloneString(&m_sFind, pFind);
7821 }
7822
7823 UT_UCSChar *
findGetFindString(void)7824 FV_View::findGetFindString(void)
7825 {
7826 UT_UCSChar * string = NULL;
7827 if (m_sFind)
7828 {
7829 if (UT_UCS4_cloneString(&string, m_sFind))
7830 return string;
7831 }
7832 else
7833 {
7834 if (UT_UCS4_cloneString_char(&string, ""))
7835 return string;
7836 }
7837
7838 return NULL;
7839 }
7840
7841 void
findSetReplaceString(const UT_UCSChar * pReplace)7842 FV_View::findSetReplaceString(const UT_UCSChar* pReplace)
7843 {
7844 FREEP(m_sReplace);
7845 UT_UCS4_cloneString(&m_sReplace, pReplace);
7846 }
7847
7848 UT_UCSChar *
findGetReplaceString(void)7849 FV_View::findGetReplaceString(void)
7850 {
7851 UT_UCSChar * string = NULL;
7852 if (m_sReplace)
7853 {
7854 if (UT_UCS4_cloneString(&string, m_sReplace))
7855 return string;
7856 }
7857 else
7858 {
7859 if (UT_UCS4_cloneString_char(&string, ""))
7860 return string;
7861 }
7862
7863 return NULL;
7864 }
7865
7866 void
findSetReverseFind(bool newValue)7867 FV_View::findSetReverseFind (bool newValue)
7868 {
7869 m_bReverseFind = newValue;
7870 }
7871
7872 bool
findGetReverseFind()7873 FV_View::findGetReverseFind ()
7874 {
7875 return m_bReverseFind;
7876 }
7877
7878 void
findSetMatchCase(bool newValue)7879 FV_View::findSetMatchCase(bool newValue)
7880 {
7881 m_bMatchCase = newValue;
7882 }
7883
7884 bool
findGetMatchCase()7885 FV_View::findGetMatchCase()
7886 {
7887 return m_bMatchCase;
7888 }
7889
7890 void
findSetWholeWord(bool newValue)7891 FV_View::findSetWholeWord(bool newValue)
7892 {
7893 m_bWholeWord = newValue;
7894 }
7895
7896 bool
findGetWholeWord()7897 FV_View::findGetWholeWord()
7898 {
7899 return m_bWholeWord;
7900 }
7901
7902 /*!
7903 Find next occurrence of last searched string
7904 \return True if found, otherwise false
7905 This function is used for non-dialog search operations.
7906 */
7907 bool
findAgain(void)7908 FV_View::findAgain(void)
7909 {
7910 bool bRes = false;
7911
7912 if (m_sFind && *m_sFind)
7913 {
7914 bool bTmp;
7915 if (m_bReverseFind)
7916 {
7917 bRes = findPrev(bTmp);
7918 }
7919 else
7920 {
7921 bRes = findNext(bTmp);
7922 }
7923
7924 if (bRes)
7925 {
7926 _drawSelection();
7927 }
7928 }
7929
7930 return bRes;
7931 }
7932
7933 bool
findReplaceReverse(bool & bDoneEntireDocument)7934 FV_View::findReplaceReverse(bool& bDoneEntireDocument)
7935 {
7936 UT_ASSERT(m_sFind && m_sReplace);
7937
7938 UT_uint32* pPrefix = _computeFindPrefix(m_sFind);
7939 bool bRes = _findReplaceReverse(pPrefix, bDoneEntireDocument, false /* do update */);
7940 FREEP(pPrefix);
7941
7942 updateScreen();
7943
7944 if (isSelectionEmpty())
7945 {
7946 _updateInsertionPoint();
7947 }
7948 else
7949 {
7950 _ensureInsertionPointOnScreen();
7951 _drawSelection();
7952 }
7953
7954 return bRes;
7955 }
7956
7957 /*!
7958 Find and replace string
7959 \param pFind String to find
7960 \param pReplace String to replace it with
7961 \param bMatchCase True to match case, false to ignore case
7962 \result bDoneEntireDocument True if entire document searched,
7963 false otherwise
7964 \return True if string was replaced, false otherwise
7965 */
7966 bool
findReplace(bool & bDoneEntireDocument)7967 FV_View::findReplace(bool& bDoneEntireDocument)
7968 {
7969 UT_ASSERT(m_sFind && m_sReplace);
7970
7971 UT_uint32* pPrefix = _computeFindPrefix(m_sFind);
7972 bool bRes = _findReplace(pPrefix, bDoneEntireDocument, false /* do update */);
7973 FREEP(pPrefix);
7974
7975 updateScreen();
7976
7977 if (isSelectionEmpty())
7978 {
7979 _updateInsertionPoint();
7980 }
7981 else
7982 {
7983 _ensureInsertionPointOnScreen();
7984 _drawSelection();
7985 }
7986
7987 return bRes;
7988 }
7989
7990 /*!
7991 Find and replace all occurrences of string
7992 \param pFind String to find
7993 \param pReplace String to replace it with
7994 \param bMatchCase True to match case, false to ignore case
7995 \return Number of replacements made
7996 */
7997 UT_uint32
findReplaceAll()7998 FV_View::findReplaceAll()
7999 {
8000 UT_uint32 iReplaced = 0;
8001 m_pDoc->beginUserAtomicGlob();
8002
8003 if (m_startPosition <2)
8004 {
8005 m_startPosition = 2;
8006 }
8007
8008 bool bDoneEntireDocument = false;
8009
8010 // find which part of the document is currently on screen -- we will only redraw and
8011 // send messages to listerners within these part of the document
8012 PT_DocPosition posVisibleStart = getDocPositionFromXY(0,0);
8013 PT_DocPosition posVisibleEnd = getDocPositionFromXY(getWindowWidth(),getWindowHeight());
8014
8015 // save point -- we will end where we started
8016 PT_DocPosition iPoint = getPoint();
8017
8018 // this could take long -- show hourglass
8019 setCursorWait();
8020
8021 // Compute search prefix
8022 UT_uint32* pPrefix = _computeFindPrefix(m_sFind);
8023
8024 // Prime with the first match - _findReplace is really
8025 // replace-then-find.
8026 _findNext(pPrefix, bDoneEntireDocument);
8027
8028 // Keep replacing until the end of the buffer is hit
8029 while (!bDoneEntireDocument)
8030 {
8031 bool bDontUpdate = getPoint() < posVisibleStart || getPoint() > posVisibleEnd;
8032 if(bDontUpdate)
8033 {
8034 m_bDontNotifyListeners = true;
8035 }
8036
8037 _findReplace(pPrefix, bDoneEntireDocument, bDontUpdate);
8038 iReplaced++;
8039 }
8040
8041 m_pDoc->endUserAtomicGlob();
8042
8043 _resetSelection();
8044 setPoint(iPoint);
8045
8046 // restore notifications if we stopped them
8047 if(m_bDontNotifyListeners)
8048 {
8049 m_bDontNotifyListeners = false;
8050 notifyListeners(AV_CHG_MOTION);
8051 }
8052
8053 _updateInsertionPoint();
8054 _generalUpdate();
8055 draw();
8056 setCursorToContext();
8057
8058 FREEP(pPrefix);
8059 return iReplaced;
8060 }
8061
8062
8063 fl_BlockLayout*
getCurrentBlock(void) const8064 FV_View::getCurrentBlock(void) const
8065 {
8066 return _findGetCurrentBlock();
8067 }
8068
insertSymbol(UT_UCSChar c,const gchar * symfont)8069 void FV_View::insertSymbol(UT_UCSChar c, const gchar * symfont)
8070 {
8071
8072 // First check to see if there is a selection already.
8073 // if so delete it then get the current font
8074 m_pDoc->beginUserAtomicGlob();
8075
8076 if (!isSelectionEmpty() && !m_FrameEdit.isActive())
8077 {
8078 _deleteSelection();
8079 _generalUpdate();
8080 }
8081 else if(m_FrameEdit.isActive())
8082 {
8083 m_FrameEdit.setPointInside();
8084 }
8085 // We have to determine the current font so we can put it back after
8086 // Inserting the Symbol
8087
8088 const gchar ** props_in = NULL;
8089 const gchar * currentfont;
8090 getCharFormat(&props_in);
8091 currentfont = UT_getAttribute("font-family",props_in);
8092 g_free(props_in);
8093
8094 if(strstr(symfont,currentfont) == NULL)
8095 {
8096 // Set the font
8097 const gchar* properties[] = { "font-family", 0, 0 };
8098 properties[1] = symfont ;
8099 setCharFormat(properties);
8100
8101 // Insert the character
8102 cmdCharInsert(&c,1);
8103
8104 // Change the font back to its original value
8105 properties[1] = currentfont;
8106 setCharFormat(properties);
8107
8108 UT_sint32 xPoint, yPoint, xPoint2, yPoint2, iPointHeight;
8109 bool bDirection;
8110
8111 fl_BlockLayout * pBL = m_pLayout->findBlockAtPosition(getPoint());
8112 fp_Run * pRun;
8113 if(pBL == NULL)
8114 {
8115 return;
8116 }
8117 pRun = pBL->findPointCoords(getPoint(), false, xPoint,
8118 yPoint, xPoint2, yPoint2,
8119 iPointHeight, bDirection);
8120 if(pRun && pRun->getPrevRun())
8121 {
8122 pRun->getPrevRun()->markAsDirty();
8123 }
8124 _generalUpdate();
8125 }
8126 else
8127 {
8128 // Just insert the character
8129
8130 cmdCharInsert(&c,1);
8131
8132 UT_sint32 xPoint, yPoint, xPoint2, yPoint2, iPointHeight;
8133 bool bDirection;
8134
8135 fl_BlockLayout * pBL = m_pLayout->findBlockAtPosition(getPoint());
8136 fp_Run * pRun;
8137 if(pBL == NULL)
8138 {
8139 return;
8140 }
8141 pRun = pBL->findPointCoords(getPoint(), false, xPoint,
8142 yPoint, xPoint2, yPoint2,
8143 iPointHeight, bDirection);
8144 if(pRun && pRun->getPrevRun())
8145 {
8146 pRun->getPrevRun()->markAsDirty();
8147 }
8148 }
8149 m_pDoc->endUserAtomicGlob();
8150 }
8151
8152
warpInsPtToXY(UT_sint32 xPos,UT_sint32 yPos,bool bClick=false)8153 void FV_View::warpInsPtToXY(UT_sint32 xPos, UT_sint32 yPos, bool bClick = false)
8154 {
8155 /*
8156 Figure out which page we clicked on.
8157 Pass the click down to that page.
8158 */
8159
8160 UT_sint32 xClick, yClick;
8161 fp_Page* pPage = _getPageForXY(xPos, yPos, xClick, yClick);
8162
8163 if (!isSelectionEmpty())
8164 _clearSelection();
8165 PT_DocPosition pos,posEnd;
8166 bool bBOL = false;
8167 bool bEOL = false;
8168 fl_HdrFtrShadow * pShadow=NULL;
8169 bool isTOC = false;
8170 pPage->mapXYToPosition(xClick, yClick, pos, bBOL, bEOL,isTOC, true, &pShadow);
8171 if(bClick)
8172 {
8173 getEditableBounds(true,posEnd,true);
8174 if((pos > posEnd) && (pShadow != NULL))
8175 {
8176 if (pos != getPoint())
8177 _clearIfAtFmtMark(getPoint());
8178 setHdrFtrEdit(pShadow);
8179 bClick = true;
8180 }
8181 else if((pos > posEnd) && (pShadow == NULL))
8182 {
8183 bClick = false;
8184 pos = posEnd;
8185 }
8186 else if(pos <= posEnd)
8187 {
8188 bClick = false;
8189 clearHdrFtrEdit();
8190 }
8191 }
8192 if ((pos != getPoint()) && !bClick)
8193 _clearIfAtFmtMark(getPoint());
8194
8195 m_FrameEdit.setMode(FV_FrameEdit_NOT_ACTIVE);
8196 m_InlineImage.setMode(FV_InlineDrag_NOT_ACTIVE);
8197 _setPoint(pos, bEOL);
8198 _ensureInsertionPointOnScreen();
8199 setCursorToContext();
8200 _updateSelectionHandles();
8201 notifyListeners(AV_CHG_MOTION | AV_CHG_HDRFTR ); // Sevior Put this in
8202 // notifyListeners(AV_CHG_HDRFTR );
8203
8204 }
8205
getPageScreenOffsets(const fp_Page * pThePage,UT_sint32 & xoff,UT_sint32 & yoff)8206 void FV_View::getPageScreenOffsets(const fp_Page* pThePage, UT_sint32& xoff,
8207 UT_sint32& yoff)
8208 {
8209 //const fp_Page* pPage = m_pLayout->getFirstPage();
8210 UT_sint32 iPageNumber = m_pLayout->findPage(const_cast<fp_Page *>(pThePage));
8211 if(iPageNumber < 0)
8212 {
8213 xoff = 0;
8214 yoff = 0;
8215 return;
8216 }
8217 UT_sint32 iRow = iPageNumber/getNumHorizPages();
8218 UT_sint32 y = getPageViewTopMargin();
8219 //UT_sint32 iPage = m_pLayout->findPage(const_cast<fp_Page *>(pThePage));
8220
8221 if(iPageNumber >= static_cast<UT_sint32>(getNumHorizPages()))
8222 {
8223 for (UT_sint32 i = 0; i < iRow; i++)
8224 {
8225 y += getMaxHeight(i) + getPageViewSep();
8226 }
8227 }
8228
8229 //
8230 // This code will work for different page size but it's slow for big docs
8231 //
8232 #if 0
8233 while (pPage)
8234 {
8235 if (pPage == pThePage)
8236 {
8237 break;
8238 }
8239 y += pPage->getHeight() + getPageViewSep();
8240 fl_DocSectionLayout * pDSL = pPage->getOwningSection();
8241 if(getViewMode() != VIEW_PRINT)
8242 {
8243 y = y - pDSL->getTopMargin() - pDSL->getBottomMargin();
8244 }
8245 pPage = pPage->getNext();
8246 }
8247 #endif
8248
8249 yoff = y - m_yScrollOffset;
8250 xoff = getWidthPrevPagesInRow(iPageNumber) + getPageViewLeftMargin() - m_xScrollOffset;
8251 }
8252
getPageYOffset(fp_Page * pThePage,UT_sint32 & yoff) const8253 void FV_View::getPageYOffset(fp_Page* pThePage, UT_sint32& yoff) const
8254 {
8255 UT_uint32 y = getPageViewTopMargin();
8256 //
8257 // Note this code assumes the page size is the same throughout the document.
8258 //
8259 UT_sint32 iPage = m_pLayout->findPage(pThePage);
8260 fp_Page* pPage = m_pLayout->getFirstPage();
8261 fl_DocSectionLayout * pDSL = pPage->getOwningSection();
8262 UT_sint32 iDiff = pPage->getHeight() + getPageViewSep();
8263 UT_uint32 iRow = iPage/getNumHorizPages();
8264 if(getViewMode() != VIEW_PRINT)
8265 {
8266 iDiff = iDiff - pDSL->getTopMargin() - pDSL->getBottomMargin();
8267 }
8268
8269 // Causes weirdness -- up arrow key jumps up to the top of the page
8270 if(iPage >= (signed)getNumHorizPages())
8271 {
8272 for (unsigned int i = 0; i < iRow-1; i++) //This is probably slowish...
8273 {
8274 iDiff += getMaxHeight(iRow) + getPageViewSep();
8275 }
8276 }
8277 else
8278 {
8279 iDiff = 0;
8280 }
8281 y += iDiff;
8282 //
8283 // This code will work for different page size but it's slow for big docs
8284 //
8285 #if 0
8286 while (pPage)
8287 {
8288 if (pPage == pThePage)
8289 {
8290 break;
8291 }
8292 y += pPage->getHeight() + getPageViewSep();
8293 if(getViewMode() != VIEW_PRINT)
8294 {
8295 y = y - pDSL->getTopMargin() - pDSL->getBottomMargin();
8296 }
8297
8298 pPage = pPage->getNext();
8299 }
8300 #endif
8301 yoff = y;
8302 }
8303
8304
getPageViewSep(void) const8305 UT_sint32 FV_View::getPageViewSep(void) const
8306 {
8307 // return the amount of gray-space we draw above the top
8308 // of the paper in "Page View". return zero if not in
8309 // "Page View".
8310 XAP_Frame * pFrame = static_cast<XAP_Frame*>(getParentData());
8311 if (isPreview() || m_pG->queryProperties(GR_Graphics::DGP_PAPER))
8312 return 0;
8313 else if (pFrame && pFrame->isMenuScrollHidden())
8314 {
8315 return 0;
8316 }
8317 else if (getViewMode() != VIEW_PRINT)
8318 {
8319 return m_pG->tlu(1);
8320 }
8321 else
8322 #ifdef EMBEDDED_TARGET
8323 return (int ) (0.2 * fl_PAGEVIEW_PAGE_SEP);
8324 #else
8325 return fl_PAGEVIEW_PAGE_SEP;
8326 #endif
8327 }
8328
8329
getPageViewLeftMargin(void) const8330 UT_sint32 FV_View::getPageViewLeftMargin(void) const
8331 {
8332 // return the amount of gray-space we draw to the left
8333 // of the paper in "Page View". return zero if not in
8334 // "Page View".
8335 XAP_Frame * pFrame = static_cast<XAP_Frame*>(getParentData());
8336 if (isPreview() || m_pG->queryProperties(GR_Graphics::DGP_PAPER) || (getViewMode() != VIEW_PRINT))
8337 return 0;
8338 else if (pFrame && pFrame->isMenuScrollHidden())
8339 {
8340 return 0;
8341 }
8342 else if(m_pLayout->isQuickPrint())
8343 {
8344 return 0;
8345 }
8346
8347 #ifdef EMBEDDED_TARGET
8348 return (int) (0.2 * fl_PAGEVIEW_MARGIN_X);
8349 #else
8350 return fl_PAGEVIEW_MARGIN_X;
8351 #endif
8352 }
8353
getPageViewTopMargin(void) const8354 UT_sint32 FV_View::getPageViewTopMargin(void) const
8355 {
8356 // return the amount of gray-space we draw above the top
8357 // of the paper in "Page View". return zero if not in
8358 // "Page View".
8359 XAP_Frame * pFrame = static_cast<XAP_Frame*>(getParentData());
8360 if (isPreview() || m_pG->queryProperties(GR_Graphics::DGP_PAPER) || (getViewMode() != VIEW_PRINT))
8361 return 0;
8362 else if (pFrame && pFrame->isMenuScrollHidden())
8363 {
8364 return 0;
8365 }
8366 else if(m_pLayout->isQuickPrint())
8367 {
8368 return 0;
8369 }
8370 else
8371 #ifdef EMBEDDED_TARGET
8372 return (int ) (0.2 * fl_PAGEVIEW_MARGIN_Y);
8373 #else
8374 return fl_PAGEVIEW_MARGIN_Y;
8375 #endif
8376
8377 }
8378
setXScrollOffset(UT_sint32 v)8379 void FV_View::setXScrollOffset(UT_sint32 v) ///////////////////////TODO: Fix this for multiple pages
8380 {
8381 CHECK_WINDOW_SIZE
8382 UT_sint32 dx = v - m_xScrollOffset;
8383
8384 if (dx == 0)
8385 return;
8386
8387 m_pG->scroll(dx, 0);
8388 m_xScrollOffset = v;
8389
8390 UT_sint32 x1 = 0;
8391 UT_sint32 dx2 = getWindowWidth();
8392
8393 if (dx > 0)
8394 {
8395 if (dx < getWindowWidth())
8396 {
8397 x1 = getWindowWidth() - dx;
8398 dx2 = dx;
8399 }
8400 }
8401 else
8402 {
8403 if (dx > -getWindowWidth())
8404 {
8405 dx2 = -dx;
8406 }
8407 }
8408
8409 _draw(x1-m_pG->tlu(1), 0, dx2+m_pG->tlu(2), getWindowHeight(), false, true);
8410
8411 _fixInsertionPointCoords();
8412 _updateSelectionHandles();
8413 }
8414
setYScrollOffset(UT_sint32 v)8415 void FV_View::setYScrollOffset(UT_sint32 v)
8416 {
8417 CHECK_WINDOW_SIZE
8418 UT_sint32 dy = v - m_yScrollOffset;
8419
8420 if (dy == 0)
8421 return;
8422
8423 m_pG->scroll(0, dy);
8424 m_yScrollOffset = v;
8425
8426 _fixInsertionPointCoords();
8427 _updateSelectionHandles();
8428 }
8429
draw(int page,dg_DrawArgs * da)8430 void FV_View::draw(int page, dg_DrawArgs* da)
8431 {
8432 UT_DEBUGMSG(("FV_View::draw_1: [page %d]\n",page));
8433 calculateNumHorizPages();
8434
8435 if(getPoint() == 0) {
8436 return;
8437 }
8438
8439 UT_ASSERT(da->pG);
8440 fp_Page* pPage = m_pLayout->getNthPage(page);
8441 if (pPage)
8442 {
8443 pPage->draw(da);
8444 }
8445 }
8446
8447 /*!
8448 The rectangle is in device coordinances
8449 */
draw(const UT_Rect * pClipRect)8450 void FV_View::draw(const UT_Rect* pClipRect)
8451 {
8452 if(getPoint() == 0) {
8453 return;
8454 }
8455
8456 if (pClipRect)
8457 {
8458 _draw(pClipRect->left,
8459 pClipRect->top,
8460 pClipRect->width,
8461 pClipRect->height,
8462 false,true);
8463 }
8464 else
8465 {
8466 _draw(0,0,getWindowWidth(),getWindowHeight(),false,false);
8467 }
8468 _fixInsertionPointCoords();
8469 }
8470
updateScreen(bool bDirtyRunsOnly)8471 void FV_View::updateScreen(bool bDirtyRunsOnly)
8472 {
8473 _draw(0,0,getWindowWidth(),getWindowHeight(),bDirtyRunsOnly,false);
8474 }
8475
8476 /*!
8477 * Draw a 1px line in selection background color with optional resize handles.
8478 * \param box Where to draw.
8479 * \param drawHandles If handles are to be drawn.
8480 */
drawSelectionBox(UT_Rect & inBox,bool drawHandles)8481 void FV_View::drawSelectionBox(UT_Rect & inBox, bool drawHandles)
8482 {
8483 GR_Graphics *pG = getGraphics();
8484 UT_sint32 boxSize = getImageSelInfo();
8485 m_InlineImage.setSelectionDrawn(true);
8486 UT_sint32 left = inBox.left;
8487 UT_sint32 top = inBox.top;
8488 UT_sint32 right = inBox.left + inBox.width;
8489 UT_sint32 bottom = inBox.top + inBox.height;
8490 xxx_UT_DEBUGMSG(("Draw selection box Top %d \n",top));
8491 // draw a line around the image
8492 pG->setLineProperties(pG->tluD(1.0),
8493 GR_Graphics::JOIN_MITER,
8494 GR_Graphics::CAP_PROJECTING,
8495 GR_Graphics::LINE_SOLID);
8496
8497 UT_RGBColor color = getColorSelBackground();
8498 pG->setColor(color);
8499 {
8500 // Need the painter lock to be released at the end of these draws
8501
8502 GR_Painter painter(pG);
8503 painter.drawLine(left, top, right, top);
8504 painter.drawLine(left, top, left, bottom);
8505 painter.drawLine(right, top, right, bottom);
8506 painter.drawLine(left, bottom, right, bottom);
8507 }
8508 // now, draw the resize boxes around the image
8509 if (drawHandles) {
8510 UT_Rect box;
8511 box = UT_Rect(left, top, boxSize, boxSize);
8512 _drawResizeHandle(box);
8513 box = UT_Rect(left + (right - left)/2 - boxSize/2, top, boxSize, boxSize);
8514 _drawResizeHandle(box); // North
8515 box = UT_Rect(right-boxSize+pG->tlu(1), top, boxSize, boxSize);
8516 _drawResizeHandle(box); // North East
8517 box = UT_Rect(right-boxSize+pG->tlu(1), top + ((bottom - top) / 2) - boxSize/2, boxSize, boxSize);
8518 _drawResizeHandle(box); // East
8519 box = UT_Rect(right-boxSize+pG->tlu(1), bottom - boxSize + pG->tlu(1), boxSize, boxSize);
8520 _drawResizeHandle(box); // South East
8521 box = UT_Rect(left + (right - left)/2 - boxSize/2, bottom - boxSize + pG->tlu(1), boxSize, boxSize);
8522 _drawResizeHandle(box); // South
8523 box = UT_Rect(left, bottom - boxSize + pG->tlu(1), boxSize, boxSize);
8524 _drawResizeHandle(box); // South West
8525 box = UT_Rect(left, top + ((bottom - top) / 2) - boxSize/2, boxSize, boxSize);
8526 _drawResizeHandle(box); // West
8527 }
8528 }
8529
8530 #define SELDOWNCOLOR(v,w)(v > w ? v - w : 0)
8531 #define SELUPCOLOR(v,w)(v > (255-w) ? 255 : v + w)
8532 /*!
8533 * Draw a nice 3d resize handle at box.
8534 * \param box Where to draw.
8535 */
_drawResizeHandle(UT_Rect & box)8536 inline void FV_View::_drawResizeHandle(UT_Rect & box)
8537 {
8538 GR_Graphics * pG = getGraphics();
8539 UT_sint32 left = box.left;
8540 UT_sint32 top = box.top;
8541 UT_sint32 right = box.left + box.width - pG->tlu(1);
8542 UT_sint32 bottom = box.top + box.height - pG->tlu(1);
8543
8544 GR_Painter painter(pG);
8545
8546 pG->setLineProperties(pG->tluD(1.0),
8547 GR_Graphics::JOIN_MITER,
8548 GR_Graphics::CAP_PROJECTING,
8549 GR_Graphics::LINE_SOLID);
8550
8551 UT_RGBColor color = getColorSelBackground();
8552 pG->setColor(color);
8553
8554 UT_RGBColor downColor1 = UT_RGBColor(SELDOWNCOLOR(color.m_red, 40), SELDOWNCOLOR(color.m_grn, 40), SELDOWNCOLOR(color.m_blu, 40));
8555 UT_RGBColor downColor2 = UT_RGBColor(SELDOWNCOLOR(color.m_red, 20), SELDOWNCOLOR(color.m_grn, 20), SELDOWNCOLOR(color.m_blu, 20));
8556 UT_RGBColor upColor1 = UT_RGBColor(SELUPCOLOR(color.m_red, 40), SELUPCOLOR(color.m_grn, 40), SELUPCOLOR(color.m_blu, 40));
8557 UT_RGBColor upColor2 = UT_RGBColor(SELUPCOLOR(color.m_red, 20), SELUPCOLOR(color.m_grn, 20), SELUPCOLOR(color.m_blu, 20));
8558
8559 painter.fillRect(color,box.left + pG->tlu(1), box.top + pG->tlu(1), box.width - pG->tlu(3), box.height - pG->tlu(3));
8560
8561 // east & south
8562 pG->setColor(downColor1);
8563 painter.drawLine(right, top, right, bottom);
8564 painter.drawLine(left, bottom, right, bottom);
8565 pG->setColor(downColor2);
8566 painter.drawLine(right - pG->tlu(1), top + pG->tlu(1), right - pG->tlu(1), bottom - pG->tlu(1));
8567 painter.drawLine(left + pG->tlu(1), bottom - pG->tlu(1), right - pG->tlu(1), bottom - pG->tlu(1));
8568
8569 // north & west
8570 pG->setColor(upColor1);
8571 painter.drawLine(left, top, right, top);
8572 painter.drawLine(left, top, left, bottom);
8573 pG->setColor(upColor2);
8574 painter.drawLine(left + pG->tlu(1), top + pG->tlu(1), right - pG->tlu(1), top + pG->tlu(1));
8575 painter.drawLine(left + pG->tlu(1), top + pG->tlu(1), left + pG->tlu(1), bottom - pG->tlu(1));
8576
8577 /* This is the original code, but rearranged above so we don't have to set the colour so often
8578 // west
8579 pG->setColor(UT_RGBColor(color.m_red - 40,color.m_grn - 40,color.m_blu - 40));
8580 painter.drawLine(right, top, right, bottom);
8581 pG->setColor(UT_RGBColor(color.m_red - 20,color.m_grn - 20,color.m_blu - 20));
8582 painter.drawLine(right - pG->tlu(1), top + pG->tlu(1), right - pG->tlu(1), bottom - pG->tlu(1));
8583
8584 // south
8585 pG->setColor(UT_RGBColor(color.m_red - 40,color.m_grn - 40,color.m_blu - 40));
8586 painter.drawLine(left, bottom, right, bottom);
8587 pG->setColor(UT_RGBColor(color.m_red - 20,color.m_grn - 20,color.m_blu - 20));
8588 painter.drawLine(left + pG->tlu(1), bottom - pG->tlu(1), right - pG->tlu(1), bottom - pG->tlu(1));
8589
8590 // north
8591 pG->setColor(UT_RGBColor(color.m_red + 40,color.m_grn + 40,color.m_blu + 40));
8592 painter.drawLine(left, top, right, top);
8593 pG->setColor(UT_RGBColor(color.m_red + 20,color.m_grn + 20,color.m_blu + 20));
8594 painter.drawLine(left + pG->tlu(1), top + pG->tlu(1), right - pG->tlu(1), top + pG->tlu(1));
8595
8596 // east
8597 pG->setColor(UT_RGBColor(color.m_red + 40,color.m_grn + 40,color.m_blu + 40));
8598 painter.drawLine(left, top, left, bottom);
8599 pG->setColor(UT_RGBColor(color.m_red + 20,color.m_grn + 20,color.m_blu + 20));
8600 painter.drawLine(left + pG->tlu(1), top + pG->tlu(1), left + pG->tlu(1), bottom - pG->tlu(1));
8601 */
8602 }
8603
isLeftMargin(UT_sint32 xPos,UT_sint32 yPos) const8604 bool FV_View::isLeftMargin(UT_sint32 xPos, UT_sint32 yPos) const
8605 {
8606 /*
8607 Figure out which page we clicked on.
8608 Pass the click down to that page.
8609 */
8610 UT_sint32 xClick, yClick;
8611 const fp_Page* pPage = _getPageForXY(xPos, yPos, xClick, yClick);
8612
8613 PT_DocPosition iNewPoint;
8614 bool bBOL = false;
8615 bool bEOL = false;
8616 bool isTOC = false;
8617 pPage->mapXYToPosition(xClick, yClick, iNewPoint, bBOL, bEOL,isTOC, true);
8618 return bBOL;
8619 }
8620
ensureInsertionPointOnScreen(void)8621 void FV_View::ensureInsertionPointOnScreen(void)
8622 {
8623 _ensureInsertionPointOnScreen();
8624 }
8625
8626
setPoint(UT_uint32 pt)8627 void FV_View::setPoint(UT_uint32 pt)
8628 {
8629 _setPoint(pt, m_bPointEOL);
8630 }
8631
8632 /* Passes through to the document's don't-change-ins-point method. */
setDontChangeInsPoint(void)8633 void FV_View::setDontChangeInsPoint(void)
8634 {
8635 m_pDoc->setDontChangeInsPoint();
8636 }
8637
allowChangeInsPoint(void)8638 void FV_View::allowChangeInsPoint(void)
8639 {
8640 m_pDoc->allowChangeInsPoint();
8641 }
8642
canDo(bool bUndo) const8643 bool FV_View::canDo(bool bUndo) const
8644 {
8645 return m_pDoc->canDo(bUndo);
8646 }
8647
undoCount(bool bUndo) const8648 UT_uint32 FV_View::undoCount (bool bUndo) const
8649 {
8650 return m_pDoc->undoCount ( bUndo );
8651 }
8652
8653 /*!
8654 * Returns true of the point presented is within a selection.
8655 */
isPosSelected(PT_DocPosition pos) const8656 bool FV_View::isPosSelected(PT_DocPosition pos) const
8657 {
8658 return m_Selection.isPosSelected(pos);
8659 }
8660
getSelectionMode(void) const8661 FV_SelectionMode FV_View::getSelectionMode(void) const
8662 {
8663 return m_Selection.getSelectionMode();
8664 }
8665
getPrevSelectionMode(void) const8666 FV_SelectionMode FV_View::getPrevSelectionMode(void) const
8667 {
8668 return m_Selection.getPrevSelectionMode();
8669 }
8670
getNthSelection(UT_sint32 i) const8671 PD_DocumentRange * FV_View::getNthSelection(UT_sint32 i) const
8672 {
8673 return m_Selection.getNthSelection(i);
8674 }
8675
getNumSelections(void) const8676 UT_sint32 FV_View::getNumSelections(void) const
8677 {
8678 return m_Selection.getNumSelections();
8679 }
8680
setSelectionMode(FV_SelectionMode selMode)8681 void FV_View::setSelectionMode(FV_SelectionMode selMode)
8682 {
8683 m_Selection.setMode(selMode);
8684 }
8685
getDocumentRangeOfCurrentSelection(PD_DocumentRange * pdr) const8686 void FV_View::getDocumentRangeOfCurrentSelection(PD_DocumentRange * pdr) const
8687 {
8688 PT_DocPosition iPos1, iPos2;
8689 if (m_Selection.getSelectionAnchor() < getPoint())
8690 {
8691 iPos1 = m_Selection.getSelectionAnchor();
8692 iPos2 = getPoint();
8693 }
8694 else
8695 {
8696 iPos1 = getPoint();
8697 iPos2 = m_Selection.getSelectionAnchor();
8698 }
8699
8700 pdr->set(m_pDoc,iPos1,iPos2);
8701 return;
8702 }
8703
8704
8705 /*!
8706 * Return the left,right,top and bottom attach points of the cell containing
8707 * the position cellPos
8708 */
getCellParams(PT_DocPosition posCell,UT_sint32 * pLeft,UT_sint32 * pRight,UT_sint32 * pTop,UT_sint32 * pBot) const8709 bool FV_View::getCellParams(PT_DocPosition posCell, UT_sint32 * pLeft, UT_sint32 * pRight,
8710 UT_sint32 * pTop, UT_sint32 * pBot) const
8711 {
8712 pf_Frag_Strux* cellSDH;
8713 bool bres = m_pDoc->getStruxOfTypeFromPosition(posCell,PTX_SectionCell,&cellSDH);
8714 if(!bres)
8715 {
8716 return false;
8717 }
8718 const char * pszLeft;
8719 const char * pszRight;
8720 const char * pszTop;
8721 const char * pszBot;
8722 m_pDoc->getPropertyFromSDH(cellSDH,isShowRevisions(),getRevisionLevel(),"left-attach",&pszLeft);
8723 if(pszLeft && *pszLeft)
8724 {
8725 *pLeft = atoi(pszLeft);
8726 }
8727 else
8728 {
8729 return false;
8730 }
8731 m_pDoc->getPropertyFromSDH(cellSDH,isShowRevisions(),getRevisionLevel(),"right-attach",&pszRight);
8732 if(pszRight && *pszRight)
8733 {
8734 *pRight = atoi(pszRight);
8735 }
8736 else
8737 {
8738 return false;
8739 }
8740 m_pDoc->getPropertyFromSDH(cellSDH,isShowRevisions(),getRevisionLevel(),"top-attach",&pszTop);
8741 if(pszTop && *pszTop)
8742 {
8743 *pTop = atoi(pszTop);
8744 }
8745 else
8746 {
8747 return false;
8748 }
8749 m_pDoc->getPropertyFromSDH(cellSDH,isShowRevisions(),getRevisionLevel(),"bot-attach",&pszBot);
8750 if(pszBot && *pszBot)
8751 {
8752 *pBot = atoi(pszBot);
8753 }
8754 else
8755 {
8756 return false;
8757 }
8758 return true;
8759 }
8760
8761 /*!
8762 * Return the left,right,top and bottom line styles of the cell containing
8763 * the position cellPos. Values will be -1 if the style is not set.
8764 */
getCellLineStyle(PT_DocPosition posCell,UT_sint32 * pLeft,UT_sint32 * pRight,UT_sint32 * pTop,UT_sint32 * pBot) const8765 bool FV_View::getCellLineStyle(PT_DocPosition posCell, UT_sint32 * pLeft, UT_sint32 * pRight,
8766 UT_sint32 * pTop, UT_sint32 * pBot) const
8767 {
8768 pf_Frag_Strux* cellSDH;
8769 bool bres = m_pDoc->getStruxOfTypeFromPosition(posCell,PTX_SectionCell,&cellSDH);
8770 if(!bres)
8771 {
8772 return false;
8773 }
8774 const char * pszLeft;
8775 const char * pszRight;
8776 const char * pszTop;
8777 const char * pszBot;
8778 m_pDoc->getPropertyFromSDH(cellSDH,isShowRevisions(),getRevisionLevel(),"left-style",&pszLeft);
8779 if(pszLeft && *pszLeft)
8780 {
8781 *pLeft = atoi(pszLeft);
8782 }
8783 else
8784 {
8785 *pLeft = -1;
8786 }
8787 m_pDoc->getPropertyFromSDH(cellSDH,isShowRevisions(),getRevisionLevel(),"right-style",&pszRight);
8788 if(pszRight && *pszRight)
8789 {
8790 *pRight = atoi(pszRight);
8791 }
8792 else
8793 {
8794 *pRight = -1;
8795 }
8796 m_pDoc->getPropertyFromSDH(cellSDH,isShowRevisions(),getRevisionLevel(),"top-style",&pszTop);
8797 if(pszTop && *pszTop)
8798 {
8799 *pTop = atoi(pszTop);
8800 }
8801 else
8802 {
8803 *pTop = -1;
8804 }
8805 m_pDoc->getPropertyFromSDH(cellSDH,isShowRevisions(),getRevisionLevel(),"bottom-style",&pszBot);
8806 if(pszBot && *pszBot)
8807 {
8808 *pBot = atoi(pszBot);
8809 }
8810 else
8811 {
8812 *pBot = -1;
8813 }
8814 return true;
8815 }
8816
8817 /*!
8818 Set cells in a table to a given format. The formatting of the current selection, row,
8819 column or the whole table can be changed.
8820 \param properties the new cell format
8821 \param applyTo the range to apply the changes to
8822 \return True if the operation was succesful, false otherwise
8823 */
setCellFormat(const gchar * properties[],FormatTable applyTo,FG_Graphic * pFG,UT_String & sDataID)8824 bool FV_View::setCellFormat(const gchar * properties[], FormatTable applyTo, FG_Graphic * pFG,UT_String & sDataID)
8825 {
8826 bool bRet;
8827 setCursorWait();
8828
8829 // Signal PieceTable Change
8830 _saveAndNotifyPieceTableChange();
8831
8832 // Turn off list updates
8833 m_pDoc->disableListUpdates();
8834
8835 // turn off immediate layout of table. uwog this stops the formatter from prematurely building the table.
8836 m_pDoc->setDontImmediatelyLayout(true);
8837
8838 PT_DocPosition posTable = 0;
8839 PT_DocPosition posStart = getPoint();
8840 PT_DocPosition posEnd = posStart;
8841 if (!isSelectionEmpty())
8842 {
8843 if (m_Selection.getSelectionAnchor() < posStart)
8844 posStart = m_Selection.getSelectionAnchor();
8845 else
8846 posEnd = m_Selection.getSelectionAnchor();
8847 if(posStart < 2)
8848 {
8849 posStart = 2;
8850 }
8851 }
8852
8853 // Find the enclosing table. If just look for the first one we can get fooled by nested tables.
8854 pf_Frag_Strux* tableSDH;
8855 bRet = m_pDoc->getStruxOfTypeFromPosition(getPoint(),PTX_SectionTable,&tableSDH);
8856 if(!bRet)
8857 {
8858 // Allow table updates
8859 m_pDoc->setDontImmediatelyLayout(false);
8860
8861 // Signal PieceTable Changes have finished
8862 _restorePieceTableState();
8863 clearCursorWait();
8864 return false;
8865 }
8866 posTable = m_pDoc->getStruxPosition(tableSDH)+1;
8867 posStart = (posTable > posStart)?posTable:posStart;
8868
8869 // Need this to trigger a table update!
8870 UT_sint32 iLineType = _changeCellParams(posTable, tableSDH);
8871
8872 // The Format Selection case needs some special attention
8873 if (applyTo == FORMAT_TABLE_SELECTION)
8874 {
8875 pf_Frag_Strux* cellSDH;
8876 PT_DocPosition posTemp = ((posTable == posStart) ? posStart + 2 : posStart);
8877 bRet = m_pDoc->getStruxOfTypeFromPosition(posTemp,PTX_SectionCell,&cellSDH);
8878 if(bRet)
8879 {
8880 posStart = m_pDoc->getStruxPosition(cellSDH)+1;
8881 //
8882 // Make sure posEnd is inside the Table.
8883 //
8884 pf_Frag_Strux* endTableSDH = m_pDoc->getEndTableStruxFromTablePos(posTable);
8885 UT_ASSERT(endTableSDH);
8886 if(endTableSDH == NULL)
8887 {
8888 return false;
8889 }
8890 PT_DocPosition posEndTable = m_pDoc->getStruxPosition(endTableSDH);
8891 if(posEnd > posEndTable)
8892 {
8893 posEnd = posEndTable -1;
8894 }
8895 // Do the actual change
8896 UT_GenericVector<fl_BlockLayout*> vBlock;
8897 getBlocksInSelection(&vBlock);
8898 fl_ContainerLayout * pCL = NULL;
8899 fl_CellLayout * pCell = NULL;
8900 UT_sint32 i =0;
8901 for(i=0; i<vBlock.getItemCount();i++)
8902 {
8903 fl_BlockLayout * pBL = vBlock.getNthItem(i);
8904 pCL = pBL->myContainingLayout();
8905 if(pCL->getContainerType() == FL_CONTAINER_CELL)
8906 {
8907 PT_DocPosition pos = pBL->getPosition();
8908 if (pos >= posStart && pos <= posEnd)
8909 bRet = m_pDoc->changeStruxFmt(PTC_AddFmt,pos,pos,NULL,properties,PTX_SectionCell);
8910 if(static_cast<fl_CellLayout *>(pCL) != pCell)
8911 {
8912 if(pFG != NULL)
8913 {
8914 pCell = static_cast<fl_CellLayout *>(pCL);
8915 pFG->insertAtStrux(m_pDoc,72,pos,PTX_SectionCell,sDataID.c_str());
8916 }
8917 else
8918 {
8919 const gchar * attributes[3] = {
8920 PT_STRUX_IMAGE_DATAID,NULL,NULL};
8921 bRet = m_pDoc->changeStruxFmt(PTC_RemoveFmt,pos,pos,attributes,NULL,PTX_SectionCell);
8922 }
8923 }
8924 }
8925 }
8926 }
8927 }
8928 else if(applyTo == FORMAT_TABLE_TABLE)
8929 {
8930 UT_DEBUGMSG(("Doing apply FORMAT_TABLE_TABLE \n"));
8931 // Loop through the table cells to adjust their formatting
8932 // get the number of rows and columns in the current table
8933
8934 UT_sint32 numRows;
8935 UT_sint32 numCols;
8936 bRet = m_pDoc->getRowsColsFromTableSDH(tableSDH, isShowRevisions(), getRevisionLevel(), &numRows, &numCols);
8937
8938 UT_sint32 rowStart = 0;
8939 UT_sint32 rowEnd;
8940 UT_sint32 colStart = 0;
8941 UT_sint32 colEnd;
8942
8943 colStart = 0;
8944 colEnd = numCols-1;
8945
8946 rowStart = 0;
8947 rowEnd = numRows-1;
8948
8949 // Loop through the table cells to adjust their formatting
8950 UT_sint32 i;
8951 UT_sint32 j;
8952 for (j = rowStart; j <= rowEnd; j++)
8953 {
8954 for (i = colStart; i <= colEnd; i++)
8955 {
8956 pf_Frag_Strux* cellSDH = m_pDoc->getCellSDHFromRowCol(tableSDH, isShowRevisions(), getRevisionLevel(),
8957 j, i);
8958 if(cellSDH)
8959 {
8960 // Do the actual change
8961 posStart = m_pDoc->getStruxPosition(cellSDH)+1;
8962 bRet = m_pDoc->changeStruxFmt(PTC_AddFmt,posStart,posStart,NULL,properties,PTX_SectionCell);
8963 if(pFG != NULL)
8964 {
8965 pFG->insertAtStrux(m_pDoc,72,posStart,
8966 PTX_SectionCell,sDataID.c_str());
8967 }
8968 else
8969 {
8970 const gchar * attributes[3] = {
8971 PT_STRUX_IMAGE_DATAID,NULL,NULL};
8972 bRet = m_pDoc->changeStruxFmt(PTC_RemoveFmt, posStart, posStart, attributes, NULL, PTX_SectionCell);
8973 }
8974 }
8975 else
8976 {
8977 UT_DEBUGMSG(("MARCM: Yikes! There is no cell at position (%dx%d)!\n", j, i));
8978 }
8979 }
8980 }
8981 }
8982 else
8983 {
8984 fp_CellContainer * cell = getCellAtPos(posStart);
8985 if (!cell)
8986 {
8987 // Allow table updates
8988 m_pDoc->setDontImmediatelyLayout(false);
8989
8990 // Signal PieceTable Changes have finished
8991 _restorePieceTableState();
8992 return false;
8993 }
8994 UT_DEBUGMSG(("MARCM: Current cell is at (%d,%d)\n", cell->getTopAttach(), cell->getLeftAttach()));
8995
8996 // get the number of rows and columns in the current table
8997 UT_sint32 numRows;
8998 UT_sint32 numCols;
8999 bRet = m_pDoc->getRowsColsFromTableSDH(tableSDH, isShowRevisions(), getRevisionLevel(), &numRows, &numCols);
9000 if(!bRet)
9001 {
9002 // Allow table updates
9003 m_pDoc->setDontImmediatelyLayout(false);
9004
9005 // Signal PieceTable Changes have finished
9006 _restorePieceTableState();
9007 return false;
9008 }
9009 UT_DEBUGMSG(("MARCM: Current table size is (%dx%d)\n", numRows, numCols));
9010
9011 // determine the range of the cells that should be adjusted
9012 UT_sint32 rowStart = 0;
9013 UT_sint32 rowEnd;
9014 UT_sint32 colStart = 0;
9015 UT_sint32 colEnd;
9016
9017 if(applyTo == FORMAT_TABLE_ROW )
9018 {
9019 rowStart = cell->getTopAttach();
9020 rowEnd = cell->getTopAttach();
9021 colStart = 0;
9022 colEnd = numCols-1;
9023 }
9024 else if( applyTo == FORMAT_TABLE_COLUMN)
9025 {
9026 rowStart = 0;
9027 rowEnd = numRows-1;
9028 colStart = cell->getLeftAttach();
9029 colEnd = cell->getLeftAttach();
9030 }
9031 else
9032 {
9033 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
9034 rowEnd = -1;
9035 colEnd = -1;
9036 }
9037 // Loop through the table cells to adjust their formatting
9038 UT_sint32 i;
9039 UT_sint32 j;
9040 for (j = rowStart; j <= rowEnd; j++)
9041 {
9042 for (i = colStart; i <= colEnd; i++)
9043 {
9044 pf_Frag_Strux* cellSDH = m_pDoc->getCellSDHFromRowCol(tableSDH, isShowRevisions(), getRevisionLevel(),
9045 j, i);
9046 if(cellSDH)
9047 {
9048 // Do the actual change
9049 posStart = m_pDoc->getStruxPosition(cellSDH)+1;
9050 bRet = m_pDoc->changeStruxFmt(PTC_AddFmt,posStart,posStart,NULL,properties,PTX_SectionCell);
9051 if(pFG != NULL)
9052 {
9053 pFG->insertAtStrux(m_pDoc,72,posStart,
9054 PTX_SectionCell,sDataID.c_str());
9055 }
9056 else
9057 {
9058 const gchar * attributes[3] = {
9059 PT_STRUX_IMAGE_DATAID,NULL,NULL};
9060 bRet = m_pDoc->changeStruxFmt(PTC_RemoveFmt,
9061 posStart,
9062 posStart,
9063 attributes,
9064 NULL,
9065 PTX_SectionCell);
9066 }
9067 }
9068 else
9069 {
9070 UT_DEBUGMSG(("MARCM: Yikes! There is no cell at position (%dx%d)!\n", j, i));
9071 }
9072 }
9073 }
9074 }
9075 // Now trigger a rebuild of the whole table by sending a changeStrux to the table strux
9076 // with the restored line-type property it has before.
9077 iLineType += 1;
9078 _restoreCellParams(posTable,iLineType);
9079
9080 // Allow table updates
9081 m_pDoc->setDontImmediatelyLayout(false);
9082
9083 // restore updates and clean up dirty lists
9084 m_pDoc->enableListUpdates();
9085
9086 // Signal PieceTable Changes have finished
9087 _restorePieceTableState();
9088
9089 _generalUpdate();
9090 m_pDoc->updateDirtyLists();
9091
9092 _ensureInsertionPointOnScreen();
9093 clearCursorWait();
9094 notifyListeners(AV_CHG_MOTION);
9095 return bRet;
9096 }
9097
9098 /*!
9099 Get the a particular property, such as the background color, of the cell containing the current cursor position
9100 \param col will be set to the cell to the property value, if the requested property exists
9101 \return True if succesful (ie. the property value is set), false otherwise
9102 */
getCellProperty(PT_DocPosition posCell,const gchar * szPropName,gchar * & szPropValue) const9103 bool FV_View::getCellProperty(PT_DocPosition posCell, const gchar * szPropName, gchar * &szPropValue) const
9104 {
9105 pf_Frag_Strux* cellSDH;
9106 bool bres = m_pDoc->getStruxOfTypeFromPosition(posCell,PTX_SectionCell,&cellSDH);
9107 if(!bres)
9108 {
9109 return false;
9110 }
9111 m_pDoc->getPropertyFromSDH(cellSDH,isShowRevisions(),getRevisionLevel(),szPropName,const_cast<const char **>(&szPropValue));
9112 if(szPropValue && *szPropValue)
9113 {
9114 return true;
9115 }
9116 else
9117 {
9118 return false;
9119 }
9120 }
9121
setTableFormat(const gchar * properties[])9122 bool FV_View::setTableFormat(const gchar * properties[])
9123 {
9124 PT_DocPosition pos = getPoint();
9125 return setTableFormat(pos, properties);
9126 }
9127
setTableFormat(PT_DocPosition pos,const gchar * properties[])9128 bool FV_View::setTableFormat(PT_DocPosition pos, const gchar * properties[])
9129 {
9130 bool bRet;
9131
9132 PT_DocPosition posStart = pos;
9133 pf_Frag_Strux* tableSDH = NULL;
9134 bRet = m_pDoc->getStruxOfTypeFromPosition(posStart, PTX_SectionTable, &tableSDH);
9135 if(!bRet)
9136 {
9137 UT_ASSERT(0);
9138 return false;
9139 }
9140 setCursorWait();
9141 //
9142 // Signal PieceTable Change
9143 _saveAndNotifyPieceTableChange();
9144 //
9145 // Put in call here to get start of the table
9146 //
9147 PT_DocPosition posEnd = posStart;
9148
9149 if (!isSelectionEmpty())
9150 {
9151 if (m_Selection.getSelectionAnchor() < posStart)
9152 posStart = m_Selection.getSelectionAnchor();
9153 else
9154 posEnd = m_Selection.getSelectionAnchor();
9155 if(posStart < 2)
9156 {
9157 posStart = 2;
9158 }
9159 }
9160 posStart = m_pDoc->getStruxPosition(tableSDH) +1 ;
9161 posEnd = posStart+1;
9162 bRet = m_pDoc->changeStruxFmt(PTC_AddFmt,posStart,posEnd,NULL,properties,PTX_SectionTable);
9163
9164 // Signal PieceTable Changes have finished
9165 _restorePieceTableState();
9166
9167 _generalUpdate();
9168 _ensureInsertionPointOnScreen();
9169 clearCursorWait();
9170 AV_View::notifyListeners(AV_CHG_MOTION);
9171 return bRet;
9172 }
9173
setSectionFormat(const gchar * properties[])9174 bool FV_View::setSectionFormat(const gchar * properties[])
9175 {
9176 bool bRet;
9177 setCursorWait();
9178 //
9179 // Signal PieceTable Change
9180 _saveAndNotifyPieceTableChange();
9181 if(isHdrFtrEdit())
9182 {
9183 clearHdrFtrEdit();
9184 warpInsPtToXY(0,0,false);
9185 }
9186
9187 // _clearIfAtFmtMark(getPoint()); TODO: This was giving problems
9188 // caused bug 431 when changing
9189 // columns.
9190
9191 PT_DocPosition posStart = getPoint();
9192 PT_DocPosition posEnd = posStart;
9193
9194 if (!isSelectionEmpty())
9195 {
9196 if (m_Selection.getSelectionAnchor() < posStart)
9197 posStart = m_Selection.getSelectionAnchor();
9198 else
9199 posEnd = m_Selection.getSelectionAnchor();
9200 if(posStart < 2)
9201 {
9202 posStart = 2;
9203 }
9204 }
9205
9206 bRet = m_pDoc->changeStruxFmt(PTC_AddFmt,posStart,posEnd,NULL,properties,PTX_Section);
9207
9208 _generalUpdate();
9209
9210 // Signal PieceTable Changes have finished
9211 _restorePieceTableState();
9212
9213 _generalUpdate();
9214
9215 // Signal PieceTable Changes have finished
9216 _restorePieceTableState();
9217 _ensureInsertionPointOnScreen();
9218 clearCursorWait();
9219 notifyListeners(AV_CHG_MOTION);
9220 return bRet;
9221 }
9222
9223 /*****************************************************************/
9224 /*****************************************************************/
9225
getTopRulerInfo(AP_TopRulerInfo * pInfo)9226 void FV_View::getTopRulerInfo(AP_TopRulerInfo * pInfo)
9227 {
9228 if(getPoint() == 0)
9229 {
9230 m_iFreePass = AV_CHG_COLUMN | AV_CHG_FMTSECTION | AV_CHG_FMTBLOCK | AV_CHG_HDRFTR;
9231 return;
9232 }
9233 getTopRulerInfo(getPoint(), pInfo);
9234 }
9235
getFrameMargin(void) const9236 UT_sint32 FV_View::getFrameMargin(void) const
9237 {
9238 return FRAME_MARGIN;// add 0.1 inch for a left border to click in
9239 }
9240
getNormalModeXOffset(void) const9241 UT_sint32 FV_View::getNormalModeXOffset(void) const
9242 {
9243 UT_ASSERT(getViewMode() != VIEW_PRINT);
9244 UT_sint32 iX = getTabToggleAreaWidth();
9245 XAP_Frame * pFrame = static_cast<XAP_Frame*>(getParentData());
9246 if(pFrame)
9247 {
9248 if(static_cast<AP_Frame *>(pFrame)->isShowMargin() && (getViewMode() != VIEW_WEB) )
9249 {
9250 iX += FRAME_MARGIN; // add 0.1 inch for a left border to click in
9251 }
9252 }
9253 return iX;
9254 }
9255
getTabToggleAreaWidth() const9256 UT_uint32 FV_View::getTabToggleAreaWidth() const
9257 {
9258 if(m_pTopRuler)
9259 return m_pTopRuler->getTabToggleAreaWidth();
9260 else
9261 #ifdef EMBEDDED_TARGET
9262 return (UT_uint32) ((float)m_pG->tlu(AP_TopRuler::getFixedWidth()) * 0.1);
9263 #else
9264 return m_pG->tlu(AP_TopRuler::getFixedWidth());
9265 #endif
9266 }
9267
setViewMode(ViewMode vm)9268 void FV_View::setViewMode (ViewMode vm)
9269 {
9270 bool bPrevWeb= (m_viewMode == VIEW_WEB);
9271 m_viewMode = vm;
9272
9273 UT_return_if_fail( m_pLayout );
9274 UT_DEBUGMSG(("View mode set calling updateviewonmodechange \n"));
9275 m_pLayout->updateOnViewModeChange();
9276 if(bPrevWeb)
9277 {
9278 rebuildLayout();
9279 m_pLayout->formatAll();
9280 _generalUpdate();
9281 }
9282 else
9283 {
9284 for(UT_sint32 i = 0; i < m_pLayout->countPages(); i++)
9285 {
9286 fp_Page * pPage = m_pLayout->getNthPage(i);
9287 UT_return_if_fail( pPage );
9288
9289 pPage->updateColumnX();
9290 }
9291 }
9292 _fixInsertionPointCoords();
9293
9294 }
9295
getTopRulerInfo(PT_DocPosition pos,AP_TopRulerInfo * pInfo)9296 void FV_View::getTopRulerInfo(PT_DocPosition pos,AP_TopRulerInfo * pInfo)
9297 {
9298 if(m_pDoc->isPieceTableChanging())
9299 {
9300 m_iFreePass = AV_CHG_COLUMN | AV_CHG_FMTSECTION | AV_CHG_FMTBLOCK | AV_CHG_HDRFTR;
9301 return;
9302 }
9303
9304 fl_BlockLayout * pBlock = NULL;
9305 fp_Run * pRun = NULL;
9306 UT_sint32 xCaret, yCaret;
9307 UT_uint32 heightCaret;
9308 UT_sint32 xCaret2, yCaret2;
9309 bool bDirection;
9310 _findPositionCoords(pos, m_bPointEOL, xCaret, yCaret, xCaret2, yCaret2, heightCaret, bDirection, &pBlock, &pRun);
9311
9312 //UT_return_if_fail(pRun);
9313 if(!pRun) return;
9314
9315 fp_Line * pLine = pRun->getLine();
9316 UT_return_if_fail(pLine);
9317
9318 fp_Container * pContainer = pLine->getContainer();
9319 UT_return_if_fail(pContainer);
9320
9321 fl_SectionLayout * pSection = pContainer->getSectionLayout();
9322 UT_return_if_fail(pSection);
9323
9324 /* clear pInfo */
9325 pInfo->~AP_TopRulerInfo();
9326 new(pInfo) AP_TopRulerInfo();
9327
9328 if (pSection->getType() == FL_SECTION_DOC || pSection->getContainerType() == FL_CONTAINER_FOOTNOTE || pSection->getContainerType() == FL_CONTAINER_ANNOTATION || pSection->getContainerType() == FL_CONTAINER_ENDNOTE)
9329 {
9330 fp_Column* pColumn = NULL;
9331 fl_DocSectionLayout* pDSL = NULL;
9332
9333 if(pSection->getType() == FL_SECTION_DOC)
9334 {
9335 pColumn = static_cast<fp_Column*>(pContainer);
9336 pDSL = static_cast<fl_DocSectionLayout*>(pSection);
9337 }
9338 else
9339 {
9340 fp_Page * pPage = pContainer->getPage();
9341 if(pPage)
9342 {
9343 pDSL = pPage->getOwningSection();
9344 pColumn = pPage->getNthColumnLeader(0);
9345 }
9346 else
9347 {
9348 return;
9349 }
9350 }
9351 if(!pColumn)
9352 return;
9353 UT_uint32 nCol=0;
9354 fp_Column * pNthColumn=pColumn->getLeader();
9355 while (pNthColumn && (pNthColumn != pColumn))
9356 {
9357 nCol++;
9358 pNthColumn = pNthColumn->getFollower();
9359 }
9360 pInfo->m_iCurrentColumn = nCol;
9361 pInfo->m_iNumColumns = pDSL->getNumColumns();
9362
9363 if((getViewMode() == VIEW_NORMAL) || (getViewMode() == VIEW_WEB))
9364 {
9365 pInfo->u.c.m_xaLeftMargin = getNormalModeXOffset();
9366 UT_sint32 iExtra = 72;
9367 pInfo->u.c.m_xaRightMargin = iExtra;
9368 }
9369 else
9370 {
9371 pInfo->u.c.m_xaLeftMargin = pDSL->getLeftMargin();
9372 pInfo->u.c.m_xaRightMargin = pDSL->getRightMargin();
9373 }
9374
9375 pInfo->u.c.m_xColumnGap = pDSL->getColumnGap();
9376 pInfo->u.c.m_xColumnWidth = pColumn->getWidth();
9377 if(pSection->getContainerType() == FL_CONTAINER_FOOTNOTE || pSection->getContainerType() == FL_CONTAINER_ANNOTATION )
9378 {
9379 pInfo->m_iCurrentColumn = 0;
9380 pInfo->m_iNumColumns = 1;
9381 pInfo->u.c.m_xColumnGap = 0;
9382 pInfo->u.c.m_xColumnWidth = pContainer->getWidth();
9383 }
9384 pInfo->m_mode = AP_TopRulerInfo::TRI_MODE_COLUMNS;
9385 pInfo->m_xrLeftIndent = pBlock->getLeftMargin();
9386 pInfo->m_xrRightIndent = pBlock->getRightMargin();
9387 pInfo->m_xrFirstLineIndent = pBlock->getTextIndent();
9388 xxx_UT_DEBUGMSG(("ap_TopRuler: xrPoint %d LeftIndent %d RightIndent %d Firs %d \n",pInfo->m_xrPoint,pInfo->m_xrLeftIndent,pInfo->m_xrRightIndent, pInfo->m_xrFirstLineIndent));
9389 }
9390 else if(isHdrFtrEdit() && (pSection->getContainerType() != FL_CONTAINER_CELL))
9391 {
9392 fp_Column* pColumn = static_cast<fp_Column*>(pContainer);
9393 fl_DocSectionLayout* pDSL = static_cast<fl_DocSectionLayout*>(pSection);
9394 pDSL = m_pEditShadow->getHdrFtrSectionLayout()->getDocSectionLayout();
9395
9396 pInfo->m_iCurrentColumn = 0;
9397 pInfo->m_iNumColumns = 1;
9398
9399 if((getViewMode() == VIEW_NORMAL) || (getViewMode() == VIEW_WEB))
9400 {
9401 pInfo->u.c.m_xaLeftMargin = getNormalModeXOffset();
9402 UT_sint32 iExtra = 72;
9403 pInfo->u.c.m_xaRightMargin = iExtra;
9404 }
9405 else
9406 {
9407 pInfo->u.c.m_xaLeftMargin = pDSL->getLeftMargin();
9408 pInfo->u.c.m_xaRightMargin = pDSL->getRightMargin();
9409 }
9410
9411 pInfo->u.c.m_xColumnGap = pDSL->getColumnGap();
9412 pInfo->u.c.m_xColumnWidth = pColumn->getWidth();
9413 pInfo->m_mode = AP_TopRulerInfo::TRI_MODE_COLUMNS;
9414
9415 pInfo->m_xrPoint = xCaret - pContainer->getX();
9416 pInfo->m_xrLeftIndent = pBlock->getLeftMargin();
9417 pInfo->m_xrRightIndent = pBlock->getRightMargin();
9418 pInfo->m_xrFirstLineIndent = pBlock->getTextIndent();
9419 }
9420 else if(pSection->getContainerType() == FL_CONTAINER_CELL)
9421 {
9422 fp_CellContainer * pCell = static_cast<fp_CellContainer *>(pContainer);
9423 fl_DocSectionLayout* pDSL = pSection->getDocSectionLayout();
9424 fp_VerticalContainer * pColumn = static_cast<fp_Column *>(pCell->getColumn(pLine));
9425 if(pColumn == NULL)
9426 {
9427 return;
9428 }
9429 fp_FrameContainer * pFrameC = NULL;
9430 UT_uint32 nCol=0;
9431 if(isInFrame(getPoint()))
9432 {
9433 fp_Container * pCon = pCell->getContainer();
9434 while(pCon && !pCon->isColumnType())
9435 {
9436 pCon = pCon->getContainer();
9437 }
9438 if(pCon == NULL)
9439 {
9440 return;
9441 }
9442 if(pCon->getContainerType() == FP_CONTAINER_FRAME)
9443 {
9444 pFrameC = static_cast<fp_FrameContainer *>(pCon);
9445 }
9446 else
9447 {
9448 return;
9449 }
9450 fp_Page * pPage = pFrameC->getPage();
9451 if(pPage == NULL)
9452 {
9453 return;
9454 }
9455 pInfo->m_iCurrentColumn = 0;
9456 pInfo->m_iNumColumns = 1;
9457 pInfo->u.c.m_xaLeftMargin = pFrameC->getFullX();
9458 pInfo->u.c.m_xaRightMargin = pDSL->getRightMargin();
9459 pInfo->u.c.m_xColumnGap = 0;
9460 pInfo->u.c.m_xaRightMargin = pPage->getWidth() - pFrameC->getFullX() - pFrameC->getFullWidth();
9461 pInfo->m_xrPoint = xCaret - pFrameC->getX();
9462 pInfo->u.c.m_xColumnWidth = pFrameC->getFullWidth();
9463 }
9464 else
9465 {
9466
9467 if(pColumn->getContainerType() == FP_CONTAINER_COLUMN)
9468 {
9469 fp_Column * pNthColumn=static_cast<fp_Column *>(pColumn)->getLeader();
9470 while (pNthColumn && (pNthColumn != pColumn))
9471 {
9472 nCol++;
9473 pNthColumn = pNthColumn->getFollower();
9474 }
9475 pInfo->m_iCurrentColumn = nCol;
9476 pInfo->m_iNumColumns = pDSL->getNumColumns();
9477 }
9478 else
9479 {
9480 pInfo->m_iCurrentColumn = 0;
9481 pInfo->m_iNumColumns = 1;
9482
9483 }
9484
9485 if((getViewMode() == VIEW_NORMAL) || (getViewMode() == VIEW_WEB))
9486 {
9487 pInfo->u.c.m_xaLeftMargin = m_pTopRuler ? m_pTopRuler->getTabToggleAreaWidth() : 0;
9488 pInfo->u.c.m_xaRightMargin = 0;
9489 }
9490 else
9491 {
9492 pInfo->u.c.m_xaLeftMargin = pDSL->getLeftMargin();
9493 pInfo->u.c.m_xaRightMargin = pDSL->getRightMargin();
9494 }
9495
9496 pInfo->u.c.m_xColumnGap = pDSL->getColumnGap();
9497 pInfo->u.c.m_xColumnWidth = pColumn->getWidth();
9498 pInfo->m_xrPoint = xCaret - pContainer->getX();
9499 }
9500 pInfo->m_mode = AP_TopRulerInfo::TRI_MODE_TABLE;
9501 pInfo->m_xrLeftIndent = pBlock->getLeftMargin();
9502 pInfo->m_xrRightIndent = pBlock->getRightMargin();
9503 pInfo->m_xrFirstLineIndent = pBlock->getTextIndent();
9504 fp_TableContainer * pTab = static_cast<fp_TableContainer *>(pCell->getContainer());
9505 fl_TableLayout * pTL = static_cast<fl_TableLayout *>(pTab->getSectionLayout());
9506 if (!pTL || !pTL->isInitialLayoutCompleted())
9507 {
9508 // The table initialization is not yet completed
9509 return;
9510 }
9511 UT_sint32 row = pCell->getTopAttach();
9512 UT_sint32 numcols = pTab->getNumCols();
9513 //UT_sint32 numrows = pTab->getNumRows();
9514 UT_sint32 i =0;
9515 fp_CellContainer * pCur = NULL;
9516 UT_sint32 iCellCount = 0;
9517 pInfo->m_vecTableColInfo = new UT_GenericVector<AP_TopRulerTableInfo*>();
9518 while( i < numcols)
9519 {
9520 pCur = pTab->getCellAtRowColumn(row,i);
9521 if(pCur == pCell)
9522 {
9523 pInfo->m_iCurCell = iCellCount;
9524 }
9525 UT_sint32 ioff_x = 0;
9526 fp_Container * pCon = static_cast<fp_Container*>(pTab->getContainer());
9527 while(pCon && !pCon->isColumnType())
9528 {
9529 ioff_x += pCon->getX();
9530 pCon = static_cast<fp_Container *>(pCon->getContainer());
9531 }
9532 if(pCur)
9533 {
9534 AP_TopRulerTableInfo *pTInfo = new AP_TopRulerTableInfo;
9535 pTInfo->m_pCell = pCur;
9536 pTInfo->m_iLeftCellPos = pCur->getLeftPos() +ioff_x;
9537 pTInfo->m_iRightCellPos = pCur->getRightPos() +ioff_x;
9538 pTInfo->m_iLeftSpacing = (pCur->getX() - pCur->getLeftPos());
9539 pTInfo->m_iRightSpacing = ( pCur->getRightPos() - pCur->getX()
9540 - pCur->getWidth());
9541 pInfo->m_vecTableColInfo->addItem(pTInfo);
9542 xxx_UT_DEBUGMSG(("TableColInfo RightPos %d LeftPos %d \n", pTInfo->m_iRightCellPos,pTInfo->m_iLeftCellPos));
9543 i = pCur->getRightAttach();
9544 iCellCount++;
9545 }
9546 else
9547 {
9548 i = numcols + 1;
9549 }
9550 }
9551 pInfo->m_iCells = pInfo->m_vecTableColInfo->getItemCount();
9552 //
9553 // Now fill the full vector including merged cells.
9554 //
9555 pInfo->m_vecFullTable = new UT_GenericVector<AP_TopRulerTableInfo *>();
9556 fp_TableRowColumn * pRC = NULL;
9557 UT_sint32 iCum = 0;
9558 UT_sint32 ioff_x = 0;
9559 fp_Container * pCon = static_cast<fp_Container*>(pTab->getContainer());
9560 while(!pCon->isColumnType())
9561 {
9562 ioff_x += pCon->getX();
9563 pCon = static_cast<fp_Container *>(pCon->getContainer());
9564 }
9565 xxx_UT_DEBUGMSG(("Initial X %d \n",ioff_x));
9566 pCur = pTab->getCellAtRowColumn(0,0);
9567 UT_return_if_fail(pCur);
9568 ioff_x += pCur->getLeftPos();
9569 pRC = pTab->getNthCol(0);
9570 xxx_UT_DEBUGMSG(("Tab X %d LeftPos %d Spacing %d \n",pTab->getX(),pCur->getLeftPos(),pRC->spacing));
9571 for( i=0;i < numcols;i++)
9572 {
9573 pCur = pTab->getCellAtRowColumn(0,i);
9574 pRC = pTab->getNthCol(i);
9575 UT_sint32 width = pRC->allocation + pRC->spacing;
9576 if(pCur)
9577 {
9578 AP_TopRulerTableInfo *pTInfo = new AP_TopRulerTableInfo;
9579 pTInfo->m_pCell = pCur;
9580 pTInfo->m_iLeftCellPos = iCum +ioff_x;
9581 pTInfo->m_iRightCellPos = iCum + width +ioff_x;
9582 pTInfo->m_iLeftSpacing = pRC->spacing/2;
9583 pTInfo->m_iRightSpacing = pRC->spacing/2;
9584 if(i== (numcols -1))
9585 {
9586 // pTInfo->m_iRightCellPos -= pTab->getBorderWidth()/2;
9587 pTInfo->m_iRightCellPos -= pTInfo->m_iRightSpacing;
9588 xxx_UT_DEBUGMSG(("FullTable RightPos %d Spacing %d \n", pTInfo->m_iRightCellPos,pTInfo->m_iRightSpacing));
9589 }
9590 pInfo->m_vecFullTable->addItem(pTInfo);
9591 xxx_UT_DEBUGMSG(("FullTable RightPos %d LeftPos %d \n", pTInfo->m_iRightCellPos,pTInfo->m_iLeftCellPos));
9592 }
9593 iCum += width;
9594 }
9595 }
9596 else if(pContainer->getContainerType() == FP_CONTAINER_FRAME && (getViewMode() != VIEW_NORMAL) && (getViewMode() != VIEW_WEB))
9597 {
9598 fp_FrameContainer * pFC = static_cast<fp_FrameContainer *>(pContainer);
9599 fl_FrameLayout * pFL = static_cast<fl_FrameLayout *>(pSection);
9600 pInfo->m_mode = AP_TopRulerInfo::TRI_MODE_FRAME;
9601 fl_DocSectionLayout * pDSL = pFL->getDocSectionLayout();
9602 if(pDSL == NULL)
9603 {
9604 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
9605 return;
9606 }
9607 pInfo->m_iCurrentColumn = 0;
9608 pInfo->m_iNumColumns = 1;
9609 fp_Page * pPage = pFC->getPage();
9610 if(pPage == NULL)
9611 {
9612 return;
9613 }
9614 pInfo->u.c.m_xaLeftMargin = pFC->getFullX();
9615 pInfo->u.c.m_xColumnGap = 0;
9616 pInfo->u.c.m_xColumnWidth = pFC->getFullWidth();
9617 pInfo->u.c.m_xaRightMargin = pPage->getWidth() - pFC->getFullX() - pFC->getFullWidth();
9618
9619 pInfo->m_xrPoint = xCaret - pFC->getX();
9620 pInfo->m_xrLeftIndent = pBlock->getLeftMargin();
9621 pInfo->m_xrRightIndent = pBlock->getRightMargin();
9622 pInfo->m_xrFirstLineIndent = pBlock->getTextIndent();
9623
9624 }
9625 else
9626 {
9627 // fill in the details
9628 }
9629
9630 static UT_String buf;
9631
9632 {
9633 UT_LocaleTransactor t(LC_NUMERIC, "C");
9634 buf = UT_String_sprintf ("%.4fin", m_pDoc->m_docPageSize.Width(DIM_IN));
9635 }
9636
9637 pInfo->m_xPaperSize = UT_convertToLogicalUnits(buf.c_str());
9638 pInfo->m_xPageViewMargin = getPageViewLeftMargin();
9639
9640 pInfo->m_pfnEnumTabStops = fl_BlockLayout::s_EnumTabStops;
9641 pInfo->m_pVoidEnumTabStopsData = static_cast<void *>(pBlock);
9642 pInfo->m_iTabStops = static_cast<UT_sint32>(pBlock->getTabsCount());
9643 pInfo->m_iDefaultTabInterval = pBlock->getDefaultTabInterval();
9644 pInfo->m_pszTabStops = pBlock->getProperty("tabstops");
9645
9646 return;
9647 }
9648
getLeftRulerInfo(AP_LeftRulerInfo * pInfo)9649 void FV_View::getLeftRulerInfo(AP_LeftRulerInfo * pInfo)
9650 {
9651 //
9652 // Can't do this before the layouts are filled.
9653 //
9654 if(getPoint()== 0)
9655 {
9656 m_iFreePass = AV_CHG_COLUMN | AV_CHG_FMTSECTION | AV_CHG_FMTBLOCK | AV_CHG_HDRFTR;
9657 return;
9658 }
9659 getLeftRulerInfo(getPoint(),pInfo);
9660 }
9661
getLeftRulerInfo(PT_DocPosition pos,AP_LeftRulerInfo * pInfo)9662 void FV_View::getLeftRulerInfo(PT_DocPosition pos, AP_LeftRulerInfo * pInfo)
9663 {
9664 //
9665 // Clear out the old table info
9666 //
9667 if(m_pDoc->isPieceTableChanging())
9668 {
9669 m_iFreePass = AV_CHG_COLUMN | AV_CHG_FMTSECTION | AV_CHG_FMTBLOCK | AV_CHG_HDRFTR;
9670 return;
9671 }
9672
9673 /* clear pInfo */
9674 pInfo->~AP_LeftRulerInfo();
9675 new(pInfo) AP_LeftRulerInfo();
9676
9677 xxx_UT_DEBUGMSG(("ap_LeftRulerInfo: get Leftruler info \n"));
9678
9679 if (1)
9680 {
9681 // we assume that we are in a column context (rather than a table)
9682
9683 pInfo->m_mode = AP_LeftRulerInfo::TRI_MODE_COLUMNS;
9684
9685 fl_BlockLayout * pBlock = NULL;
9686 fp_Run * pRun = NULL;
9687 UT_sint32 xCaret, yCaret;
9688 UT_uint32 heightCaret;
9689 UT_sint32 xCaret2, yCaret2;
9690 bool bDirection;
9691 _findPositionCoords(pos, m_bPointEOL, xCaret, yCaret, xCaret2, yCaret2, heightCaret, bDirection, &pBlock, &pRun);
9692
9693 // UT_ASSERT(pRun); // We always recover after this so no assert.
9694 //
9695 // No useful info here. Just return 0
9696 //
9697 if(!pRun)
9698 {
9699 pInfo->m_yPageStart = 0;
9700 pInfo->m_yPageSize = 0;
9701 pInfo->m_yPoint = 0;
9702 pInfo->m_yTopMargin = 0;
9703 pInfo->m_yBottomMargin = 0;
9704 return;
9705 }
9706 //
9707 // No useful info here. Just return 0
9708 //
9709 UT_ASSERT(pRun->getLine());
9710 if(!pRun->getLine())
9711 {
9712 pInfo->m_yPageStart = 0;
9713 pInfo->m_yPageSize = 0;
9714 pInfo->m_yPoint = 0;
9715 pInfo->m_yTopMargin = 0;
9716 pInfo->m_yBottomMargin = 0;
9717 return;
9718 }
9719 fl_SectionLayout * pSection = NULL;
9720 fl_DocSectionLayout * pDSL2 = NULL;
9721 fp_Container * pContainer = pRun->getLine()->getContainer();
9722 if(pContainer == NULL)
9723 {
9724 pInfo->m_yPageStart = 0;
9725 pInfo->m_yPageSize = 0;
9726 pInfo->m_yPoint = 0;
9727 pInfo->m_yTopMargin = 0;
9728 pInfo->m_yBottomMargin = 0;
9729 return;
9730 }
9731
9732 bool isFootnote = false;
9733 bool isAnnotation = false;
9734 bool isEndnote = false;
9735 xxx_UT_DEBUGMSG(("ap_leftRulerInfo: container type %d \n",pContainer->getContainerType()));
9736 fp_Page * pPage = pRun->getLine()->getPage();
9737 if(pPage == NULL)
9738 {
9739 pInfo->m_yPageStart = 0;
9740 pInfo->m_yPageSize = 0;
9741 pInfo->m_yPoint = 0;
9742 pInfo->m_yTopMargin = 0;
9743 pInfo->m_yBottomMargin = 0;
9744 return;
9745 }
9746
9747 if(pContainer->getContainerType() == FP_CONTAINER_FOOTNOTE)
9748 {
9749 pSection = pPage->getOwningSection();
9750 pDSL2 = static_cast<fl_DocSectionLayout *>(pSection);
9751 isFootnote = true;
9752 xxx_UT_DEBUGMSG(("ap_LeftRulerInfo: Found footnote at point \n"));
9753 }
9754 else if(pContainer->getContainerType() == FP_CONTAINER_ENDNOTE)
9755 {
9756 pSection = pPage->getOwningSection();
9757 pDSL2 = static_cast<fl_DocSectionLayout *>(pSection);
9758 isEndnote = true;
9759 xxx_UT_DEBUGMSG(("ap_LeftRulerInfo: Found footnote at point \n"));
9760 }
9761 else if(pContainer->getContainerType() == FP_CONTAINER_ANNOTATION)
9762 {
9763 pSection = pPage->getOwningSection();
9764 pDSL2 = static_cast<fl_DocSectionLayout *>(pSection);
9765 isAnnotation = true;
9766 xxx_UT_DEBUGMSG(("ap_LeftRulerInfo: Found footnote at point \n"));
9767 }
9768 else
9769 {
9770 pSection = pPage->getOwningSection();
9771 pDSL2 = static_cast<fl_DocSectionLayout*>(pSection);
9772 }
9773 pInfo->m_yPoint = yCaret - pContainer->getY();
9774
9775 if ((isFootnote || isAnnotation || isEndnote || pContainer->getContainerType() == FP_CONTAINER_COLUMN) && !isHdrFtrEdit())
9776 {
9777 UT_sint32 yoff = 0;
9778 getPageYOffset(pPage, yoff);
9779 pInfo->m_yPageStart = static_cast<UT_uint32>(yoff);
9780 pInfo->m_yPageSize = pPage->getHeight();
9781
9782 pInfo->m_yTopMargin = pDSL2->getTopMargin();
9783 UT_ASSERT(pInfo->m_yTopMargin>= 0);
9784
9785 pInfo->m_yBottomMargin = pDSL2->getBottomMargin();
9786 }
9787 else if(pContainer->getContainerType() == FP_CONTAINER_CELL)
9788 {
9789 fp_CellContainer * pCell = static_cast<fp_CellContainer *>(pContainer);
9790 fl_ContainerLayout * pCL = pSection->myContainingLayout();
9791 pInfo->m_mode = AP_LeftRulerInfo::TRI_MODE_TABLE;
9792 while(pCL && pCL->getContainerType() != FL_CONTAINER_DOCSECTION)
9793 {
9794 pCL = pCL->myContainingLayout();
9795 }
9796 fl_DocSectionLayout * pDSL = static_cast<fl_DocSectionLayout *>(pCL);
9797 if(pDSL == NULL)
9798 {
9799 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
9800 return;
9801 }
9802
9803 UT_sint32 yoff = 0;
9804 getPageYOffset(pPage, yoff);
9805 pInfo->m_yPageStart = static_cast<UT_uint32>(yoff);
9806 pInfo->m_yPageSize = pPage->getHeight();
9807 pDSL = pPage->getOwningSection();
9808 if(!isInFrame(getPoint()))
9809 {
9810 pInfo->m_yTopMargin = pDSL->getTopMargin();
9811 UT_ASSERT(pInfo->m_yTopMargin>= 0);
9812
9813 pInfo->m_yBottomMargin = pDSL->getBottomMargin();
9814 }
9815 else
9816 {
9817 getPageYOffset(pPage, yoff);
9818 pInfo->m_yPageStart = static_cast<UT_uint32>(yoff);
9819 pInfo->m_yPageSize = pPage->getHeight();
9820 fp_FrameContainer * pFC = static_cast<fp_FrameContainer *>(getFrameLayout()->getFirstContainer());
9821
9822 pInfo->m_yTopMargin = pFC->getFullY();
9823 UT_ASSERT(pInfo->m_yTopMargin>= 0);
9824
9825 pInfo->m_yBottomMargin = pPage->getHeight() - pFC->getFullY() - pFC->getFullHeight();
9826 }
9827 fp_TableContainer * pTab = static_cast<fp_TableContainer *>(pCell->getContainer());
9828 xxx_UT_DEBUGMSG(("In getLeftRulerInfo pCell %x pTab %x \n",pCell,pTab));
9829 UT_sint32 col = pCell->getLeftAttach();
9830 UT_sint32 numrows = pTab->getNumRows();
9831 UT_sint32 i =0;
9832 fp_CellContainer * pCur = NULL;
9833 pInfo->m_vecTableRowInfo = new UT_GenericVector<AP_LeftRulerTableInfo*>();
9834 pCur = pTab->getCellAtRowColumn(0,col);
9835 fp_CellContainer * pPrev = pCur;
9836 while( i < numrows)
9837 {
9838 bool bFound = false;
9839 pPrev = pCur;
9840 while(pCur && !bFound)
9841 {
9842 if(pCur->getLeftAttach() <= col &&
9843 pCur->getRightAttach() > col &&
9844 pCur->getTopAttach() <= i &&
9845 pCur->getBottomAttach() > i)
9846 {
9847 bFound = true;
9848 }
9849 else
9850 {
9851 pCur = static_cast<fp_CellContainer *>(pCur->getNext());
9852 }
9853 }
9854 if(pCur == pCell)
9855 {
9856 pInfo->m_iCurrentRow = i;
9857 }
9858 if(pCur)
9859 {
9860 AP_LeftRulerTableInfo *pLInfo = new AP_LeftRulerTableInfo;
9861 pLInfo->m_pCell = pCur;
9862 pLInfo->m_iTopCellPos = pCur->getStartY();
9863 pLInfo->m_iBotCellPos = pCur->getStopY();
9864 pLInfo->m_iTopSpacing = pCur->getY() - pCur->getStartY();
9865 pLInfo->m_iBotSpacing = pCur->getStopY() - (pCur->getY() + pCur->getHeight());
9866 pInfo->m_vecTableRowInfo->addItem(pLInfo);
9867 i = pCur->getBottomAttach();
9868 }
9869 else
9870 {
9871 pCur= pPrev;
9872 i = numrows + 1;
9873 }
9874 }
9875 pInfo->m_iNumRows = pInfo->m_vecTableRowInfo->getItemCount();
9876 }
9877 else if(pContainer->getContainerType() == FP_CONTAINER_FRAME)
9878 {
9879 fp_FrameContainer * pFC = static_cast<fp_FrameContainer *>(pContainer);
9880 fl_FrameLayout * pFL = static_cast<fl_FrameLayout *>(pFC->getSectionLayout());
9881 pInfo->m_mode = AP_LeftRulerInfo::TRI_MODE_FRAME;
9882 fl_DocSectionLayout * pDSL = pFL->getDocSectionLayout();
9883 if(pDSL == NULL)
9884 {
9885 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
9886 return;
9887 }
9888 UT_sint32 yoff = 0;
9889 getPageYOffset(pPage, yoff);
9890 pInfo->m_yPageStart = static_cast<UT_uint32>(yoff);
9891 pInfo->m_yPageSize = pPage->getHeight();
9892
9893 pInfo->m_yTopMargin = pFC->getFullY();
9894 UT_ASSERT(pInfo->m_yTopMargin>= 0);
9895
9896 pInfo->m_yBottomMargin = pPage->getHeight() - pFC->getFullY() - pFC->getFullHeight();
9897 }
9898 else if(isHdrFtrEdit())
9899 {
9900 fl_HdrFtrSectionLayout * pHF = m_pEditShadow->getHdrFtrSectionLayout();
9901 pDSL2 = pHF->getDocSectionLayout();
9902 UT_sint32 yoff = 0;
9903 getPageYOffset(pPage, yoff);
9904 pInfo->m_yPageStart = static_cast<UT_uint32>(yoff);
9905 pInfo->m_yPageSize = pPage->getHeight();
9906
9907 if(pHF->getHFType() >= FL_HDRFTR_FOOTER)
9908 {
9909 pInfo->m_yTopMargin = pPage->getHeight() - pDSL2->getBottomMargin();
9910 UT_ASSERT(pInfo->m_yTopMargin>= 0);
9911 pInfo->m_yBottomMargin = pDSL2->getFooterMargin();
9912 }
9913 else
9914 {
9915 pInfo->m_yTopMargin = pDSL2->getHeaderMargin();
9916 UT_ASSERT(pInfo->m_yTopMargin>= 0);
9917 pInfo->m_yBottomMargin = pPage->getHeight() - pDSL2->getTopMargin();
9918 }
9919
9920 }
9921 else
9922 {
9923 }
9924 }
9925 else
9926 {
9927 // other yet to be written contexts (frames?)
9928 }
9929 UT_ASSERT(pInfo->m_yTopMargin>= 0);
9930 return;
9931 }
9932
9933
isXYSelected(UT_sint32 xPos,UT_sint32 yPos) const9934 bool FV_View::isXYSelected(UT_sint32 xPos, UT_sint32 yPos) const
9935 {
9936 if (isSelectionEmpty())
9937 return false;
9938
9939 UT_sint32 xClick, yClick;
9940 fp_Page* pPage = _getPageForXY(xPos, yPos, xClick, yClick);
9941 if (!pPage)
9942 return false;
9943
9944 if ( (yClick < 0)
9945 || (xClick < 0)
9946 || (xClick > pPage->getWidth()) )
9947 {
9948 return false;
9949 }
9950
9951 PT_DocPosition pos;
9952 bool bBOL, bEOL,isTOC;
9953 pPage->mapXYToPosition(xClick, yClick, pos, bBOL, bEOL,isTOC, true);
9954
9955 return isPosSelected(pos);
9956 }
9957
9958 /*!
9959 * Returns a pointer to the cell container surrounding the supplied point
9960 * Return NULL if there isn't one.
9961 */
getCellAtPos(PT_DocPosition pos) const9962 fp_CellContainer * FV_View::getCellAtPos(PT_DocPosition pos) const
9963 {
9964 bool bEOL = false;
9965 UT_uint32 iPointHeight;
9966 UT_sint32 xPoint, yPoint, xPoint2, yPoint2;
9967 bool bDirection;
9968 fl_BlockLayout* pBlock;
9969 fp_Run* pRun;
9970 _findPositionCoords(pos, bEOL, xPoint, yPoint, xPoint2, yPoint2, iPointHeight, bDirection, &pBlock, &pRun);
9971 fp_CellContainer * pCell = NULL;
9972 if(isInTable(pos))
9973 {
9974 fp_Line * pLine = pRun->getLine();
9975 if(pLine)
9976 {
9977 pCell = static_cast<fp_CellContainer *>(pLine->getContainer());
9978 if(pCell && pCell->getContainerType() == FP_CONTAINER_CELL)
9979 {
9980 return pCell;
9981 }
9982 }
9983 const fl_ContainerLayout * pCL = pBlock->myContainingLayout();
9984 if((pCL->getContainerType() == FL_CONTAINER_FOOTNOTE) ||
9985 (pCL->getContainerType() == FL_CONTAINER_ANNOTATION)||
9986 (pCL->getContainerType() == FL_CONTAINER_ENDNOTE))
9987 {
9988 pBlock = pBlock->getEnclosingBlock();
9989 if(pBlock == NULL)
9990 {
9991 return NULL;
9992 }
9993 pCL = pBlock->myContainingLayout();
9994 if(pCL->getContainerType() == FL_CONTAINER_CELL)
9995 {
9996 return static_cast<fp_CellContainer *>(pCL->getFirstContainer());
9997 }
9998 }
9999 }
10000 return NULL;
10001 }
10002
getHyperLinkRun(PT_DocPosition pos)10003 fp_Run * FV_View::getHyperLinkRun(PT_DocPosition pos)
10004 {
10005 fl_BlockLayout* pBlock =_findBlockAtPosition(pos);
10006 fp_Run* pRun = NULL;
10007
10008 if(pBlock)
10009 {
10010 UT_uint32 blockOffset = pos - pBlock->getPosition();
10011 pRun = pBlock->findRunAtOffset(blockOffset);
10012 }
10013 xxx_UT_DEBUGMSG(("FV_View::getHyperLinkRun(top) block:%p run:%p\n", pBlock, pRun ));
10014 if( pRun )
10015 {
10016 xxx_UT_DEBUGMSG(("FV_View::getHyperLinkRun(top) run.t:%d\n", pRun->getType() ));
10017 xxx_UT_DEBUGMSG(("FV_View::getHyperLinkRun(top) run.w:%d\n", pRun->getWidth() ));
10018 xxx_UT_DEBUGMSG(("FV_View::getHyperLinkRun(top) run.hl:%p\n", pRun->getHyperlink() ));
10019 }
10020 // Make sure we found the starting pRun for an annotation which is
10021 // a single point in the document.
10022 if( pRun && pRun->getType() == FPRUN_HYPERLINK && pRun->getWidth() == 0 )
10023 {
10024 pRun = pRun->getPrevRun();
10025 }
10026
10027 //
10028 // If we didn't find the hyperlink run, then we might be dealing
10029 // with an annotation that is a single point rather than a range.
10030 // As such, grab the previous run and check if it is a hyperlink,
10031 // if so then make sure we return the run for the start of the hyperlink
10032 //
10033 if( pRun && pRun->getType() != FPRUN_HYPERLINK && !pRun->getHyperlink() )
10034 {
10035 xxx_UT_DEBUGMSG(("FV_View::getHyperLinkRun(1) run.x:%d\n", pRun->getX() ));
10036 xxx_UT_DEBUGMSG(("FV_View::getHyperLinkRun(1) run.w:%d\n", pRun->getWidth() ));
10037 xxx_UT_DEBUGMSG(("FV_View::getHyperLinkRun(1) run.t:%d\n", pRun->getType() ));
10038 xxx_UT_DEBUGMSG(("FV_View::getHyperLinkRun(1) run.nl:%p\n", pRun->getHyperlink() ));
10039 if( pRun->getPrevRun() && pRun->getPrevRun()->getType() == FPRUN_HYPERLINK )
10040 {
10041 xxx_UT_DEBUGMSG(("FV_View::getHyperLinkRun(prev) run.x:%d\n", pRun->getX() ));
10042 pRun = pRun->getPrevRun();
10043 if( pRun->getWidth() == 0 )
10044 pRun = pRun->getPrevRun();
10045 }
10046 else if( pRun->getNextRun() && pRun->getNextRun()->getType() == FPRUN_HYPERLINK )
10047 {
10048 xxx_UT_DEBUGMSG(("FV_View::getHyperLinkRun(next) run.x:%d\n", pRun->getX() ));
10049 pRun = pRun->getNextRun();
10050 xxx_UT_DEBUGMSG(("FV_View::getHyperLinkRun(next) run.type:%d\n", pRun->getType() ));
10051 xxx_UT_DEBUGMSG(("FV_View::getHyperLinkRun(next) run. hl:%p\n", pRun->getHyperlink() ));
10052 }
10053
10054 if( pRun )
10055 {
10056 xxx_UT_DEBUGMSG(("FV_View::getHyperLinkRun(2) run.x:%d\n", pRun->getX() ));
10057 xxx_UT_DEBUGMSG(("FV_View::getHyperLinkRun(2) run.w:%d\n", pRun->getWidth() ));
10058 xxx_UT_DEBUGMSG(("FV_View::getHyperLinkRun(2) run.t:%d\n", pRun->getType() ));
10059 }
10060
10061 if( pRun && pRun->getType() != FPRUN_HYPERLINK )
10062 {
10063 xxx_UT_DEBUGMSG(("FV_View::getHyperLinkRun(3 reset) run.x:%d\n", pRun->getX() ));
10064 pRun = 0;
10065 }
10066 }
10067 if(pRun && pRun->getHyperlink() != NULL)
10068 {
10069 xxx_UT_DEBUGMSG(("FV_View::getHyperLinkRun(ret) run.hl:%p\n", pRun->getHyperlink() ));
10070 return pRun->getHyperlink();
10071 }
10072
10073 xxx_UT_DEBUGMSG(("FV_View::getHyperLinkRun(end fail)\n" ));
10074 return NULL;
10075 }
10076
getLastMouseContext(void)10077 EV_EditMouseContext FV_View::getLastMouseContext(void)
10078 {
10079 return m_prevMouseContext;
10080 }
10081
getMousePos(UT_sint32 * x,UT_sint32 * y)10082 void FV_View::getMousePos(UT_sint32 *x, UT_sint32 * y)
10083 {
10084 *x = m_iMouseX;
10085 *y = m_iMouseY;
10086 }
10087
10088 // #undef xxx_UT_DEBUGMSG
10089 // #define xxx_UT_DEBUGMSG(x) UT_DEBUGMSG(x)
10090
getMouseContext(UT_sint32 xPos,UT_sint32 yPos)10091 EV_EditMouseContext FV_View::getMouseContext(UT_sint32 xPos, UT_sint32 yPos)
10092 {
10093 xxx_UT_DEBUGMSG(("layout view mouse pos x %d pos y %d \n",xPos,yPos));
10094 EV_EditMouseContext emc = _getMouseContext(xPos,yPos);
10095
10096 if (isAnnotationPreviewActive() && (emc != EV_EMC_HYPERLINK))
10097 {
10098 // kill the annotation preview popup
10099 UT_DEBUGMSG(("getMouseContext: Deleting previous annotation preview...\n"));
10100 killAnnotationPreview();
10101 }
10102 if(emc == EV_EMC_HYPERLINK)
10103 {
10104 xxx_UT_DEBUGMSG(("In Hyperlink \n"));
10105 }
10106 xxx_UT_DEBUGMSG(("Mouse Context %d \n",emc));
10107 return emc;
10108 }
10109
10110
_getMouseContext(UT_sint32 xPos,UT_sint32 yPos)10111 EV_EditMouseContext FV_View::_getMouseContext(UT_sint32 xPos, UT_sint32 yPos)
10112 {
10113 xxx_UT_DEBUGMSG(("layout view mouse pos x %d pos y %d \n",xPos,yPos));
10114 UT_sint32 xClick, yClick;
10115 PT_DocPosition pos = 0;
10116 bool bBOL = false;
10117 bool bEOL = false;
10118 bool isTOC = false;
10119 UT_uint32 iPointHeight;
10120 UT_sint32 xPoint, yPoint, xPoint2, yPoint2;
10121 bool bDirection;
10122 m_iMouseX = xPos;
10123 m_iMouseY = yPos;
10124
10125 if(getPoint() == 0) // We haven't loaded any layouts yet
10126 {
10127 return EV_EMC_UNKNOWN;
10128 }
10129 if(m_bDragTableLine)
10130 {
10131 return m_prevMouseContext;
10132 }
10133 fp_Page* pPage = _getPageForXY(xPos, yPos, xClick, yClick);
10134 //UT_uint32 iPageNumber m_pLayout->findPage(pPage);
10135 //UT_uint32 iRow = iPageNumber/getNumHorizPages();
10136
10137
10138 if (!pPage)
10139 {
10140 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (1)\n"));
10141 m_prevMouseContext = EV_EMC_UNKNOWN;
10142 return EV_EMC_UNKNOWN;
10143 }
10144
10145 if ( (yClick < 0)
10146 || (xClick < 0)
10147 || (xClick > static_cast<UT_sint32>(getWidthPagesInRow(pPage))) )
10148 {
10149 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (2)\n"));
10150 m_prevMouseContext = EV_EMC_UNKNOWN;
10151 return EV_EMC_UNKNOWN;
10152 }
10153 if(m_FrameEdit.isActive())
10154 {
10155 fl_FrameLayout * pFL = m_FrameEdit.getFrameLayout();
10156 if(pFL && (pFL->getFrameType() >= FL_FRAME_WRAPPER_IMAGE))
10157 {
10158 m_prevMouseContext = EV_EMC_POSOBJECT;
10159 return EV_EMC_POSOBJECT;
10160 }
10161 return EV_EMC_FRAME;
10162 }
10163 if(m_InlineImage.isActive())
10164 {
10165 xxx_UT_DEBUGMSG(("getMouseContext emc set to IMAGESIZE \n"));
10166 m_prevMouseContext = EV_EMC_IMAGESIZE;
10167 return EV_EMC_IMAGESIZE;
10168 }
10169 UT_sint32 ires = 40;
10170 pPage->mapXYToPosition(xClick, yClick, pos, bBOL, bEOL,isTOC, true);
10171 fl_BlockLayout* pBlock;
10172 fp_Run* pRun;
10173 _findPositionCoords(pos, bEOL, xPoint, yPoint, xPoint2, yPoint2, iPointHeight, bDirection, &pBlock, &pRun);
10174 xxx_UT_DEBUGMSG(("Current Pos %d \n",pos));
10175 //
10176 // Look if we're inside a frame
10177 //
10178 if(isInFrame(pos))
10179 {
10180 //
10181 // Handle case of an image only as a backdrop to a frame. Then the frame
10182 // has no content.
10183 //
10184 xxx_UT_DEBUGMSG(("In Frame \n"));
10185 if(m_pDoc->isFrameAtPos(pos))
10186 {
10187 fl_ContainerLayout* psfh = NULL;
10188 m_pDoc->getStruxOfTypeFromPosition(m_pLayout->getLID(),pos+1,
10189 PTX_SectionFrame, &psfh);
10190 fl_FrameLayout * pFL = static_cast<fl_FrameLayout *>(psfh);
10191 UT_ASSERT(pFL->getContainerType() == FL_CONTAINER_FRAME);
10192 if(pFL->getFrameType() >= FL_FRAME_WRAPPER_IMAGE)
10193 {
10194 m_prevMouseContext = EV_EMC_POSOBJECT;
10195 xxx_UT_DEBUGMSG(("Over positioned object \n"));
10196 return EV_EMC_POSOBJECT;
10197 }
10198 }
10199
10200 //TODO: this needs fixing for multipage, I think?
10201 //
10202 // OK find the coordinates of the frame.
10203 //
10204 UT_sint32 xPage,yPage;
10205 getPageScreenOffsets(pPage,xPage,yPage);
10206 fl_FrameLayout * pFL = static_cast<fl_FrameLayout *>(pBlock->myContainingLayout());
10207 fp_FrameContainer * pFCon = static_cast<fp_FrameContainer *>(pFL->getFirstContainer());
10208 UT_sint32 iLeft = xPage + pFCon->getFullX();
10209 UT_sint32 iRight = xPage + pFCon->getFullX() + pFCon->getFullWidth();
10210 UT_sint32 iTop = yPage + pFCon->getFullY();
10211 UT_sint32 iBot = yPage + pFCon->getFullY() + pFCon->getFullHeight();
10212 bool bLeft = (iLeft - xPos < ires) && (xPos - iLeft < ires);
10213 bool bRight = (iRight - xPos < ires) && (xPos - iRight < ires);
10214 bool bTop = (iTop - yPos < ires) && (yPos - iTop < ires);
10215 bool bBot = (iBot - yPos < ires) && (yPos - iBot < ires);
10216 bool bX = (iLeft - ires < xPos) && (xPos < iRight + ires);
10217 bool bY = (iTop - ires < yPos) && (iBot + ires > yPos);
10218 if( (bLeft || bRight) && bY)
10219 {
10220 // TODO put in some code to indicate which control of the frame is being
10221 // dragged. Maybe reuse topRuler stuff???
10222 //
10223 xxx_UT_DEBUGMSG(("getContext: Found left frame line \n"));
10224 m_prevMouseContext = EV_EMC_FRAME;
10225 return EV_EMC_FRAME;
10226 }
10227 if( (bTop || bBot) && bX)
10228 {
10229 // TODO put in some code to indicate which control of the frame is being
10230 // dragged. Maybe reuse topRuler stuff???
10231 //
10232 xxx_UT_DEBUGMSG(("getContext: Found left frame line \n"));
10233 m_prevMouseContext = EV_EMC_FRAME;
10234 return EV_EMC_FRAME;
10235 }
10236
10237 }
10238 if(isTOC)
10239 {
10240 m_prevMouseContext = EV_EMC_TOC;
10241 return EV_EMC_TOC;
10242 }
10243 if(isInTable(pos))
10244 {
10245 if(!pRun)
10246 return EV_EMC_UNKNOWN;
10247
10248 fp_Line * pLine = pRun->getLine();
10249 if(pLine)
10250 {
10251 fp_CellContainer * pCell = static_cast<fp_CellContainer *>(pLine->getContainer());
10252 if(pCell && pCell->getContainerType() == FP_CONTAINER_CELL)
10253 {
10254 xxx_UT_DEBUGMSG(("getcontext: Looking at Table \n"));
10255 UT_sint32 iLeft = pCell->getLeftPos();
10256 UT_sint32 iRight = pCell->getRightPos();
10257 UT_sint32 iTop = pCell->getStartY();
10258 UT_sint32 iBot = pCell->getStopY();
10259 UT_sint32 iTopAttach = pCell->getTopAttach();
10260 UT_sint32 offy =0;
10261 UT_sint32 offx =0;
10262 fp_VerticalContainer * pCol = static_cast<fp_Column *>(pCell->getColumn(pLine));
10263 UT_sint32 col_x =0;
10264 UT_sint32 col_y =0;
10265 pPage->getScreenOffsets(pCol, col_x,col_y);
10266 //
10267 // Now find the brokentable the line is in.
10268 //
10269 fp_TableContainer * pTab = static_cast<fp_TableContainer *>(pCell->getContainer());
10270 bool bNested = false;
10271 if(pTab->getContainer()->getContainerType() == FP_CONTAINER_CELL)
10272 {
10273 bNested = true;
10274 }
10275 fp_TableContainer * pBroke = pTab->getFirstBrokenTable();
10276 if(!bNested)
10277 {
10278 UT_sint32 i =0;
10279 offx = pTab->getX();
10280 while(pBroke && !pBroke->isInBrokenTable(pCell,pLine))
10281 {
10282 i++;
10283 pBroke = static_cast<fp_TableContainer *>(pBroke->getNext());
10284 }
10285 if(i==0)
10286 {
10287 offy = pTab->getY();
10288 }
10289 else if(pBroke)
10290 {
10291 offy -= pBroke->getYBreak();
10292 }
10293 }
10294 else
10295 {
10296 fp_Container * pConTmp = pTab;
10297 while(pConTmp && !pConTmp->isColumnType())
10298 {
10299 offy += pConTmp->getY();
10300 offx += pConTmp->getX();
10301 pConTmp = pConTmp->getContainer();
10302 }
10303 }
10304 iLeft += col_x + offx;
10305 iRight += col_x + offx;
10306 iTop += col_y + offy;
10307 iBot += col_y + offy;
10308 xxx_UT_DEBUGMSG(("getContext: xPos %d yPos %d iLeft %d iRight %d iTop %d iBot %d \n",xPos,yPos,iLeft,iRight,iTop,iBot));
10309 if((iLeft - xPos < ires) && (xPos - iLeft < ires))
10310 {
10311 if(((iTop - ires) < yPos) && ((iBot+ires)> yPos))
10312 {
10313 m_prevMouseContext = EV_EMC_VLINE;
10314 return EV_EMC_VLINE;
10315 }
10316 }
10317 if((iRight - xPos < ires) && (xPos - iRight < ires))
10318 {
10319 if(((iTop - ires) < yPos) && ((iBot+ires)> yPos))
10320 {
10321 xxx_UT_DEBUGMSG(("getContext: Found right cell \n"));
10322 m_prevMouseContext = EV_EMC_VLINE;
10323 return EV_EMC_VLINE;
10324 }
10325 }
10326 if((iTop - yPos < 2*ires) && (yPos - iTop < 2*ires))
10327 {
10328 //
10329 // Now look to see if the cursor is over the first row of the table.
10330 //
10331
10332 // TODO put in some code to indicate which control of which cell is being
10333 // dragged. Maybe reuse topRuler stuff???
10334 //
10335 if(iTopAttach == 0)
10336 {
10337 m_prevMouseContext = EV_EMC_TOPCELL;
10338 return EV_EMC_TOPCELL;
10339 }
10340 xxx_UT_DEBUGMSG(("getContext: Found top cell \n"));
10341 m_prevMouseContext = EV_EMC_HLINE;
10342 return EV_EMC_HLINE;
10343 }
10344 if((iBot - yPos < ires) && (yPos - iBot < ires))
10345 {
10346 xxx_UT_DEBUGMSG(("getContext: Found bot cell \n"));
10347 m_prevMouseContext = EV_EMC_HLINE;
10348 return EV_EMC_HLINE;
10349 }
10350 }
10351 }
10352 }
10353 if (!pBlock)
10354 {
10355 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (5)\n"));
10356 m_prevMouseContext = EV_EMC_UNKNOWN;
10357 return EV_EMC_UNKNOWN;
10358 }
10359
10360 if (isLeftMargin(xPos,yPos))
10361 {
10362 UT_ASSERT(pBlock);
10363 xxx_UT_DEBUGMSG(("Entered BOL margin: dir %d\n", pBlock->getDominantDirection()));
10364 if(pBlock->getDominantDirection() == UT_BIDI_RTL)
10365 {
10366 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (3)\n"));
10367 m_prevMouseContext = EV_EMC_RIGHTOFTEXT;
10368 return EV_EMC_RIGHTOFTEXT;
10369 }
10370 else
10371 {
10372 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (4)\n"));
10373 m_prevMouseContext = EV_EMC_LEFTOFTEXT;
10374 return EV_EMC_LEFTOFTEXT;
10375 }
10376 }
10377
10378 while(pRun && pRun->getType() == FPRUN_FMTMARK)
10379 {
10380 pRun = pRun->getNextRun();
10381 }
10382
10383 if (!pRun)
10384 {
10385 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (6)\n"));
10386 m_prevMouseContext = EV_EMC_UNKNOWN;
10387 return EV_EMC_UNKNOWN;
10388 }
10389
10390 #if 0 //defined(DEBUG)
10391 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: () Run.type:%d\n", pRun->getType() ));
10392 if( fp_Run* t = pRun->getNextRun() )
10393 {
10394 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: () next.type:%d\n", t->getType() ));
10395 }
10396 if( fp_Run* t = pRun->getPrevRun() )
10397 {
10398 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: () prev.type:%d\n", t->getType() ));
10399 }
10400 #endif
10401
10402 if( pRun )
10403 {
10404 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: () pRun.x %ld\n", pRun->getX() ));
10405 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: () pRun.r %ld\n", pRun->getX() + pRun->getWidth() ));
10406 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: () pRun.t %ld\n", pRun->getType() ));
10407 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: () pRun.hl %p\n", pRun->getHyperlink() ));
10408 }
10409
10410 //
10411 // Try to find the hyperlink for this mouse position. If the user
10412 // has clicked directly on a hyperlink or annotation then pRun
10413 // will already be able to produce the hyperlink. For annotations
10414 // that are on a single point in the document like the "(1)"
10415 // marker in "foo (1) bar" then we have to poke around a bit to
10416 // set pHyperRun properly.
10417 //
10418 fp_Run* pHyperRun = pRun;
10419 if(pHyperRun && pHyperRun->getHyperlink())
10420 {
10421 //
10422 // The hyperlink has actual text content which was clicked,
10423 // nothing to do.
10424 //
10425 }
10426 else
10427 {
10428 //
10429 // Sniff around for a (1) style marker before and after the
10430 // click point which has no contained content and can not
10431 // contain the point.
10432 //
10433 pHyperRun = pRun->getNextRun();
10434 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (a) pHyperRun %p\n", pHyperRun ));
10435 if(pHyperRun) {
10436 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (a) type %ld\n", pHyperRun->getType() ));
10437 }
10438 if( !pHyperRun || pHyperRun->getType() != FPRUN_HYPERLINK )
10439 {
10440 pHyperRun = pRun->getPrevRun();
10441 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (b) pHyperRun %p\n", pHyperRun ));
10442 if(pHyperRun) {
10443 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (b) type %ld\n", pHyperRun->getType() ));
10444 }
10445
10446 if( pHyperRun && pHyperRun->getType() == FPRUN_HYPERLINK )
10447 {
10448 if( pHyperRun->getWidth() == 0 )
10449 {
10450 pHyperRun = pHyperRun->getPrevRun();
10451 if( pHyperRun && pHyperRun->getType() != FPRUN_HYPERLINK )
10452 pHyperRun = 0;
10453 }
10454 }
10455 else
10456 {
10457 pHyperRun = 0;
10458 }
10459 }
10460
10461 //
10462 // As we searched around for the pHyperRun then we should check that
10463 // the mouse is actually over the pHyperRun we have found.
10464 //
10465 if( pHyperRun )
10466 {
10467 if( fp_Line * pLine = pHyperRun->getLine() )
10468 {
10469 std::auto_ptr<UT_Rect> pRec( pLine->getScreenRect() );
10470 UT_sint32 xPosAdj = xPos - pRec->left;
10471 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (x), xPosAdj %ld\n", xPosAdj ));
10472 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (x), yPos %ld\n", yPos ));
10473 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (x), top %ld\n", pRec->top ));
10474 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (x), bot %ld\n", pRec->top+pRec->height ));
10475 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (x), run.x %ld\n", pHyperRun->getX() ));
10476 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (x), run.r %ld\n", pHyperRun->getX()+pHyperRun->getWidth() ));
10477
10478 if( pHyperRun->getX() < xPosAdj && xPosAdj < (pHyperRun->getX() + pHyperRun->getWidth()))
10479 {
10480 // Everything is fine, pHyperRun is under the mouse.
10481 }
10482 else
10483 {
10484 // We found a run that is not under the mouse
10485 pHyperRun = 0;
10486 }
10487 }
10488 }
10489 }
10490
10491 //
10492 // If we are over a hyperlink then return that context
10493 //
10494 if(pHyperRun && pHyperRun->getHyperlink() != NULL)
10495 {
10496 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (7), run type %d\n", pHyperRun->getType()));
10497
10498 if(m_prevMouseContext != EV_EMC_HYPERLINK)
10499 {
10500 UT_DEBUGMSG(("Mouse context is changed to hyperlink \n"));
10501 }
10502 fp_Line * pLine= pHyperRun->getLine();
10503 if(pLine)
10504 {
10505 std::auto_ptr<UT_Rect> pRec( pLine->getScreenRect() );
10506 UT_DebugOnly<UT_sint32> xPosAdj = xPos - pRec->left;
10507 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (7), xPosAdj %ld\n", (UT_sint32)xPosAdj ));
10508 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (7), yPos %ld\n", yPos ));
10509 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (7), top %ld\n", pRec->top ));
10510 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (7), bot %ld\n", pRec->top+pRec->height ));
10511 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (7), run.x %ld\n", pHyperRun->getX() ));
10512 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (7), run.r %ld\n", pHyperRun->getX()+pHyperRun->getWidth() ));
10513
10514 if((pRec->top <= yPos) && ((pRec->top + pRec->height) >= yPos))
10515 {
10516 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (7), HYPERLINK!\n" ));
10517 m_prevMouseContext = EV_EMC_HYPERLINK;
10518 return EV_EMC_HYPERLINK;
10519 }
10520 }
10521 }
10522
10523 if(!isSelectionEmpty())
10524 {
10525 if(pRun->getType() == FPRUN_IMAGE)
10526 {
10527 // check if this image is selected
10528 UT_uint32 iRunBase = pRun->getBlock()->getPosition() + pRun->getBlockOffset();
10529
10530 UT_uint32 iSelAnchor = getSelectionAnchor();
10531 UT_uint32 iPoint = getPoint();
10532
10533 UT_uint32 iSel1 = UT_MIN(iSelAnchor, iPoint);
10534 UT_uint32 iSel2 = UT_MAX(iSelAnchor, iPoint);
10535
10536 UT_ASSERT(iSel1 <= iSel2);
10537
10538 if (
10539 /* getFocus()!=AV_FOCUS_NONE && */
10540 (iSel1 <= iRunBase)
10541 && (iSel2 > iRunBase)
10542 )
10543 {
10544 // This image is selected. Now get the image size.
10545
10546 UT_sint32 xoff = 0, yoff = 0;
10547 pRun->getLine()->getScreenOffsets(pRun, xoff, yoff);
10548
10549 // Sevior's infamous + 1....
10550 yoff += pRun->getLine()->getAscent() - pRun->getAscent() + 1;
10551
10552 // Set the image size in the image selection rect
10553 m_selImageRect = UT_Rect(xoff,yoff,pRun->getWidth(),pRun->getHeight());
10554 }
10555 xxx_UT_DEBUGMSG(("Set ImageSize Context \n"));
10556
10557 m_prevMouseContext = EV_EMC_IMAGESIZE;
10558 //m_InlineImage.mouseLeftPress(xPos, yPos);
10559 return EV_EMC_IMAGESIZE;
10560 }
10561 if(m_Selection.isPosSelected(pos))
10562 {
10563 m_prevMouseContext = EV_EMC_VISUALTEXTDRAG;
10564 return EV_EMC_VISUALTEXTDRAG;
10565 }
10566 }
10567
10568 switch (pRun->getType())
10569 {
10570 case FPRUN_TEXT:
10571 #ifdef ENABLE_SPELL
10572 if (!isPosSelected(pos))
10573 {
10574 if (pBlock->getSpellSquiggles()->get(pos - pBlock->getPosition()))
10575 {
10576 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (8) misspelt pos %d \n",pos));
10577 m_prevMouseContext = EV_EMC_MISSPELLEDTEXT;
10578 return EV_EMC_MISSPELLEDTEXT;
10579 }
10580 }
10581 else
10582 #endif
10583 {
10584 xxx_UT_DEBUGMSG(("pos selected \n"));
10585 }
10586 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (9) text pos %d \n",pos));
10587 goto handle_revisions;
10588
10589 case FPRUN_IMAGE:
10590 {
10591 // check if this image is selected
10592 UT_uint32 iRunBase = pRun->getBlock()->getPosition() + pRun->getBlockOffset();
10593
10594 UT_uint32 iSelAnchor = getSelectionAnchor();
10595 UT_uint32 iPoint = getPoint();
10596
10597 UT_uint32 iSel1 = UT_MIN(iSelAnchor, iPoint);
10598 UT_uint32 iSel2 = UT_MAX(iSelAnchor, iPoint);
10599
10600 UT_ASSERT(iSel1 <= iSel2);
10601
10602 if (
10603 /* getFocus()!=AV_FOCUS_NONE && */
10604 (iSel1 <= iRunBase)
10605 && (iSel2 > iRunBase)
10606 )
10607 {
10608 // This image is selected. Now get the image size.
10609
10610 UT_sint32 xoff = 0, yoff = 0;
10611 pRun->getLine()->getScreenOffsets(pRun, xoff, yoff);
10612
10613 // Sevior's infamous + 1....
10614 yoff += pRun->getLine()->getAscent() - pRun->getAscent() + 1;
10615
10616 // Set the image size in the image selection rect
10617 m_selImageRect = UT_Rect(xoff,yoff,pRun->getWidth(),pRun->getHeight());
10618 }
10619
10620 FV_DragWhat dragWhat = m_InlineImage.getDragWhat();
10621 if (dragWhat!=FV_DragNothing && dragWhat!=FV_DragWhole)
10622 {
10623 m_prevMouseContext = EV_EMC_IMAGESIZE;
10624 xxx_UT_DEBUGMSG(("Set ImageSize Context \n"));
10625 return EV_EMC_IMAGESIZE;
10626 }
10627 else
10628 {
10629 m_prevMouseContext = EV_EMC_IMAGE;
10630 xxx_UT_DEBUGMSG(("Set Image Context \n"));
10631 return EV_EMC_IMAGE;
10632 }
10633 }
10634 case FPRUN_TAB:
10635 case FPRUN_FORCEDLINEBREAK:
10636 case FPRUN_FORCEDCOLUMNBREAK:
10637 case FPRUN_FORCEDPAGEBREAK:
10638 case FPRUN_ENDOFPARAGRAPH:
10639 case FPRUN_FMTMARK:
10640 case FPRUN_BOOKMARK:
10641 case FPRUN_HYPERLINK:
10642 case FPRUN_DIRECTIONMARKER:
10643 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (10): %d\n", pRun->getType()));
10644 goto handle_revisions;
10645
10646 case FPRUN_FIELD:
10647 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (11)\n"));
10648 m_prevMouseContext = EV_EMC_FIELD;
10649 return EV_EMC_FIELD;
10650
10651 case FPRUN_MATH:
10652 m_prevMouseContext = EV_EMC_MATH;
10653 return EV_EMC_MATH;
10654 case FPRUN_EMBED:
10655 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: EMBED \n"));
10656 m_prevMouseContext = EV_EMC_EMBED;
10657 return EV_EMC_EMBED;
10658 default:
10659 UT_ASSERT(UT_NOT_IMPLEMENTED);
10660 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (12)\n"));
10661 m_prevMouseContext = EV_EMC_UNKNOWN;
10662 return EV_EMC_UNKNOWN;
10663 }
10664
10665 // should be last evaluated context, so that other context menus do not get overshadowed when
10666 // document history is on; this code is only reached by jump from the above switch (we really
10667 // need these values to be orable, so that menus can be combined)
10668 handle_revisions:
10669 if(pRun->containsRevisions())
10670 {
10671 m_prevMouseContext = EV_EMC_REVISION;
10672 return EV_EMC_REVISION;
10673 }
10674 else
10675 {
10676 m_prevMouseContext = EV_EMC_TEXT;
10677 return EV_EMC_TEXT;
10678 }
10679
10680
10681
10682 /*NOTREACHED*/
10683 UT_ASSERT(0);
10684 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (13)\n"));
10685 m_prevMouseContext = EV_EMC_UNKNOWN;
10686 return EV_EMC_UNKNOWN;
10687 }
10688
10689
10690 // #undef xxx_UT_DEBUGMSG
10691 // #define xxx_UT_DEBUGMSG(x)
10692
10693
10694 /*!
10695 * Returns true if the (x,y) location on the screen is over a selected
10696 * fp_MathRun.
10697 */
isMathSelected(UT_sint32 x,UT_sint32 y,PT_DocPosition & pos) const10698 bool FV_View::isMathSelected(UT_sint32 x, UT_sint32 y, PT_DocPosition & pos) const
10699 {
10700 if(isSelectionEmpty())
10701 {
10702 return false;
10703 }
10704 // Figure out which page we clicked on.
10705 // Pass the click down to that page.
10706 UT_sint32 xClick, yClick;
10707 fp_Page* pPage = _getPageForXY(x,y, xClick, yClick);
10708 bool bBOL = false;
10709 bool bEOL = false;
10710 bool isTOC = false;
10711 bool bUseHdrFtr = true;
10712 pPage->mapXYToPosition(false,xClick, yClick, pos, bBOL, bEOL,isTOC, bUseHdrFtr,NULL);
10713 fl_BlockLayout * pBlock = NULL;
10714 fp_Run * pRun = NULL;
10715 UT_sint32 xCaret, yCaret;
10716 UT_uint32 heightCaret;
10717 UT_sint32 xCaret2, yCaret2;
10718 bool bDirection;
10719 _findPositionCoords(pos, m_bPointEOL, xCaret, yCaret, xCaret2, yCaret2, heightCaret, bDirection, &pBlock, &pRun);
10720 if(pRun && pRun->getType() == FPRUN_MATH)
10721 {
10722 if(pos >= getPoint() && pos <= getSelectionAnchor())
10723 return true;
10724 if(pos >= getSelectionAnchor() && pos <= getPoint())
10725 return true;
10726 }
10727 return false;
10728 }
10729
10730 /*!
10731 * Return the document position from the most recent mouse positions
10732 */
getDocPositionFromLastXY(void)10733 PT_DocPosition FV_View::getDocPositionFromLastXY(void)
10734 {
10735 return getDocPositionFromXY(m_iMouseX,m_iMouseY);
10736 }
10737
10738 /*!
10739 * This sets the mouse pointer to show the little watch or some other icon if
10740 * if a long operation is in progress.
10741 */
setCursorWait(void)10742 void FV_View::setCursorWait(void)
10743 {
10744 if (!getGraphics()->queryProperties(GR_Graphics::DGP_SCREEN))
10745 return;
10746
10747 m_pG->setCursor(GR_Graphics::GR_CURSOR_WAIT);
10748 XAP_Frame * pFrame = static_cast<XAP_Frame*>(getParentData());
10749 if(pFrame)
10750 {
10751 pFrame->setCursor(GR_Graphics::GR_CURSOR_WAIT);
10752 }
10753 }
10754
10755 /*!
10756 * The clears the "waiting" icon from the mouse pointer.
10757 */
clearCursorWait(void)10758 void FV_View::clearCursorWait(void)
10759 {
10760 if (!getGraphics()->queryProperties(GR_Graphics::DGP_SCREEN))
10761 return;
10762
10763 setCursorToContext();
10764 XAP_Frame * pFrame = static_cast<XAP_Frame*>(getParentData());
10765 if(pFrame)
10766 pFrame->setCursor(GR_Graphics::GR_CURSOR_DEFAULT);
10767 }
10768
10769 /*!
10770 * This method sets the cursor to match current context.
10771 */
setCursorToContext()10772 void FV_View::setCursorToContext()
10773 {
10774 if (!getGraphics()->queryProperties(GR_Graphics::DGP_SCREEN))
10775 return;
10776
10777 EV_EditMouseContext evMC = getMouseContext(m_iMouseX,m_iMouseY);
10778 GR_Graphics::Cursor cursor = GR_Graphics::GR_CURSOR_DEFAULT;
10779 switch (evMC)
10780 {
10781 case EV_EMC_UNKNOWN:
10782 break;
10783 case EV_EMC_TEXT:
10784 cursor = GR_Graphics::GR_CURSOR_IBEAM;
10785 break;
10786 case EV_EMC_LEFTOFTEXT:
10787 cursor = GR_Graphics::GR_CURSOR_RIGHTARROW;
10788 break;
10789 case EV_EMC_MISSPELLEDTEXT:
10790 cursor = GR_Graphics::GR_CURSOR_IBEAM;
10791 break;
10792 case EV_EMC_IMAGE:
10793 cursor = GR_Graphics::GR_CURSOR_IMAGE;
10794 break;
10795 case EV_EMC_IMAGESIZE:
10796 xxx_UT_DEBUGMSG(("Imagesize context \n"));
10797 if(m_InlineImage.getDragWhat() == FV_DragTopLeftCorner)
10798 {
10799 cursor = GR_Graphics::GR_CURSOR_IMAGESIZE_NW;
10800 }
10801 else if(m_InlineImage.getDragWhat() ==FV_DragTopRightCorner)
10802 {
10803 cursor = GR_Graphics::GR_CURSOR_IMAGESIZE_NE;
10804 }
10805 else if(m_InlineImage.getDragWhat() ==FV_DragBotLeftCorner)
10806 {
10807 cursor = GR_Graphics::GR_CURSOR_IMAGESIZE_SW;
10808 }
10809 else if(m_InlineImage.getDragWhat() ==FV_DragBotRightCorner)
10810 {
10811 cursor = GR_Graphics::GR_CURSOR_IMAGESIZE_SE;
10812 }
10813 else if(m_InlineImage.getDragWhat() ==FV_DragLeftEdge)
10814 {
10815 cursor = GR_Graphics::GR_CURSOR_IMAGESIZE_W;
10816 }
10817 else if(m_InlineImage.getDragWhat() ==FV_DragTopEdge)
10818 {
10819 cursor = GR_Graphics::GR_CURSOR_IMAGESIZE_N;
10820 }
10821 else if(m_InlineImage.getDragWhat() ==FV_DragRightEdge)
10822 {
10823 cursor = GR_Graphics::GR_CURSOR_IMAGESIZE_E;
10824 }
10825 else if(m_InlineImage.getDragWhat() ==FV_DragBotEdge)
10826 {
10827 cursor = GR_Graphics::GR_CURSOR_IMAGESIZE_S;
10828 }
10829 else if(!m_InlineImage.isActive())
10830 {
10831 cursor = GR_Graphics::GR_CURSOR_IMAGE;
10832 }
10833 else
10834 {
10835 cursor = GR_Graphics::GR_CURSOR_GRAB;
10836 }
10837 break;
10838 case EV_EMC_FIELD:
10839 cursor = GR_Graphics::GR_CURSOR_DEFAULT;
10840 break;
10841 case EV_EMC_HYPERLINK:
10842 cursor = GR_Graphics::GR_CURSOR_LINK;
10843 break;
10844 case EV_EMC_RIGHTOFTEXT:
10845 cursor = GR_Graphics::GR_CURSOR_LEFTARROW;
10846 break;
10847 case EV_EMC_HYPERLINKTEXT:
10848 cursor = GR_Graphics::GR_CURSOR_LINK;
10849 break;
10850 case EV_EMC_HYPERLINKMISSPELLED:
10851 cursor = GR_Graphics::GR_CURSOR_LINK;
10852 break;
10853 // RIVERA
10854 case EV_EMC_ANNOTATIONTEXT:
10855 cursor = GR_Graphics::GR_CURSOR_LINK;
10856 break;
10857 case EV_EMC_ANNOTATIONMISSPELLED:
10858 cursor = GR_Graphics::GR_CURSOR_LINK;
10859 break;
10860 case EV_EMC_VLINE:
10861 UT_DEBUGMSG(("setCursor: Set to VLINE_DRAG \n"));
10862 cursor = GR_Graphics::GR_CURSOR_VLINE_DRAG;
10863 break;
10864 case EV_EMC_HLINE:
10865 cursor = GR_Graphics::GR_CURSOR_HLINE_DRAG;
10866 break;
10867 case EV_EMC_TOPCELL:
10868 UT_DEBUGMSG(("setCursor: Set to select Col \n"));
10869 cursor = GR_Graphics::GR_CURSOR_DOWNARROW;
10870 break;
10871 case EV_EMC_VISUALTEXTDRAG:
10872 cursor = GR_Graphics::GR_CURSOR_IMAGE;
10873 break;
10874
10875 case EV_EMC_FRAME:
10876 case EV_EMC_POSOBJECT:
10877 if(m_FrameEdit.getFrameEditMode() == FV_FrameEdit_WAIT_FOR_FIRST_CLICK_INSERT)
10878 {
10879 cursor = GR_Graphics::GR_CURSOR_CROSSHAIR;
10880 }
10881 else if(m_FrameEdit.getDragWhat() ==FV_DragTopLeftCorner)
10882 {
10883 cursor = GR_Graphics::GR_CURSOR_IMAGESIZE_NW;
10884 }
10885 else if(m_FrameEdit.getDragWhat() ==FV_DragTopRightCorner)
10886 {
10887 cursor = GR_Graphics::GR_CURSOR_IMAGESIZE_NE;
10888 }
10889 else if(m_FrameEdit.getDragWhat() ==FV_DragBotLeftCorner)
10890 {
10891 cursor = GR_Graphics::GR_CURSOR_IMAGESIZE_SW;
10892 }
10893 else if(m_FrameEdit.getDragWhat() ==FV_DragBotRightCorner)
10894 {
10895 cursor = GR_Graphics::GR_CURSOR_IMAGESIZE_SE;
10896 }
10897 else if(m_FrameEdit.getDragWhat() ==FV_DragLeftEdge)
10898 {
10899 cursor = GR_Graphics::GR_CURSOR_IMAGESIZE_W;
10900 }
10901 else if(m_FrameEdit.getDragWhat() ==FV_DragTopEdge)
10902 {
10903 cursor = GR_Graphics::GR_CURSOR_IMAGESIZE_N;
10904 }
10905 else if(m_FrameEdit.getDragWhat() ==FV_DragRightEdge)
10906 {
10907 cursor = GR_Graphics::GR_CURSOR_IMAGESIZE_E;
10908 }
10909 else if(m_FrameEdit.getDragWhat() ==FV_DragBotEdge)
10910 {
10911 cursor = GR_Graphics::GR_CURSOR_IMAGESIZE_S;
10912 }
10913 else if(m_FrameEdit.isActive() && m_FrameEdit.getDragWhat() ==FV_DragWhole)
10914 {
10915 cursor = GR_Graphics::GR_CURSOR_IMAGE;
10916 }
10917 else
10918 {
10919 cursor = GR_Graphics::GR_CURSOR_GRAB;
10920 }
10921 break;
10922 case EV_EMC_MATH:
10923 cursor = GR_Graphics::GR_CURSOR_IMAGE;
10924 break;
10925 case EV_EMC_EMBED:
10926 cursor = GR_Graphics::GR_CURSOR_IMAGE;
10927 break;
10928 default:
10929 break;
10930 }
10931 getGraphics()->setCursor(cursor);
10932 }
10933
10934 #ifdef ENABLE_SPELL
isTextMisspelled() const10935 bool FV_View::isTextMisspelled() const
10936 {
10937 PT_DocPosition pos = getPoint();
10938 fl_BlockLayout* pBlock = _findBlockAtPosition(pos);
10939 if(pBlock == NULL)
10940 {
10941 return false;
10942 }
10943 if (!isPosSelected(pos))
10944 if (pBlock->getSpellSquiggles()->get(pos - pBlock->getPosition()))
10945 {
10946 return true;
10947 }
10948
10949 return false;
10950 }
10951 #endif
10952
doesSelectionContainRevision() const10953 bool FV_View::doesSelectionContainRevision() const
10954 {
10955 fl_BlockLayout* pBlock;
10956 fp_Run* pRun;
10957 UT_sint32 x, y, x2, y2;
10958 UT_uint32 h;
10959 bool b;
10960
10961 UT_uint32 iPos1 = UT_MIN(m_iInsPoint, getSelectionAnchor());
10962 UT_uint32 iPos2 = UT_MAX(m_iInsPoint, getSelectionAnchor());
10963
10964 _findPositionCoords(iPos1, false, x, y, x2, y2, h, b,&pBlock, &pRun);
10965
10966 if (!pBlock)
10967 return false;
10968
10969 if (!pRun)
10970 return false;
10971
10972 while(pBlock)
10973 {
10974 if(!pRun)
10975 pRun = pBlock->getFirstRun();
10976
10977 while(pRun)
10978 {
10979 if(pRun->getBlockOffset() + pBlock->getPosition() >= iPos2)
10980 return false;
10981
10982 if(pRun->containsRevisions())
10983 return true;
10984
10985 pRun = pRun->getNextRun();
10986 }
10987
10988 pBlock = pBlock->getNextBlockInDocument();
10989 }
10990
10991 return false;
10992 }
10993
10994
getInsertionPointContext(UT_sint32 * pxPos,UT_sint32 * pyPos)10995 EV_EditMouseContext FV_View::getInsertionPointContext(UT_sint32 * pxPos, UT_sint32 * pyPos)
10996 {
10997 // compute an EV_EMC_ context for the position
10998 // of the current insertion point and return
10999 // the window coordinates of the insertion point.
11000 // this is to allow a keyboard binding to raise
11001 // a context menu.
11002
11003 if (pxPos)
11004 *pxPos = m_xPoint;
11005 if (pyPos)
11006 *pyPos = m_yPoint + m_iPointHeight;
11007
11008 fl_BlockLayout* pBlock;
11009 fp_Run* pRun;
11010 UT_sint32 x, y, x2, y2;
11011 UT_uint32 h;
11012 bool b;
11013
11014 _findPositionCoords(m_iInsPoint, false, x, y, x2, y2, h, b,&pBlock, &pRun);
11015
11016 if (!pBlock)
11017 {
11018 xxx_UT_DEBUGMSG(("fv_View::getMouseContext: (5)\n"));
11019 return EV_EMC_UNKNOWN;
11020 }
11021
11022 if (!pRun)
11023 {
11024 return EV_EMC_UNKNOWN;
11025 }
11026
11027 if(pRun->containsRevisions())
11028 {
11029 return EV_EMC_REVISION;
11030 }
11031
11032 if(pRun->getHyperlink() != NULL)
11033 {
11034 return EV_EMC_HYPERLINK;
11035 }
11036
11037 switch (pRun->getType())
11038 {
11039 case FPRUN_TEXT:
11040 #ifdef ENABLE_SPELL
11041 if (!isPosSelected(m_iInsPoint))
11042 if (pBlock->getSpellSquiggles()->get(m_iInsPoint - pBlock->getPosition()))
11043 {
11044 return EV_EMC_MISSPELLEDTEXT;
11045 }
11046 #endif
11047 return EV_EMC_TEXT;
11048
11049 case FPRUN_IMAGE:
11050 {
11051 // check if this image is selected
11052 UT_uint32 iRunBase = pRun->getBlock()->getPosition() + pRun->getBlockOffset();
11053
11054 UT_uint32 iSelAnchor = getSelectionAnchor();
11055 UT_uint32 iPoint = getPoint();
11056
11057 UT_uint32 iSel1 = UT_MIN(iSelAnchor, iPoint);
11058 UT_uint32 iSel2 = UT_MAX(iSelAnchor, iPoint);
11059
11060 UT_ASSERT(iSel1 <= iSel2);
11061
11062 if (
11063 /* getFocus()!=AV_FOCUS_NONE && */
11064 (iSel1 <= iRunBase)
11065 && (iSel2 > iRunBase)
11066 )
11067 {
11068 // This image is selected. Now get the image size.
11069
11070 UT_sint32 xoff = 0, yoff = 0;
11071 pRun->getLine()->getScreenOffsets(pRun, xoff, yoff);
11072
11073 // Sevior's infamous + 1....
11074 yoff += pRun->getLine()->getAscent() - pRun->getAscent() + 1;
11075
11076 // Set the image size in the image selection rect
11077 m_selImageRect = UT_Rect(xoff,yoff,pRun->getWidth(),pRun->getHeight());
11078 }
11079 UT_DEBUGMSG(("Insertion Point Context IMAGE \n"));
11080 return EV_EMC_IMAGE;
11081 }
11082 case FPRUN_TAB:
11083 case FPRUN_FORCEDLINEBREAK:
11084 case FPRUN_FORCEDCOLUMNBREAK:
11085 case FPRUN_FORCEDPAGEBREAK:
11086 case FPRUN_ENDOFPARAGRAPH:
11087 case FPRUN_FMTMARK:
11088 case FPRUN_BOOKMARK:
11089 case FPRUN_HYPERLINK:
11090 case FPRUN_DIRECTIONMARKER:
11091 return EV_EMC_TEXT;
11092
11093 case FPRUN_FIELD:
11094 return EV_EMC_FIELD;
11095
11096 default:
11097 UT_ASSERT(UT_NOT_IMPLEMENTED);
11098 return EV_EMC_UNKNOWN;
11099 }
11100
11101 /*NOTREACHED*/
11102 UT_ASSERT(0);
11103 return EV_EMC_UNKNOWN;
11104 }
11105
getCurrentPage(void) const11106 fp_Page* FV_View::getCurrentPage(void) const
11107 {
11108 UT_sint32 xPoint, yPoint, xPoint2, yPoint2;
11109 UT_uint32 pos = getPoint();
11110 UT_uint32 iPointHeight;
11111 bool bDirection;
11112
11113 //
11114 // Check we have a vaild layout. At startup we don't
11115 //
11116 if(getLayout()->getFirstSection() == NULL)
11117 {
11118 return NULL;
11119 }
11120
11121 fl_BlockLayout * pBlock;
11122 fp_Run * pRun;
11123
11124 _findPositionCoords(pos,
11125 m_bPointEOL,
11126 xPoint,
11127 yPoint,
11128 xPoint2,
11129 yPoint2,
11130 iPointHeight,
11131 bDirection,
11132 &pBlock,
11133 &pRun);
11134
11135 //
11136 // Detect if we have no Lines at the curren tpoint and bail out.
11137 //
11138 if(pRun == NULL || pRun->getLine() == NULL || iPointHeight == 0)
11139 {
11140 return NULL;
11141 }
11142
11143 // NOTE prior call will fail if the block isn't currently formatted,
11144 // NOTE so we won't be able to figure out more specific geometry
11145
11146 if (pRun)
11147 {
11148 // we now have coords relative to the page containing the ins pt
11149
11150 fl_BlockLayout * pBL = pRun->getBlock();
11151 fp_Page* pPointPage = NULL;
11152 if(pBL->isHdrFtr())
11153 {
11154 UT_DEBUGMSG(("Yikes! What page am I on? \n"));
11155 }
11156 else
11157 {
11158 pPointPage = pRun->getLine()->getPage();
11159 }
11160 return pPointPage;
11161 }
11162
11163 return NULL;
11164 }
11165
11166 /*!
11167 * Returns true if there is some Layout classes defined. Not true at startup.
11168 */
isDocumentPresent(void) const11169 bool FV_View::isDocumentPresent(void) const
11170 {
11171 return (getLayout()->getFirstSection() != NULL);
11172 }
11173
getCurrentPageNumForStatusBar(void) const11174 UT_uint32 FV_View::getCurrentPageNumForStatusBar(void) const
11175 {
11176 fp_Page* pCurrentPage = getCurrentPage();
11177 if(pCurrentPage == NULL)
11178 {
11179 return 0;
11180 }
11181 UT_uint32 ndx = 1;
11182
11183 fp_Page* pPage = m_pLayout->getFirstPage();
11184 while (pPage)
11185 {
11186 if (pPage == pCurrentPage)
11187 {
11188 return ndx;
11189 }
11190
11191 ndx++;
11192 pPage = pPage->getNext();
11193 }
11194 UT_DEBUGMSG(("Current page not found - could be has been deleted. Hopefully we can recover \n"));
11195 // UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
11196
11197 return 0;
11198 }
11199
11200 #ifdef ENABLE_SPELL
11201 // ndx is one-based, not zero-based
getContextSuggest(UT_uint32 ndx)11202 UT_UCSChar * FV_View::getContextSuggest(UT_uint32 ndx)
11203 {
11204 // locate the squiggle
11205 PT_DocPosition pos = 0 ;
11206 fl_BlockLayout* pBL = NULL ;
11207
11208 pos = getPoint();
11209 pBL = _findBlockAtPosition(pos);
11210 UT_return_val_if_fail(pBL,NULL);
11211
11212 PT_DocPosition epos = 0;
11213 getDocument()->getBounds(true, epos);
11214 UT_DEBUGMSG(("end bound is %d\n", epos));
11215 const fl_PartOfBlockPtr& pPOB = pBL->getSpellSquiggles()->get(pos - pBL->getPosition());
11216 UT_return_val_if_fail(pPOB, NULL);
11217
11218 // grab the suggestion
11219 return _lookupSuggestion(pBL, pPOB, ndx);
11220 }
11221 #endif
11222
s_notChar(UT_UCSChar c)11223 static bool s_notChar(UT_UCSChar c)
11224 {
11225 switch (c)
11226 {
11227 case UCS_TAB:
11228 case UCS_LF:
11229 case UCS_VTAB:
11230 case UCS_FF:
11231 case UCS_CR:
11232 {
11233 return true;
11234 }
11235 default:
11236 return false;
11237 }
11238 }
11239
11240
11241 /*!
11242 Count words
11243 \return structure with word counts
11244 Count words in document (or selection).
11245 */
countWords(bool bActuallyCountWords)11246 FV_DocCount FV_View::countWords(bool bActuallyCountWords)
11247 {
11248 FV_DocCount wCount;
11249 memset(&wCount,0,sizeof(wCount));
11250
11251 bool isPara = false;
11252
11253 PT_DocPosition low, high;
11254
11255 // Find selection bounds - if no selection, use bounds of entire
11256 // document
11257 if (isSelectionEmpty())
11258 {
11259 m_pDoc->getBounds(false, low); // Need the whole document otherwise we just
11260 m_pDoc->getBounds(true, high); // word in the header/footer while editting there
11261 }
11262 else
11263 {
11264 if(m_iInsPoint < m_Selection.getSelectionAnchor())
11265 {
11266 low = m_iInsPoint;
11267 high = m_Selection.getSelectionAnchor();
11268 }
11269 else
11270 {
11271 high = m_iInsPoint;
11272 low = m_Selection.getSelectionAnchor();
11273 }
11274 }
11275
11276 fl_BlockLayout * pBL = _findBlockAtPosition(low);
11277 if (pBL && pBL->isEmbeddedType())
11278 {
11279 fl_EmbedLayout * pEmbedL= static_cast<fl_EmbedLayout*>(pBL->myContainingLayout());
11280 pBL = pEmbedL->getContainingBlock();
11281 }
11282 if(pBL == NULL)
11283 {
11284 return wCount;
11285 }
11286 // Selection may start inside first block
11287 fp_Line* pLine = static_cast<fp_Line *>(pBL->getFirstContainer());
11288 if(!pLine->getContainer())
11289 {
11290 return (wCount);
11291 }
11292
11293 UT_sint32 iStartOffset = 0;
11294 if (low > pBL->getPosition(false))
11295 {
11296 iStartOffset = low - pBL->getPosition(false);
11297 if (!isSelectionEmpty() && (iStartOffset == pBL->getLength() - 1))
11298 {
11299 // If the selection begin at the complete end of a line, we want to start
11300 // counting at the next block. This allows to match the user perception of
11301 // the number of lines with the actual line count.
11302 // Note: the first line is visibly part of the selection only when the formatting
11303 // markers are shown.
11304 pBL = static_cast<fl_BlockLayout *>(pBL->getNextBlockInDocument());
11305 iStartOffset = 0;
11306 if (pBL) {
11307 pLine = static_cast<fp_Line *>(pBL->getFirstContainer());
11308 }
11309 }
11310 // Find first line in selection
11311 fp_Line* pNextLine = NULL;
11312 while (pLine)
11313 {
11314 pNextLine = static_cast<fp_Line*>(pLine->getNext());
11315 if (!pNextLine || (pNextLine->getFirstRun()->getBlockOffset() > static_cast<UT_uint32>(iStartOffset)))
11316 {
11317 break;
11318 }
11319 else
11320 {
11321 pLine = pNextLine;
11322 }
11323 }
11324 }
11325
11326 fp_Page* pPage = pLine->getPage();
11327 fp_Page* pOldPage = pPage;
11328 wCount.page++;
11329
11330 bool bFirstBlock = true;
11331 while (pBL)
11332 {
11333 if (pBL->getPosition(false) >= high)
11334 {
11335 break;
11336 }
11337 bool bEndInThisBlock = false;
11338 UT_uint32 iMaxOffset = 0;
11339 if (pBL->getPosition(false) + pBL->getLength() > high)
11340 {
11341 bEndInThisBlock = true;
11342 iMaxOffset = high - pBL->getPosition(false);
11343 }
11344 UT_GrowBuf gb(1024);
11345 pBL->getBlockBuf(&gb);
11346 const UT_UCSChar * pSpan = reinterpret_cast<UT_UCSChar*>(gb.getPointer(0));
11347 UT_uint32 len = gb.getLength();
11348
11349 // Count lines and pages
11350 while (pLine && (!bEndInThisBlock || (pLine->getFirstRun()->getBlockOffset() < iMaxOffset)))
11351 {
11352 wCount.line++;
11353
11354 // If this line is on a new page, increment page count
11355 pPage = pLine->getPage();
11356 if ((pOldPage != pPage) && (pOldPage->getPageNumber() < pPage->getPageNumber()))
11357 {
11358 wCount.page++;
11359 pOldPage = pPage;
11360 }
11361
11362 pLine = static_cast<fp_Line *>(pLine->getNext());
11363 }
11364
11365 if (bActuallyCountWords)
11366 {
11367 bool newWord = false;
11368 bool delim = true;
11369
11370 UT_sint32 i = (bFirstBlock ? iStartOffset : 0);
11371 UT_sint32 imax = len;
11372 if (bEndInThisBlock)
11373 {
11374 UT_ASSERT_HARMLESS(iMaxOffset <= len);
11375 imax = UT_MIN(iMaxOffset,len);
11376 }
11377 fl_ContainerLayout * pNoteCL = NULL;
11378 UT_sint32 iNote = pBL->getEmbeddedOffset(0,pNoteCL);
11379 UT_sint32 iNoteEnd = -1;
11380 if (pNoteCL)
11381 {
11382 iNoteEnd = iNote + static_cast<fl_EmbedLayout*>(pNoteCL)->getLength() - 1;
11383 }
11384 for (; i < imax; i++)
11385 {
11386 if (!s_notChar(pSpan[i]))
11387 {
11388 wCount.ch_sp++;
11389 isPara = true;
11390
11391 switch (pSpan[i])
11392 {
11393 case UCS_SPACE:
11394 case UCS_NBSP:
11395 case UCS_EN_SPACE:
11396 case UCS_EM_SPACE:
11397 break;
11398
11399 default:
11400 wCount.ch_no++;
11401 }
11402 }
11403 UT_UCSChar followChar, prevChar;
11404 followChar = (static_cast<UT_uint32>(i+1) < len) ? pSpan[i+1] : UCS_UNKPUNK;
11405 prevChar = i > 0 ? pSpan[i-1] : UCS_UNKPUNK;
11406
11407 newWord = (delim && !UT_isWordDelimiter(pSpan[i], followChar, prevChar));
11408
11409 delim = UT_isWordDelimiter(pSpan[i], followChar, prevChar);
11410
11411 if (delim) { // debatable...
11412 if (pSpan[i]=='-' || pSpan[i]=='_') delim = false;
11413 }
11414
11415 // CJK-FIXME: this can work incorrectly under CJK locales
11416 // since it can give 'true' for UCS with value >0xff (like
11417 // quotes, etc).
11418 if (newWord || XAP_EncodingManager::get_instance()->is_cjk_letter(pSpan[i]))
11419 {
11420 wCount.word++;
11421 wCount.words_no_notes++;
11422 if ((iNote >= 0) && (i >= iNote))
11423 {
11424 while ((iNote >= 0) && i > iNoteEnd)
11425 {
11426 iNote = pBL->getEmbeddedOffset(iNoteEnd + 1,pNoteCL);
11427 if (pNoteCL)
11428 {
11429 iNoteEnd = iNote + static_cast<fl_EmbedLayout*>(pNoteCL)->getLength() - 1;
11430 }
11431 }
11432
11433 if (iNote >= 0 && (i >= iNote) && (i < iNoteEnd))
11434 {
11435 // We are inside a note
11436 wCount.words_no_notes--;
11437 }
11438 }
11439 }
11440 }
11441 }
11442
11443 if (isPara)
11444 {
11445 wCount.para++;
11446 isPara = false;
11447 }
11448
11449 // Get next block, we want to include footnotes so can't use getNextBlockLayout
11450 pBL = static_cast<fl_BlockLayout *>(pBL->getNextBlockInDocument());
11451 bFirstBlock = false;
11452 if (pBL)
11453 {
11454 pLine = static_cast<fp_Line *>(pBL->getFirstContainer());
11455 }
11456 }
11457
11458 return (wCount);
11459 }
11460
setShowPara(bool bShowPara)11461 void FV_View::setShowPara(bool bShowPara)
11462 {
11463 if (bShowPara != m_bShowPara)
11464 {
11465 m_bShowPara = bShowPara;
11466 m_pDoc->setDontChangeInsPoint();
11467 // FIXME: test if next line can be safely removed
11468 //m_pLayout->rebuildFromHere(static_cast<fl_DocSectionLayout *>(m_pLayout->getFirstSection()));
11469 m_pDoc->allowChangeInsPoint();
11470 if(getPoint() > 0)
11471 {
11472 draw();
11473 }
11474 }
11475 }
11476
11477
11478 /*!
11479 * This method combines all the things we need to save before doing
11480 * extensive piecetable manipulations.
11481 */
SetupSavePieceTableState(void)11482 void FV_View::SetupSavePieceTableState(void)
11483 {
11484 //
11485 // Fix up the insertion point stuff.
11486 //
11487 if (!isSelectionEmpty())
11488 _clearSelection();
11489
11490 m_pDoc->beginUserAtomicGlob();
11491 _saveAndNotifyPieceTableChange();
11492 m_pDoc->disableListUpdates();
11493 setScreenUpdateOnGeneralUpdate( false);
11494 }
11495
11496 /*!
11497 * This method combines all the things we need to save before doing
11498 * extensive piecetable manipulations.
11499 */
RestoreSavedPieceTableState(void)11500 void FV_View::RestoreSavedPieceTableState(void)
11501 {
11502 // restore updates and clean up dirty lists
11503 m_pDoc->enableListUpdates();
11504 m_pDoc->updateDirtyLists();
11505
11506 // Signal PieceTable Changes have Ended
11507
11508 m_pDoc->notifyPieceTableChangeEnd();
11509 m_iPieceTableState = 0;
11510 setScreenUpdateOnGeneralUpdate(true);
11511 _generalUpdate();
11512 m_pDoc->endUserAtomicGlob(); // End the big undo block
11513 _updateInsertionPoint();
11514 }
11515
11516
11517 /*!
11518 * Remove the Header/Footer type specified by hfType
11519 \param HdrFtrType hfType the type of the Header/Footer to be removed.
11520 \param bool bSkipPTSaves if true don't save the PieceTable stuff
11521 */
removeThisHdrFtr(HdrFtrType hfType,bool bSkipPTSaves)11522 void FV_View::removeThisHdrFtr(HdrFtrType hfType, bool bSkipPTSaves)
11523 {
11524 setCursorWait();
11525 if(!bSkipPTSaves)
11526 {
11527 //
11528 // Fix up the insertion point stuff.
11529 //
11530 if (!isSelectionEmpty())
11531 _clearSelection();
11532
11533 m_pDoc->beginUserAtomicGlob();
11534
11535 _saveAndNotifyPieceTableChange();
11536 }
11537 //
11538 // Save current document position.
11539 //
11540 PT_DocPosition curPoint = getPoint();
11541
11542 fl_DocSectionLayout * pDSL = static_cast<fl_DocSectionLayout *>(getCurrentBlock()->getDocSectionLayout());
11543
11544 if(hfType == FL_HDRFTR_HEADER)
11545 {
11546 UT_DEBUGMSG(("View: Remove HDRFTR HEADER \n"));
11547 _removeThisHdrFtr(pDSL->getHeader());
11548 }
11549 else if(hfType == FL_HDRFTR_HEADER_EVEN)
11550 {
11551 UT_DEBUGMSG(("View: Remove HDRFTR HEADER_EVEN \n"));
11552 _removeThisHdrFtr(pDSL->getHeaderEven());
11553 }
11554 else if(hfType == FL_HDRFTR_HEADER_LAST)
11555 {
11556 UT_DEBUGMSG(("View: Remove HDRFTR HEADER_LAST \n"));
11557 _removeThisHdrFtr(pDSL->getHeaderLast());
11558 }
11559 else if(hfType == FL_HDRFTR_HEADER_FIRST)
11560 {
11561 UT_DEBUGMSG(("View: Remove HDRFTR HEADER_FIRST \n"));
11562 _removeThisHdrFtr(pDSL->getHeaderFirst());
11563 }
11564 else if(hfType == FL_HDRFTR_FOOTER)
11565 {
11566 _removeThisHdrFtr(pDSL->getFooter());
11567 }
11568 else if(hfType == FL_HDRFTR_FOOTER_EVEN)
11569 {
11570 _removeThisHdrFtr(pDSL->getFooterEven());
11571 }
11572 else if(hfType == FL_HDRFTR_FOOTER_LAST)
11573 {
11574 _removeThisHdrFtr(pDSL->getFooterLast());
11575 }
11576 else if(hfType == FL_HDRFTR_FOOTER_FIRST)
11577 {
11578 _removeThisHdrFtr(pDSL->getFooterFirst());
11579 }
11580 //
11581 // After erarsing the cursor, Restore to the point before all this mess started.
11582 //
11583 _setPoint(curPoint);
11584
11585 if(!bSkipPTSaves)
11586 {
11587
11588 // Signal PieceTable Changes have finished
11589 _restorePieceTableState();
11590 _generalUpdate();
11591 updateScreen (); // fix 1803, force screen update/redraw
11592
11593 _updateInsertionPoint();
11594 m_pDoc->endUserAtomicGlob();
11595 }
11596 clearCursorWait();
11597 }
11598
11599 /*!
11600 * Returns true if the point at at the end of a section or document and the
11601 * previous strux is not a block
11602 */
isParaBreakNeededAtPos(PT_DocPosition pos) const11603 bool FV_View::isParaBreakNeededAtPos(PT_DocPosition pos) const
11604 {
11605
11606 PT_DocPosition posEOD = 0;
11607 getEditableBounds(true, posEOD);
11608 if(m_pDoc->isEndFrameAtPos(pos) && m_pDoc->isEndTableAtPos(pos-1))
11609 {
11610 return true;
11611 }
11612 if(!m_pDoc->isSectionAtPos(pos) && !m_pDoc->isHdrFtrAtPos(pos) &&
11613 (pos < posEOD))
11614 {
11615 return false;
11616 }
11617 pf_Frag * pf = m_pDoc->getFragFromPosition(pos);
11618 while(pf && pf->getType() != pf_Frag::PFT_Strux)
11619 {
11620 pf = pf->getPrev();
11621 }
11622 if(pf == NULL)
11623 {
11624 return false;
11625 }
11626 pf_Frag_Strux * pfs2 = static_cast<pf_Frag_Strux *>(pf);
11627 if(pfs2->getStruxType() == PTX_EndTOC)
11628 {
11629 return true;
11630 }
11631 if((pfs2->getStruxType() == PTX_EndFootnote) ||
11632 (pfs2->getStruxType() == PTX_EndAnnotation)||
11633 (pfs2->getStruxType() == PTX_EndEndnote) ||
11634 (pfs2->getStruxType() == PTX_Block) )
11635 {
11636 return false;
11637 }
11638 if((pfs2->getStruxType() == PTX_Section) || (pfs2->getStruxType() == PTX_SectionHdrFtr))
11639 {
11640 if(pfs2->getPos() < pos)
11641 {
11642 return true;
11643 }
11644 pf = pf->getPrev();
11645 while(pf && pf->getType() != pf_Frag::PFT_Strux)
11646 {
11647 pf = pf->getPrev();
11648 }
11649 if(pf == NULL)
11650 {
11651 return false;
11652 }
11653 pf_Frag_Strux * pfs = static_cast<pf_Frag_Strux *>(pf);
11654 if((pfs->getStruxType() == PTX_EndFootnote) ||
11655 (pfs->getStruxType() == PTX_EndAnnotation) ||
11656 (pfs->getStruxType() == PTX_EndEndnote) ||
11657 (pfs->getStruxType() == PTX_Block) )
11658 {
11659 return false;
11660 }
11661 }
11662 return true;
11663 }
11664
11665 /*!
11666 * Insrts a block and returns true if the point is at the end of a
11667 * section or document and the
11668 * previous strux is not a block
11669 */
insertParaBreakIfNeededAtPos(PT_DocPosition pos)11670 bool FV_View::insertParaBreakIfNeededAtPos(PT_DocPosition pos)
11671 {
11672 if(!isParaBreakNeededAtPos(pos))
11673 {
11674 return false;
11675 }
11676 m_pDoc->insertStrux(pos,PTX_Block);
11677 return true;
11678 }
11679
11680 /*!
11681 * Insert the header/footer. Save the cursor position before we do this and
11682 * restore it to where it was before we did this.
11683 \param HdrFtrType hfType
11684 \param bool bSkipPTSaves if true don't save the PieceTable stuff
11685 */
createThisHdrFtr(HdrFtrType hfType,bool bSkipPTSaves)11686 void FV_View::createThisHdrFtr(HdrFtrType hfType, bool bSkipPTSaves)
11687 {
11688 setCursorWait();
11689 const gchar* block_props[] = {
11690 "text-align", "left",
11691 NULL, NULL
11692 };
11693 if(!isSelectionEmpty())
11694 {
11695 _clearSelection();
11696 }
11697 PT_DocPosition oldPos = getPoint();
11698 fp_Page * pPage = getCurrentPage();
11699 if(pPage == NULL)
11700 {
11701 clearCursorWait();
11702 return;
11703 }
11704 fl_DocSectionLayout * pDSLP = pPage->getOwningSection();
11705 fl_DocSectionLayout * pDSL = getCurrentBlock()->getDocSectionLayout();
11706 if(pDSL != pDSLP)
11707 {
11708 clearCursorWait();
11709 return;
11710 }
11711 if(!bSkipPTSaves)
11712 {
11713 if(isHdrFtrEdit())
11714 clearHdrFtrEdit();
11715 //
11716 // Fix up the insertion point stuff.
11717 //
11718 if (!isSelectionEmpty())
11719 _clearSelection();
11720 m_pDoc->beginUserAtomicGlob(); // Begin the big undo block
11721
11722 // Signal PieceTable Changes have Started
11723 m_pDoc->notifyPieceTableChangeStart();
11724
11725 m_pDoc->disableListUpdates();
11726 }
11727 insertHeaderFooter(block_props, hfType); // cursor is now in the header/footer
11728
11729 // restore updates and clean up dirty lists
11730 if(!bSkipPTSaves)
11731 {
11732 m_pDoc->enableListUpdates();
11733 m_pDoc->updateDirtyLists();
11734
11735 // Signal PieceTable Changes have Ended
11736
11737 m_pDoc->notifyPieceTableChangeEnd();
11738 m_iPieceTableState = 0;
11739 m_pDoc->endUserAtomicGlob(); // End the big undo block
11740 }
11741 //
11742 // Restore old point
11743 //
11744 _setPoint(oldPos);
11745
11746 // restore updates and clean up dirty lists
11747 if(!bSkipPTSaves)
11748 {
11749 _generalUpdate();
11750 _updateInsertionPoint();
11751 }
11752 clearCursorWait();
11753 }
11754
11755
11756 /*!
11757 * OK, This method copies the content from either the header or footer to
11758 * the HdrFtrType specified here. This is used by the set HdrFtr properties
11759 * types in the GUI.
11760 \param HdrFtrType hfType
11761 \param bool bSkipPTSaves if true don't save the PieceTable stuff
11762 */
populateThisHdrFtr(HdrFtrType hfType,bool bSkipPTSaves)11763 void FV_View::populateThisHdrFtr(HdrFtrType hfType, bool bSkipPTSaves)
11764 {
11765 //
11766 // This won't work if we're not allowed to insert a HdrFtr on the current page
11767 // Detect and abort if so.
11768 //
11769 fp_Page * pPage = getCurrentPage();
11770 if(pPage == NULL)
11771 {
11772 return;
11773 }
11774 fl_DocSectionLayout * pDSLP = pPage->getOwningSection();
11775 fl_DocSectionLayout * pDSL = getCurrentBlock()->getDocSectionLayout();
11776 if(pDSL != pDSLP)
11777 {
11778 return;
11779 }
11780
11781 //
11782 // Fix up the insertion point stuff.
11783 //
11784 setCursorWait();
11785 if(!bSkipPTSaves)
11786 {
11787 if (!isSelectionEmpty())
11788 _clearSelection();
11789
11790 m_pDoc->beginUserAtomicGlob(); // Begin the big undo block
11791
11792 // Signal PieceTable Changes have Started
11793 m_pDoc->notifyPieceTableChangeStart();
11794
11795 m_pDoc->disableListUpdates();
11796 }
11797 //
11798 // Save Old Position
11799 //
11800 PT_DocPosition oldPos = getPoint();
11801
11802 if(pPage)
11803 {
11804 pDSL = pDSLP;
11805 }
11806
11807 UT_ASSERT(pDSL->getContainerType() == FL_CONTAINER_DOCSECTION);
11808 fl_HdrFtrSectionLayout * pHdrFtrSrc = NULL;
11809 fl_HdrFtrSectionLayout * pHdrFtrDest = NULL;
11810 if(pDSL && (hfType < FL_HDRFTR_FOOTER))
11811 {
11812 pHdrFtrSrc = pDSL->getHeader();
11813 }
11814 else if(pDSL)
11815 {
11816 pHdrFtrSrc = pDSL->getFooter();
11817 }
11818 if(pHdrFtrSrc == NULL)
11819 {
11820
11821 // restore updates and clean up dirty lists
11822 if(!bSkipPTSaves)
11823 {
11824 m_pDoc->enableListUpdates();
11825 m_pDoc->updateDirtyLists();
11826
11827 // Signal PieceTable Changes have Ended
11828
11829 m_pDoc->notifyPieceTableChangeEnd();
11830 m_iPieceTableState = 0;
11831 _generalUpdate();
11832 m_pDoc->endUserAtomicGlob(); // End the big undo block
11833 _updateInsertionPoint();
11834 }
11835 clearCursorWait();
11836 return;
11837 }
11838 //
11839 // Make sure we have everythimng formatted.
11840 //
11841 pHdrFtrSrc->format();
11842 if(hfType == FL_HDRFTR_HEADER_FIRST)
11843 {
11844 pHdrFtrDest = pDSL->getHeaderFirst();
11845 }
11846 else if( hfType == FL_HDRFTR_HEADER_EVEN)
11847 {
11848 pHdrFtrDest = pDSL->getHeaderEven();
11849 }
11850 else if( hfType == FL_HDRFTR_HEADER_LAST)
11851 {
11852 pHdrFtrDest = pDSL->getHeaderLast();
11853 }
11854 else if(hfType == FL_HDRFTR_FOOTER_FIRST)
11855 {
11856 pHdrFtrDest = pDSL->getFooterFirst();
11857 }
11858 else if( hfType == FL_HDRFTR_FOOTER_EVEN)
11859 {
11860 pHdrFtrDest = pDSL->getFooterEven();
11861 }
11862 else if( hfType == FL_HDRFTR_FOOTER_LAST)
11863 {
11864 pHdrFtrDest = pDSL->getFooterLast();
11865 }
11866 UT_ASSERT(pHdrFtrDest);
11867 if(pHdrFtrDest)
11868 {
11869 _populateThisHdrFtr(pHdrFtrSrc, pHdrFtrDest);
11870 _setPoint(oldPos);
11871 }
11872 // restore updates and clean up dirty lists
11873 if(!bSkipPTSaves)
11874 {
11875 m_pDoc->enableListUpdates();
11876 m_pDoc->updateDirtyLists();
11877
11878 // Signal PieceTable Changes have Ended
11879
11880 m_pDoc->notifyPieceTableChangeEnd();
11881 m_iPieceTableState = 0;
11882 _generalUpdate();
11883 m_pDoc->endUserAtomicGlob(); // End the big undo block
11884 _updateInsertionPoint();
11885 }
11886 clearCursorWait();
11887 }
11888
11889 /*!
11890 * This function returns true if there is a header on the current page.
11891 \returns true if is there a header on the current page.
11892 */
isHeaderOnPage(void) const11893 bool FV_View::isHeaderOnPage(void) const
11894 {
11895 const fp_Page * pPage = getCurrentPage();
11896 //UT_return_val_if_fail(pPage, false);
11897 if(!pPage)
11898 return false;
11899 return (pPage->getHdrFtrP(FL_HDRFTR_HEADER) != NULL);
11900 }
11901
11902 /*!
11903 * This function returns true if there is a footer on the current page.
11904 \returns true if is there a footer on the current page.
11905 */
isFooterOnPage(void) const11906 bool FV_View::isFooterOnPage(void) const
11907 {
11908 const fp_Page * pPage = getCurrentPage();
11909 //UT_return_val_if_fail(pPage, false);
11910 if(!pPage)
11911 return false;
11912 return (pPage->getHdrFtrP(FL_HDRFTR_FOOTER) != NULL);
11913 }
11914
11915 /*!
11916 * This method sets a bool variable which tells getEditableBounds we are
11917 * editing a header/Footer.
11918 * \param pSectionLayout pointer to the SectionLayout being editted.
11919 */
setHdrFtrEdit(fl_HdrFtrShadow * pShadow)11920 void FV_View::setHdrFtrEdit(fl_HdrFtrShadow * pShadow)
11921 {
11922 m_bEditHdrFtr = true;
11923 m_pEditShadow = pShadow;
11924 //
11925 // Draw the decorations around the Header/Footer
11926 //
11927 updateScreen();
11928 }
11929
11930
11931 /*!
11932 * This method clears the bool variable which tells
11933 * getEditableBounds we are
11934 * editting a header/Footer.
11935 */
clearHdrFtrEdit(void)11936 void FV_View::clearHdrFtrEdit(void)
11937 {
11938 m_bEditHdrFtr = false;
11939 m_pEditShadow = NULL;
11940 //
11941 // Remove the decorations around the Header/Footer
11942 //
11943 updateScreen();
11944 }
11945
11946 /*!
11947 * Returns the pointer to the current shadow.
11948 */
getEditShadow(void) const11949 fl_HdrFtrShadow * FV_View::getEditShadow(void) const
11950 {
11951 return m_pEditShadow;
11952 }
11953
11954 /*!
11955 * Returns true if we're currently editting a HdrFtr section.
11956 */
isHdrFtrEdit(void) const11957 bool FV_View::isHdrFtrEdit(void) const
11958 {
11959 return m_bEditHdrFtr;
11960 }
11961
11962 /*!
11963 * This method saves the current insertion point of the insertion point in the
11964 * doc. This is needed during undo's of insert Page Number. Maybe elsewhere
11965 * later.
11966 */
rememberCurrentPosition(void)11967 void FV_View::rememberCurrentPosition(void)
11968 {
11969 m_iSavedPosition = getPoint();
11970 m_bNeedSavedPosition = false;
11971 }
11972
11973 /*!
11974 * This method returns the saved insertion point of the insertion point in the
11975 * doc. This is needed during undo's of insert Page Number. Maybe elsewhere
11976 * later.
11977 */
11978
getSavedPosition(void) const11979 PT_DocPosition FV_View::getSavedPosition(void) const
11980 {
11981 return m_iSavedPosition;
11982 }
11983
11984 /*!
11985 * This method clears the saved position of the insertion point in the
11986 * doc.
11987 */
clearSavedPosition(void)11988 void FV_View::clearSavedPosition(void)
11989 {
11990 m_iSavedPosition = static_cast<PT_DocPosition>(0);
11991 m_bNeedSavedPosition = false;
11992 }
11993
11994 /*!
11995 * This method tells us we need the old position after an undo because of
11996 * header/footer undo's. Might be useful for other stuff later.
11997 */
needSavedPosition(void) const11998 bool FV_View::needSavedPosition(void) const
11999 {
12000 return m_bNeedSavedPosition;
12001 }
12002
12003 /*!
12004 * This method tells the undo to use the remembered position.
12005 */
markSavedPositionAsNeeded(void)12006 void FV_View::markSavedPositionAsNeeded(void)
12007 {
12008 m_bNeedSavedPosition = true;
12009 }
12010
12011
12012 /*!
12013
12014 This method is a replacement for getBounds which returns the beginning
12015 and end points of the document. It keeps the insertion point out of the
12016 header/footer region of the document by not counting the size of the
12017 header/footer region in the document length.
12018 HOWEVER if m_bHdrFtr is true this means we are editting in the Header/Footer
12019 region so the insertion piont is constrained to be in shadow section UNLESS
12020 bOverride is true in which case we return the Edittable region again.
12021
12022 We need all this so that we can jump into a Header/Footer region, stay
12023 there with simple keyboard motions and jump out again with a cursor click
12024 outside the header/footer.
12025
12026 \param isEnd true to get the end of the document. False gets the beginning
12027 \param posEnd is the value of the doc position at the beginning and end
12028 of the doc
12029 \param bOveride if true the EOD is made within the edittable region
12030 \return true if succesful
12031 \todo speed this up by finding clever way to cache the size of the
12032 header/footer region so we can just subtract it off.
12033 */
getEditableBounds(bool isEnd,PT_DocPosition & posEOD,bool bOveride) const12034 bool FV_View::getEditableBounds(bool isEnd, PT_DocPosition &posEOD, bool bOveride) const
12035 {
12036 bool res=true;
12037 fl_SectionLayout * pSL = NULL;
12038 fl_BlockLayout * pBL = NULL;
12039 if(!isEnd && (!m_bEditHdrFtr || bOveride))
12040 {
12041 res = m_pDoc->getBounds(isEnd,posEOD);
12042 return res;
12043 }
12044 if(!m_bEditHdrFtr || bOveride)
12045 {
12046 pSL = static_cast<fl_SectionLayout *>(m_pLayout->getLastSection());
12047
12048 if(!pSL)
12049 {
12050 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
12051 res = m_pDoc->getBounds(isEnd,posEOD);
12052 return res;
12053 }
12054
12055 // So if there are no HdrFtr sections, return m_pDoc->getBounds.
12056
12057 while(pSL->getNext() != NULL && (pSL->getContainerType() != FL_CONTAINER_HDRFTR))
12058 {
12059 pSL = static_cast<fl_SectionLayout *>(pSL->getNext());
12060 }
12061 if(pSL->getContainerType() != FL_CONTAINER_HDRFTR)
12062 {
12063 res = m_pDoc->getBounds(isEnd,posEOD);
12064 return res;
12065 }
12066 //
12067 // Now loop through all the HdrFtrSections, find the first in the doc and
12068 // use that to get the end of editttable region.
12069 //
12070 fl_ContainerLayout * pFirstCL = pSL->getFirstLayout();
12071 if(pFirstCL == NULL)
12072 {
12073 res = m_pDoc->getBounds(isEnd,posEOD);
12074 return res;
12075 }
12076
12077 PT_DocPosition posFirst = pFirstCL->getPosition(true) - 1;
12078 PT_DocPosition posNext;
12079 while((pSL->getNext() != NULL) && (pSL->getNextBlockInDocument() != NULL))
12080 {
12081 pSL = static_cast<fl_SectionLayout *>(pSL->getNext());
12082 pFirstCL = pSL->getFirstLayout();
12083 // Make sure the first fl_BlockLayout of this new
12084 // fl_SectionLayout is valid.
12085 if (pFirstCL)
12086 {
12087 posNext = pFirstCL->getPosition(true) - 1;
12088 if(posNext < posFirst)
12089 posFirst = posNext;
12090 }
12091 }
12092 posEOD = posFirst;
12093 return res;
12094 }
12095 //
12096 // Constrain insertion point to the header/Footer Layout
12097 //
12098 if(!isEnd)
12099 {
12100 UT_return_val_if_fail(m_pEditShadow->getFirstLayout(), false);
12101 posEOD = m_pEditShadow->getFirstLayout()->getPosition();
12102 return true;
12103 }
12104 pBL = static_cast<fl_BlockLayout *>(m_pEditShadow->getLastLayout());
12105 UT_return_val_if_fail(pBL, false);
12106 posEOD = pBL->getPosition(false);
12107 fp_Run * pRun = pBL->getFirstRun();
12108 while( pRun && pRun->getNextRun() != NULL)
12109 {
12110 pRun = pRun->getNextRun();
12111 }
12112 if(pRun)
12113 {
12114 posEOD += pRun->getBlockOffset();
12115 }
12116 return true;
12117 }
12118
12119
insertHeaderFooter(HdrFtrType hfType)12120 void FV_View::insertHeaderFooter(HdrFtrType hfType)
12121 {
12122 const gchar* block_props[] = {
12123 "text-align", "left",
12124 NULL, NULL
12125 };
12126 if(!isSelectionEmpty())
12127 {
12128 _clearSelection();
12129 }
12130 //
12131 // insert the header/footer and leave the cursor in there. Set us in header/footer
12132 // edit mode.
12133 //
12134 setCursorWait();
12135 UT_uint32 iPageNo = getCurrentPageNumber() - 1;
12136
12137 m_pDoc->beginUserAtomicGlob(); // Begin the big undo block
12138
12139 // Signal PieceTable Changes have Started
12140 m_pDoc->notifyPieceTableChangeStart();
12141
12142 m_pDoc->disableListUpdates();
12143
12144 insertHeaderFooter(block_props, hfType); // cursor is now in the header/footer
12145 if(isHdrFtrEdit())
12146 clearHdrFtrEdit();
12147
12148 // restore updates and clean up dirty lists
12149 m_pDoc->enableListUpdates();
12150 m_pDoc->updateDirtyLists();
12151
12152 // Signal PieceTable Changes have Ended
12153
12154 m_pDoc->notifyPieceTableChangeEnd();
12155 m_iPieceTableState = 0;
12156
12157 // Update Layout everywhere. This actually creates the header/footer container
12158
12159 m_pLayout->updateLayout(); // Update document layout everywhere
12160 m_pDoc->endUserAtomicGlob(); // End the big undo block
12161 //
12162 // Now extract the shadow section from this.
12163 //
12164 fp_Page * pPage = m_pLayout->getNthPage(iPageNo);
12165 fl_HdrFtrShadow * pShadow = NULL;
12166 fp_ShadowContainer * pHFCon = NULL;
12167 if(hfType >= FL_HDRFTR_FOOTER)
12168 pHFCon = pPage->getHdrFtrP(FL_HDRFTR_FOOTER);
12169 else if (hfType < FL_HDRFTR_FOOTER)
12170 pHFCon = pPage->getHdrFtrP(FL_HDRFTR_HEADER);
12171 else
12172 {
12173 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
12174 }
12175 UT_return_if_fail(pHFCon);
12176 pShadow = pHFCon->getShadow();
12177 UT_ASSERT(pShadow);
12178 //
12179 // Set Header/footer mode and we're done! Easy :-)
12180 //
12181 setHdrFtrEdit(pShadow);
12182
12183 _generalUpdate();
12184 _fixInsertionPointCoords();
12185 _ensureInsertionPointOnScreen();
12186 _fixInsertionPointCoords();
12187 clearCursorWait();
12188 notifyListeners(AV_CHG_MOTION | AV_CHG_HDRFTR );
12189 }
12190
insertHeaderFooter(const gchar ** props,HdrFtrType hfType,fl_DocSectionLayout * pDSL)12191 bool FV_View::insertHeaderFooter(const gchar ** props, HdrFtrType hfType, fl_DocSectionLayout * pDSL)
12192 {
12193 // UT_ASSERT(hfType == FL_HDRFTR_HEADER || hfType == FL_HDRFTR_FOOTER);
12194
12195 /*
12196 This inserts a header/footer at the end of the document,
12197 and leaves the insertion point there.
12198 This provides NO undo stuff. Do it yourself.
12199 */
12200
12201 UT_String szString;
12202 if(hfType == FL_HDRFTR_HEADER)
12203 {
12204 szString = "header";
12205 }
12206 else if( hfType == FL_HDRFTR_HEADER_EVEN)
12207 {
12208 szString = "header-even";
12209 }
12210 else if( hfType == FL_HDRFTR_HEADER_FIRST)
12211 {
12212 szString = "header-first";
12213 }
12214 else if( hfType == FL_HDRFTR_HEADER_LAST)
12215 {
12216 szString = "header-last";
12217 }
12218 else if(hfType == FL_HDRFTR_FOOTER)
12219 {
12220 szString = "footer";
12221 }
12222 else if( hfType == FL_HDRFTR_FOOTER_EVEN)
12223 {
12224 szString = "footer-even";
12225 }
12226 else if( hfType == FL_HDRFTR_FOOTER_FIRST)
12227 {
12228 szString = "footer-first";
12229 }
12230 else if( hfType == FL_HDRFTR_FOOTER_LAST)
12231 {
12232 szString = "footer-last";
12233 }
12234
12235 static gchar sid[15];
12236
12237 UT_return_val_if_fail(m_pDoc,false);
12238 UT_uint32 id = m_pDoc->getUID(UT_UniqueId::HeaderFtr);
12239 sprintf(sid, "%i", id);
12240
12241 const gchar* sec_attributes1[] = {
12242 "type", szString.c_str(),
12243 "id",sid,"listid","0","parentid","0",
12244 NULL, NULL
12245 };
12246
12247 const gchar* sec_attributes2[] = {
12248 szString.c_str(), sid,
12249 NULL, NULL
12250 };
12251
12252
12253 const gchar* block_props[] = {
12254 "text-align", "center",
12255 NULL, NULL
12256 };
12257
12258 if(!props)
12259 props = block_props; // use the defaults
12260
12261 //
12262 // Find the section that owns this page.
12263 //
12264 fl_DocSectionLayout * pDocL = pDSL;
12265 if(pDocL == NULL)
12266 {
12267 fp_Page* pCurrentPage = getCurrentPage();
12268 pDocL = pCurrentPage->getOwningSection();
12269 }
12270
12271 //
12272 // Now find the position of this section
12273 //
12274 fl_BlockLayout * pBL = pDocL->getNextBlockInDocument();
12275 PT_DocPosition posSec = pBL->getPosition();
12276
12277 // change the section to point to the footer which doesn't exist yet.
12278
12279 m_pDoc->changeStruxFmt(PTC_AddFmt, posSec, posSec, sec_attributes2, NULL, PTX_Section);
12280 PT_DocPosition iPos = _getDocPos(FV_DOCPOS_EOD);
12281 _setPoint(iPos); // Move to the end, where we will create the header/footer
12282
12283
12284 // insert the Header/Footer
12285 PT_DocPosition posBlock = getPoint() +1;
12286 m_pDoc->insertStrux(getPoint(), PTX_SectionHdrFtr,sec_attributes1, NULL);
12287
12288 // Now the block strux for the content
12289
12290 m_pDoc->insertStrux(posBlock, PTX_Block,NULL, props);
12291 setPoint(posBlock+1);
12292 // OK it's in!
12293 m_pDoc->signalListeners(PD_SIGNAL_REFORMAT_LAYOUT);
12294 return true;
12295 }
12296
12297 /*!
12298 * This method returns the depth of the embedding level at the requested point.
12299 * If the point is not inside a footnote or Endnote, we return zero. If the
12300 * point is inside a footnote or endnote return 1, if the point is inside
12301 * an endnote inside a footnote return 2 etc.
12302 */
getEmbedDepth(PT_DocPosition pos) const12303 UT_sint32 FV_View::getEmbedDepth(PT_DocPosition pos) const
12304 {
12305 fl_BlockLayout * pBL = m_pLayout->findBlockAtPosition(pos);
12306 if(pBL == NULL)
12307 {
12308 return 0;
12309 }
12310 fl_ContainerLayout * pCL = static_cast<fl_ContainerLayout *>(pBL->myContainingLayout());
12311 bool bStop = false;
12312 UT_sint32 count =-1;
12313 while(!bStop && pCL)
12314 {
12315 count++;
12316 bStop = ((pCL->getContainerType() != FL_CONTAINER_FOOTNOTE) &&
12317 (pCL->getContainerType() != FL_CONTAINER_ENDNOTE) &&
12318 (pCL->getContainerType() != FL_CONTAINER_ANNOTATION));
12319 pCL = static_cast<fl_ContainerLayout *>(pCL->myContainingLayout());
12320 }
12321 return count;
12322 }
12323 /*!
12324 * This method returns the closest footnote before or that contains the
12325 * requested doc position. If the is no footnote before the doc position, NULL
12326 * is returned.
12327 */
getClosestFootnote(PT_DocPosition pos) const12328 fl_FootnoteLayout * FV_View::getClosestFootnote(PT_DocPosition pos) const
12329 {
12330 fl_FootnoteLayout * pFL = NULL;
12331 fl_FootnoteLayout * pClosest = NULL;
12332 UT_sint32 i = 0;
12333 for(i = 0; i< static_cast<UT_sint32>(m_pLayout->countFootnotes());i++)
12334 {
12335 pFL = m_pLayout->getNthFootnote(i);
12336 if(pFL->getDocPosition() <= pos)
12337 {
12338 if(pClosest == NULL)
12339 {
12340 pClosest = pFL;
12341 }
12342 else if( pClosest->getDocPosition() < pFL->getDocPosition())
12343 {
12344 pClosest = pFL;
12345 }
12346 }
12347 }
12348 return pClosest;
12349 }
12350
12351
12352 /*!
12353 * This method returns the closest endnote before or that contains the
12354 * requested doc position. If the is no footnote before the doc position, NULL
12355 * is returned.
12356 */
getClosestEndnote(PT_DocPosition pos) const12357 fl_EndnoteLayout * FV_View::getClosestEndnote(PT_DocPosition pos) const
12358 {
12359 fl_EndnoteLayout * pFL = NULL;
12360 fl_EndnoteLayout * pClosest = NULL;
12361 UT_sint32 i = 0;
12362 for(i = 0; i< static_cast<UT_sint32>(m_pLayout->countEndnotes());i++)
12363 {
12364 pFL = m_pLayout->getNthEndnote(i);
12365 if(pFL->getDocPosition() <= pos)
12366 {
12367 if(pClosest == NULL)
12368 {
12369 pClosest = pFL;
12370 }
12371 else if( pClosest->getDocPosition() < pFL->getDocPosition())
12372 {
12373 pClosest = pFL;
12374 }
12375 }
12376 }
12377 return pClosest;
12378 }
12379
12380
12381
12382 /*!
12383 * This method returns the closest annotation before or that contains the
12384 * requested doc position. If the is no annnotation before the doc position, NULL
12385 * is returned.
12386 */
getClosestAnnotation(PT_DocPosition pos) const12387 fl_AnnotationLayout * FV_View::getClosestAnnotation(PT_DocPosition pos) const
12388 {
12389 fl_AnnotationLayout * pAL = NULL;
12390 fl_AnnotationLayout * pClosest = NULL;
12391 UT_sint32 i = 0;
12392 for(i = 0; i< static_cast<UT_sint32>(m_pLayout->countAnnotations());i++)
12393 {
12394 pAL = m_pLayout->getNthAnnotation(i);
12395 if(pAL->getDocPosition() <= pos)
12396 {
12397 if(pClosest == NULL)
12398 {
12399 pClosest = pAL;
12400 }
12401 else if( pClosest->getDocPosition() < pAL->getDocPosition())
12402 {
12403 pClosest = pAL;
12404 }
12405 }
12406 }
12407 return pClosest;
12408 }
12409
isInHdrFtr(PT_DocPosition pos) const12410 bool FV_View::isInHdrFtr(PT_DocPosition pos) const
12411 {
12412 fl_BlockLayout * pBL = _findBlockAtPosition(pos);
12413 if(pBL == NULL)
12414 {
12415 return false;
12416 }
12417 fl_ContainerLayout * pCL = pBL->myContainingLayout();
12418 while(pCL && ((pCL->getContainerType() != FL_CONTAINER_DOCSECTION)
12419 && (pCL->getContainerType() != FL_CONTAINER_HDRFTR)
12420 && (pCL->getContainerType() != FL_CONTAINER_SHADOW)))
12421 {
12422 pCL = pCL->myContainingLayout();
12423 }
12424 if(pCL && ( (pCL->getContainerType() == FL_CONTAINER_HDRFTR)
12425 || (pCL->getContainerType() == FL_CONTAINER_SHADOW)))
12426 {
12427 return true;
12428 }
12429 return false;
12430 }
12431
12432 /*!
12433 * Returns true if the point is located with a block so stuff can be typed
12434 * or inserted.
12435 */
isPointLegal(PT_DocPosition pos) const12436 bool FV_View::isPointLegal(PT_DocPosition pos) const
12437 {
12438 pf_Frag_Strux* prevSDH = NULL;
12439 pf_Frag_Strux* nextSDH = NULL;
12440 PT_DocPosition nextPos =0;
12441
12442 //
12443 // Special cases which would otherwise fail..
12444 //
12445 if(m_pDoc->isEndFootnoteAtPos(pos))
12446 {
12447 return true;
12448 }
12449 if(m_pDoc->isFootnoteAtPos(pos))
12450 {
12451 return true;
12452 }
12453 fl_BlockLayout * pBL = _findBlockAtPosition(pos);
12454 if(pBL == NULL)
12455 {
12456 return false;
12457 }
12458
12459 if(!pBL->canContainPoint())
12460 {
12461 return false;
12462 }
12463
12464 bool bres = m_pDoc->getStruxOfTypeFromPosition(pos,PTX_Block,&prevSDH);
12465 if(!bres)
12466 {
12467 return false;
12468 }
12469 //
12470 // Can't place point at endToc
12471 //
12472 if( m_pDoc->isTOCAtPos(pos-1) && m_pDoc->isTOCAtPos(pos))
12473 {
12474 return false;
12475 }
12476 //
12477 // Can't place between frames and the next paragraph
12478 //
12479 if(m_pDoc->isEndFrameAtPos(pos) && m_pDoc->isFrameAtPos(pos-1))
12480 {
12481 return false;
12482 }
12483
12484 // another corner case
12485
12486 if(m_pDoc->isEndTableAtPos(pos-1) && m_pDoc->isEndFrameAtPos(pos))
12487 {
12488 return false;
12489 }
12490 if(m_pDoc->isEndFrameAtPos(pos) && !m_pDoc->isFrameAtPos(pos-1))
12491 {
12492 return true; // This is how we insert into frames
12493 }
12494
12495 if(m_pDoc->isEndFrameAtPos(pos-1) && m_pDoc->isFrameAtPos(pos))
12496 {
12497 return false;
12498 }
12499 PT_DocPosition posEnd = 0;
12500 getEditableBounds(true, posEnd);
12501 if(pos > posEnd)
12502 {
12503 return false;
12504 }
12505 if(pos == posEnd && m_pDoc->isEndFrameAtPos(pos-1))
12506 {
12507 return false;
12508 }
12509 if((pos+1) == posEnd && m_pDoc->isEndFrameAtPos(pos))
12510 {
12511 return false;
12512 }
12513 if(((pos+1) == posEnd) && m_pDoc->isTOCAtPos(pos-1))
12514 {
12515 return false;
12516 }
12517
12518 bres = m_pDoc->getNextStrux(prevSDH,&nextSDH);
12519 if(!bres)
12520 {
12521 return true;
12522 }
12523 nextPos = m_pDoc->getStruxPosition(nextSDH);
12524 if(pos > nextPos && (m_pDoc->getStruxType(nextSDH) != PTX_Block))
12525 {
12526 return false;
12527 }
12528 if((pos > pBL->getPosition(true)) && (pos <= (pBL->getPosition(true) + pBL->getLength())))
12529 {
12530 return true;
12531 }
12532 return false;
12533 }
12534
isPointLegal(void) const12535 bool FV_View::isPointLegal(void) const
12536 {
12537 return isPointLegal(getPoint());
12538 }
12539
12540 /*!
12541 * Returns true if the current insertion point is inside a footnote.
12542 */
isInFootnote(void) const12543 bool FV_View::isInFootnote(void) const
12544 {
12545 return isInFootnote(getPoint());
12546 }
12547
12548 /*!
12549 * Returns true if the requested position is inside a footnote.
12550 */
isInFootnote(PT_DocPosition pos) const12551 bool FV_View::isInFootnote(PT_DocPosition pos) const
12552 {
12553 fl_FootnoteLayout * pFL = getClosestFootnote(pos);
12554 if(pFL == NULL)
12555 {
12556 return false;
12557 }
12558 if(!pFL->isEndFootnoteIn())
12559 {
12560 return false;
12561 }
12562 if((pFL->getDocPosition() <= pos) && ((pFL->getDocPosition() + pFL->getLength()) > pos))
12563 {
12564 return true;
12565 }
12566 return false;
12567 }
12568
12569 /*!
12570 * Returns true if the current insertion point is inside a footnote.
12571 */
isInEndnote(void) const12572 bool FV_View::isInEndnote(void) const
12573 {
12574 return isInEndnote(getPoint());
12575 }
12576
12577 /*!
12578 * Returns true if the requested position is inside a endnote.
12579 */
isInEndnote(PT_DocPosition pos) const12580 bool FV_View::isInEndnote(PT_DocPosition pos) const
12581 {
12582 fl_EndnoteLayout * pFL = getClosestEndnote(pos);
12583 if(pFL == NULL)
12584 {
12585 return false;
12586 }
12587 if(!pFL->isEndFootnoteIn())
12588 {
12589 return false;
12590 }
12591 if((pFL->getDocPosition() <= pos) && ((pFL->getDocPosition() + pFL->getLength()) > pos))
12592 {
12593 return true;
12594 }
12595 return false;
12596 }
12597
12598
12599 /*!
12600 * Returns true if the current insertion point is inside a annotation.
12601 */
isInAnnotation(void) const12602 bool FV_View::isInAnnotation(void) const
12603 {
12604 return isInAnnotation(getPoint());
12605 }
12606
12607 /*!
12608 * Returns true if the requested position is inside a endnote.
12609 */
isInAnnotation(PT_DocPosition pos) const12610 bool FV_View::isInAnnotation(PT_DocPosition pos) const
12611 {
12612 fl_AnnotationLayout * pAL = getClosestAnnotation(pos);
12613 if(pAL == NULL)
12614 {
12615 return false;
12616 }
12617 if(!pAL->isEndFootnoteIn())
12618 {
12619 return false;
12620 }
12621 if((pAL->getDocPosition() <= pos) && ((pAL->getDocPosition() + pAL->getLength()) > pos))
12622 {
12623 return true;
12624 }
12625 return false;
12626 }
12627
getAnnotationLayout(UT_uint32 iAnnotation) const12628 fl_AnnotationLayout * FV_View::getAnnotationLayout(UT_uint32 iAnnotation) const
12629 {
12630 fl_AnnotationLayout * pAnn = m_pLayout->findAnnotationLayout(iAnnotation);
12631 return pAnn;
12632 }
12633
12634
countAnnotations(void) const12635 UT_uint32 FV_View::countAnnotations(void) const
12636 {
12637 return m_pLayout->countAnnotations();
12638 }
12639
12640
getAnnotationText(UT_uint32 iAnnotation) const12641 std::string FV_View::getAnnotationText(UT_uint32 iAnnotation) const
12642 {
12643 std::string ret;
12644 if(!getAnnotationText( iAnnotation, ret ))
12645 ret = "";
12646 return ret;
12647 }
12648
12649
12650
12651 /*!
12652 * Return the plain text content of the annotation specified by iAnnotaion
12653 * Content is returned in UT_UTF8String sText.
12654 * Returns true if a valid annotation was found with valid content.
12655 */
getAnnotationText(UT_uint32 iAnnotation,std::string & sText) const12656 bool FV_View::getAnnotationText(UT_uint32 iAnnotation, std::string & sText) const
12657 {
12658 fl_AnnotationLayout * pAL = getAnnotationLayout(iAnnotation);
12659 if(!pAL)
12660 return false;
12661 pf_Frag_Strux* sdhStart = pAL->getStruxDocHandle();
12662 PT_DocPosition posStart = getDocument()->getStruxPosition(sdhStart)+1; // Pos of Block o Text
12663 UT_GrowBuf buffer;
12664 fl_BlockLayout * block;
12665
12666 block = m_pLayout->findBlockAtPosition(posStart+1);
12667 fp_Run * pRun = NULL;
12668 while(block && (static_cast<fl_AnnotationLayout *>(block->myContainingLayout()) == pAL))
12669 {
12670 UT_GrowBuf tmp;
12671 block->getBlockBuf(&tmp);
12672 pRun = block->getFirstRun();
12673 while(pRun)
12674 {
12675 if(pRun->getType() == FPRUN_TEXT)
12676 {
12677 buffer.append(tmp.getPointer(pRun->getBlockOffset()),pRun->getLength());
12678 }
12679 pRun = pRun->getNextRun();
12680 }
12681 tmp.truncate(0);
12682 block = block->getNextBlockInDocument();
12683 }
12684 UT_UCS4String uText(reinterpret_cast<const UT_UCS4Char *>( buffer.getPointer(0)),
12685 buffer.getLength());
12686 sText = uText.utf8_str();
12687 return true;
12688 }
12689
12690 /*!
12691 * Select the text that is covered by the annotation
12692 */
selectAnnotation(fl_AnnotationLayout * pAL)12693 bool FV_View::selectAnnotation(fl_AnnotationLayout * pAL)
12694 {
12695 pf_Frag_Strux* sdhAnn = pAL->getStruxDocHandle();
12696 pf_Frag_Strux* sdhEnd = NULL;
12697 getDocument()->getNextStruxOfType(sdhAnn,PTX_EndAnnotation, &sdhEnd);
12698
12699 UT_return_val_if_fail(sdhEnd != NULL, false);
12700 //
12701 // Start of the text covered by the annotations
12702 //
12703 PT_DocPosition posStart = getDocument()->getStruxPosition(sdhEnd);
12704 posStart++;
12705 fp_Run * pRun = getHyperLinkRun(posStart);
12706 UT_DEBUGMSG(("FV_View::selectAnnotation() pRun:%p\n", pRun ));
12707 UT_return_val_if_fail(pRun, false);
12708 pRun = pRun->getNextRun();
12709 while(pRun && (pRun->getType() != FPRUN_HYPERLINK))
12710 pRun = pRun->getNextRun();
12711 UT_return_val_if_fail(pRun, false);
12712 UT_return_val_if_fail(pRun->getType() == FPRUN_HYPERLINK, false);
12713 PT_DocPosition posEnd = pRun->getBlock()->getPosition(false) + pRun->getBlockOffset();
12714 if(posStart> posEnd)
12715 posStart = posEnd;
12716 setPoint(posEnd);
12717 _ensureInsertionPointOnScreen();
12718 setCursorToContext();
12719 cmdSelect(posStart,posEnd);
12720 notifyListeners(AV_CHG_MOTION | AV_CHG_HDRFTR );
12721
12722 return true;
12723 }
12724
12725 /*!
12726 * Set the content of the annotation to the plain text supplied by
12727 * UT_UTF8String sText.
12728 * Returns true if a valid annotation was found with valid content.
12729 */
setAnnotationText(UT_uint32 iAnnotation,const std::string & sText)12730 bool FV_View::setAnnotationText(UT_uint32 iAnnotation, const std::string & sText)
12731 {
12732 fl_AnnotationLayout * pAL = getAnnotationLayout(iAnnotation);
12733 if(!pAL)
12734 return false;
12735 pf_Frag_Strux* sdhStart = pAL->getStruxDocHandle();
12736 pf_Frag_Strux* sdhEnd = NULL;
12737 getDocument()->getNextStruxOfType(sdhStart,PTX_EndAnnotation, &sdhEnd);
12738
12739 UT_return_val_if_fail(sdhEnd != NULL, false);
12740 PT_DocPosition posStart = getDocument()->getStruxPosition(sdhStart)+1; // Pos of Block o Text
12741 PT_DocPosition posEnd = getDocument()->getStruxPosition(sdhEnd);
12742 //
12743 // First set up a glob
12744 //
12745 m_pDoc->beginUserAtomicGlob();
12746 _saveAndNotifyPieceTableChange();
12747 m_pDoc->disableListUpdates();
12748 //
12749 // Cut out current content
12750 //
12751 UT_uint32 iRealDeleteCount2;
12752 PP_AttrProp * pAttrProp_Before = NULL;
12753 m_pDoc->deleteSpan(posStart+1, posEnd, pAttrProp_Before, iRealDeleteCount2);
12754 //
12755 // Insert the new text
12756 //
12757 UT_UCS4String text(sText);
12758 m_pDoc->insertSpan(posStart+1, text.ucs4_str(),text.size(),pAttrProp_Before);
12759 m_pDoc->endUserAtomicGlob();
12760
12761 // Signal PieceTable Changes have finished
12762 _restorePieceTableState();
12763 _generalUpdate();
12764 return true;
12765
12766 }
12767
12768
12769 /*!
12770 * Set the content of the annotation to the plain text supplied by
12771 * UT_UTF8String sText.
12772 * Returns true if a valid annotation was found with valid content.
12773 */
setAnnotationText(UT_uint32 iAnnotation,const std::string & sText,const std::string & sAuthor,const std::string & sTitle)12774 bool FV_View::setAnnotationText(UT_uint32 iAnnotation, const std::string & sText,
12775 const std::string & sAuthor, const std::string & sTitle)
12776 {
12777 fl_AnnotationLayout * pAL = getAnnotationLayout(iAnnotation);
12778 if(!pAL)
12779 return false;
12780 pf_Frag_Strux* sdhStart = pAL->getStruxDocHandle();
12781 pf_Frag_Strux* sdhEnd = NULL;
12782 getDocument()->getNextStruxOfType(sdhStart,PTX_EndAnnotation, &sdhEnd);
12783
12784 UT_return_val_if_fail(sdhEnd != NULL, false);
12785 PT_DocPosition posStart = getDocument()->getStruxPosition(sdhStart)+1; // Pos of Block o Text
12786 PT_DocPosition posEnd = getDocument()->getStruxPosition(sdhEnd);
12787 //
12788 // First set up a glob
12789 //
12790 m_pDoc->beginUserAtomicGlob();
12791 _saveAndNotifyPieceTableChange();
12792 m_pDoc->disableListUpdates();
12793 //
12794 // Cut out current content (if any, as "" is allowed as annotation content)
12795 //
12796 PP_AttrProp * pAttrProp_Before = NULL;
12797 if (posStart+1 < posEnd)
12798 {
12799 UT_uint32 iRealDeleteCount2;
12800 m_pDoc->deleteSpan(posStart+1, posEnd, pAttrProp_Before, iRealDeleteCount2);
12801 }
12802 //
12803 // Insert the new text
12804 //
12805 UT_UCS4String text(sText);
12806 m_pDoc->insertSpan(posStart+1, text.ucs4_str(), text.size(),pAttrProp_Before);
12807 //
12808 // Set the annotation properties
12809 //
12810 const char * pszAnn[7] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL};
12811 pszAnn[0] = "annotation-author";
12812 pszAnn[1] = sAuthor.c_str();
12813 pszAnn[2] = "annotation-title";
12814 pszAnn[3] = sTitle.c_str();
12815 pszAnn[4] = "annotation-date";
12816 GDate gDate;
12817 g_date_set_time_t (&gDate, time (NULL));
12818 std::string sDate;
12819 sDate = UT_std_string_sprintf("%d-%d-%d",gDate.month,gDate.day,gDate.year);
12820 pszAnn[5] = sDate.c_str();
12821 xxx_UT_DEBUGMSG((" Set Author %s Title %s posStart %d \n", sAuthor.c_str(),sTitle.c_str(),posStart));
12822 m_pDoc->changeStruxFmt(PTC_AddFmt,posStart,posStart,NULL,pszAnn,PTX_SectionAnnotation);
12823
12824 m_pDoc->endUserAtomicGlob();
12825
12826 // Signal PieceTable Changes have finished
12827 _restorePieceTableState();
12828 _generalUpdate();
12829 return true;
12830
12831 }
12832
getAnnotationTitle(UT_uint32 iAnnotation) const12833 std::string FV_View::getAnnotationTitle(UT_uint32 iAnnotation) const
12834 {
12835 std::string ret;
12836 if( !getAnnotationTitle( iAnnotation, ret ))
12837 ret = "";
12838 return ret;
12839 }
12840
12841
12842 // TODO getters and setters to implement/change/add as judged necessary
getAnnotationTitle(UT_uint32 iAnnotation,std::string & sTitle) const12843 bool FV_View::getAnnotationTitle(UT_uint32 iAnnotation, std::string & sTitle) const
12844 {
12845 fl_AnnotationLayout * pAL = getAnnotationLayout(iAnnotation);
12846 if(!pAL)
12847 return false;
12848 sTitle = pAL->getTitle();
12849 return true;
12850 }
setAnnotationTitle(UT_uint32 iAnnotation,const std::string & sTitle)12851 bool FV_View::setAnnotationTitle(UT_uint32 iAnnotation, const std::string & sTitle)
12852 {
12853 fl_AnnotationLayout * pAL = getAnnotationLayout(iAnnotation);
12854 if(!pAL)
12855 return false;
12856 pf_Frag_Strux* sdhAnn = pAL->getStruxDocHandle();
12857 PT_DocPosition posAnn = m_pDoc->getStruxPosition(sdhAnn);
12858 const char * pszAnn[3] = {NULL,NULL,NULL};
12859 pszAnn[0] = "annotation-title";
12860 pszAnn[1] = sTitle.c_str();
12861 m_pDoc->changeStruxFmt(PTC_AddFmt,posAnn,posAnn,NULL,pszAnn,PTX_SectionAnnotation);
12862 return true;
12863 }
getAnnotationAuthor(UT_uint32 iAnnotation) const12864 std::string FV_View::getAnnotationAuthor(UT_uint32 iAnnotation) const
12865 {
12866 std::string ret;
12867 if(!getAnnotationAuthor(iAnnotation,ret))
12868 ret = "";
12869 return ret;
12870 }
12871
getAnnotationAuthor(UT_uint32 iAnnotation,std::string & sAuthor) const12872 bool FV_View::getAnnotationAuthor(UT_uint32 iAnnotation, std::string & sAuthor) const
12873 {
12874 fl_AnnotationLayout * pAL = getAnnotationLayout(iAnnotation);
12875 if(!pAL)
12876 return false;
12877 sAuthor = pAL->getAuthor();
12878 return true;
12879 }
setAnnotationAuthor(UT_uint32 iAnnotation,const std::string & sAuthor)12880 bool FV_View::setAnnotationAuthor(UT_uint32 iAnnotation, const std::string & sAuthor)
12881 {
12882 fl_AnnotationLayout * pAL = getAnnotationLayout(iAnnotation);
12883 if(!pAL)
12884 return false;
12885 pf_Frag_Strux* sdhAnn = pAL->getStruxDocHandle();
12886 PT_DocPosition posAnn = m_pDoc->getStruxPosition(sdhAnn);
12887 const char * pszAnn[3] = {NULL,NULL,NULL};
12888 pszAnn[0] = "annotation-author";
12889 pszAnn[1] = sAuthor.c_str();
12890 m_pDoc->changeStruxFmt(PTC_AddFmt,posAnn,posAnn,NULL,pszAnn,PTX_SectionAnnotation);
12891 return true;
12892 }
12893
12894 /*!
12895 * Insert annotation number iAnnotation across the current selection.
12896 * The text of the annotation is contained in pStr.
12897 * If pstr is NULL default text is inserted.
12898 * If bCopy is true, the current selection is copied and placed into
12899 * an annotation.
12900 */
insertAnnotation(UT_sint32 iAnnotation,const std::string & sDescr,const std::string & sAuthor,const std::string & sTitle,bool bCopy)12901 bool FV_View::insertAnnotation(UT_sint32 iAnnotation,
12902 const std::string & sDescr,
12903 const std::string & sAuthor,
12904 const std::string & sTitle,
12905 bool bCopy)
12906 {
12907 // can only apply an Annotation to an FL_SECTION_DOC or a Table
12908 // TODO allow applying to empty selection (cursor position)
12909 fl_BlockLayout * pBlock = _findBlockAtPosition(getPoint());
12910 if(pBlock == NULL)
12911 {
12912 return false;
12913 }
12914 fl_SectionLayout * pSL = pBlock->getSectionLayout();
12915
12916 if ( (pSL->getContainerType() != FL_CONTAINER_DOCSECTION) && (pSL->getContainerType() != FL_CONTAINER_CELL) )
12917 return false;
12918 if(getHyperLinkRun(getPoint()) != NULL)
12919 {
12920 return false;
12921 }
12922 if(m_FrameEdit.isActive())
12923 {
12924 return false;
12925 }
12926 //
12927 // Do this first
12928 //
12929 if(m_pDoc->isTOCAtPos(getPoint()-1))
12930 {
12931 if(getPoint() ==2 || (pSL->getPosition(true) >= (getPoint() -2)))
12932 {
12933 return false;
12934 }
12935 setPoint(getPoint()-1);
12936 }
12937 UT_GenericVector<fl_BlockLayout*> vBlocks;
12938
12939 PT_DocPosition posStart = getPoint();
12940 PT_DocPosition posEnd = posStart;
12941
12942 if (m_Selection.getSelectionAnchor() < posStart)
12943 {
12944 posStart = m_Selection.getSelectionAnchor();
12945 }
12946 else
12947 {
12948 posEnd = m_Selection.getSelectionAnchor();
12949 }
12950
12951 // Hack for bug 2940
12952 if (posStart <= 1) posStart=2;
12953
12954 //
12955 // Look to see if the selection spans multiple blocks. If so, pick the
12956 // Block containing the largest amount of selected text.
12957 //
12958 PT_DocPosition posAnnStart;
12959 PT_DocPosition posAnnEnd;
12960 getBlocksInSelection(&vBlocks);
12961 if(vBlocks.getItemCount() > 1)
12962 {
12963 fl_BlockLayout * pBMax = NULL;
12964 UT_sint32 iMaxSize = 0;
12965 UT_sint32 j = 0;
12966 for(j=0; j<vBlocks.getItemCount(); j++)
12967 {
12968 UT_sint32 iBSize = 0;
12969 fl_BlockLayout * pB = vBlocks.getNthItem(j);
12970 iBSize = pB->getLength();
12971 if(j == 0)
12972 {
12973 iBSize = iBSize - (posStart - pB->getPosition(true));
12974 }
12975 else if(j == (vBlocks.getItemCount() - 1))
12976 {
12977 iBSize = posEnd - pB->getPosition(true);
12978 }
12979 if(iBSize > iMaxSize)
12980 {
12981 iMaxSize = iBSize;
12982 pBMax = pB;
12983 }
12984 }
12985 posAnnStart = pBMax->getPosition();
12986 posAnnEnd = pBMax->getPosition(true) + pBMax->getLength();
12987 if(posAnnStart < posStart)
12988 posAnnStart = posStart;
12989 if(posAnnEnd > posEnd)
12990 posAnnEnd = posEnd;
12991 posStart = posAnnStart;
12992 posEnd = posAnnEnd;
12993 }
12994
12995 // the selection has to be within a single block
12996 // we could implement hyperlinks spaning arbitrary part of the document
12997 // but then we could not use <a href=> </a> in the output and
12998 // I see no obvious need for hyperlinks to span more than a single block
12999 fl_BlockLayout * pBl1 = _findBlockAtPosition(posStart);
13000 fl_BlockLayout * pBl2 = _findBlockAtPosition(posEnd);
13001 //
13002 // Only allow annotations within a single block - for now
13003 //
13004 if(pBl1 != pBl2)
13005 {
13006 return false;
13007 }
13008 // Silently fail (TODO: pop up message) if we try to nest annotations or hyperlinks.
13009 if (_getHyperlinkInRange(posStart, posEnd) != NULL)
13010 return false;
13011 //
13012 // Under sum1 induced conditions posEnd could give the same block pointer
13013 // despite being past the end of the block. This extra fail-safe code
13014 // prevents this.
13015 //
13016 if((pBl1->getPosition() + pBl1->getLength() -1) < posEnd)
13017 {
13018 return false;
13019 }
13020 const gchar * pAttr[4];
13021 pAttr[0] = PT_ANNOTATION_NUMBER;
13022 std::string sNum;
13023 sNum = UT_std_string_sprintf("%d",iAnnotation);
13024 pAttr[1] = sNum.c_str();
13025 pAttr[2] = 0;
13026 pAttr[3] = 0;
13027 //
13028 // First set up a glob
13029 //
13030 m_pDoc->beginUserAtomicGlob();
13031 _saveAndNotifyPieceTableChange();
13032 m_pDoc->disableListUpdates();
13033 //
13034 // Cut out current selection.
13035 //
13036 if(bCopy)
13037 {
13038 copyToLocal(posStart,posEnd);
13039 }
13040 _clearSelection();
13041 //
13042 // Now insert the Hyperlink-like field
13043 //
13044
13045 // Now insert the annotation end run, so that we can use it as a stop
13046 // after inserting the start run when marking the runs in between
13047 // as a hyperlink
13048 bool bRet = m_pDoc->insertObject(posEnd, PTO_Annotation, NULL, NULL);
13049 if(bRet)
13050 {
13051 const gchar ** pProps = 0;
13052 bRet = m_pDoc->insertObject(posStart, PTO_Annotation, pAttr, pProps);
13053 }
13054
13055 //
13056 // We insert the annotations struxes right after the annotation start
13057 //
13058 PT_DocPosition posAnnotation = posStart+1;
13059 const gchar* ann_attrs[4];
13060 ann_attrs[0] = "annotation-id";
13061 ann_attrs[1] = sNum.c_str();
13062 ann_attrs[2] = 0;
13063 ann_attrs[3] = 0;
13064 const char * pszAnn[7] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL};
13065 pszAnn[0] = "annotation-author";
13066 pszAnn[1] = sAuthor.c_str();
13067 pszAnn[2] = "annotation-title";
13068 pszAnn[3] = sTitle.c_str();
13069 pszAnn[4] = "annotation-date";
13070 GDate gDate;
13071 g_date_set_time_t (&gDate, time (NULL));
13072 std::string sDate;
13073 sDate = UT_std_string_sprintf("%d-%d-%d",gDate.month,gDate.day,gDate.year);
13074 pszAnn[5] = sDate.c_str();
13075 const gchar* block_atts[] = {PT_STYLE_ATTRIBUTE_NAME,
13076 "Normal",
13077 NULL,
13078 NULL
13079 };
13080 //
13081 //
13082 // OK now insert the Annotation struxes
13083 //
13084 m_pDoc->insertStrux(posAnnotation,PTX_SectionAnnotation,ann_attrs,pszAnn);
13085 m_pDoc->insertStrux(posAnnotation+1,PTX_Block,block_atts,NULL);
13086 m_pDoc->insertStrux(posAnnotation+2,PTX_EndAnnotation,NULL,NULL);
13087 //
13088 // OK now Insert the text into the annotation strux
13089 //
13090 if(bCopy)
13091 {
13092 //
13093 // Paste in the selected text
13094 //
13095 _pasteFromLocalTo(posAnnotation+2);
13096 }
13097 else
13098 {
13099 UT_UCS4String sUCS4(sDescr);
13100 const PP_AttrProp * pSpanAP = NULL;
13101 const PP_AttrProp * pBlockAP = NULL;
13102 getAttributes(&pSpanAP,&pBlockAP,posAnnotation+2);
13103 bRet = m_pDoc->insertSpan(posAnnotation+2, sUCS4.ucs4_str(),sUCS4.length(),const_cast<PP_AttrProp *>(pSpanAP));
13104
13105 }
13106 // Signal piceTable is stable again and close off the glob
13107
13108 _restorePieceTableState();
13109 _generalUpdate();
13110 m_pDoc->endUserAtomicGlob();
13111 m_pDoc->enableListUpdates();
13112 fl_AnnotationLayout * pAL = getClosestAnnotation(posAnnotation+2);
13113 selectAnnotation(pAL);
13114
13115 return true;
13116 }
13117
13118 // RIVERA
killAnnotationPreview()13119 void FV_View::killAnnotationPreview()
13120 {
13121 UT_DEBUGMSG(("killAnnotationPreview: Deleting annotation preview...\n"));
13122 XAP_Frame * pFrame = static_cast<XAP_Frame *>(getParentData());
13123 XAP_DialogFactory * pDialogFactory
13124 = static_cast<XAP_DialogFactory *>(pFrame->getDialogFactory());
13125
13126 AP_Preview_Annotation * pPview
13127 = static_cast<AP_Preview_Annotation *>(pDialogFactory->requestDialog( AP_DIALOG_ID_ANNOTATION_PREVIEW));
13128 UT_ASSERT(pPview);
13129 pDialogFactory->releaseDialog(pPview);
13130 pPview->destroy();
13131 setAnnotationPreviewActive(false);
13132 }
13133
13134 FV_View_BubbleBlocker
getBubbleBlocker()13135 FV_View::getBubbleBlocker()
13136 {
13137 if(isAnnotationPreviewActive())
13138 killAnnotationPreview();
13139
13140 UT_DEBUGMSG(("FV_View::getBubbleBlocker()\n"));
13141
13142 FV_View_BubbleBlocker ret( this );
13143 return ret;
13144 }
13145
13146 bool
bubblesAreBlocked() const13147 FV_View::bubblesAreBlocked() const
13148 {
13149 UT_DEBUGMSG(("bubblesAreBlocked() v:%d\n", m_bubbleBlockerCount ));
13150 return m_bubbleBlockerCount > 0;
13151 }
13152
13153
13154
13155 void
incremenetBubbleBlockerCount()13156 FV_View::incremenetBubbleBlockerCount()
13157 {
13158 m_bubbleBlockerCount++;
13159 UT_DEBUGMSG(("FV_View::inrremenetBubbleBlockerCount() %d\n",m_bubbleBlockerCount));
13160 }
13161 void
decremenetBubbleBlockerCount()13162 FV_View::decremenetBubbleBlockerCount()
13163 {
13164 m_bubbleBlockerCount--;
13165 UT_DEBUGMSG(("FV_View::decremenetBubbleBlockerCount() %d\n",m_bubbleBlockerCount));
13166 }
13167
FV_View_BubbleBlocker(FV_View * pView)13168 FV_View_BubbleBlocker::FV_View_BubbleBlocker( FV_View* pView )
13169 :
13170 m_pView( pView )
13171 {
13172 if( m_pView )
13173 m_pView->incremenetBubbleBlockerCount();
13174 }
~FV_View_BubbleBlocker()13175 FV_View_BubbleBlocker::~FV_View_BubbleBlocker()
13176 {
13177 if( m_pView )
13178 m_pView->decremenetBubbleBlockerCount();
13179 }
13180
13181 FV_View_BubbleBlocker&
operator =(const FV_View_BubbleBlocker & r)13182 FV_View_BubbleBlocker::operator=( const FV_View_BubbleBlocker& r )
13183 {
13184 if( this != &r )
13185 {
13186 if( m_pView )
13187 m_pView->decremenetBubbleBlockerCount();
13188
13189 m_pView = r.m_pView;
13190
13191 if( m_pView )
13192 m_pView->incremenetBubbleBlockerCount();
13193 }
13194 return *this;
13195 }
13196
13197
13198
13199
insertFootnote(bool bFootnote)13200 bool FV_View::insertFootnote(bool bFootnote)
13201 {
13202 // can only insert Footnote into an FL_SECTION_DOC or a Table
13203 fl_BlockLayout * pBlock = _findBlockAtPosition(getPoint());
13204 if(pBlock == NULL)
13205 {
13206 return false;
13207 }
13208 fl_SectionLayout * pSL = pBlock->getSectionLayout();
13209
13210 if ( (pSL->getContainerType() != FL_CONTAINER_DOCSECTION) && (pSL->getContainerType() != FL_CONTAINER_CELL) )
13211 return false;
13212 if(getHyperLinkRun(getPoint()) != NULL)
13213 {
13214 return false;
13215 }
13216 if(m_FrameEdit.isActive())
13217 {
13218 return false;
13219 }
13220 //
13221 // Do this first
13222 //
13223 if(m_pDoc->isTOCAtPos(getPoint()-1))
13224 {
13225 if(getPoint() ==2 || (pSL->getPosition(true) >= (getPoint() -2)))
13226 {
13227 return false;
13228 }
13229 setPoint(getPoint()-1);
13230 }
13231
13232 _saveAndNotifyPieceTableChange();
13233 m_pDoc->beginUserAtomicGlob();
13234 if (!isSelectionEmpty() && !m_FrameEdit.isActive())
13235 {
13236 _deleteSelection(); // TODO use this text as content of footnote instead of simply deleting it...
13237 }
13238 else if(m_FrameEdit.isActive())
13239 {
13240 m_FrameEdit.setPointInside();
13241 }
13242 _makePointLegal();
13243 const PP_AttrProp * pAP_in = getAttrPropForPoint();
13244
13245 // add field for footnote reference
13246 // first, make up an id for this footnote.
13247 std::string footpid;
13248 UT_return_val_if_fail(m_pDoc, false);
13249 UT_uint32 pid = m_pDoc->getUID(bFootnote ? UT_UniqueId::Footnote : UT_UniqueId::Endnote);
13250 footpid = UT_std_string_sprintf("%d",pid);
13251
13252 const gchar* attrs[] = {
13253 "footnote-id", footpid.c_str(),
13254 NULL, NULL,
13255 NULL, NULL
13256 };
13257 if(!bFootnote)
13258 {
13259 attrs[0] = "endnote-id";
13260 }
13261
13262 /* Apply the character style at insertion point and insert the
13263 Footnote reference. */
13264
13265
13266 PT_DocPosition FrefStart = getPoint();
13267 PT_DocPosition FanchStart;
13268 PT_DocPosition FanchEnd;
13269
13270 PT_DocPosition dpFT = 0;
13271 const gchar * dumProps[3] = {"list-tag","123",NULL};
13272 PT_DocPosition dpBody = getPoint();
13273 //
13274 // This does a rebuild of the affected paragraph
13275 //
13276 m_pDoc->changeStruxFmt(PTC_AddFmt,dpBody,dpBody,NULL,dumProps,PTX_Block);
13277 if (!insertFootnoteSection(bFootnote,footpid.c_str()))
13278 {
13279 m_pDoc->endUserAtomicGlob();
13280 _restorePieceTableState();
13281 return false;
13282 }
13283 dpFT = getPoint(); // Points right at the EndFootnote strux
13284 _setPoint(dpBody);
13285 FrefStart = dpBody;
13286 UT_DebugOnly<bool> bRet = false;
13287 if(bFootnote)
13288 {
13289 attrs[2] = "style";
13290 attrs[3] = "Footnote Reference";
13291 if (_insertField("footnote_ref", attrs)==false)
13292 return false;
13293 }
13294 else
13295 {
13296 attrs[2] = "style";
13297 attrs[3] = "Endnote Reference";
13298 if (_insertField("endnote_ref", attrs)==false)
13299 return false;
13300 }
13301 attrs[2] = NULL;
13302 attrs[3] = NULL;
13303 fl_BlockLayout * pBL;
13304
13305 //
13306 // Now set the insertion point inside the Footnote and insert the anchor field
13307 // there.
13308 //
13309
13310 // add footnote anchor, inside footnote section
13311 //get ready to apply Footnote Reference style
13312 FanchStart = dpFT;
13313
13314 // if the block after which were inserted was not the last block
13315 // we have to adjust the postion, because we are now siting at the
13316 // start of the next block instead of our own
13317 UT_DEBUGMSG(("fv_View::insertFootnote: FanchStart %d\n",FanchStart));
13318
13319 _resetSelection();
13320 _setPoint(FanchStart);
13321 if(bFootnote)
13322 {
13323 _insertField("footnote_anchor", attrs);
13324 }
13325 else
13326 {
13327 _insertField("endnote_anchor", attrs);
13328 }
13329 //
13330 // Place a format mark before the field so we can select the field.
13331 //
13332 const gchar * propListTag[] = {"list-tag",NULL,NULL};
13333 static gchar sid[15];
13334 UT_uint32 id = m_pDoc->getUID(UT_UniqueId::HeaderFtr);
13335 sprintf(sid, "%i", id);
13336 propListTag[1] = sid;
13337 bRet = m_pDoc->changeSpanFmt(PTC_AddFmt,FanchStart,FanchStart,NULL,propListTag);
13338
13339 FanchEnd = FanchStart+1;
13340 UT_DEBUGMSG(("insertFootnote: Inserting space after anchor field \n"));
13341 //insert a TAB after the anchor
13342 UT_UCSChar tab = UCS_TAB;
13343 const PP_AttrProp * pSpanAP = NULL;
13344 const PP_AttrProp * pBlockAP = NULL;
13345 getAttributes(&pSpanAP,&pBlockAP,FanchStart);
13346
13347 m_pDoc->insertSpan(FanchEnd, &tab, 1, const_cast<PP_AttrProp *>(pSpanAP));
13348
13349 //
13350 // Put the character format after footnote back to its previous value
13351 //
13352 // But if we are the first thing in the document, we have no attr prop.
13353 if (pAP_in) {
13354 PP_AttrProp * pAP_after = pAP_in->createExactly(pAP_in->getAttributes(),pAP_in->getProperties());
13355 bRet = m_pDoc->insertFmtMark(PTC_AddFmt,FanchEnd+2,pAP_after);
13356 UT_ASSERT(bRet);
13357 }
13358
13359 _setPoint(FanchEnd+1);
13360
13361 /* some magic to make the endnote reference and anchor recalculate
13362 its widths
13363 */
13364 fp_Run* pRun;
13365 UT_sint32 x, y, x2, y2;
13366 UT_uint32 height;
13367 bool bDirection;
13368 _findPositionCoords(FrefStart, false, x, y, x2, y2, height, bDirection,&pBL,&pRun);
13369
13370 UT_ASSERT(pBL != 0);
13371 UT_ASSERT(pRun != 0);
13372
13373 UT_DebugOnly<bool> bWidthChange = pRun->recalcWidth();
13374 xxx_UT_DEBUGMSG(("run type %d, width change %d\n", pRun->getType(),bWidthChange));
13375 pBL->setNeedsReformat(pBL);
13376
13377 pBL = _findBlockAtPosition(FanchStart);
13378 UT_ASSERT(pBL != 0);
13379
13380 if (pBL->getFirstRun()->getNextRun())
13381 {
13382 bWidthChange = pBL->getFirstRun()->getNextRun()->recalcWidth();
13383 xxx_UT_DEBUGMSG(("run type %d, width change %d\n", pBL->getFirstRun()->getNextRun()->getType(),bWidthChange));
13384 pBL->setNeedsReformat(pBL);
13385 }
13386 //
13387 // This does a rebuild of the affected paragraph
13388 //
13389 m_pDoc->changeStruxFmt(PTC_RemoveFmt,dpBody,dpBody,NULL,dumProps,PTX_Block);
13390 setScreenUpdateOnGeneralUpdate( true);
13391 _restorePieceTableState(); // clean up remaining measures
13392 _updateInsertionPoint();
13393 _generalUpdate();
13394 m_pDoc->endUserAtomicGlob();
13395 _fixInsertionPointCoords();
13396 _ensureInsertionPointOnScreen();
13397 notifyListeners(AV_CHG_MOTION | AV_CHG_ALL);
13398 //
13399 // Lets have a peek at the doc structure, shall we?
13400 //
13401 // m_pDoc->miniDump(pBL->getStruxDocHandle(),8);
13402 return true;
13403 }
13404
insertFootnoteSection(bool bFootnote,const gchar * enpid)13405 bool FV_View::insertFootnoteSection(bool bFootnote,const gchar * enpid)
13406 {
13407 const gchar* block_attrs[] = {
13408 "footnote-id", enpid,
13409 NULL, NULL
13410 };
13411 if(!bFootnote)
13412 {
13413 block_attrs[0] = "endnote-id";
13414 }
13415 const gchar* block_attrs2[] = {
13416 "footnote-id", enpid,
13417 "style", "Footnote", // xxx 'Footnote Body'
13418 NULL, NULL
13419 };
13420 if(!bFootnote)
13421 {
13422 block_attrs2[0] = "endnote-id";
13423 block_attrs2[3] = "Endnote";
13424 }
13425 m_pDoc->beginUserAtomicGlob(); // Begin the big undo block
13426
13427 // Signal PieceTable Changes have Started
13428 //UT_DEBUGMSG(("insertFootnoteSection: about to save and notify\n"));
13429 _saveAndNotifyPieceTableChange();
13430 m_pDoc->disableListUpdates();
13431
13432 bool e = false;
13433
13434 /*
13435 This inserts a footnote at the current point
13436 and leaves the insertion point there.
13437 */
13438 PT_DocPosition pointBreak = 0;
13439
13440 pointBreak = getPoint();
13441 PT_DocPosition pointFootnote = 0;
13442 //
13443 // Insert the footnote strux at this spot. The footnote strux in the piecetable
13444 // will make all the text inside the footnote section invisible so that only
13445 // we can place the footnote section inside the block containing the reference.
13446 //
13447 UT_DEBUGMSG(("insertFootnoteSection: about to insert footnote section at %d\n",pointBreak));
13448 if(bFootnote)
13449 {
13450 e |= m_pDoc->insertStrux(pointBreak,PTX_SectionFootnote,block_attrs,NULL);
13451 }
13452 else
13453 {
13454 e |= m_pDoc->insertStrux(pointBreak,PTX_SectionEndnote,block_attrs,NULL);
13455 }
13456
13457 pointFootnote = pointBreak+1;
13458 UT_DEBUGMSG(("insertFootnoteSection: about to insert block for footnote section at %d \n",pointFootnote));
13459 e |= m_pDoc->insertStrux(pointFootnote,PTX_Block,block_attrs2,NULL);
13460 pointFootnote++;
13461 UT_DEBUGMSG(("insertFootnoteSection: about to insert end footnote at %d \n",pointFootnote));
13462 if(bFootnote)
13463 {
13464 e |= m_pDoc->insertStrux(pointFootnote,PTX_EndFootnote,block_attrs,NULL);
13465 }
13466 else
13467 {
13468 e |= m_pDoc->insertStrux(pointFootnote,PTX_EndEndnote,block_attrs,NULL);
13469 }
13470 pointFootnote++;
13471 _setPoint(pointFootnote);
13472 UT_DEBUGMSG(("insertFootnoteSection: inserted everything final point is %d \n",getPoint()));
13473
13474 // m_pDoc->signalListeners(PD_SIGNAL_REFORMAT_LAYOUT);
13475
13476 // restore updates and clean up dirty lists
13477 m_pDoc->enableListUpdates();
13478 m_pDoc->updateDirtyLists();
13479
13480 // Signal PieceTable Changes have Ended
13481 _restorePieceTableState();
13482
13483 _generalUpdate();
13484
13485 m_pDoc->endUserAtomicGlob(); // End the big undo block
13486 _updateInsertionPoint();
13487 UT_DEBUGMSG(("insertFootnoteSection: Finished point is %d \n",getPoint()));
13488
13489 return e;
13490 }
13491
insertPageNum(const gchar ** props,HdrFtrType hfType)13492 bool FV_View::insertPageNum(const gchar ** props, HdrFtrType hfType)
13493 {
13494
13495 /*
13496 This code implements some hardcoded hacks to insert a page number.
13497 It allows you to set the properties, but nothing else. Use that
13498 to center, etc.
13499
13500 Warning: this code assumes that _insertFooter() leaves the insertion
13501 point in a place where it can write the page_num field.
13502 */
13503
13504 const gchar* f_attributes[] = {
13505 "type", "page_number",
13506 NULL, NULL
13507 };
13508
13509 m_pDoc->beginUserAtomicGlob(); // Begin the big undo block
13510
13511 // Signal PieceTable Changes have Started
13512 _saveAndNotifyPieceTableChange();
13513 m_pDoc->disableListUpdates();
13514
13515 UT_uint32 oldPos = getPoint(); // This ends up being redundant, but it's neccessary
13516 bool bResult = insertHeaderFooter(props, hfType);
13517
13518 //
13519 // after this call the insertion point is at the position where stuff
13520 // can be inserted into the header/footer
13521 //
13522 if(!bResult)
13523 return false;
13524
13525 // Insert the page_number field
13526
13527 bResult = m_pDoc->insertObject(getPoint(), PTO_Field, f_attributes, NULL);
13528
13529 moveInsPtTo(oldPos); // Get back to where you once belonged.
13530
13531 m_pLayout->updateLayout(); // Update document layout everywhere
13532
13533 // restore updates and clean up dirty lists
13534 m_pDoc->enableListUpdates();
13535 m_pDoc->updateDirtyLists();
13536
13537 // Signal PieceTable Changes have Ended
13538 _restorePieceTableState();
13539
13540 _generalUpdate();
13541 m_pDoc->endUserAtomicGlob(); // End the big undo block
13542 _updateInsertionPoint();
13543 return bResult;
13544 }
13545
getPageSize(void) const13546 const fp_PageSize & FV_View::getPageSize(void) const
13547 {
13548 return m_pDoc->m_docPageSize;
13549 }
13550
13551
calculateZoomPercentForPageWidth() const13552 UT_uint32 FV_View::calculateZoomPercentForPageWidth() const
13553 {
13554 const fp_PageSize pageSize = getPageSize();
13555 double pageWidth = pageSize.Width(DIM_IN);
13556
13557 // Verify scale as a positive non-zero number else return old zoom
13558 UT_uint32 iZoom = 100;
13559 UT_sint32 iWindowWidth = getWindowWidth();
13560 if(iWindowWidth == 0)
13561 {
13562 // Get fall-back defaults for zoom from prefs
13563 const gchar * szZoom = NULL;
13564 m_pApp->getPrefsValue(XAP_PREF_KEY_ZoomPercentage,
13565 static_cast<const gchar**>(&szZoom));
13566 UT_DEBUGMSG(("!!!! Zoom percentage %s \n",szZoom));
13567 if(szZoom)
13568 {
13569 iZoom = atoi(szZoom);
13570 if(iZoom < XAP_DLG_ZOOM_MINIMUM_ZOOM)
13571 iZoom = 100;
13572 else if (iZoom > XAP_DLG_ZOOM_MAXIMUM_ZOOM)
13573 iZoom = 100;
13574 return iZoom;
13575 }
13576 return getGraphics()->getZoomPercentage();
13577 }
13578 if ( ( iWindowWidth - (2 * getPageViewLeftMargin()) ) <= 0 )
13579 return getGraphics()->getZoomPercentage();
13580
13581 double scale = (getWindowWidth() - (2 * getPageViewLeftMargin())) /
13582 (pageWidth * (static_cast<double>(getGraphics()->getResolution())/
13583 static_cast<double>(getGraphics()->getZoomPercentage()) * 100.0));
13584 // (100.0 * 100.0)));
13585 //
13586 // Fill the whole width for non-Print view
13587 //
13588 if(getViewMode() != VIEW_PRINT)
13589 {
13590 fl_DocSectionLayout *pDSL = m_pLayout->getFirstSection();
13591 UT_sint32 iLeft = pDSL->getLeftMargin();
13592 UT_sint32 iRight = pDSL->getRightMargin();
13593 UT_sint32 iNormalOffset = getNormalModeXOffset();
13594 UT_sint32 iExtra = 72; // extra 0.5 inches for rounding errors
13595 xxx_UT_DEBUGMSG(("Doing extra calculation Left %d Right %d \n",iLeft,iRight));
13596 scale = (getWindowWidth() - 2 * getPageViewLeftMargin() + iLeft +iRight - iExtra - iNormalOffset) /
13597 (pageWidth * (static_cast<double>(getGraphics()->getResolution()) /
13598 static_cast<double>(getGraphics()->getZoomPercentage()) * 100.0));
13599 }
13600 return static_cast<UT_uint32>(scale * 100.0);
13601 }
13602
calculateZoomPercentForPageHeight() const13603 UT_uint32 FV_View::calculateZoomPercentForPageHeight() const
13604 {
13605
13606 const fp_PageSize pageSize = getPageSize();
13607 double pageHeight = pageSize.Height(DIM_IN);
13608 UT_uint32 iZoom = 100;
13609 UT_sint32 iWindowHeight = getWindowHeight();
13610 if(iWindowHeight == 0)
13611 {
13612 // Get fall-back defaults for zoom from prefs
13613 const gchar * szZoom = NULL;
13614 m_pApp->getPrefsValue(XAP_PREF_KEY_ZoomPercentage,
13615 static_cast<const gchar**>(&szZoom));
13616 if(szZoom)
13617 {
13618 iZoom = atoi(szZoom);
13619 UT_DEBUGMSG(("!!!! Zoom percentage %s \n",szZoom));
13620 if(iZoom < XAP_DLG_ZOOM_MINIMUM_ZOOM)
13621 iZoom = 100;
13622 else if (iZoom > XAP_DLG_ZOOM_MAXIMUM_ZOOM)
13623 iZoom = 100;
13624 return iZoom;
13625 }
13626 return getGraphics()->getZoomPercentage();
13627 }
13628 // Verify scale as a positive non-zero number else return old zoom
13629 if ( ( iWindowHeight - (2 * getPageViewTopMargin())) <= 0 )
13630 return getGraphics()->getZoomPercentage();
13631
13632 double scale = (getWindowHeight() - (2 * getPageViewTopMargin())) /
13633 (pageHeight * (static_cast<double>(getGraphics()->getResolution()) /
13634 static_cast<double>(getGraphics()->getZoomPercentage()) * 100.0));
13635
13636 return static_cast<UT_uint32>(scale * 100.0);
13637 }
13638
calculateZoomPercentForWholePage() const13639 UT_uint32 FV_View::calculateZoomPercentForWholePage() const
13640 {
13641 return UT_MIN( calculateZoomPercentForPageWidth(),
13642 calculateZoomPercentForPageHeight());
13643 }
13644
13645 /* Revision related functions */
toggleMarkRevisions()13646 void FV_View::toggleMarkRevisions()
13647 {
13648 m_pDoc->toggleMarkRevisions();
13649
13650 // force screen update to fix 7673
13651 updateScreen();
13652 }
13653
setShowRevisions(bool bShow)13654 void FV_View::setShowRevisions(bool bShow)
13655 {
13656 if(m_bShowRevisions != bShow)
13657 {
13658 m_bShowRevisions = bShow;
13659
13660 // set the doc value as well, so that on save we preserve the last
13661 // used setting
13662 m_pDoc->setShowRevisions(bShow);
13663
13664 // now we have to re-do document layout from bottom up
13665 m_pLayout->rebuildFromHere(static_cast<fl_DocSectionLayout *>(m_pLayout->getFirstSection()));
13666
13667 /* have to force redraw -- see 10486 */
13668 draw(NULL);
13669
13670 _fixInsertionPointCoords();
13671 }
13672 }
13673
toggleShowRevisions()13674 void FV_View::toggleShowRevisions()
13675 {
13676 setShowRevisions(!m_bShowRevisions);
13677 }
13678
13679 /*!
13680 same as cmdSetRevisionLevel() except without layout rebuild
13681 */
setRevisionLevel(UT_uint32 i)13682 void FV_View::setRevisionLevel(UT_uint32 i)
13683 {
13684 UT_return_if_fail( i <= PD_MAX_REVISION );
13685 m_pDoc->setShowRevisionId(i);
13686 m_iViewRevision = i;
13687 }
13688
13689 /*!
13690 Revision level i means that the document is to be shown as it looks _after_ revision with id ==
13691 i. In non-revisioning mode, any revision level is OK, but when marking revisions legal values
13692 are >= current revisioning level - 1.
13693 */
getRevisionLevel() const13694 UT_uint32 FV_View::getRevisionLevel()const
13695 {
13696 if(m_iViewRevision && isMarkRevisions())
13697 {
13698 UT_uint32 iRevLevel = m_pDoc->getHighestRevisionId();
13699
13700 if(!iRevLevel)
13701 return 0;
13702
13703 --iRevLevel;
13704
13705 if(m_iViewRevision < iRevLevel)
13706 return PD_MAX_REVISION;
13707 }
13708
13709 return m_iViewRevision;
13710 }
13711
isMarkRevisions() const13712 bool FV_View::isMarkRevisions() const
13713 {
13714 return m_pDoc->isMarkRevisions();
13715 }
13716 /*!
13717 This function brings our revision settings into sync with the document-wide settings and is
13718 called by fl_DocListener in response to PD_SIGNAL_REVISION_MODE_CHANGED. This funciton does not
13719 initiate layout rebuild, that is the responsibility of the caller.
13720 */
updateRevisionMode()13721 void FV_View::updateRevisionMode()
13722 {
13723 if(m_pDoc->isAutoRevisioning())
13724 {
13725 // when in auto-revisioning mode, we respect all document-wide settings -- basically this
13726 // means that the doc in all views looks like a normal document without the revision marking
13727 // highlighted.
13728 m_iViewRevision = m_pDoc->getShowRevisionId();
13729 m_bShowRevisions = m_pDoc->isShowRevisions();
13730 }
13731
13732 // in non-auto mode, we ignore document wide settings -- this allows different views to show
13733 // different state of the document
13734
13735 // make sure we have no left-over revision attribs, etc., at the insertion point
13736 _fixInsertionPointAfterRevision();
13737 }
13738
13739
13740
13741 /* Table related functions */
13742 /*!
13743 * returns true if the current insertion point is inside a table.
13744 */
isInTable() const13745 bool FV_View::isInTable() const
13746 {
13747 PT_DocPosition pos = getPoint();
13748
13749 if (isSelectionEmpty())
13750 {
13751 return isInTable(pos);
13752 }
13753 else
13754 {
13755 PT_DocPosition posA = getSelectionAnchor();
13756 return (isInTable(posA) && isInTable(pos));
13757 }
13758 }
13759
getTableAtPos(PT_DocPosition pos) const13760 fl_TableLayout * FV_View::getTableAtPos(PT_DocPosition pos) const
13761 {
13762 fl_BlockLayout * pBL = m_pLayout->findBlockAtPosition(pos);
13763 if(!pBL)
13764 {
13765 return NULL;
13766 }
13767 fl_ContainerLayout * pCL = pBL->myContainingLayout();
13768 if(!pCL)
13769 {
13770 return NULL;
13771 }
13772 if(pCL->getContainerType() == FL_CONTAINER_CELL)
13773 {
13774 pCL = pCL->myContainingLayout();
13775 if(!pCL)
13776 {
13777 return NULL;
13778 }
13779 if(pCL->getContainerType() != FL_CONTAINER_TABLE)
13780 {
13781 return NULL;
13782 }
13783 fl_TableLayout * pTab = static_cast<fl_TableLayout *>(pCL);
13784 return pTab;
13785 }
13786 return NULL;
13787 }
13788
13789 /*!
13790 * Returns true if the point supplied is inside a Table.
13791 */
isInTable(PT_DocPosition pos) const13792 bool FV_View::isInTable( PT_DocPosition pos) const
13793 {
13794 xxx_UT_DEBUGMSG(("Look in table at pos %d \n",pos));
13795 if(m_pDoc->isTableAtPos(pos))
13796 {
13797 //
13798 // This could be the start of nested table. If so return true!
13799 //
13800 pf_Frag_Strux* sdhTable = NULL;
13801 bool bRes = m_pDoc->getStruxOfTypeFromPosition(pos+1,PTX_SectionTable,&sdhTable);
13802 UT_return_val_if_fail(bRes,false);
13803 UT_ASSERT(sdhTable && sdhTable->getPos() == pos);
13804 fl_TableLayout * pTL = static_cast<fl_TableLayout *>(m_pDoc->getNthFmtHandle(sdhTable,m_pLayout->getLID()));
13805 UT_return_val_if_fail(pTL,false);
13806 fp_TableContainer *pTable = static_cast <fp_TableContainer*>(pTL->getFirstContainer());
13807 if (pTable && pTable->getContainer() &&
13808 (pTable->getContainer()->getContainerType() == FP_CONTAINER_CELL))
13809 {
13810 return true;
13811 }
13812 return false;
13813 }
13814 if(m_pDoc->isCellAtPos(pos))
13815 {
13816 xxx_UT_DEBUGMSG(("As cell pos in table pos %d \n",pos));
13817 return true;
13818 }
13819 fl_BlockLayout * pBL = m_pLayout->findBlockAtPosition(pos,true);
13820 xxx_UT_DEBUGMSG((" Got Bokc at pos %d looking at pos %d \n",pBL->getPosition(true),pos));
13821 if(!pBL)
13822 {
13823 xxx_UT_DEBUGMSG(("Not in table \n"));
13824 return false;
13825 }
13826 UT_ASSERT(pBL->getContainerType() == FL_CONTAINER_BLOCK);
13827 fl_ContainerLayout * pCL = pBL->myContainingLayout();
13828 if(!pCL)
13829 {
13830 xxx_UT_DEBUGMSG(("Not in table \n"));
13831 return false;
13832 }
13833 UT_ASSERT(pCL->getContainerType() != FL_CONTAINER_TABLE);
13834 xxx_UT_DEBUGMSG(("Containing Layout is %s pos %d \n",pCL->getContainerString(),pos));
13835 if((pCL->getContainerType() == FL_CONTAINER_FOOTNOTE) || (pCL->getContainerType() == FL_CONTAINER_ENDNOTE) || (pCL->getContainerType() == FL_CONTAINER_ANNOTATION))
13836 {
13837 pBL = pBL->getEnclosingBlock();
13838 if(pBL == NULL)
13839 {
13840 return false;
13841 }
13842 pCL = pBL->myContainingLayout();
13843 }
13844 if(pCL->getContainerType() == FL_CONTAINER_CELL)
13845 {
13846 xxx_UT_DEBUGMSG(("Inside Table cell pos %d this pos %d \n",pCL->getPosition(),pos));
13847 fl_TableLayout * pTL = static_cast<fl_TableLayout *>(pCL->myContainingLayout());
13848 if (!pTL)
13849 {
13850 return false;
13851 }
13852 return true;
13853 }
13854 pCL = pBL->getNext();
13855 if(pCL == NULL)
13856 {
13857 xxx_UT_DEBUGMSG(("Get Next is NULL \n"));
13858 return false;
13859 }
13860 xxx_UT_DEBUGMSG(("Get Next Containing Layout is %s \n",pCL->getContainerString()));
13861 if(pCL->getContainerType() == FL_CONTAINER_TABLE)
13862 {
13863 PT_DocPosition posTable = m_pDoc->getStruxPosition(pCL->getStruxDocHandle());
13864 if(posTable <= pos) // TODO CHECK THIS very carefully!!
13865 {
13866 return true;
13867 }
13868 else
13869 {
13870 return false;
13871 }
13872 }
13873 pCL = pBL->getPrev();
13874 if(pCL == NULL)
13875 {
13876 return false;
13877 }
13878 if(pCL->getContainerType() == FL_CONTAINER_TABLE)
13879 {
13880 pf_Frag_Strux* sdh = pCL->getStruxDocHandle();
13881 pf_Frag_Strux* sdhEnd = m_pDoc->getEndTableStruxFromTableSDH(sdh);
13882 if(sdhEnd != NULL)
13883 {
13884 PT_DocPosition posEnd = m_pDoc->getStruxPosition(sdhEnd);
13885 if(posEnd == pos)
13886 {
13887 xxx_UT_DEBUGMSG(("Exactly at end of table \n"));
13888 return true;
13889 }
13890 }
13891 }
13892 xxx_UT_DEBUGMSG(("Last Not in table \n"));
13893 return false;
13894 }
13895
13896 /*!
13897 * Returns the position of the cell strux of cell specified by (row,col) within the
13898 * Table surrounding the supplied point.
13899 */
findCellPosAt(PT_DocPosition posTable,UT_sint32 row,UT_sint32 col) const13900 PT_DocPosition FV_View::findCellPosAt(PT_DocPosition posTable, UT_sint32 row, UT_sint32 col) const
13901 {
13902 pf_Frag_Strux* cellSDH,*tableSDH;
13903 bool bRes = m_pDoc->getStruxOfTypeFromPosition(posTable,PTX_SectionTable,&tableSDH);
13904 if(!bRes)
13905 {
13906 return 0;
13907 }
13908 fl_TableLayout * pTL = static_cast<fl_TableLayout *>(m_pDoc->getNthFmtHandle(tableSDH,m_pLayout->getLID()));
13909 fp_TableContainer * pTC = static_cast<fp_TableContainer *>(pTL->getFirstContainer());
13910 //
13911 // This is MUCH faster than linearly searching through the Piecetable.
13912 //
13913 if(pTC != NULL)
13914 {
13915 fp_CellContainer * pCell = pTC->getCellAtRowColumn(row,col);
13916 if(pCell)
13917 {
13918 fl_ContainerLayout * pCL = static_cast<fl_ContainerLayout *>(pCell->getSectionLayout());
13919 if(pCL)
13920 {
13921 return pCL->getPosition(true);
13922 }
13923 }
13924 }
13925 cellSDH = m_pDoc->getCellSDHFromRowCol(tableSDH, isShowRevisions(), getRevisionLevel(), row,col);
13926 if(cellSDH == NULL)
13927 {
13928 return 0;
13929 }
13930 return m_pDoc->getStruxPosition(cellSDH);
13931 }
13932
13933 /*! find out which pages in the document are visible on the screen and
13934 calculate the rectangles of their view-ports (the rectangles are
13935 relative to the top-left corner of the page, not to the screen
13936 the caller must use UT_VECTOR_PURGEALL() on vRect to delete the
13937 objects allocated by this function, but NOT on vPages
13938 \param vRect -- vector where to store UT_Rect* referring to vieports of pages in vPages
13939 \param vPage -- vector where to store pointers to currently visible pages
13940 */
getVisibleDocumentPagesAndRectangles(UT_GenericVector<UT_Rect * > & vRect,UT_GenericVector<fp_Page * > & vPages) const13941 void FV_View:: getVisibleDocumentPagesAndRectangles(UT_GenericVector<UT_Rect*> &vRect,
13942 UT_GenericVector<fp_Page*> &vPages) const
13943 {
13944 UT_sint32 curY = getPageViewTopMargin();
13945 fp_Page * pPage = m_pLayout->getFirstPage();
13946
13947 while (pPage)
13948 {
13949 UT_sint32 iPageWidth = pPage->getWidth();
13950 UT_sint32 iPageHeight = pPage->getHeight();
13951 UT_sint32 adjustedTop = curY - m_yScrollOffset;
13952 fl_DocSectionLayout * pDSL = pPage->getOwningSection();
13953 if(getViewMode() != VIEW_PRINT)
13954 {
13955 iPageHeight = iPageHeight - pDSL->getTopMargin() - pDSL->getBottomMargin();
13956 }
13957
13958 UT_sint32 adjustedBottom = adjustedTop + iPageHeight + getPageViewSep();
13959
13960 if (adjustedTop > getWindowHeight())
13961 {
13962 // the start of this page is past the bottom
13963 // of the window, so we don't need to draw it.
13964
13965 xxx_UT_DEBUGMSG(("page below port: PageHeight=%d curY=%d nPos=%d WindowHeight=%d\n",
13966 iPageHeight,
13967 curY,
13968 m_yScrollOffset,
13969 getWindowHeight()));
13970
13971 // since all other pages are below this one, we
13972 // don't need to draw them either. exit loop now.
13973 break;
13974 }
13975 else if (adjustedBottom < 0)
13976 {
13977 // the end of this page is above the top of
13978 // the window, so we don't need to draw it.
13979
13980 xxx_UT_DEBUGMSG(("page above port: PageHeight=%d curY=%d nPos=%d WindowHeight=%d\n",
13981 iPageHeight,
13982 curY,
13983 m_yScrollOffset,
13984 getWindowHeight()));
13985 }
13986 else
13987 {
13988 // this page is on screen
13989 xxx_UT_DEBUGMSG(("page visible: height=%d curY=%d nPos=%d WindowHeight=%d\n",
13990 iPageHeight,
13991 curY,
13992 m_yScrollOffset,
13993 getWindowHeight()));
13994
13995
13996 vPages.addItem(pPage);
13997
13998 // now create the rectangle
13999 // NB the adjustedTop is relative to the screen, but we
14000 // want the rect to be relative to the top left page
14001 // corner
14002
14003 UT_sint32 iLeftGrayWidth = getPageViewLeftMargin() - m_xScrollOffset;
14004 UT_uint32 iPortTop = adjustedTop >= 0 ? 0 : -adjustedTop;
14005 UT_uint32 iPortLeft = iLeftGrayWidth >= 0 ? 0 : -iLeftGrayWidth;
14006 UT_uint32 iWindowWidth = getWindowWidth() - iLeftGrayWidth > 0 ? getWindowWidth() - iLeftGrayWidth : 0;
14007 UT_uint32 iPortHeight = 0;
14008 if( adjustedBottom <= getWindowHeight() && adjustedTop >=0)
14009 {
14010 iPortHeight = adjustedBottom - adjustedTop;
14011 }
14012 else if(adjustedBottom <= getWindowHeight() && adjustedTop <= 0)
14013 {
14014 iPortHeight = adjustedBottom;
14015 }
14016 else if(adjustedBottom >= getWindowHeight() && adjustedTop >=0)
14017 {
14018 iPortHeight = getWindowHeight() - adjustedTop;
14019 }
14020 else if(adjustedBottom >= getWindowHeight() && adjustedTop <=0)
14021 {
14022 iPortHeight = getWindowHeight();
14023 }
14024 else
14025 {
14026 UT_ASSERT( UT_SHOULD_NOT_HAPPEN );
14027 }
14028
14029
14030 UT_uint32 iPortWidth = UT_MIN(static_cast<UT_uint32>(iPageWidth), iWindowWidth);
14031
14032 UT_Rect * pRect = new UT_Rect(iPortLeft,
14033 iPortTop,
14034 iPortWidth,
14035 iPortHeight);
14036
14037 vRect.addItem(pRect);
14038 }
14039
14040 curY += iPageHeight + getPageViewSep();
14041
14042 pPage = pPage->getNext();
14043 UT_sint32 iPage = m_pLayout->findPage(pPage);
14044 if(iPage < 0)
14045 break;
14046 }
14047 }
14048
14049 /*! Returns the size of the image selection boxes
14050 */
getImageSelInfo() const14051 UT_sint32 FV_View::getImageSelInfo() const
14052 {
14053 return getGraphics()->tlu(m_InlineImage.getImageSelBoxSize());
14054 }
14055
getImageSelCursor() const14056 GR_Graphics::Cursor FV_View::getImageSelCursor() const
14057 {
14058 return m_imageSelCursor;
14059 }
14060
14061 /*!
14062 Check that an image is currently selected
14063
14064 \return true if an image is selected otherwise false.
14065 \todo eventually make it faster by not fetching the image data ID.
14066 */
isImageSelected(void) const14067 bool FV_View::isImageSelected(void) const
14068 {
14069 const char * dataId;
14070 PT_DocPosition pos = getSelectedImage(&dataId);
14071
14072 if (pos == 0) {
14073 return false;
14074 }
14075 else {
14076 return true;
14077 }
14078 return false;
14079 }
14080
14081 #ifdef ENABLE_SPELL
getDictForSelection() const14082 SpellChecker * FV_View::getDictForSelection () const
14083 {
14084 SpellChecker * checker = NULL;
14085 const char * szLang = NULL;
14086
14087 const gchar ** props_in = NULL;
14088 if (getCharFormat(&props_in))
14089 {
14090 szLang = UT_getAttribute("lang", props_in);
14091 FREEP(props_in);
14092 }
14093
14094 if (szLang)
14095 {
14096 // we get smart and request the proper dictionary
14097 checker = SpellManager::instance().requestDictionary(szLang);
14098 }
14099 else
14100 {
14101 // we just (dumbly) default to the last dictionary
14102 checker = SpellManager::instance().lastDictionary();
14103 }
14104
14105 return checker;
14106 }
14107 #endif
14108
14109 /*
14110 There are some 'document' properties that are specific for a given
14111 view, but which should be transferred into the document at point of save.
14112 For example, whether the document is displayed in Normal view / Web
14113 view, etc, or whether the document should be layout in visual or
14114 logical order
14115
14116 the returned pointer is to a static variable, so use it or loose it
14117 */
getViewPersistentProps() const14118 const gchar ** FV_View::getViewPersistentProps() const
14119 {
14120 const UT_uint32 iMax = 3;
14121 static const gchar * pProps[iMax];
14122 UT_uint32 i = 0;
14123
14124 if(m_eBidiOrder == FV_Order_Logical_LTR)
14125 {
14126 pProps[i++] = "dom-dir";
14127 pProps[i++] = "logical-ltr";
14128 }
14129 else if(m_eBidiOrder == FV_Order_Logical_RTL)
14130 {
14131 pProps[i++] = "dom-dir";
14132 pProps[i++] = "logical-rtl";
14133 }
14134
14135 UT_ASSERT( i < iMax );
14136 pProps[i] = NULL;
14137
14138 return pProps;
14139 }
14140
rebuildLayout()14141 void FV_View::rebuildLayout()
14142 {
14143 m_pLayout->rebuildFromHere(static_cast<fl_DocSectionLayout *>(m_pLayout->getFirstSection()));
14144 }
14145
fv_PropCache(void)14146 fv_PropCache::fv_PropCache(void):
14147 m_iTick(0),
14148 m_iNumProps(0),
14149 m_pszProps(NULL),
14150 m_pCurrentCL(NULL)
14151 {
14152 }
14153
~fv_PropCache(void)14154 fv_PropCache::~fv_PropCache(void)
14155 {
14156 clearProps();
14157 }
14158
setTick(UT_uint32 iTick)14159 void fv_PropCache::setTick(UT_uint32 iTick)
14160 {
14161 m_iTick = iTick;
14162 }
14163
getTick(void) const14164 UT_uint32 fv_PropCache::getTick(void) const
14165 {
14166 return m_iTick;
14167 }
14168
setCurrentCL(fl_ContainerLayout * pCL)14169 void fv_PropCache::setCurrentCL(fl_ContainerLayout* pCL)
14170 {
14171 m_pCurrentCL = pCL;
14172 }
14173
getCurrentCL(void) const14174 fl_ContainerLayout* fv_PropCache::getCurrentCL(void) const
14175 {
14176 return m_pCurrentCL;
14177 }
14178
getCopyOfProps(void) const14179 const gchar ** fv_PropCache::getCopyOfProps(void) const
14180 {
14181 const gchar ** props = static_cast<const gchar **>(UT_calloc(m_iNumProps+1, sizeof(gchar *)));
14182 UT_uint32 i =0;
14183 const gchar ** p = props;
14184 for(i =0; i< m_iNumProps;i++)
14185 {
14186 p[i] = m_pszProps[i];
14187 xxx_UT_DEBUGMSG((" copy i %d m_pszProps[i] %x m_pszProps %s props %x props %s\n",i,m_pszProps[i],m_pszProps[i],props[i],props[i]));
14188 }
14189 p[m_iNumProps] = NULL;
14190 xxx_UT_DEBUGMSG(("getCopy: props %x m_pszProps %x \n",props,m_pszProps));
14191 UT_ASSERT(NULL != m_pszProps);
14192 return props;
14193 }
14194
fillProps(UT_uint32 numProps,const gchar ** props)14195 void fv_PropCache::fillProps(UT_uint32 numProps, const gchar ** props)
14196 {
14197 m_iNumProps = numProps;
14198 m_pszProps = static_cast<gchar **>(UT_calloc(m_iNumProps, sizeof(gchar *)));
14199 UT_uint32 i = 0;
14200 xxx_UT_DEBUGMSG(("m_pszProps %x props %x ",m_pszProps,props));
14201 for(i =0; i< m_iNumProps && (props[i] != NULL);i++)
14202 {
14203 if(props[i] != NULL)
14204 {
14205 m_pszProps[i] = const_cast<gchar *>(props[i]);
14206 xxx_UT_DEBUGMSG((" i %d m_pszProps[i] %x m_pszProps %s \n",i,m_pszProps[i],m_pszProps[i]));
14207 }
14208 else
14209 {
14210 m_pszProps[i] = NULL;
14211 }
14212 }
14213 UT_ASSERT(NULL != m_pszProps);
14214 }
14215
isValid(void) const14216 bool fv_PropCache::isValid(void) const
14217 {
14218 bool b = ((m_iNumProps > 0) && (NULL != m_pszProps));
14219 if(m_iNumProps > 0)
14220 {
14221 UT_ASSERT(NULL != m_pszProps);
14222 }
14223 xxx_UT_DEBUGMSG(("Numprops %d m_pszProps %x \n",m_iNumProps,m_pszProps));
14224 return b;
14225 }
14226
clearProps(void)14227 void fv_PropCache::clearProps(void)
14228 {
14229 xxx_UT_DEBUGMSG(("clearing props NumProps %d m_pszProps %x \n",m_iNumProps,m_pszProps));
14230 FREEP(m_pszProps);
14231 m_iNumProps = 0;
14232 xxx_UT_DEBUGMSG(("clearing props numProps %d \n",m_iNumProps));
14233 }
14234
14235 /*!
14236 This method forces remeasuring of widths for all characters in the document.
14237 It is called on zoom to allow us to adjust positioning of individual chars in response
14238 to changes to metrics of screen font.
14239
14240 NB: this function does not force rebuild; on the zoom the actual character sizes
14241 remain the same, and so does the overall layout.
14242 */
remeasureCharsWithoutRebuild()14243 void FV_View::remeasureCharsWithoutRebuild()
14244 {
14245 fl_BlockLayout * pBL = getBlockAtPosition(2);
14246
14247 while(pBL)
14248 {
14249 fp_Run * pRun = pBL->getFirstRun();
14250
14251 while(pRun)
14252 {
14253 if(pRun->getType() == FPRUN_TEXT)
14254 {
14255 fp_TextRun * pTR = (fp_TextRun*) pRun;
14256 pTR->measureCharWidths();
14257 }
14258
14259 pRun = pRun->getNextRun();
14260 }
14261 pBL = pBL->getNextBlockInDocument();
14262 }
14263
14264 updateLayout();
14265 }
14266
14267 /*!
14268 This function is called when the font metrics for the view change. This happens for
14269 example when on win32 the user changes the currently selected printer. In order to
14270 maintain WYSIWYG behaviour, we have to remeasure and rebuild
14271 */
fontMetricsChange()14272 void FV_View::fontMetricsChange()
14273 {
14274 fl_BlockLayout * pBL = getBlockAtPosition(2);
14275
14276 while(pBL)
14277 {
14278 fp_Run * pRun = pBL->getFirstRun();
14279
14280 while(pRun)
14281 {
14282 // The order here matters; marking width dirty before call to
14283 // updateVerticalMetric() allows some fp_Run subclasses to clear the width
14284 // flag in the updateVerticalMetric() call (see fp_EmbedRun for example)
14285
14286 pRun->markWidthDirty(); // width will be recalculated during rebuild
14287 pRun->updateVerticalMetric();
14288 pRun = pRun->getNextRun();
14289 }
14290 pBL = pBL->getNextBlockInDocument();
14291 }
14292
14293 m_pLayout->rebuildFromHere(static_cast<fl_DocSectionLayout *>(m_pLayout->getFirstSection()));
14294 }
14295
getNumHorizPages() const14296 UT_uint32 FV_View::getNumHorizPages() const
14297 {
14298 if(!getGraphics()->queryProperties(GR_Graphics::DGP_SCREEN))
14299 return 1;
14300 return m_iNumHorizPages;
14301 }
14302
calculateNumHorizPages()14303 void FV_View::calculateNumHorizPages()
14304 {
14305 UT_sint32 scrollbarWidth = 1000; //Because my scrollbar is about this wide.
14306 UT_sint32 windowWidth = getWindowWidth() - scrollbarWidth;
14307 UT_sint32 iOldNo = m_iNumHorizPages;
14308 if(windowWidth < 0)
14309 {
14310 m_iNumHorizPages = 1;
14311 return;
14312 }
14313 if(!getGraphics()->queryProperties(GR_Graphics::DGP_SCREEN))
14314 {
14315 m_iNumHorizPages = 1;
14316 return;
14317 }
14318 xxx_UT_DEBUGMSG(("Initial Number horizontal pages %d \n",iOldNo));
14319 if (!m_autoNumHorizPages || getViewMode() != VIEW_PRINT || m_iNumHorizPages < 1)
14320 {
14321 m_iNumHorizPages = 1; //TODO: get this from the default or prefrences.
14322 }
14323 else if (m_iNumHorizPages > 20) //20 seems like a reasonable max...
14324 {
14325 m_iNumHorizPages = 20;
14326 }
14327 else if(getWindowWidth() < m_pLayout->getFirstPage()->getWidth())
14328 {
14329 m_iNumHorizPages = 1;
14330 }
14331 else //Find the new m_iNumPages
14332 {
14333 m_getNumHorizPagesCachedWindowWidth = windowWidth;
14334 UT_sint32 widthPagesInRow = 0;
14335 UT_sint32 iFirstPageInRow = 0; //iRow * m_iNumHorizPages; //TODO:make this use the row of the current page.
14336 fp_Page * pPage = m_pLayout->getNthPage(iFirstPageInRow);
14337
14338 widthPagesInRow = getWidthPagesInRow(pPage);
14339
14340 if ( (windowWidth < widthPagesInRow) && (m_iNumHorizPages > 1) )
14341 {
14342 do
14343 {
14344 m_iNumHorizPages--;
14345 widthPagesInRow = getWidthPagesInRow(pPage);
14346 }while ((windowWidth < widthPagesInRow) && (m_iNumHorizPages > 1));
14347 }
14348 else if ((windowWidth > widthPagesInRow) && (widthPagesInRow + pPage->getWidth() + static_cast<UT_sint32>(getHorizPageSpacing()) < windowWidth))
14349 {
14350 do
14351 {
14352 m_iNumHorizPages++;
14353 widthPagesInRow = getWidthPagesInRow(pPage);
14354 } while ((windowWidth > widthPagesInRow) && (widthPagesInRow + static_cast<UT_sint32>(pPage->getWidth()) + static_cast<UT_sint32>(getHorizPageSpacing()) < windowWidth) && (static_cast<UT_sint32>(m_iNumHorizPages) <= m_pLayout->countPages()));
14355 }
14356 xxx_UT_DEBUGMSG(("m_iNumHorizPages %d | windowWidth %d | widthPagesInRow %d | pPage->getWidth() %d\n", m_iNumHorizPages,windowWidth,widthPagesInRow,pPage->getWidth()));
14357 }
14358 if (m_iNumHorizPages > 20) //20 seems like a reasonable max...
14359 {
14360 m_iNumHorizPages = 20;
14361 }
14362 if(static_cast<UT_sint32>(m_iNumHorizPages) > m_pLayout->countPages())
14363 {
14364 m_iNumHorizPages = m_pLayout->countPages();
14365 }
14366 if (m_iNumHorizPages > 1)
14367 {
14368 XAP_App::getApp()->setEnableSmoothScrolling(false);
14369 }
14370 else
14371 {
14372 XAP_App::getApp()->setEnableSmoothScrolling(true);
14373 }
14374 if(iOldNo != static_cast<UT_sint32>(m_iNumHorizPages))
14375 {
14376 UT_uint32 iPrevYOffset = m_yScrollOffset;
14377 XAP_Frame * pFrame = static_cast<XAP_Frame*>(getParentData());
14378 pFrame->setYScrollRange();
14379 pFrame->nullUpdate();
14380 pFrame->nullUpdate();
14381 double totOffset = static_cast<double>(iPrevYOffset)*static_cast<double>(iOldNo);
14382 xxx_UT_DEBUGMSG(("Number horizontal pages changed totoffset %f \n",totOffset));
14383 UT_uint32 newOffset = static_cast<UT_uint32>(totOffset / static_cast<double>(m_iNumHorizPages));
14384 UT_sint32 idiff = newOffset - m_yScrollOffset;
14385
14386 if(idiff > 0)
14387 {
14388 cmdScroll(AV_SCROLLCMD_LINEDOWN,idiff);
14389 }
14390 else
14391 {
14392 cmdScroll(AV_SCROLLCMD_LINEUP,-idiff);
14393 }
14394 pFrame->nullUpdate();
14395 pFrame->nullUpdate();
14396 _ensureInsertionPointOnScreen();
14397 }
14398 return;
14399 }
14400
getMaxHeight(UT_uint32 iRow) const14401 UT_uint32 FV_View::getMaxHeight(UT_uint32 iRow) const
14402 {
14403 fp_Page * pPage = m_pLayout->getNthPage(iRow * getNumHorizPages());
14404 if(!pPage)
14405 {
14406 pPage = m_pLayout->getNthPage(0);
14407 }
14408 UT_sint32 iMaxPageHeight = 0;
14409 if(!pPage)
14410 {
14411 fl_DocSectionLayout * pDSL =m_pLayout->getFirstSection();
14412 iMaxPageHeight = pDSL->getMaxSectionColumnHeight();
14413 if(getViewMode() == VIEW_PRINT)
14414 {
14415 iMaxPageHeight += (pDSL->getTopMargin() + pDSL->getBottomMargin());
14416 }
14417 return iMaxPageHeight;
14418 }
14419 fl_DocSectionLayout * pDSL = pPage->getOwningSection();
14420
14421 for(unsigned int i = 0; i < getNumHorizPages(); i++)
14422 {
14423 UT_sint32 iPageHeight = pPage->getHeight();
14424 if(getViewMode() != VIEW_PRINT)
14425 {
14426 iPageHeight = iPageHeight - pDSL->getTopMargin() - pDSL->getBottomMargin();
14427 }
14428 if (iPageHeight > iMaxPageHeight)
14429 {
14430 iMaxPageHeight = iPageHeight;
14431 }
14432
14433 if(pPage->getNext())
14434 {
14435 pPage = pPage->getNext();
14436 }
14437 else
14438 {
14439 break;
14440 }
14441 }
14442
14443
14444 return iMaxPageHeight;
14445 }
14446
getWidthPrevPagesInRow(UT_uint32 iPageNumber) const14447 UT_uint32 FV_View::getWidthPrevPagesInRow(UT_uint32 iPageNumber) const
14448 {
14449 if (getNumHorizPages() == 1)
14450 {
14451 return 0;
14452 }
14453
14454 UT_sint32 totalWidth = 0;
14455 UT_sint32 iRow = iPageNumber/getNumHorizPages(); //yay truncation.
14456 UT_sint32 iFirstPageInRow = 0;
14457 UT_sint32 diff = 0; //diff between current & prev pages in row
14458
14459 if(!rtlPages())
14460 {
14461 iFirstPageInRow = iRow * getNumHorizPages();
14462 diff = iPageNumber - iFirstPageInRow;
14463 }
14464 else
14465 {
14466 iFirstPageInRow = (iRow * getNumHorizPages()) + (getNumHorizPages() -1);
14467 diff = iFirstPageInRow - iPageNumber;
14468 }
14469 if(diff < 0)
14470 diff = 0;
14471 if (iFirstPageInRow != static_cast<UT_sint32>(iPageNumber))
14472 {
14473 fp_Page * pPage = 0;
14474
14475 if (m_pLayout->getNthPage(iFirstPageInRow))
14476 {
14477 pPage = m_pLayout->getNthPage(iFirstPageInRow);
14478 for (UT_sint32 i = 0; i < diff; i++)
14479 {
14480 totalWidth += getHorizPageSpacing() + pPage->getWidth();
14481
14482 if (pPage->getNext())
14483 {
14484 pPage = pPage->getNext();
14485 }
14486 else
14487 {
14488 break;
14489 }
14490 }
14491 }
14492 }
14493 return totalWidth;
14494 }
14495
getWidthPagesInRow(fp_Page * page) const14496 UT_uint32 FV_View::getWidthPagesInRow(fp_Page *page) const
14497 {
14498 UT_sint32 iPageNumber = m_pLayout->findPage(page);
14499 if(iPageNumber < 0)
14500 {
14501 fp_Page * pPage = m_pLayout->getFirstPage();
14502 if(pPage)
14503 return pPage->getWidth();
14504 else
14505 return m_pLayout->getFirstSection()->getWidth();
14506 }
14507 fp_Page * pPage = m_pLayout->getNthPage(iPageNumber);
14508 UT_uint32 iRow = iPageNumber/getNumHorizPages();
14509 UT_uint32 iLastPageInRow = 0;
14510
14511 if(!rtlPages())
14512 {
14513 iLastPageInRow = iRow * getNumHorizPages() + (getNumHorizPages() - 1);
14514 }
14515 else
14516 {
14517 iLastPageInRow = iRow * getNumHorizPages();
14518 }
14519
14520 return (getWidthPrevPagesInRow(iLastPageInRow) + pPage->getWidth());
14521 }
14522
getHorizPageSpacing() const14523 UT_uint32 FV_View::getHorizPageSpacing() const
14524 {
14525 //TODO: Make this change depending on the amount of free space when m_autoNumHorizPages == false
14526 return m_horizPageSpacing;
14527 }
14528
rtlPages() const14529 bool FV_View::rtlPages() const
14530 {
14531 /*bool bRTL; //This doesn't seem to be working.
14532 XAP_App::getApp()->getPrefsValueBool(static_cast<const gchar *>(AP_PREF_KEY_DefaultDirectionRtl), &bRTL);
14533 return bRTL;*/
14534
14535 return FALSE;
14536 }
14537
14538 void
selectRange(PT_DocPosition start,PT_DocPosition end)14539 FV_View::selectRange( PT_DocPosition start, PT_DocPosition end )
14540 {
14541 PT_DocPosition prev_start, prev_end;
14542
14543 prev_start = m_Selection.getSelectionLeftAnchor();
14544 prev_end = m_Selection.getSelectionRightAnchor();
14545
14546 if (prev_start == start && prev_end == end)
14547 return;
14548
14549 _clearSelection(false);
14550 _setPoint(start);
14551 m_Selection.setSelectionLeftAnchor(start);
14552 _setSelectionAnchor();
14553 setPoint(end);
14554 m_Selection.setSelectionRightAnchor(end);
14555
14556 _drawBetweenPositions(MIN (prev_start, start), MAX (prev_end, end));
14557 _updateSelectionHandles();
14558 }
14559
14560 void
selectRange(const std::pair<PT_DocPosition,PT_DocPosition> & range)14561 FV_View::selectRange( const std::pair< PT_DocPosition, PT_DocPosition >& range )
14562 {
14563 selectRange( range.first, range.second );
14564 }
14565
14566 /*!
14567 Reverse the direction of the current selection
14568 Does so without changing the screen.
14569 */
swapSelectionOrientation(void)14570 void FV_View::swapSelectionOrientation(void)
14571 {
14572 UT_ASSERT(!isSelectionEmpty());
14573 _fixInsertionPointCoords();
14574 PT_DocPosition curPos = getPoint();
14575 UT_ASSERT(curPos != m_Selection.getSelectionAnchor());
14576 _setPoint(m_Selection.getSelectionAnchor());
14577 m_Selection.setSelectionAnchor(curPos);
14578 }
14579
14580