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