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 #define BENCHLAYOUT 0
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <ctype.h>
29 #include <string.h>
30 #include <locale.h>
31 #include <vector>
32
33 #include "ut_assert.h"
34 #include "ut_debugmsg.h"
35 #include "ut_go_file.h"
36 #include "ut_growbuf.h"
37 #include "ut_misc.h"
38 #include "ut_string.h"
39 #include "ut_bytebuf.h"
40 #include "ut_timer.h"
41 #include "ut_Language.h"
42 #include "ut_uuid.h"
43
44 #include "xav_View.h"
45 #include "fl_DocLayout.h"
46 #include "fl_BlockLayout.h"
47 #ifdef ENABLE_SPELL
48 #include "fl_Squiggles.h"
49 #endif
50 #include "fl_SectionLayout.h"
51 #include "fl_AutoNum.h"
52 #include "fp_Page.h"
53 #include "fp_PageSize.h"
54 #include "fp_Column.h"
55 #include "fp_Line.h"
56 #include "fp_Run.h"
57 #include "fp_TextRun.h"
58 #include "fg_Graphic.h"
59 #include "fg_GraphicRaster.h"
60 #include "pd_Document.h"
61 #include "pd_Style.h"
62 #include "pp_Property.h"
63 #include "pp_AttrProp.h"
64 #include "gr_Graphics.h"
65 #include "gr_Painter.h"
66 #include "gr_DrawArgs.h"
67 #include "ie_types.h"
68 #include "xap_App.h"
69 #include "xap_Frame.h"
70 #include "xap_Clipboard.h"
71 #include "ap_TopRuler.h"
72 #include "ap_LeftRuler.h"
73 #include "ap_Prefs.h"
74 #include "ap_Strings.h"
75 #include "fd_Field.h"
76 #include "pf_Frag_Strux.h"
77 #include "fp_FootnoteContainer.h"
78 #include "fv_ViewDoubleBuffering.h"
79
80 #ifdef ENABLE_SPELL
81 #include "spell_manager.h"
82 #if 1
83 // todo: work around to remove the INPUTWORDLEN restriction for pspell
84 #include "ispell_def.h"
85 #endif
86 #endif
87
88 #include "ut_rand.h"
89 #include "fp_TableContainer.h"
90 #include "fl_FootnoteLayout.h"
91 #include "fl_ContainerLayout.h"
92 #include "fl_TOCLayout.h"
93 #include "pp_Revision.h"
94
95 #include "ap_Dialog_SplitCells.h"
96 #include "ev_Mouse.h"
97 #include "fv_View.h"
98
99 // RIVERA
100 #include "ap_Dialog_Annotation.h"
101 #include "xap_Dialog.h"
102 #include "xap_DialogFactory.h"
103 #include "ap_Dialog_Id.h"
104
105 // NB -- irrespective of this size, the piecetable will store
106 // at max BOOKMARK_NAME_LIMIT of chars as defined in pf_Frag_Bookmark.h
107 #define BOOKMARK_NAME_SIZE 30
108 #define CHECK_WINDOW_SIZE if(getWindowHeight() < 20) return;
109 #if BENCHLAYOUT
110 #include <time.h>
111 #endif
112
113 #include "pd_DocumentRDF.h"
114
115 /****************************************************************/
116
cmdUnselectSelection(void)117 void FV_View::cmdUnselectSelection(void)
118 {
119 _clearSelection();
120 }
121
122
123 /*!
124 Move point a number of character positions
125 \param bForward True if moving forward
126 \param count Number of char positions to move
127
128 \note Cursor movement while there's a selection has the effect of
129 clearing the selection. And only that. See bug 993.
130 */
cmdCharMotion(bool bForward,UT_uint32 count)131 void FV_View::cmdCharMotion(bool bForward, UT_uint32 count)
132 {
133 if (!isSelectionEmpty())
134 {
135 _moveToSelectionEnd(bForward);
136 _fixInsertionPointCoords();
137 _ensureInsertionPointOnScreen();
138 notifyListeners(AV_CHG_MOTION);
139 return;
140 }
141
142 PT_DocPosition iPoint = getPoint();
143 if (!_charMotion(bForward, count))
144 {
145 if(bForward)
146 {
147 //
148 // Reached end of document.
149 //
150 UT_DEBUGMSG(("SEVIOR: Reached end of document \n"));
151 m_bPointEOL = true;
152 }
153 else
154 {
155 if(m_bInsertAtTablePending)
156 {
157 m_iInsPoint = iPoint;
158 }
159 else
160 {
161 _setPoint(iPoint);
162 }
163 }
164
165 bool bOK = true;
166 while(bOK && !isPointLegal() && (getPoint() > 2))
167 {
168 bOK = _charMotion(false,1);
169 }
170 }
171 else
172 {
173 PT_DocPosition iPoint1 = getPoint();
174 if ( iPoint1 == iPoint )
175 {
176 if(!_charMotion(bForward, count))
177 {
178 _setPoint(iPoint);
179 _fixInsertionPointCoords();
180 _ensureInsertionPointOnScreen();
181 notifyListeners(AV_CHG_MOTION);
182 return;
183 }
184 if(!isPointLegal())
185 {
186 _setPoint(iPoint);
187 _fixInsertionPointCoords();
188 _ensureInsertionPointOnScreen();
189 notifyListeners(AV_CHG_MOTION);
190 return;
191 }
192 }
193 }
194 _fixInsertionPointCoords();
195 _ensureInsertionPointOnScreen();
196 notifyListeners(AV_CHG_MOTION);
197 }
198
199
200 /*!
201 * Split the merged cells located at the current point in the way specified
202 * by iSplitType
203 */
cmdSplitCells(AP_CellSplitType iSplitType)204 bool FV_View::cmdSplitCells(AP_CellSplitType iSplitType)
205 {
206 STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
207
208 pf_Frag_Strux* cellSDH,*tableSDH,*curSDH,*endTableSDH;
209 pf_Frag_Strux* prevCellSDH1,*prevCellSDH2;
210 PT_DocPosition posTable,posCell,posFirstInsert,posEndTable;
211 posFirstInsert = 0;
212 UT_sint32 iLeft,iRight,iTop,iBot;
213 UT_sint32 jLeft,jRight,jTop,jBot;
214 PT_DocPosition posCol = getPoint();
215 if(!isInTable(posCol))
216 {
217 return false;
218 }
219 getCellParams(posCol, &iLeft, &iRight,&iTop,&iBot);
220 UT_String sCellProps;
221 getCellFormat(posCol,sCellProps);
222 //
223 // Find the Row and column of the cell at the current point. The strategy
224 // will be insert a new cell with the same (row/col depending on the split)
225 // and to adjust the rest of the table past this point.
226 //
227 UT_sint32 rowSpan = iBot - iTop;
228 UT_sint32 colSpan = iRight - iLeft;
229 bool bRes = m_pDoc->getStruxOfTypeFromPosition(posCol,PTX_SectionCell,&cellSDH);
230 bRes = m_pDoc->getStruxOfTypeFromPosition(posCol,PTX_SectionTable,&tableSDH);
231 UT_return_val_if_fail(bRes, false);
232
233 posTable = m_pDoc->getStruxPosition(tableSDH) + 1;
234 posCell = m_pDoc->getStruxPosition(cellSDH);
235 endTableSDH = m_pDoc->getEndTableStruxFromTableSDH(tableSDH);
236 posEndTable = m_pDoc->getStruxPosition(endTableSDH);
237
238 // Get the attributes and properties of the current block. These attributes and properties
239 // will be copied in the new cell.
240 fl_BlockLayout * pBL = getBlockAtPosition(getPoint());
241 const PP_AttrProp * pAP = NULL;
242 m_pDoc->getAttrProp(m_pDoc->getAPIFromSDH(pBL->getStruxDocHandle()), &pAP);
243 UT_return_val_if_fail(pAP, false);
244
245 //
246 // Got all we need, now set things up to do the insert nicely
247 //
248 // Signal PieceTable Change
249 _saveAndNotifyPieceTableChange();
250
251 // Turn off list updates
252
253 m_pDoc->disableListUpdates();
254 m_pDoc->beginUserAtomicGlob();
255 if (!isSelectionEmpty())
256 {
257 _clearSelection();
258 }
259 m_pDoc->setDontImmediatelyLayout(true);
260 //
261 // Now trigger a rebuild of the whole table by sending a changeStrux to the table strux
262 // with a bogus line-type property. We'll restore it later.
263 //
264 const char * pszTable[3] = {NULL,NULL,NULL};
265 pszTable[0] = "list-tag";
266 const char * szListTag = NULL;
267 UT_String sListTag;
268 UT_sint32 iListTag;
269 m_pDoc->getPropertyFromSDH(tableSDH,isShowRevisions(),getRevisionLevel(),pszTable[0],&szListTag);
270 if(szListTag == NULL || *szListTag == '\0')
271 {
272 iListTag = 0;
273 }
274 else
275 {
276 iListTag = atoi(szListTag);
277 iListTag -= 1;
278 }
279 UT_String_sprintf(sListTag,"%d",iListTag);
280 pszTable[1] = sListTag.c_str();
281 UT_DEBUGMSG(("SEVIOR: Doing Table strux change of %s %s \n",pszTable[0],pszTable[1]));
282 m_pDoc->changeStruxFmt(PTC_AddFmt,posTable,posTable,NULL,pszTable,PTX_SectionTable);
283 UT_sint32 splitLeft,splitRight,splitTop,splitBot;
284 splitLeft = splitRight = 0;
285 UT_sint32 newLeft,newRight,newTop,newBot;
286 newTop = newBot = 0;
287 UT_sint32 numRows = 0;
288 UT_sint32 numCols = 0;
289 bool bDoSplitSolidHori = false;
290 bool bDoSplitSolidVert = false;
291 //
292 // OK now insert the cell and do the update
293 //
294 m_pDoc-> getRowsColsFromTableSDH(tableSDH, isShowRevisions(), getRevisionLevel(), &numRows, &numCols);
295
296 if(iSplitType <= hori_right)
297 {
298 //
299 // This is similar to "insert column"
300 //
301 if(iSplitType == hori_left)
302 {
303 splitLeft = iLeft;
304 splitRight = iLeft+1;
305 }
306 else if(iSplitType == hori_mid)
307 {
308 splitLeft = iLeft;
309 if(colSpan == 1)
310 {
311 bDoSplitSolidHori = true;
312 splitRight = iLeft+1;
313 }
314 else
315 {
316 splitRight = iLeft + colSpan/2;
317 }
318 }
319 else if(iSplitType == hori_right)
320 {
321 splitLeft = iLeft;
322 splitRight = iRight -1;
323 }
324 splitTop = iTop;
325 splitBot = iBot;
326 newTop = iTop;
327 newBot = iBot;
328 if(!bDoSplitSolidHori)
329 {
330 newLeft = splitRight;
331 newRight = iRight;
332 }
333 else
334 {
335 newLeft = splitRight;
336 newRight = newLeft+1;
337 }
338
339 }
340 else
341 {
342 if(iSplitType == vert_above)
343 {
344 newTop = iTop;
345 newBot = iTop +1;
346 }
347 else if(iSplitType == vert_mid)
348 {
349 newTop = iTop;
350 if(rowSpan == 1)
351 {
352 bDoSplitSolidVert = true;
353 newBot = newTop+1;
354 }
355 else
356 {
357 newBot = iTop + rowSpan/2;
358 }
359 }
360 else if(iSplitType == vert_below)
361 {
362 newTop = iTop;
363 newBot = iBot -1;
364 }
365 //
366 // we need to get the location of where to place this cell.
367 //
368 splitLeft = iLeft;
369 splitRight = iRight;
370 newLeft = iLeft;
371 newRight = iRight;
372 if(!bDoSplitSolidVert)
373 {
374 splitTop = newBot;
375 splitBot = iBot;
376 }
377 else
378 {
379 newTop = iTop;
380 newBot = newTop+1;
381 splitTop = newBot;
382 splitBot = splitTop+1;
383 }
384 //
385 // OK now we have to find the place to insert this. It should be the cell
386 // immediately after (splitTop,splitLeft)
387 //
388 //(except if it's a splitSolidVert in which case it should be placed as the
389 // next next on the row in the first cell before (splitleft,splittop)
390 //
391 if(bDoSplitSolidVert)
392 {
393 //
394 // OK start with cellSDH and scan until we either reach the end of the table
395 // or we find a cell past where splitcell should be. Then we insert the cell
396 // at where cell just after splitcell is.
397 //
398 bool bStop = false;
399 curSDH = cellSDH;
400 while(!bStop)
401 {
402 posCell = m_pDoc->getStruxPosition(curSDH)+1;
403 bRes = getCellParams(posCell,&jLeft,&jRight,&jTop,&jBot);
404 UT_ASSERT(bRes);
405 if(jTop >= splitTop)
406 {
407 //
408 // Found it!
409 //
410 bStop = true;
411 posCell = m_pDoc->getStruxPosition(curSDH);
412 break;
413 }
414 bRes = m_pDoc->getNextStruxOfType(curSDH,PTX_SectionCell,&curSDH);
415 if(!bRes)
416 {
417 bStop = true;
418 posCell = m_pDoc->getStruxPosition(endTableSDH);
419 break;
420 }
421 posCell = m_pDoc->getStruxPosition(curSDH);
422 if(posCell > posEndTable)
423 {
424 bStop = true;
425 posCell = m_pDoc->getStruxPosition(endTableSDH);
426 break;
427 }
428 }
429 }
430 else
431 {
432 jTop = splitTop;
433 jBot = jTop+1;
434 jLeft = splitRight;
435 if(jLeft >= numCols)
436 {
437 jLeft = 0;
438 jTop += 1;
439 jBot +=1;
440 }
441 jRight = jLeft+1;
442 if(jTop >= numRows)
443 {
444 //
445 // Place right before endTable Strux
446 //
447 if(endTableSDH == NULL)
448 {
449 //
450 // Disaster! the table structure in the piecetable is screwed.
451 // we're totally stuffed now.
452 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
453 return false;
454 }
455 posCell = m_pDoc->getStruxPosition(endTableSDH);
456 }
457 else
458 {
459 //
460 // now we have to loop until we find a cell precisely at jLeft,jTop
461 //
462 bool bFound = false;
463 while(!bFound)
464 {
465 curSDH = m_pDoc-> getCellSDHFromRowCol(tableSDH,isShowRevisions(), getRevisionLevel(), jTop,jLeft);
466 if(curSDH == NULL)
467 {
468 endTableSDH = m_pDoc->getEndTableStruxFromTableSDH(tableSDH);
469 if(endTableSDH == NULL)
470 {
471 //
472 // Disaster! the table structure in the piecetable is screwed.
473 // we're totally stuffed now.
474 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
475 return false;
476 }
477 posCell = m_pDoc->getStruxPosition(endTableSDH);
478 bFound = true;
479 }
480 UT_sint32 kLeft,kRight,kTop,kBot;
481 PT_DocPosition posTmp = m_pDoc->getStruxPosition(curSDH)+1;
482 getCellParams(posTmp,&kLeft,&kRight,&kTop,&kBot);
483 if((kLeft == jLeft) && (kTop == jTop))
484 {
485 bFound = true;
486 posCell = m_pDoc->getStruxPosition(curSDH);
487 }
488 else
489 {
490 jLeft++;
491 jRight++;
492 if(jLeft >= numCols)
493 {
494 jLeft = 0;
495 jTop++;
496 jRight =1;
497 jBot++;
498 }
499 if(jTop >= numRows)
500 {
501 endTableSDH = m_pDoc->getEndTableStruxFromTableSDH(tableSDH);
502 if(endTableSDH == NULL)
503 {
504 //
505 // Disaster! the table structure in the piecetable is screwed.
506 // we're totally stuffed now.
507 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
508 return false;
509 }
510 posCell = m_pDoc->getStruxPosition(endTableSDH);
511 bFound = true;
512 }
513 }
514 }
515 }
516 }
517 }
518 //
519 // OK build the table properties
520 //
521 UT_String sRowTop = "top-attach";
522 UT_String sRowBot = "bot-attach";
523 UT_String sColLeft = "left-attach";
524 UT_String sColRight = "right-attach";
525 UT_String sTop,sBot,sLeft,sRight;
526 UT_String_sprintf(sTop,"%d",splitTop);
527 UT_String_sprintf(sBot,"%d",splitBot);
528 UT_String_sprintf(sLeft,"%d",splitLeft);
529 UT_String_sprintf(sRight,"%d",splitRight);
530 UT_String_setProperty(sCellProps,sRowTop,sTop);
531 UT_String_setProperty(sCellProps,sRowBot,sBot);
532 UT_String_setProperty(sCellProps,sColLeft,sLeft);
533 UT_String_setProperty(sCellProps,sColRight,sRight);
534 UT_DEBUGMSG(("Cells props for new cell:\n %s \n",sCellProps.c_str()));
535 //
536 // Insert the cell
537 //
538 const gchar * atts[4] = {"props",NULL,NULL,NULL};
539 atts[1] = sCellProps.c_str();
540 bRes = m_pDoc->insertStrux(posCell,PTX_SectionCell,atts,NULL);
541 bRes = m_pDoc->insertStrux(posCell+1,PTX_Block,pAP->getAttributes(),pAP->getProperties());
542 posFirstInsert = posCell + 2;
543 //
544 // Save the cell SDH for later..
545 //
546 m_pDoc->getStruxOfTypeFromPosition(posCell+1,PTX_SectionCell,&prevCellSDH1);
547
548 bRes = m_pDoc->insertStrux(posCell+2,PTX_EndCell);
549
550 // Changes the props of the new cell
551 UT_String_sprintf(sTop,"%d",newTop);
552 UT_String_sprintf(sBot,"%d",newBot);
553 UT_String_sprintf(sLeft,"%d",newLeft);
554 UT_String_sprintf(sRight,"%d",newRight);
555 UT_String_setProperty(sCellProps,sRowTop,sTop);
556 UT_String_setProperty(sCellProps,sRowBot,sBot);
557 UT_String_setProperty(sCellProps,sColLeft,sLeft);
558 UT_String_setProperty(sCellProps,sColRight,sRight);
559 posCell = m_pDoc->getStruxPosition(cellSDH)+1;
560 UT_DEBUGMSG(("New Cells props for old cell:\n %s \n",sCellProps.c_str()));
561 atts[1] = sCellProps.c_str();
562 UT_DebugOnly<bool> bres = m_pDoc->changeStruxFmt(PTC_AddFmt,posCell,posCell,atts,NULL,PTX_SectionCell);
563 UT_ASSERT(bres);
564 m_pDoc->getStruxOfTypeFromPosition(posCell,PTX_SectionCell,&prevCellSDH2); if(bDoSplitSolidHori)
565 {
566 //
567 // OK now we have to adjust all the cells with left or right >= splitleft
568 // If left of a given cell is < splitLeft it is not adjusted but the right
569 // of the cell if it's > splitleft is incremented. In this way our new cell
570 // span two columns
571 //
572 UT_sint32 myleft,myright,mytop,mybot;
573 //
574 // start at the first cell and scan through the table adjusting each cell.
575 //
576 bres = m_pDoc->getStruxOfTypeFromPosition(posTable+1,PTX_SectionCell,&cellSDH);
577 UT_ASSERT(bres);
578 bool bStop= false;
579 while(!bStop)
580 {
581 posCell = m_pDoc->getStruxPosition(cellSDH)+1;
582 bres = getCellParams(posCell,&myleft,&myright,&mytop,&mybot);
583 UT_ASSERT(bres);
584 bool bChange =false;
585 if((cellSDH == prevCellSDH1) || (cellSDH == prevCellSDH2))
586 {
587 //
588 // Igore me!
589 //
590 bChange = false;
591 }
592 else
593 {
594 if(myright> splitLeft)
595 {
596 myright++;
597 bChange = true;
598 }
599 if(myleft>splitLeft)
600 {
601 myleft++;
602 bChange = true;
603 }
604 if(bChange)
605 {
606 // Changes the props of the cell
607 UT_String_sprintf(sTop,"%d",mytop);
608 UT_String_sprintf(sBot,"%d",mybot);
609 UT_String_sprintf(sLeft,"%d",myleft);
610 UT_String_sprintf(sRight,"%d",myright);
611 UT_String_setProperty(sCellProps,sRowTop,sTop);
612 UT_String_setProperty(sCellProps,sRowBot,sBot);
613 UT_String_setProperty(sCellProps,sColLeft,sLeft);
614 UT_String_setProperty(sCellProps,sColRight,sRight);
615 atts[1] = sCellProps.c_str();
616 m_pDoc->changeStruxFmt(PTC_AddFmt,posCell,posCell,atts,NULL,PTX_SectionCell);
617 }
618 }
619 if(!m_pDoc->getNextStruxOfType(cellSDH,PTX_SectionCell,&cellSDH))
620 {
621 bStop = true;
622 break;
623 }
624 posCell = m_pDoc->getStruxPosition(cellSDH);
625 if(posCell > posEndTable)
626 {
627 bStop = true;
628 break;
629 }
630 }
631 }
632 if(bDoSplitSolidVert)
633 {
634 //
635 // OK now we have to adjust all the cells with top or bot >= newTop
636 // If top of a given cell is < newTop it is not adjusted but the bot
637 // of the cell if it's > newTop is incremented. In this way our new cell
638 // spans two rows
639 //
640 UT_sint32 myleft,myright,mytop,mybot;
641 //
642 // start at the first cell and scan through the table adjusting each cell.
643 //
644 m_pDoc->getStruxOfTypeFromPosition(posTable+1,PTX_SectionCell,&cellSDH);
645 bool bStop= false;
646 while(!bStop)
647 {
648 posCell = m_pDoc->getStruxPosition(cellSDH) +1;
649 getCellParams(posCell,&myleft,&myright,&mytop,&mybot);
650 bool bChange =false;
651 if((cellSDH == prevCellSDH1) || (cellSDH == prevCellSDH2))
652 {
653 //
654 // Igore me!
655 //
656 bChange = false;
657 }
658 else
659 {
660 if(mytop>newTop)
661 {
662 mytop++;
663 bChange = true;
664 }
665 if(mybot>newTop)
666 {
667 mybot++;
668 bChange = true;
669 }
670 if(bChange)
671 {
672 // Changes the props of the cell
673 UT_String_sprintf(sTop,"%d",mytop);
674 UT_String_sprintf(sBot,"%d",mybot);
675 UT_String_sprintf(sLeft,"%d",myleft);
676 UT_String_sprintf(sRight,"%d",myright);
677 UT_String_setProperty(sCellProps,sRowTop,sTop);
678 UT_String_setProperty(sCellProps,sRowBot,sBot);
679 UT_String_setProperty(sCellProps,sColLeft,sLeft);
680 UT_String_setProperty(sCellProps,sColRight,sRight);
681 atts[1] = sCellProps.c_str();
682 m_pDoc->changeStruxFmt(PTC_AddFmt,posCell,posCell,atts,NULL,PTX_SectionCell);
683 }
684 }
685 if(!m_pDoc->getNextStruxOfType(cellSDH,PTX_SectionCell,&cellSDH))
686 {
687 bStop = true;
688 break;
689 }
690 posCell = m_pDoc->getStruxPosition(cellSDH);
691 if(posCell > posEndTable)
692 {
693 bStop = true;
694 break;
695 }
696 }
697 }
698
699 //
700 // Now trigger a rebuild of the whole table by sending a changeStrux to the table strux
701 // with the restored line-type property it has before.
702 //
703 iListTag += 1;
704 UT_String_sprintf(sListTag,"%d",iListTag);
705 pszTable[1] = sListTag.c_str();
706 UT_DEBUGMSG(("SEVIOR: Doing Table strux change of %s %s \n",pszTable[0],pszTable[1]));
707 m_pDoc->changeStruxFmt(PTC_AddFmt,posTable,posTable,NULL,pszTable,PTX_SectionTable);
708 //
709 // OK finish everything off with the various parameters which allow the formatter to
710 // be updated.
711 //
712 m_pDoc->setDontImmediatelyLayout(false);
713
714 // Signal PieceTable Changes have finished
715 _restorePieceTableState();
716 _generalUpdate();
717
718 m_pDoc->endUserAtomicGlob();
719
720 // restore updates and clean up dirty lists
721 m_pDoc->enableListUpdates();
722 m_pDoc->updateDirtyLists();
723 // Put the insertion point in a legal position
724 //
725 setPoint(posFirstInsert);
726 _fixInsertionPointCoords();
727 _ensureInsertionPointOnScreen();
728 notifyListeners(AV_CHG_MOTION);
729 return true;
730 }
731
cmdSelectTOC(UT_sint32 x,UT_sint32 y)732 void FV_View::cmdSelectTOC(UT_sint32 x, UT_sint32 y)
733 {
734 UT_sint32 xClick=0,yClick = 0;
735 fp_Page* pPage = _getPageForXY(x,y,xClick,yClick);
736 fl_TOCLayout * pTOCL = pPage->getLastMappedTOC();
737 UT_return_if_fail(pTOCL);
738 m_Selection.setTOCSelected(pTOCL);
739 PT_DocPosition pos = pTOCL->getPosition();
740 m_iInsPoint = pos+1;
741 if(m_pG)
742 {
743 m_pG->allCarets()->disable();
744 }
745 m_countDisable++;
746 }
747
748 /*!
749 * Select the column of the table identified by the document position
750 * posOfColumn
751 */
cmdSelectColumn(PT_DocPosition posOfColumn)752 bool FV_View::cmdSelectColumn(PT_DocPosition posOfColumn)
753 {
754 pf_Frag_Strux* cellSDH,*tableSDH;
755 PT_DocPosition posTable;
756 UT_sint32 iLeft,iRight,iTop,iBot;
757 UT_sint32 Left,Right,Top,Bot;
758 bool bEOL = false; // added this stop compiler warning. Tomas
759 if(!isInTable(posOfColumn))
760 {
761 return false;
762 }
763 if(!isSelectionEmpty())
764 {
765 _clearSelection();
766 _resetSelection();
767 }
768 getCellParams(posOfColumn, &iLeft, &iRight,&iTop,&iBot);
769 bool bRes = m_pDoc->getStruxOfTypeFromPosition(posOfColumn,PTX_SectionCell,&cellSDH);
770 bRes = m_pDoc->getStruxOfTypeFromPosition(posOfColumn,PTX_SectionTable,&tableSDH);
771 UT_return_val_if_fail(bRes, false);
772
773 posTable = m_pDoc->getStruxPosition(tableSDH) + 1;
774
775 //
776 // Now find the number of rows and columns inthis table.
777 //
778 UT_sint32 numRows = 0;
779 UT_sint32 numCols = 0;
780 m_pDoc->getRowsColsFromTableSDH(tableSDH, isShowRevisions(), getRevisionLevel(), &numRows, &numCols);
781 //
782 // Ok set the selection type to that of a column
783 //
784 m_Selection.setMode(FV_SelectionMode_TableColumn);
785
786 fl_BlockLayout * pBlock = NULL;
787 fp_Run * pRun = NULL;
788 UT_sint32 xCaret, yCaret;
789 UT_uint32 heightCaret;
790 UT_sint32 xCaret2, yCaret2;
791 bool bDirection;
792 _findPositionCoords(posOfColumn, bEOL, xCaret, yCaret, xCaret2, yCaret2, heightCaret, bDirection, &pBlock, &pRun);
793 UT_return_val_if_fail(pBlock,false);
794 fl_ContainerLayout * pCL2 = pBlock->myContainingLayout();
795 UT_return_val_if_fail(pCL2,false);
796 pCL2 = pCL2->myContainingLayout();
797 UT_return_val_if_fail(pCL2,false);
798 UT_return_val_if_fail((pCL2->getContainerType() == FL_CONTAINER_TABLE),false);
799 fl_TableLayout * pTL = static_cast<fl_TableLayout *>(pCL2);
800 m_Selection.setTableLayout(pTL);
801 //
802 // Now loop through the column and collect all the cells.
803 //
804 UT_sint32 j = 0;
805 UT_sint32 jPrev = -1;
806 for(j=0; j<numRows; j++)
807 {
808 PT_DocPosition posWork = findCellPosAt(posTable,j,iLeft) +1;
809 getCellParams(posWork,&Left,&Right,&Top,&Bot);
810 UT_DEBUGMSG(("Adding cell at left %d right %d top %d bot %d posWork %d \n",Left,Right,Top,Bot,posWork));
811 if(Top == jPrev)
812 {
813 continue;
814 }
815 _findPositionCoords(posWork+1, bEOL, xCaret, yCaret, xCaret2, yCaret2, heightCaret, bDirection, &pBlock, &pRun);
816 UT_return_val_if_fail(pBlock,false);
817 UT_DEBUGMSG(("Block pos = %d \n",pBlock->getPosition(false)));
818 fl_ContainerLayout * pCL = pBlock->myContainingLayout();
819 UT_return_val_if_fail((pCL->getContainerType() == FL_CONTAINER_CELL),false);
820 fl_CellLayout * pCell = static_cast<fl_CellLayout *>(pCL);
821 m_Selection.addCellToSelection(pCell);
822 jPrev = j;
823 }
824 PD_DocumentRange * pRange = getNthSelection(getNumSelections()-1);
825 _setPoint(pRange->m_pos2);
826 _drawSelection();
827 notifyListeners(AV_CHG_MOTION);
828 return true;
829 }
830
831 /*!
832 * Convert a table to Text with each cell separated by commas, Tabs,
833 * or tabs and commas as follows:
834 * iSepType == 0 Use Commas
835 * iSepType == 1 Use Tabs
836 * iSepType == 2 Use Tabs and Commas
837 * We place a paragraph break at the end of of each row but otherwise we simply
838 * extract just the text from each cell.
839 */
cmdTableToText(PT_DocPosition posSource,UT_sint32 iSepType)840 bool FV_View::cmdTableToText(PT_DocPosition posSource,UT_sint32 iSepType)
841 {
842 fl_TableLayout * pTL = getTableAtPos(posSource);
843 UT_return_val_if_fail(pTL,false);
844 if (!isSelectionEmpty())
845 {
846 _clearSelection();
847 }
848
849 pf_Frag_Strux* tableSDH;
850 bool bRes = m_pDoc->getStruxOfTypeFromPosition(posSource,PTX_SectionTable,&tableSDH);
851 UT_return_val_if_fail(bRes, false);
852 PT_DocPosition posTable = m_pDoc->getStruxPosition(tableSDH) + 1;
853
854 //
855 // Now find the number of rows and columns inthis table.
856 //
857 UT_sint32 numRows = 0;
858 UT_sint32 numCols = 0;
859 m_pDoc->getRowsColsFromTableSDH(tableSDH, isShowRevisions(), getRevisionLevel(), &numRows, &numCols);
860 PT_DocPosition posInsert = pTL->getPosition(true);
861
862 // Signal PieceTable Changes
863 _saveAndNotifyPieceTableChange();
864
865 // Turn off list updates
866
867 m_pDoc->disableListUpdates();
868 m_pDoc->beginUserAtomicGlob();
869 setPoint(posInsert);
870 insertParagraphBreak();
871
872 UT_sint32 i,j =0;
873 fp_TableContainer * pTAB = static_cast<fp_TableContainer *>(pTL->getFirstContainer());
874 fp_CellContainer * pCCell = NULL;
875 fl_CellLayout * pCellL = NULL;
876 UT_GrowBufElement iComma = static_cast<UT_GrowBufElement>(',');
877 UT_GrowBufElement iTab = static_cast<UT_GrowBufElement>(UCS_TAB);
878 for(i=0;i<numRows;i++)
879 {
880 for(j=0; j< numCols;j++)
881 {
882 pCCell = pTAB->getCellAtRowColumn(i,j);
883 if(pCCell == NULL)
884 {
885 continue;
886 }
887 pCellL = static_cast<fl_CellLayout *>(pCCell->getSectionLayout());
888 if(pCellL == NULL)
889 {
890 continue;
891 }
892 UT_GrowBuf buf;
893 buf.truncate(0);
894 pCellL->appendTextToBuf(buf);
895 if (j < numCols - 1)
896 {
897 switch (iSepType)
898 {
899 case 0:
900 buf.append(&iComma,1);
901 break;
902 case 1:
903 buf.append(&iTab,1);
904 break;
905 default:
906 buf.append(&iTab,1);
907 buf.append(&iComma,1);
908 }
909 }
910 if (buf.getPointer(0))
911 {
912 cmdCharInsert(reinterpret_cast<UT_UCSChar *>(buf.getPointer(0)),buf.getLength());
913 }
914 }
915 if (i < numRows - 1)
916 {
917 insertParagraphBreak();
918 }
919 }
920 posTable = pTL->getPosition(true) + 2;
921 cmdDeleteTable(posTable, true);
922
923 // Signal PieceTable Changes have finished
924 _restorePieceTableState();
925 _generalUpdate();
926 m_pDoc->endUserAtomicGlob();
927
928
929 // restore updates and clean up dirty lists
930 m_pDoc->enableListUpdates();
931 m_pDoc->updateDirtyLists();
932 _fixInsertionPointCoords();
933 _ensureInsertionPointOnScreen();
934 notifyListeners(AV_CHG_MOTION);
935 return true;
936 }
937
938 /*!
939 * Merge the cells located at posSource with posDestination by copying the data from
940 * source to destination. Then deleting source and expanding destination into it's location
941 * in the table.
942 */
cmdMergeCells(PT_DocPosition posSource,PT_DocPosition posDestination)943 bool FV_View::cmdMergeCells(PT_DocPosition posSource, PT_DocPosition posDestination)
944 {
945 STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
946
947 UT_sint32 sLeft,sRight,sTop,sBot;
948 UT_sint32 dLeft,dRight,dTop,dBot;
949 UT_sint32 Left,Right,Top,Bot; // need these for working variables.
950 getCellParams(posSource,&sLeft,&sRight,&sTop,&sBot);
951 getCellParams(posDestination,&dLeft,&dRight,&dTop,&dBot);
952
953 PT_DocPosition posTable,posWork;
954 pf_Frag_Strux* tableSDH;
955 bool bRes = m_pDoc->getStruxOfTypeFromPosition(posSource,PTX_SectionTable,&tableSDH);
956 UT_return_val_if_fail(bRes, false);
957 posTable = m_pDoc->getStruxPosition(tableSDH) + 1;
958
959 //
960 // Now find the number of rows and columns inthis table.
961 //
962 UT_sint32 numRows = 0;
963 UT_sint32 numCols = 0;
964 m_pDoc->getRowsColsFromTableSDH(tableSDH, isShowRevisions(), getRevisionLevel(), &numRows, &numCols);
965 bool bChanged = false;
966 UT_sint32 iLineType = 0;
967
968 //
969 // Got all we need, now set things up to do the merge nicely
970 //
971 //
972 // OK that's done, now do the merge
973 //
974 // Have to worry about merging cell spanning multiple rows and columns. We do this
975 // by matching the the widths and heights of the source and destination cells.
976 //
977 if((sLeft == dLeft) && (sTop == dTop))
978 {
979 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
980 return false;
981 }
982
983 if(sLeft == dLeft)
984 {
985 //
986 // Merge vertically
987 //
988 // might have d | | | |
989 // ----------
990 // s | |
991 // To solve this merge all top cells horizontally then merge this combined set vertically
992 //
993 // First check that top row ends at bottom row boundary. We reject attempts to merge cells
994 // like this
995 // d | | | |
996 // ------------
997 // s | |
998 if(sRight >= dRight)
999 {
1000 if(sRight < numCols -1)
1001 {
1002 posWork = findCellPosAt(posTable,dTop,sRight) +1;
1003 getCellParams(posWork,&Left,&Right,&Top,&Bot);
1004 if(Left != sRight)
1005 {
1006 //
1007 // Right column of src cell doesn't match the row above it. Bail out.
1008 //
1009 // fixme: Put in a dialog to explain this to the user
1010 //
1011 return false;
1012 }
1013 }
1014 //
1015 // OK now merge all the cells in the destination cell together.
1016 //
1017 Left = dRight;
1018 while(Left < sRight)
1019 {
1020 posWork = findCellPosAt(posTable,dTop,Left) +1;
1021 getCellParams(posWork,&Left,&Right,&Top,&Bot);
1022 //
1023 // Do the merge without all the undo/update trimings
1024 // append onto destination
1025 if(!bChanged)
1026 {
1027 iLineType = _changeCellParams(posTable, tableSDH);
1028 }
1029 bChanged = true;
1030 _MergeCells(posDestination,posWork,false);
1031 Left = Right;
1032 }
1033 //
1034 // Now merge the merged destination into the source
1035 //
1036 if(!bChanged)
1037 {
1038 iLineType = _changeCellParams(posTable, tableSDH);
1039 }
1040 bChanged = true;
1041 posSource = findCellPosAt(posTable,sTop,sLeft) +1;
1042 posDestination = findCellPosAt(posTable,dTop,dLeft) +1;
1043 _MergeCells(posDestination,posSource,true);
1044 }
1045 else
1046 {
1047 //
1048 // Here we have this scenario:
1049 //
1050 // d | |
1051 // ------------
1052 // s | | | |
1053 //
1054 // ie destination is narrower than the source
1055 //
1056 // check that the source column lines up with the destination column.
1057 //
1058 if(dRight < numCols -1)
1059 {
1060 posWork = findCellPosAt(posTable,sTop,dRight) +1;
1061 getCellParams(posWork,&Left,&Right,&Top,&Bot);
1062 if(Left != dRight)
1063 {
1064 //
1065 // Right column of src cell doesn't match the row above it. Bail out.
1066 // fixme: Put in a dialog to explain this to the user
1067 //
1068 return false;
1069 }
1070 }
1071 //
1072 // OK now merge all the cells in the src cell together.
1073 //
1074 Left = sRight;
1075 while(Left < dRight)
1076 {
1077 posWork = findCellPosAt(posTable,sTop,Left) +1;
1078 getCellParams(posWork,&Left,&Right,&Top,&Bot);
1079 //
1080 // Do the merge without all the undo/update trimings
1081 //
1082 if(!bChanged)
1083 {
1084 iLineType = _changeCellParams(posTable, tableSDH);
1085 }
1086 bChanged = true;
1087 _MergeCells(posSource,posWork,false);
1088 Left = Right;
1089 }
1090 //
1091 // Now merge the merged destination into the source
1092 //
1093 if(!bChanged)
1094 {
1095 iLineType = _changeCellParams(posTable, tableSDH);
1096 }
1097 bChanged = true;
1098 posSource = findCellPosAt(posTable,sTop,sLeft) +1;
1099 posDestination = findCellPosAt(posTable,dTop,dLeft) +1;
1100 _MergeCells(posDestination,posSource,true);
1101 }
1102 }
1103 else if(sTop == dTop)
1104 {
1105 //
1106 // Merge horizontally
1107 //
1108 // might have rows spanning several columns
1109 // d s
1110 // ---------
1111 // | | |
1112 // | -----
1113 // | | |
1114 // | -----
1115 // | | |
1116 // ---------
1117 // To solve this merge all cells vertically then merge this combined set horizontally
1118 //
1119 // First check that left column ends at right column boundary.
1120 // We reject attempts to merge cells that don't have this condition.
1121 // ie this:
1122 // d s
1123 // ---------
1124 // | | |
1125 // | -----
1126 // | | |
1127 // | -----
1128 // | | |
1129 // | -----
1130 // |---| |
1131 // | -----
1132 //
1133 if(dBot >= sBot)
1134 {
1135 if(dBot < numRows -1)
1136 {
1137 posWork = findCellPosAt(posTable,dBot,sLeft) +1;
1138 getCellParams(posWork,&Left,&Right,&Top,&Bot);
1139 if(Top != dBot)
1140 {
1141 //
1142 // Bot col of src cell doesn't match the column before. Bail out.
1143 //
1144 // fixme: Put in a dialog to explain this to the user
1145 //
1146 return false;
1147 }
1148 }
1149 //
1150 // OK now merge all the cells right of the src cell together.
1151 //
1152 Bot = sBot;
1153 Top = sBot;
1154 while(Top < dBot)
1155 {
1156 posWork = findCellPosAt(posTable,Top,sLeft) +1;
1157 getCellParams(posWork,&Left,&Right,&Top,&Bot);
1158 //
1159 // Do the merge without all the undo/update trimings
1160 //
1161 if(!bChanged)
1162 {
1163 iLineType = _changeCellParams(posTable, tableSDH);
1164 }
1165 bChanged = true;
1166 _MergeCells(posSource,posWork,false);
1167 UT_ASSERT(Bot > Top);
1168 if(Bot <= Top)
1169 {
1170 break;
1171 }
1172 Top = Bot;
1173 }
1174 //
1175 // Now merge the merged destination into the source
1176 //
1177 if(!bChanged)
1178 {
1179 iLineType = _changeCellParams(posTable, tableSDH);
1180 }
1181 bChanged = true;
1182 posSource = findCellPosAt(posTable,sTop,sLeft) +1;
1183 posDestination = findCellPosAt(posTable,dTop,dLeft) +1;
1184 _MergeCells(posDestination,posSource,true);
1185 }
1186 else
1187 {
1188 //
1189 // Here we have this scenario:
1190 //
1191 //
1192 // might have rows spanning several columns
1193 // d s
1194 // ---------
1195 // | | |
1196 // ----- |
1197 // | | |
1198 // ----- |
1199 // | | |
1200 // ---------
1201 // To solve this merge all cells vertically then merge this combined set horizontally
1202 //
1203 // First check that left column ends at right column boundary.
1204 // We reject attempts to merge cells that don't have this condition.
1205 // ie this:
1206 // d s
1207 // ---------
1208 // | | |
1209 // ----| |
1210 // | | |
1211 // ----| |
1212 // | | |
1213 // | | |
1214 // |---| |
1215 // | -----
1216 //
1217
1218 if(sBot < numRows -1)
1219 {
1220 posWork = findCellPosAt(posTable,sBot,dLeft) +1;
1221 getCellParams(posWork,&Left,&Right,&Top,&Bot);
1222 if(Top != sBot)
1223 {
1224 //
1225 // Right column of src cell doesn't match the row above it. Bail out.
1226 //
1227 // fixme: Put in a dialog to explain this to the user
1228 //
1229 return false;
1230 }
1231 }
1232 //
1233 // OK now merge all the cells above the src cell together.
1234 //
1235 Top = dBot;
1236 while(Top < sBot)
1237 {
1238 posWork = findCellPosAt(posTable,Top,dLeft) + 1;
1239 getCellParams(posWork,&Left,&Right,&Top,&Bot);
1240 //
1241 // Do the merge without all the undo/update trimings
1242 //
1243 if(!bChanged)
1244 {
1245 iLineType = _changeCellParams(posTable, tableSDH);
1246 }
1247 bChanged = true;
1248 _MergeCells(posDestination,posWork,false);
1249 Top = Bot;
1250 }
1251 //
1252 // Now merge the source into the merged destination
1253 //
1254 if(!bChanged)
1255 {
1256 iLineType = _changeCellParams(posTable, tableSDH);
1257 }
1258 bChanged = true;
1259 posSource = findCellPosAt(posTable,sTop,sLeft) +1;
1260 posDestination = findCellPosAt(posTable,dTop,dLeft) +1;
1261 _MergeCells(posDestination,posSource,true);
1262 }
1263 }
1264 else
1265 {
1266 //
1267 // Neight left or top align of the cells to be merged.
1268 // bali out
1269
1270 return false;
1271 }
1272 //
1273 // Now check if we've merged a whole row of height 2 or a whole col of width two//
1274 // Start with whole row.
1275 //
1276 posDestination = findCellPosAt(posTable,dTop,dLeft) +2;
1277 getCellParams(posDestination,&dLeft,&dRight,&dTop,&dBot);
1278 UT_sint32 origTop = dTop;
1279 if((dLeft==0) && (dRight== numCols))
1280 {
1281 //
1282 // Yep one whole row merged.
1283 //
1284 // Look for the number of rows spanned now
1285 //
1286 if(dBot > (dTop+1))
1287 {
1288 //
1289 // Yep we have problem, we'll fix it. Subtract this number from all the cells
1290 // top and Bottom attach
1291 //
1292 UT_sint32 diff = dBot - dTop -1;
1293 pf_Frag_Strux* sdhCell = NULL;
1294 pf_Frag_Strux* sdhNextCell = NULL;
1295 pf_Frag_Strux* sdhEndTable = NULL;
1296 PT_DocPosition posEndTable = 0;
1297 PT_DocPosition posCell = 0;
1298 bRes = m_pDoc->getStruxOfTypeFromPosition(posDestination,PTX_SectionCell,&sdhCell);
1299 UT_return_val_if_fail(bRes,false);
1300 sdhEndTable = m_pDoc->getEndTableStruxFromTableSDH(tableSDH);
1301 UT_return_val_if_fail(sdhEndTable,false);
1302 posEndTable = m_pDoc->getStruxPosition(sdhEndTable);
1303 bool bKeepGoing = true;
1304 while(bKeepGoing)
1305 {
1306 posCell = m_pDoc->getStruxPosition(sdhCell)+1;
1307 getCellParams(posCell,&dLeft,&dRight,&dTop,&dBot);
1308 dBot -= diff;
1309 UT_sint32 row = dTop;
1310 if(dTop != origTop)
1311 {
1312 dTop -= diff;
1313 }
1314 _changeCellTo(posTable,row,dLeft,dLeft,dRight,dTop,dBot);
1315
1316 bRes = m_pDoc->getNextStruxOfType(sdhCell,PTX_SectionCell,&sdhNextCell);
1317 PT_DocPosition posNextCell = 0;
1318 if(bRes)
1319 {
1320 posNextCell = m_pDoc->getStruxPosition(sdhNextCell);
1321 if(posNextCell > posEndTable)
1322 {
1323 posNextCell = 0;
1324 bKeepGoing = false;
1325 break;
1326 }
1327 }
1328 else
1329 {
1330 bKeepGoing = false;
1331 break;
1332 }
1333 sdhCell = sdhNextCell;
1334 }
1335
1336 }
1337 }
1338 //
1339 // Look for a whole merged column
1340 //
1341 if((dTop==0) && (dBot == numRows))
1342 {
1343 //
1344 // Yep one whole col merged.
1345 //
1346 // Look for the number of cols spanned now
1347 //
1348 if(dRight > (dLeft+1))
1349 {
1350 //
1351 // Yep we have problem, we'll fix it. Subtract this number from all the cells
1352 // Right attach from this cell and left and right for all cells to the right
1353 // of it
1354 // This is a bit tricky
1355 // because we don't want to subtract the difference twice so we'll make a
1356 // vector of unique cell sdh's and only do our thing one those that aren't in
1357 // it
1358 //
1359 UT_sint32 diff = dRight - dLeft -1;
1360 UT_sint32 origLeft = dLeft;
1361 UT_sint32 origRight = dRight;
1362 pf_Frag_Strux* sdhCell = NULL;
1363 PT_DocPosition posCell = 0;
1364 UT_GenericVector<pf_Frag_Strux*> vecCells;
1365 posCell = findCellPosAt(posTable, dTop, dLeft)+1;
1366 m_pDoc->getStruxOfTypeFromPosition(posCell,PTX_SectionCell,&sdhCell);
1367 vecCells.addItem(sdhCell);
1368 getCellParams(posCell,&dLeft,&dRight,&dTop,&dBot);
1369 dRight -= diff;
1370 _changeCellTo(posTable,dTop,dLeft,dLeft,dRight,dTop,dBot);
1371 UT_sint32 row,col=0;
1372 for (col = 0; col < numCols; col++)
1373 {
1374 for(row =0; row < numRows;row++)
1375 {
1376 posCell = findCellPosAt(posTable, row, col)+1;
1377 m_pDoc->getStruxOfTypeFromPosition(posCell,PTX_SectionCell,&sdhCell);
1378 if((sdhCell==NULL) || (vecCells.findItem(sdhCell) >= 0))
1379 {
1380 continue;
1381 }
1382 getCellParams(posCell,&dLeft,&dRight,&dTop,&dBot);
1383 bool bDoIt = false;
1384 if(dLeft > origLeft)
1385 {
1386 dLeft -= diff;
1387 bDoIt = true;
1388 }
1389 if(dRight >= origRight)
1390 {
1391 dRight -= diff;
1392 bDoIt = true;
1393 }
1394 if(bDoIt)
1395 {
1396 vecCells.addItem(sdhCell);
1397 _changeCellTo(posTable,row,col,dLeft,dRight,dTop,dBot);
1398 }
1399 }
1400 }
1401 }
1402 }
1403 //
1404 // Now trigger a rebuild of the whole table by sending a changeStrux to the table strux
1405 // with the restored line-type property it has before.
1406 //
1407 iLineType += 1;
1408 _restoreCellParams(posTable,iLineType);
1409 setPoint(posDestination);
1410 _fixInsertionPointCoords();
1411 _ensureInsertionPointOnScreen();
1412 notifyListeners(AV_CHG_MOTION);
1413 return true;
1414 }
1415
1416
1417 /*!
1418 * Move the caret to the next or previous cell in a table. If at either end
1419 * insert a new row.
1420 */
cmdAdvanceNextPrevCell(bool bGoNext)1421 bool FV_View::cmdAdvanceNextPrevCell(bool bGoNext)
1422 {
1423 if(!isInTable())
1424 {
1425 return false;
1426 }
1427
1428 pf_Frag_Strux* sdhCell = NULL;
1429 pf_Frag_Strux* sdhNextPrevCell = NULL;
1430 bool bRes = m_pDoc->getStruxOfTypeFromPosition(getPoint(),PTX_SectionCell,&sdhCell);
1431 UT_return_val_if_fail(bRes,false);
1432 fl_CellLayout * pCL = static_cast<fl_CellLayout *>(m_pDoc->getNthFmtHandle(sdhCell,m_pLayout->getLID()));
1433 UT_return_val_if_fail(pCL,false);
1434 if (bGoNext && pCL->getNext())
1435 {
1436 sdhNextPrevCell = pCL->getNext()->getStruxDocHandle();
1437 UT_return_val_if_fail(sdhNextPrevCell && (sdhNextPrevCell->getPos() > sdhCell->getPos()),false);
1438 }
1439 else if (!bGoNext && pCL->getPrev())
1440 {
1441 sdhNextPrevCell = pCL->getPrev()->getStruxDocHandle();
1442 UT_return_val_if_fail(sdhNextPrevCell && (sdhNextPrevCell->getPos() < sdhCell->getPos()),false);
1443 }
1444 else
1445 {
1446 return cmdInsertRow(getPoint(),!bGoNext);
1447 }
1448
1449 setPoint(sdhNextPrevCell->getPos()+2);
1450 _fixInsertionPointCoords();
1451 _ensureInsertionPointOnScreen();
1452 notifyListeners(AV_CHG_MOTION);
1453 return true;
1454 }
1455
1456 /*!
1457 * Convert a text fragment to a table to Text.
1458 * The column delimiters are tabs, commas and spaces as follows:
1459 * iDelim == 0 Use tabs
1460 * iDelim == 1 Use commas
1461 * iDelim == 2 Use spaces
1462 * iDelim == 3 Use tabs, commas and spaces as delemiters
1463 * Paragraph breaks are the row delimiters.
1464 */
1465
cmdTextToTable(UT_uint32 iDelim)1466 bool FV_View::cmdTextToTable(UT_uint32 iDelim)
1467 {
1468 STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
1469
1470 UT_return_val_if_fail(!isSelectionEmpty(), false);
1471 UT_return_val_if_fail(!isInHdrFtr(getPoint()), false);
1472 UT_return_val_if_fail(getSelectionMode() == FV_SelectionMode_Single, false);
1473 UT_GenericVector<fl_BlockLayout *> vecBlocks;
1474 getBlocksInSelection(&vecBlocks, false);
1475 UT_return_val_if_fail(vecBlocks.getItemCount() > 0, false);
1476 fl_BlockLayout * pBL = NULL;
1477 UT_uint32 numCols = 0;
1478 PT_DocPosition posStart = 0;
1479 PT_DocPosition begPos = 0;
1480 PT_DocPosition endPos = 0;
1481 UT_UTF8String sWords;
1482 UT_GrowBuf * pBuf = NULL;
1483 for (UT_sint32 k = 0; k < vecBlocks.getItemCount(); k++)
1484 {
1485 pBL = vecBlocks.getNthItem(k);
1486 pBuf = new UT_GrowBuf(1024);
1487 pBL->getBlockBuf(pBuf);
1488 posStart = pBL->getPosition(false);
1489 UT_uint32 count = 0;
1490 bool bGetNext = true;
1491 while(bGetNext)
1492 {
1493 bGetNext = pBL->getNextTableElement(pBuf,posStart,begPos,endPos, sWords, iDelim);
1494 if(begPos != 0)
1495 {
1496 count++;
1497 posStart = endPos+1;
1498 }
1499 }
1500 delete pBuf;
1501 numCols = UT_MAX(numCols, count);
1502 }
1503 UT_uint32 numRows = vecBlocks.getItemCount();
1504 UT_return_val_if_fail(numCols > 0, false);
1505 UT_return_val_if_fail(numRows > 0, false);
1506
1507 pBL = vecBlocks.getNthItem(numRows-1);
1508 PT_DocPosition posTableStart = pBL->getPosition(true) + pBL->getLength();
1509
1510 // Signal PieceTable Change
1511 _saveAndNotifyPieceTableChange();
1512
1513 // Turn off list updates
1514
1515 m_pDoc->disableListUpdates();
1516 m_pDoc->beginUserAtomicGlob();
1517 _clearSelection();
1518 setPoint(posTableStart);
1519 UT_Error e = UT_OK;
1520 //
1521 // OK let's create that table now!
1522 //
1523 //
1524 // insert a block to terminate the text before this.
1525 //
1526 PT_DocPosition pointBreak = getPoint();
1527 e = m_pDoc->insertStrux(getPoint(),PTX_Block);
1528 //
1529 // Insert the table strux at the same spot. This will make the table link correctly in the
1530 // middle of the broken text.
1531 //
1532 e |= static_cast<UT_sint32>(m_pDoc->insertStrux(getPoint(),PTX_SectionTable,NULL,NULL));
1533 //
1534 // stuff for cell insertion.
1535 //
1536 UT_uint32 i,j;
1537 const gchar * attrs[3] = {"style","Normal",NULL};
1538 const gchar * props[9] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
1539 UT_String sRowTop = "top-attach";
1540 UT_String sRowBot = "bot-attach";
1541 UT_String sColLeft = "left-attach";
1542 UT_String sColRight = "right-attach";
1543 UT_String sTop,sBot,sLeft,sRight;
1544 for(i=0;i<numRows;i++)
1545 {
1546 UT_String_sprintf(sTop,"%d",i);
1547 UT_String_sprintf(sBot,"%d",i+1);
1548 props[0] = sRowTop.c_str();
1549 props[1] = sTop.c_str();
1550 props[2] = sRowBot.c_str();
1551 props[3] = sBot.c_str();
1552 for(j=0;j<numCols;j++)
1553 {
1554 UT_String_sprintf(sLeft,"%d",j);
1555 UT_String_sprintf(sRight,"%d",j+1);
1556 props[4] = sColLeft.c_str();
1557 props[5] = sLeft.c_str();
1558 props[6] = sColRight.c_str();
1559 props[7] = sRight.c_str();
1560 e |= static_cast<UT_sint32>(m_pDoc->insertStrux(getPoint(),PTX_SectionCell,NULL,props));
1561 pointBreak = getPoint();
1562 e |= static_cast<UT_sint32>(m_pDoc->insertStrux(getPoint(),PTX_Block,attrs,NULL));
1563 UT_DEBUGMSG(("SEVIOR: 4 cur point %d \n",getPoint()));
1564 if(getPoint() == pointBreak)
1565 {
1566 setPoint(pointBreak+1);
1567 }
1568 e |= static_cast<UT_sint32>(m_pDoc->insertStrux(getPoint(),PTX_EndCell));
1569 }
1570 }
1571 e |= static_cast<UT_sint32>(m_pDoc->insertStrux(getPoint(),PTX_EndTable));
1572 //
1573 // Done! Now fill it.
1574 //
1575 posTableStart +=3;
1576 pf_Frag_Strux* sdhTable = NULL;
1577 pf_Frag_Strux* sdhCell = NULL;
1578 bool b =m_pDoc->getStruxOfTypeFromPosition(posTableStart,PTX_SectionTable,&sdhTable);
1579 UT_return_val_if_fail(b,false);
1580 PT_DocPosition posCell = posTableStart;
1581 for(i =0; i< numRows;i++)
1582 {
1583 pBL = vecBlocks.getNthItem(i);
1584 pBuf = new UT_GrowBuf(1024);
1585 pBL->getBlockBuf(pBuf);
1586 posStart = pBL->getPosition(false);
1587 bool bEnd = false;
1588 for( j = 0; !bEnd && j < numCols; j++)
1589 {
1590 sdhCell = m_pDoc->getCellSDHFromRowCol(sdhTable,isShowRevisions(),PD_MAX_REVISION,i,j);
1591 posCell = m_pDoc->getStruxPosition(sdhCell)+1; // Points at block
1592 sWords.clear();
1593 bEnd = !pBL->getNextTableElement(pBuf,posStart, begPos, endPos, sWords, iDelim);
1594 if(begPos == endPos)
1595 {
1596 posStart = endPos+1;
1597 continue;
1598 }
1599 if(((j < numCols-1) && (begPos > 0)) || ((j == numCols-1) && (endPos - pBL->getPosition(false)) >= pBuf->getLength()))
1600 {
1601 copyToLocal(begPos, endPos);
1602 _pasteFromLocalTo(posCell+1);
1603 posStart = endPos+1;
1604 }
1605 else if((j==numCols-1) && (begPos > 0))
1606 {
1607 copyToLocal(begPos, endPos);
1608 _pasteFromLocalTo(posCell+1);
1609 posStart = endPos+1;
1610 break;
1611 }
1612 }
1613 delete pBuf;
1614 }
1615 pBL = vecBlocks.getNthItem(0);
1616 begPos = pBL->getPosition();
1617 pBL = vecBlocks.getNthItem(numRows-1);
1618 endPos = pBL->getPosition(true) + pBL->getLength();
1619 UT_uint32 iRealDeleteCount;
1620
1621 m_pDoc->deleteSpan(begPos,endPos,NULL,iRealDeleteCount);
1622
1623
1624 // Signal PieceTable Changes have finished
1625 while(m_iPieceTableState > 0)
1626 _restorePieceTableState();
1627
1628 _restorePieceTableState();
1629 m_pDoc->clearDoingPaste();
1630 m_pDoc->setDontImmediatelyLayout(false);
1631
1632 // restore updates and clean up dirty lists
1633 m_pDoc->enableListUpdates();
1634 m_pDoc->updateDirtyLists();
1635
1636 _generalUpdate();
1637
1638 m_pDoc->endUserAtomicGlob();
1639
1640
1641 setPoint(posTableStart);
1642 PT_DocPosition posEOD;
1643 UT_DebugOnly<bool> bRes = getEditableBounds(true, posEOD);
1644 UT_ASSERT(bRes);
1645 while(!isPointLegal() && getPoint() < posEOD)
1646 {
1647 setPoint(getPoint()+1);
1648 }
1649 while(!isPointLegal() && (getPoint() > 2))
1650 {
1651 setPoint(getPoint()-1);
1652 }
1653 _fixInsertionPointCoords();
1654 _ensureInsertionPointOnScreen();
1655 //
1656 // We're done!
1657 //
1658 return true;
1659 }
1660 /*!
1661 * Make a table columns autosizing by removing all the column properties.
1662 */
cmdAutoSizeCols(void)1663 bool FV_View::cmdAutoSizeCols(void)
1664 {
1665 STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
1666
1667 //
1668 // Got all we need, now set things up to do the delete nicely
1669 //
1670 // Signal PieceTable Change
1671 _saveAndNotifyPieceTableChange();
1672
1673 // Turn off list updates
1674
1675 m_pDoc->disableListUpdates();
1676 m_pDoc->beginUserAtomicGlob();
1677 const char * pszTable[3] = {NULL,NULL,NULL};
1678 pszTable[0] = "table-column-props";
1679 pszTable[1] = "1";
1680 m_pDoc->changeStruxFmt(PTC_RemoveFmt,getPoint(),getPoint(),NULL,pszTable,PTX_SectionTable);
1681 pszTable[0] = "table-column-leftpos";
1682 m_pDoc->changeStruxFmt(PTC_RemoveFmt,getPoint(),getPoint(),NULL,pszTable,PTX_SectionTable);
1683 m_pDoc->setDontImmediatelyLayout(false);
1684
1685 // Signal PieceTable Changes have finished
1686 _restorePieceTableState();
1687 _generalUpdate();
1688 m_pDoc->endUserAtomicGlob();
1689
1690
1691 // restore updates and clean up dirty lists
1692 m_pDoc->enableListUpdates();
1693 m_pDoc->updateDirtyLists();
1694 _fixInsertionPointCoords();
1695 _ensureInsertionPointOnScreen();
1696 notifyListeners(AV_CHG_MOTION);
1697 return true;
1698 }
1699
1700
1701 /*!
1702 * Make a table Rows autosizing by removing all the row properties.
1703 */
cmdAutoSizeRows(void)1704 bool FV_View::cmdAutoSizeRows(void)
1705 {
1706 STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
1707
1708 //
1709 // Got all we need, now set things up to do the delete nicely
1710 //
1711 // Signal PieceTable Change
1712 _saveAndNotifyPieceTableChange();
1713
1714 // Turn off list updates
1715
1716 m_pDoc->disableListUpdates();
1717 m_pDoc->beginUserAtomicGlob();
1718 const char * pszTable[3] = {NULL,NULL,NULL};
1719 pszTable[0] = "table-row-heights";
1720 pszTable[1] = "1";
1721 pszTable[2] = NULL;
1722 m_pDoc->changeStruxFmt(PTC_RemoveFmt,getPoint(),getPoint(),NULL,pszTable,PTX_SectionTable);
1723 pszTable[0] = "table-column-leftpos";
1724 m_pDoc->changeStruxFmt(PTC_RemoveFmt,getPoint(),getPoint(),NULL,pszTable,PTX_SectionTable);
1725 m_pDoc->setDontImmediatelyLayout(false);
1726
1727 // Signal PieceTable Changes have finished
1728 _restorePieceTableState();
1729 _generalUpdate();
1730 m_pDoc->endUserAtomicGlob();
1731
1732
1733 // restore updates and clean up dirty lists
1734 m_pDoc->enableListUpdates();
1735 m_pDoc->updateDirtyLists();
1736 _fixInsertionPointCoords();
1737 _ensureInsertionPointOnScreen();
1738 notifyListeners(AV_CHG_MOTION);
1739 return true;
1740 }
1741
1742
1743 /*!
1744 * Make a table Rows autosizing by removing all the row and col properties.
1745 */
cmdAutoFitTable(void)1746 bool FV_View::cmdAutoFitTable(void)
1747 {
1748 STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
1749
1750 //
1751 // Got all we need, now set things up to do the delete nicely
1752 //
1753 // Signal PieceTable Change
1754 _saveAndNotifyPieceTableChange();
1755
1756 // Turn off list updates
1757
1758 m_pDoc->disableListUpdates();
1759 m_pDoc->beginUserAtomicGlob();
1760 const char * pszTable[7] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL};
1761 pszTable[0] = "table-row-heights";
1762 pszTable[1] = "1";
1763 pszTable[2] = "table-column-leftpos";
1764 pszTable[3] = "1";
1765 pszTable[4] = "table-column-props";
1766 pszTable[5] = "1";
1767
1768 m_pDoc->changeStruxFmt(PTC_RemoveFmt,getPoint(),getPoint(),NULL,pszTable,PTX_SectionTable);
1769 pszTable[0] = "homogeneous";
1770 pszTable[1] = "1";
1771 pszTable[2] = NULL;
1772 pszTable[3] = NULL;
1773
1774 m_pDoc->changeStruxFmt(PTC_AddFmt,getPoint(),getPoint(),NULL,pszTable,PTX_SectionTable);
1775 m_pDoc->setDontImmediatelyLayout(false);
1776
1777 // Signal PieceTable Changes have finished
1778 _restorePieceTableState();
1779 _generalUpdate();
1780 m_pDoc->endUserAtomicGlob();
1781
1782
1783 // restore updates and clean up dirty lists
1784 m_pDoc->enableListUpdates();
1785 m_pDoc->updateDirtyLists();
1786 _fixInsertionPointCoords();
1787 _ensureInsertionPointOnScreen();
1788 notifyListeners(AV_CHG_MOTION);
1789 return true;
1790 }
1791
1792
1793 /*!
1794 * Insert a column containing the position posCol, insert the column before the
1795 * current column.
1796 */
cmdInsertCol(PT_DocPosition posCol,bool bBefore)1797 bool FV_View::cmdInsertCol(PT_DocPosition posCol, bool bBefore)
1798 {
1799 STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
1800
1801 UT_sint32 numColsForInsertion = getNumColumnsInSelection();
1802 if(numColsForInsertion == 0)
1803 {
1804 return false;
1805 }
1806
1807 pf_Frag_Strux* cellSDH,*tableSDH;
1808 bool bRes = m_pDoc->getStruxOfTypeFromPosition(posCol,PTX_SectionCell,&cellSDH);
1809 UT_return_val_if_fail(bRes, false);
1810 bRes = m_pDoc->getStruxOfTypeFromPosition(posCol,PTX_SectionTable,&tableSDH);
1811 UT_return_val_if_fail(bRes, false);
1812 PT_DocPosition posTable = m_pDoc->getStruxPosition(tableSDH) + 1;
1813 PT_DocPosition posCell = posCol;
1814 UT_sint32 iLeft,iRight,iTop,iBot;
1815 getCellParams(posCell, &iLeft, &iRight,&iTop,&iBot);
1816
1817 //
1818 // Now find the number of rows and columns in this table. This is easiest to
1819 // get from the table container
1820 //
1821 fl_TableLayout * pTL = static_cast<fl_TableLayout*>(m_pDoc->getNthFmtHandle(tableSDH,m_pLayout->getLID()));
1822 UT_return_val_if_fail(pTL,false);
1823 fp_TableContainer *pTab = static_cast <fp_TableContainer*>(pTL->getFirstContainer());
1824 UT_return_val_if_fail(pTab,false);
1825 bool bInsertEnd = (!bBefore && iRight == pTab->getNumCols());
1826
1827 // Get the attributes and properties of the block containing posCol. These attributes and properties
1828 // will be copied in the new cells.
1829 fl_BlockLayout * pBL = getBlockAtPosition(posCol);
1830 const PP_AttrProp * pAP = NULL;
1831 m_pDoc->getAttrProp(m_pDoc->getAPIFromSDH(pBL->getStruxDocHandle()), &pAP);
1832 UT_return_val_if_fail(pAP, false);
1833
1834 // Signal PieceTable Change
1835 _saveAndNotifyPieceTableChange();
1836
1837 // Turn off list updates
1838
1839 m_pDoc->disableListUpdates();
1840 m_pDoc->beginUserAtomicGlob();
1841 if (!isSelectionEmpty())
1842 {
1843 _clearSelection();
1844 }
1845 m_pDoc->setDontImmediatelyLayout(true);
1846 //
1847 // Now trigger a rebuild of the whole table by sending a changeStrux to the table strux
1848 // with a bogus line-type property. We'll restore it later.
1849 //
1850 const char * pszTable[3] = {NULL,NULL,NULL};
1851 pszTable[0] = "list-tag";
1852 const char * szListTag = NULL;
1853 UT_String sListTag;
1854 UT_sint32 iListTag;
1855 m_pDoc->getPropertyFromSDH(tableSDH,isShowRevisions(),getRevisionLevel(),pszTable[0],&szListTag);
1856 if(szListTag == NULL || *szListTag == '\0')
1857 {
1858 iListTag = 0;
1859 }
1860 else
1861 {
1862 iListTag = atoi(szListTag);
1863 iListTag -= 1;
1864 }
1865 UT_String_sprintf(sListTag,"%d",iListTag);
1866 pszTable[1] = sListTag.c_str();
1867 UT_DEBUGMSG((" Doing Table strux change of %s %s \n",pszTable[0],pszTable[1]));
1868 m_pDoc->changeStruxFmt(PTC_AddFmt,posTable,posTable,NULL,pszTable,PTX_SectionTable);
1869 //
1870 // Loop trough the whole table creating new cells where necessary to add a column.
1871 // Also shift the left and right attach of the existing cells to make place for
1872 // the new cells.
1873 //
1874 fl_CellLayout* pCL = static_cast<fl_CellLayout*>(pTL->getFirstLayout());
1875 UT_sint32 iLeftInsert = (bBefore ? iLeft:iRight);
1876 PT_DocPosition posFirstInsert = 0;
1877 UT_sint32 iCurLeft, iCurRight, iCurTop, iCurBot;
1878 UT_sint32 iRow = 0;
1879 while (pCL)
1880 {
1881 if (!bInsertEnd && (pCL->getLeftAttach() < iLeftInsert) && (pCL->getRightAttach() > iLeftInsert))
1882 {
1883 // There is a merged cell. Do not add cells
1884 iRow += pCL->getBottomAttach() - pCL->getTopAttach();
1885 }
1886 else if ((!bInsertEnd && (pCL->getTopAttach() == iRow) && (pCL->getLeftAttach() >= iLeftInsert)) ||
1887 (bInsertEnd && (pCL->getTopAttach() == iRow + 1)))
1888 {
1889 // add cells before pCL
1890 posCell = pCL->getPosition(true);
1891 if (posFirstInsert == 0)
1892 {
1893 posFirstInsert = posCell + 2;
1894 }
1895 iCurLeft = iLeftInsert;
1896 for (UT_sint32 k = 0; k < numColsForInsertion; k++)
1897 {
1898 bRes |= _insertCellAt(posCell, iCurLeft, iCurLeft + 1, iRow, iRow + 1,
1899 pAP->getAttributes(), pAP->getProperties());
1900 UT_ASSERT(bRes);
1901 posCell += 3;
1902 iCurLeft++;
1903 }
1904 iRow++; // this variable is incremented when the cells on a given row have been added.
1905 }
1906
1907 if (pCL->getRightAttach() > iLeftInsert)
1908 {
1909 // shift left and right attach
1910 iCurLeft = pCL->getLeftAttach();
1911 iCurRight = pCL->getRightAttach();
1912 iCurTop = pCL->getTopAttach();
1913 iCurBot = pCL->getBottomAttach();
1914 if (pCL->getLeftAttach() >= iLeftInsert)
1915 {
1916 iCurLeft += numColsForInsertion;
1917 }
1918 iCurRight += numColsForInsertion;
1919 posCell = m_pDoc->getStruxPosition(pCL->getStruxDocHandle());
1920 bRes |= _changeCellAttach(posCell+1, iCurLeft, iCurRight, iCurTop, iCurBot);
1921 UT_ASSERT(bRes);
1922 }
1923 pCL = static_cast<fl_CellLayout*>(pCL->getNext());
1924 }
1925
1926 if (bInsertEnd)
1927 {
1928 // Add cells at the end of the table
1929 posCell = m_pDoc->getStruxPosition(pTL->getEndStruxDocHandle());
1930 if (posFirstInsert == 0)
1931 {
1932 posFirstInsert = posCell + 2;
1933 }
1934 iCurLeft = iLeftInsert;
1935 for (UT_sint32 k = 0; k < numColsForInsertion; k++)
1936 {
1937 bRes |= _insertCellAt(posCell, iCurLeft, iCurLeft + 1, iRow, iRow + 1,
1938 pAP->getAttributes(), pAP->getProperties());
1939 UT_ASSERT(bRes);
1940 posCell += 3;
1941 iCurLeft++;
1942 }
1943 iRow++; // this variable is incremented when the cells on a given row have been added.
1944 }
1945
1946 //
1947 // Now trigger a rebuild of the whole table by sending a changeStrux to the table strux
1948 // with the restored line-type property it has before.
1949 //
1950 iListTag += 1;
1951 UT_String_sprintf(sListTag,"%d",iListTag);
1952 pszTable[1] = sListTag.c_str();
1953 UT_DEBUGMSG(("SEVIOR: Doing Table strux change of %s %s \n",pszTable[0],pszTable[1]));
1954 m_pDoc->changeStruxFmt(PTC_AddFmt,posTable,posTable,NULL,pszTable,PTX_SectionTable);
1955 //
1956 // OK finish everything off with the various parameters which allow the formatter to
1957 // be updated.
1958 //
1959 m_pDoc->setDontImmediatelyLayout(false);
1960
1961 // Signal PieceTable Changes have finished
1962 _restorePieceTableState();
1963 _generalUpdate();
1964 m_pDoc->endUserAtomicGlob();
1965
1966 // restore updates and clean up dirty lists
1967 m_pDoc->enableListUpdates();
1968 m_pDoc->updateDirtyLists();
1969 // Put the insertion point in a legal position
1970 //
1971 setPoint(posFirstInsert);
1972 _fixInsertionPointCoords();
1973 _ensureInsertionPointOnScreen();
1974 notifyListeners(AV_CHG_MOTION);
1975 return bRes;
1976 }
1977
1978 /*!
1979 * posRow is the position of the start of the selection in the table.
1980 * insert rows into the table.
1981 */
cmdInsertRow(PT_DocPosition posRow,bool bBefore)1982 bool FV_View::cmdInsertRow(PT_DocPosition posRow, bool bBefore)
1983 {
1984 STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
1985
1986 UT_sint32 numRowsForInsertion = getNumRowsInSelection();
1987 if(numRowsForInsertion == 0)
1988 {
1989 if(isSelectionEmpty() && isInTable(posRow))
1990 {
1991 numRowsForInsertion = 1;
1992 }
1993 else
1994 {
1995 return false;
1996 }
1997 }
1998
1999 pf_Frag_Strux* cellSDH,*tableSDH;
2000 bool bRes = m_pDoc->getStruxOfTypeFromPosition(posRow,PTX_SectionCell,&cellSDH);
2001 UT_return_val_if_fail(bRes, false);
2002 bRes = m_pDoc->getStruxOfTypeFromPosition(posRow,PTX_SectionTable,&tableSDH);
2003 UT_return_val_if_fail(bRes, false);
2004 PT_DocPosition posTable = m_pDoc->getStruxPosition(tableSDH) + 1;
2005 PT_DocPosition posCell = posRow;
2006 UT_sint32 iLeft,iRight,iTop,iBot;
2007 getCellParams(posCell, &iLeft, &iRight,&iTop,&iBot);
2008
2009 //
2010 // Now find the number of rows and columns in this table. This is easiest to
2011 // get from the table container
2012 //
2013 fl_TableLayout * pTL = static_cast<fl_TableLayout*>(m_pDoc->getNthFmtHandle(tableSDH,m_pLayout->getLID()));
2014 UT_return_val_if_fail(pTL,false);
2015 fp_TableContainer *pTab = static_cast <fp_TableContainer*>(pTL->getFirstContainer());
2016 UT_return_val_if_fail(pTab,false);
2017 UT_sint32 numCols = pTab->getNumCols();
2018 UT_sint32 numRows = pTab->getNumRows();
2019
2020 // Get the attributes and properties of the block containing posRow. These attributes and properties
2021 // will be copied in the new cell.
2022 fl_BlockLayout * pBL = getBlockAtPosition(posRow);
2023 const PP_AttrProp * pAP = NULL;
2024 m_pDoc->getAttrProp(m_pDoc->getAPIFromSDH(pBL->getStruxDocHandle()), &pAP);
2025 UT_return_val_if_fail(pAP, false);
2026
2027 //
2028 // Find the position in the piece table to insert the row.
2029 // Have to handle table with merged cells. Find out if a merged cell
2030 // interferes with the insert cmd and set bComplexInsert to true in that case.
2031 // Then create a vector of columns where a new cell should be inserted
2032
2033 fl_CellLayout* pCL = NULL;
2034 fp_CellContainer* pCell = NULL;
2035 bool bComplexInsert = false;
2036 UT_sint32 iTopInsert = (bBefore ? iTop:iBot);
2037 UT_sint32 prevTop = iTopInsert;
2038 std::vector<UT_sint32> vColInsert;
2039 if (bBefore || (iBot < numRows))
2040 {
2041 pCell = pTab->getCellAtRowColumn(iTopInsert,0);
2042 UT_return_val_if_fail(pCell,false);
2043 UT_sint32 iPrevRight = 0;
2044 while (pCell && pCell->getTopAttach() < iTopInsert)
2045 {
2046 pCell = static_cast<fp_CellContainer*>(pCell->getNext());
2047 }
2048 UT_return_val_if_fail(pCell,false);
2049 pCL = static_cast<fl_CellLayout *>(pCell->getSectionLayout());
2050 UT_return_val_if_fail(pCL,false);
2051 posCell = pCL->getPosition(true);
2052 while (pCell && pCell->getTopAttach() == iTopInsert)
2053 {
2054 if (pCell->getLeftAttach() != iPrevRight)
2055 {
2056 bComplexInsert = true;
2057 }
2058 iPrevRight = pCell->getRightAttach();
2059 for (UT_sint32 k = pCell->getLeftAttach(); k < pCell->getRightAttach(); k++)
2060 {
2061 vColInsert.push_back(k);
2062 }
2063 pCell = static_cast<fp_CellContainer*>(pCell->getNext());
2064 }
2065 if (iPrevRight != numCols)
2066 {
2067 bComplexInsert = true;
2068 }
2069 }
2070 else
2071 {
2072 // insert cells at the end of the table
2073 pf_Frag_Strux* endTableSDH = pTL->getEndStruxDocHandle();
2074 UT_return_val_if_fail(endTableSDH,false);
2075 posCell = m_pDoc->getStruxPosition(endTableSDH);
2076 for (UT_sint32 k = 0; k < numCols; k++)
2077 {
2078 vColInsert.push_back(k);
2079 }
2080 }
2081
2082 //
2083 // Got all we need, now set things up to do the delete nicely
2084 //
2085
2086 // Signal PieceTable Change
2087 _saveAndNotifyPieceTableChange();
2088
2089 // Turn off list updates
2090 m_pDoc->disableListUpdates();
2091 m_pDoc->beginUserAtomicGlob();
2092 if (!isSelectionEmpty())
2093 {
2094 _clearSelection();
2095 }
2096 m_pDoc->setDontImmediatelyLayout(true);
2097
2098 //
2099 // Now trigger a rebuild of the whole table by sending a changeStrux to the table strux
2100 // with a bogus line-type property. We'll restore it later.
2101 //
2102 const char * pszTable[3] = {NULL,NULL,NULL};
2103 pszTable[0] = "list-tag";
2104 const char * szListTag = NULL;
2105 UT_String sListTag;
2106 UT_sint32 iListTag;
2107 m_pDoc->getPropertyFromSDH(tableSDH,isShowRevisions(),getRevisionLevel(),pszTable[0],&szListTag);
2108 if(szListTag == NULL || *szListTag == '\0')
2109 {
2110 iListTag = 0;
2111 }
2112 else
2113 {
2114 iListTag = atoi(szListTag);
2115 iListTag -= 1;
2116 }
2117 UT_String_sprintf(sListTag,"%d",iListTag);
2118 pszTable[1] = sListTag.c_str();
2119 UT_DEBUGMSG(("Sevior: Doing Table strux change of %s %s \n",pszTable[0],pszTable[1]));
2120 m_pDoc->changeStruxFmt(PTC_AddFmt,posTable,posTable,NULL,pszTable,PTX_SectionTable);
2121
2122 //
2123 // Now insert rows.
2124 //
2125
2126 PT_DocPosition posInsert = posCell + 2;
2127
2128 UT_sint32 j = 0;
2129 for(j=0; j< numRowsForInsertion; j++)
2130 {
2131 std::vector<UT_sint32>::iterator it = vColInsert.begin();
2132 for(; it != vColInsert.end(); ++it)
2133 {
2134 bRes |= _insertCellAt(posCell, (*it), (*it)+1, prevTop, prevTop+1,
2135 pAP->getAttributes(), pAP->getProperties());
2136 UT_ASSERT(bRes);
2137 posCell += 3;
2138 }
2139 prevTop++;
2140 }
2141 //
2142 // OK! starting immediately after this insert loop through the table adding 1 to top and bottom
2143 //
2144 UT_sint32 iCurLeft,iCurRight,iCurTop,iCurBot;
2145 bRes = m_pDoc->getStruxOfTypeFromPosition(posCell-2,PTX_SectionCell,&cellSDH);
2146 pCL = static_cast<fl_CellLayout*>(m_pDoc->getNthFmtHandle(cellSDH,m_pLayout->getLID()));
2147 pCL = static_cast<fl_CellLayout*>(pCL->getNext());
2148 while(pCL)
2149 {
2150 iCurLeft = pCL->getLeftAttach();
2151 iCurRight = pCL->getRightAttach();
2152 iCurTop = pCL->getTopAttach() + numRowsForInsertion;
2153 iCurBot = pCL->getBottomAttach() + numRowsForInsertion;
2154 posCell = m_pDoc->getStruxPosition(pCL->getStruxDocHandle());
2155 bRes |= _changeCellAttach(posCell+1,iCurLeft,iCurRight,iCurTop,iCurBot);
2156 UT_ASSERT(bRes);
2157 pCL = static_cast<fl_CellLayout*>(pCL->getNext());
2158 }
2159
2160 if (bComplexInsert)
2161 {
2162 // We also need to modify bot-Attach of the merged cells that interfere with the inserted rows
2163 pTab = static_cast <fp_TableContainer*>(pTL->getFirstContainer());
2164 std::vector<UT_sint32>::iterator it = vColInsert.begin();
2165 for (UT_sint32 k = 0; k < numCols;)
2166 {
2167 if (k == (*it))
2168 {
2169 ++k;
2170 if (it != vColInsert.end())
2171 {
2172 ++it;
2173 }
2174 continue;
2175 }
2176 pCell = pTab->getCellAtRowColumn(iTopInsert,k);
2177 pCL = static_cast<fl_CellLayout*>(pCell->getSectionLayout());
2178 UT_ASSERT(pCL);
2179 posCell = pCL->getPosition(true);
2180 iCurLeft = pCL->getLeftAttach();
2181 iCurRight = pCL->getRightAttach();
2182 iCurTop = pCL->getTopAttach();
2183 iCurBot = pCL->getBottomAttach() + numRowsForInsertion;
2184 bRes |= _changeCellAttach(posCell+1,iCurLeft,iCurRight,iCurTop,iCurBot);
2185 UT_ASSERT(bRes);
2186 k = iCurRight;
2187 }
2188 }
2189
2190 //
2191 // Now trigger a rebuild of the whole table by sending a changeStrux to the table strux
2192 // with the restored line-type property it has before.
2193 //
2194 iListTag += 1;
2195 UT_String_sprintf(sListTag,"%d",iListTag);
2196 pszTable[1] = sListTag.c_str();
2197 UT_DEBUGMSG(("SEVIOR: Doing Table strux change of %s %s \n",pszTable[0],pszTable[1]));
2198 m_pDoc->changeStruxFmt(PTC_AddFmt,posTable,posTable,NULL,pszTable,PTX_SectionTable);
2199
2200 //
2201 // OK finish everything off with the various parameters which allow the formatter to
2202 // be updated.
2203 //
2204 setPoint(posInsert);
2205 m_pDoc->setDontImmediatelyLayout(false);
2206
2207 // Signal PieceTable Changes have finished
2208 _restorePieceTableState();
2209 _generalUpdate();
2210 m_pDoc->endUserAtomicGlob();
2211
2212 // restore updates and clean up dirty lists
2213 m_pDoc->enableListUpdates();
2214 m_pDoc->updateDirtyLists();
2215 _fixInsertionPointCoords();
2216 _ensureInsertionPointOnScreen();
2217 notifyListeners(AV_CHG_MOTION);
2218 return bRes;
2219 }
2220
2221 /*!
2222 * Delete the column containing the position posCol
2223 */
cmdDeleteCol(PT_DocPosition posCol)2224 bool FV_View::cmdDeleteCol(PT_DocPosition posCol)
2225 {
2226 STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
2227
2228 pf_Frag_Strux* cellSDH,*tableSDH,*endTableSDH,*endCellSDH;
2229 PT_DocPosition posTable,posCell2;
2230 UT_sint32 iLeft,iRight,iTop,iBot;
2231 getCellParams(posCol, &iLeft, &iRight,&iTop,&iBot);
2232
2233 bool bRes = m_pDoc->getStruxOfTypeFromPosition(posCol,PTX_SectionCell,&cellSDH);
2234 bRes = m_pDoc->getStruxOfTypeFromPosition(posCol,PTX_SectionTable,&tableSDH);
2235 UT_return_val_if_fail(bRes, false);
2236
2237 posTable = m_pDoc->getStruxPosition(tableSDH) + 1;
2238 //
2239 // Now find the number of rows and columns inthis table. This is easiest to
2240 // get from the table container
2241 //
2242 fl_BlockLayout * pBL = m_pLayout->findBlockAtPosition(posCol);
2243 fp_Run * pRun;
2244 UT_sint32 xPoint,yPoint,xPoint2,yPoint2,iPointHeight;
2245 bool bDirection;
2246 pRun = pBL->findPointCoords(posCol, false, xPoint,
2247 yPoint, xPoint2, yPoint2,
2248 iPointHeight, bDirection);
2249
2250 UT_return_val_if_fail(pRun, false);
2251
2252 fp_Line * pLine = pRun->getLine();
2253 UT_return_val_if_fail(pLine, false);
2254
2255 fp_Container * pCon = pLine->getContainer();
2256 UT_return_val_if_fail(pCon, false);
2257
2258 fp_TableContainer * pTab = static_cast<fp_TableContainer *>(pCon->getContainer());
2259 UT_return_val_if_fail(pTab, false);
2260
2261 UT_sint32 numRows = pTab->getNumRows();
2262 //
2263 // If we delete the last column we're actually deleteing the table. So let's
2264 // do it.
2265 //
2266 if(pTab->getNumCols() ==1)
2267 {
2268 cmdDeleteTable(posCol);
2269 return true;
2270 }
2271 //
2272 // Got all we need, now set things up to do the delete nicely
2273 //
2274 // Signal PieceTable Change
2275 _saveAndNotifyPieceTableChange();
2276
2277 // Turn off list updates
2278
2279 m_pDoc->disableListUpdates();
2280 m_pDoc->beginUserAtomicGlob();
2281 if (!isSelectionEmpty() && !m_FrameEdit.isActive())
2282 {
2283 m_pDoc->beginUserAtomicGlob();
2284 PP_AttrProp AttrProp_Before;
2285 _deleteSelection(&AttrProp_Before);
2286 m_pDoc->endUserAtomicGlob();
2287 }
2288 else if(m_FrameEdit.isActive())
2289 {
2290 m_FrameEdit.setPointInside();
2291 }
2292 m_pDoc->setDontImmediatelyLayout(true);
2293 //
2294 // Now trigger a rebuild of the whole table by sending a changeStrux to the table strux
2295 // with a bogus line-type property. We'll restore it later.
2296 //
2297 const char * pszTable[3] = {NULL,NULL,NULL};
2298 pszTable[0] = "list-tag";
2299 const char * szListTag = NULL;
2300 UT_String sListTag;
2301 UT_sint32 iListTag;
2302 m_pDoc->getPropertyFromSDH(tableSDH,isShowRevisions(),getRevisionLevel(),pszTable[0],&szListTag);
2303 if(szListTag == NULL || *szListTag == '\0')
2304 {
2305 iListTag = 0;
2306 }
2307 else
2308 {
2309 iListTag = atoi(szListTag);
2310 iListTag -= 1;
2311 }
2312 UT_String_sprintf(sListTag,"%d",iListTag);
2313 pszTable[1] = sListTag.c_str();
2314 UT_DEBUGMSG(("SEVIOR: Doing Table strux change of %s %s \n",pszTable[0],pszTable[1]));
2315 m_pDoc->changeStruxFmt(PTC_AddFmt,posTable,posTable,NULL,pszTable,PTX_SectionTable);
2316 //
2317 // OK loop through all the rows in this column and delete the entries in the specified
2318 // column if the cell spans just the width of the column..
2319 //
2320 UT_sint32 i =0;
2321 for(i=0; i <numRows; i++)
2322 {
2323 PT_DocPosition posCell = findCellPosAt(posTable,i,iLeft);
2324 UT_sint32 Left,Right,Top,Bot;
2325 getCellParams(posCell+1,&Left,&Right,&Top,&Bot);
2326 UT_DEBUGMSG(("SEVIOR: Before delete left %d right %d top %d bot %d \n",Left,Right,Top,Bot));
2327 if((Right - Left) == 1)
2328 {
2329 _deleteCellAt(posTable,i, iLeft);
2330 }
2331 }
2332 //
2333 // OK now subtract one from all the column coordinates in the table with iLeft > iLeft
2334 // do this by running through the linked list of SectionCell fragments in the piecetable
2335 //
2336 // We stop when the position of the endCell strux is just before the position of
2337 // the endTable strux. So lets's get that now.
2338 //
2339 bRes = m_pDoc->getNextStruxOfType(tableSDH,PTX_EndTable,&endTableSDH);
2340 if(!bRes)
2341 {
2342 //
2343 // Disaster! the table structure in the piecetable is screwed.
2344 // we're totally stuffed now.
2345 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
2346 }
2347 PT_DocPosition posEndTable = m_pDoc->getStruxPosition(endTableSDH);
2348 PT_DocPosition posEndCell;
2349 bool bEnd = false;
2350 UT_sint32 iCurLeft,iCurRight,iCurTop,iCurBot,iNewLeft,iNewRight;
2351 cellSDH = tableSDH;
2352 while(!bEnd)
2353 {
2354 bRes = m_pDoc->getNextStruxOfType(cellSDH,PTX_SectionCell,&cellSDH);
2355 if(!bRes)
2356 {
2357 bEnd = true;
2358 break;
2359 }
2360 posCell2 = m_pDoc->getStruxPosition(cellSDH);
2361 getCellParams(posCell2+1, &iCurLeft, &iCurRight,&iCurTop,&iCurBot);
2362 UT_DEBUGMSG(("SEVIOR: Looking at cell left %d right %d top %d bot %d \n",iCurLeft,iCurRight,iCurTop,iCurBot));
2363 bool bChange = false;
2364 iNewLeft = iCurLeft;
2365 iNewRight = iCurRight;
2366 if(iCurLeft > iLeft)
2367 {
2368 bChange = true;
2369 iNewLeft--;
2370 }
2371 if(iCurRight > iLeft)
2372 {
2373 bChange = true;
2374 iNewRight--;
2375 }
2376 if(bChange)
2377 {
2378 UT_DEBUGMSG(("SEVIOR: changing cell to left %d right %d top %d bot %d \n",iNewLeft,iNewRight,iCurTop,iCurBot));
2379 const char * props[9] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
2380 UT_String sLeft,sRight,sTop,sBot;
2381 props[0] = "left-attach";
2382 UT_String_sprintf(sLeft,"%d",iNewLeft);
2383 props[1] = sLeft.c_str();
2384 props[2] = "right-attach";
2385 UT_String_sprintf(sRight,"%d",iNewRight);
2386 props[3] = sRight.c_str();
2387 props[4] = "top-attach";
2388 UT_String_sprintf(sTop,"%d",iCurTop);
2389 props[5] = sTop.c_str();
2390 props[6] = "bot-attach";
2391 UT_String_sprintf(sBot,"%d",iCurBot);
2392 props[7] = sBot.c_str();
2393 bRes = m_pDoc->changeStruxFmt(PTC_AddFmt,posCell2+1,posCell2+1,NULL,props,PTX_SectionCell);
2394 }
2395 endCellSDH = m_pDoc->getEndCellStruxFromCellSDH(cellSDH);
2396 posEndCell = m_pDoc->getStruxPosition(endCellSDH);
2397 if(posEndCell+1 >= posEndTable)
2398 {
2399 bEnd = true;
2400 }
2401 }
2402 //
2403 // Now trigger a rebuild of the whole table by sending a changeStrux to the table strux
2404 // with the restored line-type property it has before.
2405 //
2406 iListTag += 1;
2407 UT_String_sprintf(sListTag,"%d",iListTag);
2408 pszTable[1] = sListTag.c_str();
2409 UT_DEBUGMSG(("SEVIOR: Doing Table strux change of %s %s \n",pszTable[0],pszTable[1]));
2410 m_pDoc->changeStruxFmt(PTC_AddFmt,posTable,posTable,NULL,pszTable,PTX_SectionTable);
2411 //
2412 // OK finish everything off with the various parameters which allow the formatter to
2413 // be updated.
2414 //
2415 m_pDoc->setDontImmediatelyLayout(false);
2416
2417 // Signal PieceTable Changes have finished
2418 _restorePieceTableState();
2419 _generalUpdate();
2420 m_pDoc->endUserAtomicGlob();
2421
2422
2423 // restore updates and clean up dirty lists
2424 m_pDoc->enableListUpdates();
2425 m_pDoc->updateDirtyLists();
2426 _fixInsertionPointCoords();
2427
2428 _ensureInsertionPointOnScreen();
2429 notifyListeners(AV_CHG_MOTION);
2430 return true;
2431 }
2432
2433
2434 /*!
2435 * Delete the table containing the position posRow
2436 */
cmdDeleteTable(PT_DocPosition posTable,bool bDontNotify)2437 bool FV_View::cmdDeleteTable(PT_DocPosition posTable, bool bDontNotify)
2438 {
2439 STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
2440
2441 pf_Frag_Strux* tableSDH,*endTableSDH;
2442 PT_DocPosition posStartTable,posEndTable;
2443 bool bRes = m_pDoc->getStruxOfTypeFromPosition(posTable,PTX_SectionTable,&tableSDH);
2444 if(!bRes)
2445 {
2446 return false;
2447 }
2448 posStartTable = m_pDoc->getStruxPosition(tableSDH);
2449 endTableSDH = m_pDoc->getEndTableStruxFromTableSDH(tableSDH);
2450 posEndTable = m_pDoc->getStruxPosition(endTableSDH)+1;
2451 //
2452 // Got all we need, now set things up to do the delete nicely
2453 //
2454 // Signal PieceTable Change
2455 _saveAndNotifyPieceTableChange();
2456
2457 // Turn off list updates
2458
2459 m_pDoc->disableListUpdates();
2460 m_pDoc->beginUserAtomicGlob();
2461 if (!isSelectionEmpty())
2462 {
2463 _clearSelection();
2464 _resetSelection();
2465 }
2466 m_pDoc->setDontImmediatelyLayout(true);
2467 //
2468 // OK do the delete
2469 //
2470 UT_uint32 iRealDeleteCount;
2471 // if(m_pDoc->isFrameAtPos(posStartTable-1))
2472 // posStartTable--;
2473 m_pDoc->deleteSpan( posStartTable, posEndTable, NULL,iRealDeleteCount,true);
2474 //
2475 // OK finish everything off with the various parameters which allow the formatter to
2476 // be updated.
2477 //
2478 m_pDoc->setDontImmediatelyLayout(false);
2479
2480 // Signal PieceTable Changes have finished
2481 _restorePieceTableState();
2482 _generalUpdate();
2483 m_pDoc->endUserAtomicGlob();
2484
2485 // restore updates and clean up dirty lists
2486 m_pDoc->enableListUpdates();
2487 m_pDoc->updateDirtyLists();
2488 setPoint(getPoint());
2489 //
2490 // This method could be called from text to tablein which case
2491 // we don't want to do this.
2492 //
2493 if(!bDontNotify)
2494 {
2495 notifyListeners(AV_CHG_ALL);
2496 _fixInsertionPointCoords();
2497 _ensureInsertionPointOnScreen();
2498 }
2499 return true;
2500 }
2501
2502 /*!
2503 * Delete the row containing the position posRow
2504 */
cmdDeleteRow(PT_DocPosition posRow)2505 bool FV_View::cmdDeleteRow(PT_DocPosition posRow)
2506 {
2507 STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
2508
2509 pf_Frag_Strux* cellSDH,*tableSDH,*endTableSDH,*endCellSDH;
2510 PT_DocPosition posTable,posCell2;
2511 UT_sint32 iLeft,iRight,iTop,iBot;
2512 getCellParams(posRow, &iLeft, &iRight,&iTop,&iBot);
2513
2514 bool bRes = m_pDoc->getStruxOfTypeFromPosition(posRow,PTX_SectionCell,&cellSDH);
2515 bRes = m_pDoc->getStruxOfTypeFromPosition(posRow,PTX_SectionTable,&tableSDH);
2516 UT_return_val_if_fail(bRes, false);
2517
2518 posTable = m_pDoc->getStruxPosition(tableSDH) + 1;
2519 //
2520 // Now find the number of rows and columns inthis table. This is easiest to
2521 // get from the table container
2522 //
2523 fl_TableLayout * pTabL = getTableAtPos(posRow);
2524 if(pTabL == NULL)
2525 {
2526 pTabL = getTableAtPos(posRow+1);
2527 if(pTabL == NULL)
2528 {
2529 pTabL = getTableAtPos(posRow+2);
2530 UT_return_val_if_fail(pTabL, false);
2531 }
2532 }
2533 fp_TableContainer * pTab = static_cast<fp_TableContainer *>(pTabL->getFirstContainer());
2534 UT_return_val_if_fail(pTab, false);
2535 UT_sint32 numCols = pTab->getNumCols();
2536 //
2537 // If we delete the last row we're actually deleting the table, so do that
2538 // instead.
2539 //
2540 UT_sint32 nRows = getNumRowsInSelection();
2541 if(pTab->getNumRows() == 1 || (nRows == pTab->getNumRows()))
2542 {
2543 cmdDeleteTable(posRow);
2544 return true;
2545 }
2546 //
2547 // Got all we need, now set things up to do the delete nicely
2548 //
2549 // Signal PieceTable Change
2550 _saveAndNotifyPieceTableChange();
2551
2552 // Turn off list updates
2553
2554 m_pDoc->disableListUpdates();
2555 m_pDoc->beginUserAtomicGlob();
2556 UT_sint32 numRows = getNumRowsInSelection();
2557 if (!isSelectionEmpty() && !m_FrameEdit.isActive())
2558 {
2559 m_pDoc->beginUserAtomicGlob();
2560 PP_AttrProp AttrProp_Before;
2561 _deleteSelection(&AttrProp_Before);
2562 m_pDoc->endUserAtomicGlob();
2563 }
2564 else if(m_FrameEdit.isActive())
2565 {
2566 m_FrameEdit.setPointInside();
2567 }
2568 m_pDoc->setDontImmediatelyLayout(true);
2569 //
2570 // Now trigger a rebuild of the whole table by sending a changeStrux to the table strux
2571 // with a bogus line-type property. We'll restore it later.
2572 //
2573 const char * pszTable[3] = {NULL,NULL,NULL};
2574 pszTable[0] = "list-tag";
2575 const char * szListTag = NULL;
2576 UT_String sListTag;
2577 UT_sint32 iListTag;
2578 m_pDoc->getPropertyFromSDH(tableSDH,isShowRevisions(),getRevisionLevel(),pszTable[0],&szListTag);
2579 if(szListTag == NULL || *szListTag == '\0')
2580 {
2581 iListTag = 0;
2582 }
2583 else
2584 {
2585 iListTag = atoi(szListTag);
2586 iListTag -= 1;
2587 }
2588 UT_String_sprintf(sListTag,"%d",iListTag);
2589 pszTable[1] = sListTag.c_str();
2590 UT_DEBUGMSG(("SEVIOR: Doing Table strux change of %s %s \n",pszTable[0],pszTable[1]));
2591 m_pDoc->changeStruxFmt(PTC_AddFmt,posTable,posTable,NULL,pszTable,PTX_SectionTable);
2592 //
2593 // OK loop through all the rows in this column and delete the entries in the specified
2594 // column if the cell spans just the width of the column..
2595 //
2596 UT_sint32 i =0;
2597 UT_sint32 j = 0;
2598 for(j=numRows-1; j>=0; j--)
2599 {
2600 for(i=numCols-1; i >=0; i--)
2601 {
2602 PT_DocPosition posCell = findCellPosAt(posTable,iTop+j,i);
2603 UT_sint32 Left,Right,Top,Bot;
2604 getCellParams(posCell+1,&Left,&Right,&Top,&Bot);
2605 UT_DEBUGMSG(("SEVIOR: Before delete left %d right %d top %d bot %d \n",Left,Right,Top,Bot));
2606 if((Bot - Top) == 1)
2607 {
2608 _deleteCellAt(posTable,iTop+j, i);
2609 }
2610 }
2611 }
2612 //
2613 // OK now subtract numRows from all the row coordinates in the table with iTop,iBot > iTop
2614 // do this by running through the linked list of SectionCell fragments in the piecetable
2615 //
2616 // We stop when the position of the endCell strux is just before the position of
2617 // the endTable strux. So lets's get that now.
2618 //
2619 endTableSDH = m_pDoc->getEndTableStruxFromTableSDH(tableSDH);
2620 if(!bRes || (endTableSDH == NULL))
2621 {
2622 //
2623 // Disaster! the table structure in the piecetable is screwed.
2624 // we're totally stuffed now.
2625 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
2626 m_pDoc->setDontImmediatelyLayout(false);
2627
2628 // Signal PieceTable Changes have finished
2629 _restorePieceTableState();
2630 m_pDoc->endUserAtomicGlob();
2631 return false;
2632 }
2633 PT_DocPosition posEndTable = m_pDoc->getStruxPosition(endTableSDH);
2634 PT_DocPosition posEndCell;
2635 bool bEnd = false;
2636 UT_sint32 iCurLeft,iCurRight,iCurTop,iCurBot,iNewTop,iNewBot;
2637 cellSDH = tableSDH;
2638 while(!bEnd)
2639 {
2640 bRes = m_pDoc->getNextStruxOfType(cellSDH,PTX_SectionCell,&cellSDH);
2641 if(!bRes)
2642 {
2643 bEnd = true;
2644 break;
2645 }
2646 posCell2 = m_pDoc->getStruxPosition(cellSDH);
2647 getCellParams(posCell2+1, &iCurLeft, &iCurRight,&iCurTop,&iCurBot);
2648 UT_DEBUGMSG(("SEVIOR: Looking at cell left %d right %d top %d bot %d \n",iCurLeft,iCurRight,iCurTop,iCurBot));
2649 bool bChange = false;
2650 iNewTop = iCurTop;
2651 iNewBot = iCurBot;
2652 if(iCurTop > iTop)
2653 {
2654 bChange = true;
2655 iNewTop -= numRows;
2656 }
2657 if(iCurBot > iTop)
2658 {
2659 bChange = true;
2660 iNewBot -= numRows;
2661 }
2662 if(bChange)
2663 {
2664 UT_DEBUGMSG(("SEVIOR: changing cell to left %d right %d top %d bot %d \n",iCurLeft,iCurRight,iNewTop,iNewBot));
2665 const char * props[9] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
2666 UT_String sLeft,sRight,sTop,sBot;
2667 props[0] = "left-attach";
2668 UT_String_sprintf(sLeft,"%d",iCurLeft);
2669 props[1] = sLeft.c_str();
2670 props[2] = "right-attach";
2671 UT_String_sprintf(sRight,"%d",iCurRight);
2672 props[3] = sRight.c_str();
2673 props[4] = "top-attach";
2674 UT_String_sprintf(sTop,"%d",iNewTop);
2675 props[5] = sTop.c_str();
2676 props[6] = "bot-attach";
2677 UT_String_sprintf(sBot,"%d",iNewBot);
2678 props[7] = sBot.c_str();
2679 bRes = m_pDoc->changeStruxFmt(PTC_AddFmt,posCell2+1,posCell2+1,NULL,props,PTX_SectionCell);
2680 }
2681 endCellSDH = m_pDoc->getEndCellStruxFromCellSDH(cellSDH);
2682 posEndCell = m_pDoc->getStruxPosition(endCellSDH);
2683 if(posEndCell+1 >= posEndTable)
2684 {
2685 bEnd = true;
2686 }
2687 }
2688 //
2689 // Now trigger a rebuild of the whole table by sending a changeStrux to the table strux
2690 // with the restored line-type property it has before.
2691 //
2692 iListTag += 1;
2693 UT_String_sprintf(sListTag,"%d",iListTag);
2694 pszTable[1] = sListTag.c_str();
2695 UT_DEBUGMSG(("SEVIOR: Doing Table strux change of %s %s \n",pszTable[0],pszTable[1]));
2696 m_pDoc->changeStruxFmt(PTC_AddFmt,posTable,posTable,NULL,pszTable,PTX_SectionTable);
2697 //
2698 // OK finish everything off with the various parameters which allow the formatter to
2699 // be updated.
2700 //
2701 m_pDoc->setDontImmediatelyLayout(false);
2702
2703 // Signal PieceTable Changes have finished
2704 _restorePieceTableState();
2705 _generalUpdate();
2706 m_pDoc->endUserAtomicGlob();
2707
2708
2709 // restore updates and clean up dirty lists
2710 m_pDoc->enableListUpdates();
2711 m_pDoc->updateDirtyLists();
2712 _fixInsertionPointCoords();
2713
2714 _ensureInsertionPointOnScreen();
2715 notifyListeners(AV_CHG_MOTION);
2716 return true;
2717 }
2718
2719
2720 /*!
2721 * Delete the cell at the specified position
2722 */
cmdDeleteCell(PT_DocPosition)2723 bool FV_View::cmdDeleteCell(PT_DocPosition /*cellPos*/ )
2724 {
2725 #if 1
2726 UT_ASSERT(UT_NOT_IMPLEMENTED);
2727 return true ;
2728 #else
2729 pf_Frag_Strux* cellSDH;
2730 const char * pszLeftAttach =NULL;
2731 const char * pszTopAttach = NULL;
2732 UT_sint32 iLeft =-999;
2733 UT_sint32 iTop = -999;
2734 bool bRes = m_pDoc->getStruxOfTypeFromPosition(cellPos,PTX_SectionCell,&cellSDH);
2735 if(!bRes)
2736 {
2737 return false;
2738 }
2739 m_pDoc->getPropertyFromSDH(cellSDH,"left-attach",&pszLeftAttach);
2740 m_pDoc->getPropertyFromSDH(cellSDH,"top-attach",&pszTopAttach);
2741 if(pszLeftAttach && *pszLeftAttach)
2742 {
2743 iLeft = atoi(pszLeftAttach);
2744 }
2745 if(pszTopAttach && *pszTopAttach)
2746 {
2747 iTop = atoi(pszTopAttach);
2748 }
2749 //
2750 // Got all we need, now set things up to do the delete nicely
2751 //
2752 // Signal PieceTable Change
2753 _saveAndNotifyPieceTableChange();
2754
2755 // Turn off list updates
2756
2757 m_pDoc->disableListUpdates();
2758 m_pDoc->beginUserAtomicGlob();
2759 if (!isSelectionEmpty() && !m_FrameEdit.isActive())
2760 {
2761 m_pDoc->beginUserAtomicGlob();
2762 PP_AttrProp AttrProp_Before;
2763 _deleteSelection(&AttrProp_Before);
2764 m_pDoc->endUserAtomicGlob();
2765 }
2766 else if(m_FrameEdit.isActive())
2767 {
2768 m_FrameEdit.setPointInside();
2769 }
2770 m_pDoc->setDontImmediatelyLayout(true);
2771 //
2772 // delete the cell.
2773 //
2774 _deleteCellAt(cellPos,iTop, iLeft);
2775 //
2776 // OK do all the piecetable finished changing business
2777 //
2778 m_pDoc->setDontImmediatelyLayout(false);
2779
2780 // Signal PieceTable Changes have finished
2781 _restorePieceTableState();
2782 _generalUpdate();
2783 m_pDoc->endUserAtomicGlob();
2784
2785
2786 // restore updates and clean up dirty lists
2787 m_pDoc->enableListUpdates();
2788 m_pDoc->updateDirtyLists();
2789 _fixInsertionPointCoords();
2790
2791 _ensureInsertionPointOnScreen();
2792 notifyListeners(AV_CHG_MOTION);
2793 return true;
2794 #endif
2795 }
2796
2797
2798 /*!
2799 * Insert a table of the number of rows and columns given.
2800 */
cmdInsertTable(UT_sint32 numRows,UT_sint32 numCols,const gchar * pPropsArray[])2801 UT_Error FV_View::cmdInsertTable(UT_sint32 numRows, UT_sint32 numCols, const gchar * pPropsArray[])
2802 {
2803 STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
2804
2805 // TODO -- why does this function return UT_Error? If bool is
2806 // sufficient, it should return bool, and if not, than the
2807 // UT_Error & bool operations below are probably not safe
2808 UT_Error e = UT_OK;
2809 if(numRows == 0 || numCols==0)
2810 {
2811 return 0;
2812 }
2813 if(isInTable(getPoint()-1) && isInTable() && isHdrFtrEdit())
2814 {
2815 return 0;
2816 }
2817 if(isInTable(getPoint()) && !isSelectionEmpty() && isHdrFtrEdit())
2818 {
2819 return 0;
2820 }
2821 #if BENCHLAYOUT
2822 printf("Doing Insert Table \n");
2823 timespec t1;
2824 clock_gettime(CLOCK_REALTIME, &t1);
2825 #endif
2826
2827
2828 //
2829 // Do all the stuff we need to make this go smoothly and to undo in a single step.
2830 //
2831 // Signal PieceTable Changes
2832 _saveAndNotifyPieceTableChange();
2833
2834 // Turn off list updates
2835
2836 m_pDoc->disableListUpdates();
2837 m_pDoc->beginUserAtomicGlob();
2838 if (!isSelectionEmpty() && !m_FrameEdit.isActive())
2839 {
2840 m_pDoc->setDontImmediatelyLayout(true);
2841 m_pDoc->beginUserAtomicGlob();
2842 PP_AttrProp AttrProp_Before;
2843 _deleteSelection(&AttrProp_Before);
2844 m_pDoc->endUserAtomicGlob();
2845 }
2846 else if(m_FrameEdit.isActive())
2847 {
2848 m_FrameEdit.setPointInside();
2849 }
2850 else
2851 {
2852 m_pDoc->setDontImmediatelyLayout(true);
2853 }
2854 if(getHyperLinkRun(getPoint()) != NULL)
2855 {
2856
2857 // Signal PieceTable Changes have finished
2858 // restore updates and clean up dirty lists
2859 m_pDoc->enableListUpdates();
2860 m_pDoc->updateDirtyLists();
2861 _restorePieceTableState();
2862 return 0;
2863 }
2864 //
2865 // Handle corner case of point at endTOC
2866 //
2867 if(m_pDoc->isTOCAtPos(getPoint()-1))
2868 {
2869 setPoint(getPoint()-1);
2870 }
2871 //
2872 // insert a block to terminate the text before this.
2873 //
2874 PT_DocPosition pointBreak = getPoint();
2875 PT_DocPosition pointTable = 0;
2876 //
2877 // Don't do this if there is a block at pointBreak already.
2878 //
2879 bool bInsert = false;
2880 if((!m_pDoc->isBlockAtPos(getPoint()) && !m_pDoc->isTableAtPos(getPoint()) && !(m_pDoc->isEndFrameAtPos(getPoint()) && m_pDoc->isBlockAtPos(getPoint()-1) )) || m_pDoc->isTOCAtPos(getPoint()-2) )
2881 {
2882 e = m_pDoc->insertStrux(getPoint(),PTX_Block);
2883 bInsert = true;
2884 }
2885 bool bPointBreak = false;
2886 if(!bInsert && !m_pDoc->isTableAtPos(getPoint()) && !m_pDoc->isEndFootnoteAtPos(getPoint()-2) && !m_pDoc->isEndFootnoteAtPos(getPoint()-1) && !m_pDoc->isBlockAtPos(getPoint()))
2887 {
2888 pointBreak--;
2889 bPointBreak = true;
2890 }
2891 if(!bPointBreak && m_pDoc->isBlockAtPos(getPoint()))
2892 {
2893 PT_DocPosition posEnd = 0;
2894 getEditableBounds(true,posEnd);
2895 if(posEnd == getPoint())
2896 {
2897 pointBreak--;
2898 bPointBreak = true;
2899 }
2900 else if(m_pDoc->isSectionAtPos(getPoint()-1) || m_pDoc->isEndTableAtPos(getPoint()-1) || m_pDoc->isEndFrameAtPos(getPoint() - 1))
2901 {
2902 pointBreak--;
2903 bPointBreak = true;
2904 }
2905 else if(m_pDoc->isSectionAtPos(getPoint()-2))
2906 {
2907 pointBreak--;
2908 bPointBreak = true;
2909 }
2910 if(m_pDoc->isEndFootnoteAtPos(pointBreak))
2911 {
2912 pointBreak++;
2913 bPointBreak = false;
2914 }
2915 if(bPointBreak && !m_pDoc->isBlockAtPos(pointBreak))
2916 {
2917 pointBreak++;
2918 bPointBreak = false;
2919 }
2920
2921 }
2922 //
2923 // Insert the table strux at the same spot. This will make the table link correctly in the
2924 // middle of the broken text.
2925 //
2926 // Handle special case of not putting a table immediately after a section break
2927 //
2928 pf_Frag_Strux* secSDH = NULL;
2929 UT_DebugOnly<bool> bres = m_pDoc->getStruxOfTypeFromPosition(pointBreak-1,PTX_Section,&secSDH);
2930 #if DEBUG
2931 UT_ASSERT(bres);
2932 PT_DocPosition secPos2 = m_pDoc->getStruxPosition(secSDH);
2933 UT_DEBUGMSG(("SEVIOR: SecPos %d pointBreak %d \n",secPos2,pointBreak));
2934 #endif
2935 secSDH = NULL;
2936 bres = m_pDoc->getStruxOfTypeFromPosition(pointBreak,PTX_SectionCell,&secSDH);
2937 #if DEBUG
2938 if(secSDH != NULL)
2939 {
2940 PT_DocPosition secPos = m_pDoc->getStruxPosition(secSDH);
2941 UT_DEBUGMSG(("SEVIOR: Cell Pos %d pointBreak %d \n",secPos,pointBreak));
2942 }
2943 #endif
2944 //
2945 // Handle special case of not putting a table immediately after an end text box
2946 //
2947 if(m_pDoc->isEndFrameAtPos(pointBreak-1))
2948 {
2949 pointBreak--;
2950 }
2951 //
2952 // Handle special case of not putting a table in a TOC
2953 //
2954 if(m_pDoc->isTOCAtPos(pointBreak-1))
2955 {
2956 pointBreak++;
2957 }
2958
2959 setPoint(pointBreak);
2960 // Get the current attributes and properties. The user likely does not want the block properties as
2961 // the margins and indents might not be right for a much narrower container (the cell).
2962 // This is a ugly hack. We will only copy 2 fonts properties, font-family and font-size.
2963 const gchar ** props_in = NULL;
2964 const gchar * attrsBlock[3] = {"style","Normal",NULL};
2965 const gchar * propsBlock[5] = {NULL,NULL,NULL,NULL,NULL};
2966 const gchar * propFamily = "font-family";
2967 const gchar * propSize = "font-size";
2968 const gchar * szFamily = NULL;
2969 const gchar * szSize = NULL;
2970 const gchar * szNormalFamily = NULL;
2971 const gchar * szNormalSize = NULL;
2972 getCharFormat(&props_in);
2973 if (props_in && props_in[0])
2974 {
2975 szFamily = UT_getAttribute(propFamily, props_in);
2976 szSize = UT_getAttribute(propSize, props_in);
2977 }
2978 m_pDoc->getStyleProperty(attrsBlock[1],propFamily,szNormalFamily);
2979 m_pDoc->getStyleProperty(attrsBlock[1],propSize,szNormalSize);
2980 bool bFamily = (szFamily && (!szNormalFamily || (strcmp(szNormalFamily,szFamily) != 0)));
2981 bool bSize = (szSize && (!szNormalSize || (strcmp(szNormalSize,szSize) != 0)));
2982 if (bFamily && bSize)
2983 {
2984 propsBlock[0] = propFamily;
2985 propsBlock[1] = szFamily;
2986 propsBlock[2] = propSize;
2987 propsBlock[3] = szSize;
2988 }
2989 else if (bFamily)
2990 {
2991 propsBlock[0] = propFamily;
2992 propsBlock[1] = szFamily;
2993 }
2994 else if (bSize)
2995 {
2996 propsBlock[0] = propSize;
2997 propsBlock[1] = szSize;
2998 }
2999
3000 e |= static_cast<UT_sint32>(m_pDoc->insertStrux(getPoint(),PTX_SectionTable,NULL,pPropsArray));
3001 //
3002 // stuff for cell insertion.
3003 //
3004 UT_sint32 i,j;
3005 const gchar * props[9] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
3006 UT_String sRowTop = "top-attach";
3007 UT_String sRowBot = "bot-attach";
3008 UT_String sColLeft = "left-attach";
3009 UT_String sColRight = "right-attach";
3010 UT_String sTop,sBot,sLeft,sRight;
3011 for(i=0;i<numRows;i++)
3012 {
3013 UT_String_sprintf(sTop,"%d",i);
3014 UT_String_sprintf(sBot,"%d",i+1);
3015 props[0] = sRowTop.c_str();
3016 props[1] = sTop.c_str();
3017 props[2] = sRowBot.c_str();
3018 props[3] = sBot.c_str();
3019 for(j=0;j<numCols;j++)
3020 {
3021 UT_String_sprintf(sLeft,"%d",j);
3022 UT_String_sprintf(sRight,"%d",j+1);
3023 props[4] = sColLeft.c_str();
3024 props[5] = sLeft.c_str();
3025 props[6] = sColRight.c_str();
3026 props[7] = sRight.c_str();
3027 e |= static_cast<UT_sint32>(m_pDoc->insertStrux(getPoint(),PTX_SectionCell,NULL,props));
3028 pointBreak = getPoint();
3029 e |= static_cast<UT_sint32>(m_pDoc->insertStrux(getPoint(),PTX_Block,attrsBlock,propsBlock));
3030 UT_DEBUGMSG(("SEVIOR: 4 cur point %d \n",getPoint()));
3031 if(getPoint() == pointBreak)
3032 {
3033 setPoint(pointBreak+1);
3034 }
3035 if(i == 0 && j==0)
3036 {
3037 pointTable = getPoint();
3038 }
3039 e |= static_cast<UT_sint32>(m_pDoc->insertStrux(getPoint(),PTX_EndCell));
3040 }
3041 }
3042 m_pDoc->setDontImmediatelyLayout(false);
3043
3044 #if BENCHLAYOUT
3045 timespec t2;
3046 clock_gettime(CLOCK_REALTIME, &t2);
3047 double millidiff = (t2.tv_sec-t1.tv_sec)*1e3 + (t2.tv_nsec-t1.tv_nsec)/1e6;
3048 printf("Insert TIME: %lf milliseconds\n", millidiff);
3049 #endif
3050 e |= static_cast<UT_sint32>(m_pDoc->insertStrux(getPoint(),PTX_EndTable));
3051
3052 // restore updates and clean up dirty lists
3053 m_pDoc->enableListUpdates();
3054 m_pDoc->updateDirtyLists();
3055
3056 // Signal PieceTable Changes have finished
3057 _restorePieceTableState();
3058 _generalUpdate();
3059
3060 m_pDoc->endUserAtomicGlob();
3061 setPoint(pointTable);
3062 _makePointLegal();
3063 _fixInsertionPointCoords();
3064 focusChange(AV_FOCUS_HERE);
3065 _fixInsertionPointCoords();
3066 _ensureInsertionPointOnScreen();
3067 AV_View::notifyListeners (AV_CHG_ALL);
3068 return e;
3069 }
3070
3071 bool
cmdCharInsert(const std::string & s,bool bForce)3072 FV_View::cmdCharInsert(const std::string& s, bool bForce)
3073 {
3074 UT_UCS4String t( s );
3075 return cmdCharInsert( t.ucs4_str(), t.length(), bForce );
3076 }
3077
3078
cmdCharInsert(const UT_UCSChar * text,UT_uint32 count,bool bForce)3079 bool FV_View::cmdCharInsert(const UT_UCSChar * text, UT_uint32 count, bool bForce)
3080 {
3081 STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
3082
3083 //
3084 // Look if we should insert a pargraph before the table
3085 //
3086 if(m_bInsertAtTablePending && (count==1) && (text[0] != UCS_FF) && (text[0] != UCS_VTAB))
3087 {
3088 m_pDoc->beginUserAtomicGlob();
3089
3090 // Prevent access to Piecetable for things like spellchecks until
3091 // paragraphs have stablized
3092 //
3093 _saveAndNotifyPieceTableChange();
3094 m_pDoc->disableListUpdates();
3095 PT_DocPosition pos = m_iPosAtTable;
3096 m_pDoc->insertStrux( m_iPosAtTable,PTX_Block);
3097 m_bInsertAtTablePending = false;
3098
3099 // Signal piceTable is stable again
3100 _restorePieceTableState();
3101
3102 // Signal piceTable is stable again
3103 // Signal PieceTable Changes have finished
3104 _generalUpdate();
3105 // restore updates and clean up dirty lists
3106 m_pDoc->enableListUpdates();
3107 m_pDoc->updateDirtyLists();
3108 setPoint(pos+1);
3109 m_iPosAtTable = 0;
3110 _generalUpdate();
3111 bool res = _charInsert(text, count, bForce);
3112 m_pDoc->endUserAtomicGlob();
3113 return res;
3114 }
3115
3116 // the code below inserts a direction marker before a space if the automatic insertion of such
3117 // markers is indicated by user's preferences and if the current keyboard language direction is
3118 // inconsistent with the dominant direction of the paragraph (this makes phone numbers and similar
3119 // to work in rtl languages more intuitively)
3120
3121 // we only do this for space ... (certain other chars can be handled in ap_EditMethods.cpp
3122 // because they do not need knowledge of block direction)
3123 fl_BlockLayout * pBlock = NULL;
3124 if(count == 1 && text[0] == UCS_SPACE)
3125 {
3126 bool bLang = false, bMarker = false;
3127
3128 XAP_App::getApp()->getPrefsValueBool(static_cast<const gchar *>(XAP_PREF_KEY_ChangeLanguageWithKeyboard),
3129 &bLang);
3130
3131 const UT_LangRecord * pLR = NULL;
3132
3133 if(bLang)
3134 {
3135 pLR = XAP_App::getApp()->getKbdLanguage();
3136
3137 XAP_App::getApp()->getPrefsValueBool(static_cast<const gchar *>(XAP_PREF_KEY_DirMarkerAfterClosingParenthesis), &bMarker);
3138 }
3139
3140 if(bMarker && pLR)
3141 {
3142 pBlock = m_pLayout->findBlockAtPosition(getPoint());
3143
3144 if(!pBlock)
3145 goto normal_insert;
3146
3147 {
3148 UT_BidiCharType iDomDir = pBlock->getDominantDirection();
3149
3150 UT_UCS4Char data[2];
3151 data[1] = *text;
3152
3153 if(pLR->m_eDir == UTLANG_RTL && iDomDir != UT_BIDI_RTL)
3154 {
3155 data[0] = UCS_RLM;
3156 }
3157 else if(pLR->m_eDir == UTLANG_LTR && iDomDir != UT_BIDI_LTR)
3158 {
3159 data[0] = UCS_LRM;
3160 }
3161 else
3162 {
3163 goto normal_insert;
3164 }
3165
3166 return _charInsert(&data[0],2,bForce);
3167 }
3168 }
3169 }
3170 else if(count == 1 && text[0] == UCS_FF)
3171 {
3172 m_pDoc->beginUserAtomicGlob();
3173 bool b = _charInsert(text, count, bForce);
3174 if(b)
3175 {
3176 insertParagraphBreak();
3177 }
3178 m_pDoc->endUserAtomicGlob();
3179 return b;
3180 }
3181 else if(count == 1 && text[0] == UCS_VTAB)
3182 {
3183 m_pDoc->beginUserAtomicGlob();
3184 bool b = _charInsert(text, count, bForce);
3185 if(b)
3186 {
3187 insertParagraphBreak();
3188 }
3189 m_pDoc->endUserAtomicGlob();
3190 return b;
3191 }
3192
3193 normal_insert:
3194 return _charInsert(text, count, bForce);
3195 }
3196
cmdStartList(const gchar * style)3197 bool FV_View::cmdStartList(const gchar * style)
3198 {
3199 m_pDoc->beginUserAtomicGlob();
3200 fl_BlockLayout * pBlock = getCurrentBlock();
3201 pBlock->StartList( style);
3202 m_pDoc->endUserAtomicGlob();
3203
3204 return true;
3205 }
3206
3207
cmdStopList(void)3208 bool FV_View::cmdStopList(void)
3209 {
3210
3211
3212 // Signal PieceTable Change
3213 _saveAndNotifyPieceTableChange();
3214
3215 m_pDoc->beginUserAtomicGlob();
3216 fl_BlockLayout * pBlock = getCurrentBlock();
3217 m_pDoc->StopList(pBlock->getStruxDocHandle());
3218 m_pDoc->endUserAtomicGlob();
3219
3220 // Signal PieceTable Changes have finished
3221 _restorePieceTableState();
3222 return true;
3223 }
3224
3225
cmdCharDelete(bool bForward,UT_uint32 count)3226 void FV_View::cmdCharDelete(bool bForward, UT_uint32 count)
3227 {
3228 STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
3229
3230 const gchar * properties[] = { "font-family", NULL, 0};
3231 const gchar ** props_in = NULL;
3232 const gchar * currentfont;
3233 bool bisList = false;
3234 fl_BlockLayout * curBlock = NULL;
3235 fl_BlockLayout * nBlock = NULL;
3236 UT_uint32 iRealDeleteCount = 0;
3237 bool bSimple = false;
3238
3239 if (!isSelectionEmpty() && !m_FrameEdit.isActive())
3240 {
3241
3242 // Signal PieceTable Change
3243 _saveAndNotifyPieceTableChange();
3244 m_pDoc->disableListUpdates();
3245
3246 _deleteSelection();
3247
3248 _generalUpdate();
3249
3250 // restore updates and clean up dirty lists
3251 m_pDoc->enableListUpdates();
3252 m_pDoc->updateDirtyLists();
3253 _fixInsertionPointCoords();
3254 _ensureInsertionPointOnScreen();
3255 }
3256 else if(m_FrameEdit.isActive())
3257 {
3258 deleteFrame();
3259 }
3260 else
3261 {
3262 bool b_editStarted = false;
3263 bool b_delBlockWithFrames = false;
3264 //
3265 // Look to see if there is a tab - list label deal with these together
3266 //
3267 if((bForward == false) && (count == 1))
3268 {
3269 UT_sint32 myCount= 0;
3270 if(isTabListBehindPoint(myCount) == true)
3271 {
3272 curBlock = _findBlockAtPosition(getPoint());
3273 nBlock = _findBlockAtPosition(getPoint()-myCount);
3274 if(nBlock == curBlock)
3275 {
3276 count = myCount;
3277 bisList = true;
3278 }
3279 }
3280 }
3281 if((bForward == true) && (count == 1))
3282 {
3283 if(isTabListAheadPoint() == true)
3284 {
3285 //
3286 // Check we're at the start of a block
3287 //
3288 if(getPoint() == getCurrentBlock()->getPosition())
3289 {
3290 bisList = true;
3291 count = 2;
3292 }
3293 }
3294 }
3295 //
3296 // Move frames to a good position in the piece table when deleting a block (joining two paragraphs
3297 // together). Also keep frame at the same position with respect to the top of the first block.
3298 //
3299 //
3300 fl_BlockLayout * pFirstBlock = NULL;
3301 fl_BlockLayout * pSecondBlock = NULL;
3302
3303 if((bForward == false) && (count == 1))
3304 {
3305 fl_BlockLayout * pBlock = getCurrentBlock();
3306 if (pBlock && getPoint() == pBlock->getPosition())
3307 {
3308 fl_ContainerLayout * pPrevCL = pBlock->getPrev();
3309 while (pPrevCL && pPrevCL->getContainerType() == FL_CONTAINER_FRAME)
3310 {
3311 pPrevCL = pPrevCL->getPrev();
3312 }
3313 if (pPrevCL && pPrevCL->getContainerType() == FL_CONTAINER_BLOCK)
3314 {
3315 pFirstBlock = static_cast <fl_BlockLayout *> (pPrevCL);
3316 pSecondBlock = pBlock;
3317 if ((pFirstBlock->getNumFrames() > 0) || (pSecondBlock->getNumFrames() > 0))
3318 {
3319 b_delBlockWithFrames = true;
3320 }
3321 }
3322 }
3323 }
3324 else if((bForward == true) && (count == 1))
3325 {
3326 fl_BlockLayout * pBlock = getCurrentBlock();
3327 if (pBlock && (getPoint() == (pBlock->getPosition()+pBlock->getLength()-1)))
3328 {
3329 fl_ContainerLayout * pNextCL = pBlock->getNext();
3330 while (pNextCL && pNextCL->getContainerType() == FL_CONTAINER_FRAME)
3331 {
3332 pNextCL = pNextCL->getNext();
3333 }
3334 if (pNextCL && pNextCL->getContainerType() == FL_CONTAINER_BLOCK)
3335 {
3336 pFirstBlock = pBlock;
3337 pSecondBlock = static_cast <fl_BlockLayout *> (pNextCL);
3338 if ((pFirstBlock->getNumFrames() > 0) || (pSecondBlock->getNumFrames() > 0))
3339 {
3340 b_delBlockWithFrames = true;
3341 }
3342 }
3343 }
3344 }
3345
3346 if (b_delBlockWithFrames)
3347 {
3348 _saveAndNotifyPieceTableChange();
3349 m_pDoc->beginUserAtomicGlob();
3350 m_pDoc->disableListUpdates();
3351 b_editStarted = true;
3352
3353 UT_sint32 extraHeight = 0;
3354 bool b_evalHeightOfFirstBlock = false;
3355 UT_sint32 i = 0;
3356 UT_sint32 imax = pSecondBlock->getNumFrames();
3357 for(i=0; i < imax;i++)
3358 {
3359 fl_FrameLayout * pFL = pSecondBlock->getNthFrameLayout(i);
3360 if(pFL->isHidden() > FP_VISIBLE)
3361 continue;
3362 if(pFL->getContainerType() != FL_CONTAINER_FRAME)
3363 {
3364 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
3365 continue;
3366 }
3367 if(pFL->getFramePositionTo() == FL_FRAME_POSITIONED_TO_BLOCK)
3368 {
3369 const PP_AttrProp* pAP = NULL;
3370 const gchar * pszYPos = NULL;
3371 double ypos = 0.;
3372 pFL->getAP(pAP);
3373 if(!pAP || !pAP->getProperty("ypos",pszYPos))
3374 {
3375 pszYPos = "0.0in";
3376 }
3377 if (!b_evalHeightOfFirstBlock)
3378 {
3379 extraHeight = pFirstBlock->getHeightOfBlock(false);
3380 b_evalHeightOfFirstBlock = true;
3381 }
3382 ypos = UT_convertToInches(pszYPos) + double(extraHeight)/double(UT_LAYOUT_RESOLUTION);
3383 UT_String sValY = UT_formatDimensionString(DIM_IN,ypos);
3384 const gchar * frameProperties[] = {"ypos",sValY.c_str(),NULL};
3385 PT_DocPosition posStart = pFL->getPosition(true)+1;
3386 PT_DocPosition posEnd = posStart;
3387 UT_DebugOnly<bool> bRet = m_pDoc->changeStruxFmt(PTC_AddFmt,posStart,posEnd,NULL,
3388 frameProperties,PTX_SectionFrame);
3389 UT_ASSERT(bRet);
3390 }
3391 }
3392 imax = pFirstBlock->getNumFrames();
3393 for(i=0; i < imax;i++)
3394 {
3395 fl_FrameLayout * pFL = pFirstBlock->getNthFrameLayout(0);
3396 if(pFL->getContainerType() != FL_CONTAINER_FRAME)
3397 {
3398 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
3399 break;
3400 }
3401 m_pLayout->relocateFrame(pFL,pSecondBlock);
3402 }
3403 if (bForward)
3404 {
3405 setPoint(pFirstBlock->getPosition()+pFirstBlock->getLength()-1);
3406 }
3407 else
3408 {
3409 setPoint(pSecondBlock->getPosition());
3410 }
3411 }
3412 //
3413 // Code to deal with deleting a footnote reference that embeds a footnote Layout.
3414 //
3415 if(bForward)
3416 {
3417 if(!isInFootnote() && isInFootnote(getPoint() + count))
3418 {
3419 fl_FootnoteLayout * pFL = getClosestFootnote(getPoint() + count +1);
3420 count += pFL->getLength();
3421 }
3422 if(!isInEndnote() && isInEndnote(getPoint() + count))
3423 {
3424 fl_EndnoteLayout * pEL = getClosestEndnote(getPoint() + count +1);
3425 count += pEL->getLength();
3426 }
3427 if(m_pDoc->isTOCAtPos(getPoint()))
3428 {
3429 if(m_pDoc->isTOCAtPos(getPoint()-1))
3430 {
3431 m_iInsPoint--;
3432 }
3433 count++;
3434
3435 }
3436 }
3437 else
3438 {
3439 if(!isInFootnote(getPoint()) && isInFootnote(getPoint() - count))
3440 {
3441 fl_FootnoteLayout * pFL = getClosestFootnote(getPoint());
3442 count += pFL->getLength();
3443 }
3444 else if(isInFootnote(getPoint()))
3445 {
3446 if(!isInFootnote(getPoint() - count))
3447 {
3448 return;
3449 }
3450 else if(!isInFootnote(getPoint() -2))
3451 {
3452 //
3453 // Don't delete the paragraph strux in footnote
3454 //
3455 return;
3456 }
3457 else if(!isInFootnote(getPoint() -3))
3458 {
3459 //
3460 // Don't delete the paragraph strux in footnote
3461 //
3462 return;
3463 }
3464 }
3465 else if(!isInEndnote() && isInEndnote(getPoint() - count))
3466 {
3467 fl_EndnoteLayout * pEL = getClosestEndnote(getPoint());
3468 count += pEL->getLength();
3469 }
3470 else if(isInEndnote(getPoint()))
3471 {
3472 if(!isInEndnote(getPoint() - count))
3473 {
3474 return;
3475 }
3476 else if(!isInEndnote(getPoint() -2))
3477 {
3478 //
3479 // Don't delete the paragraph strux in endnote
3480 //
3481 return;
3482 }
3483 else if(!isInEndnote(getPoint() -3))
3484 {
3485 //
3486 // Don't delete the paragraph strux in endnote
3487 //
3488 return;
3489 }
3490
3491 }
3492 if(m_pDoc->isTOCAtPos(getPoint()-2))
3493 {
3494 count +=2;
3495 }
3496 }
3497
3498 // Code that deals with deleting runs that do not like to be deleted ... This handles runs
3499 // that return true for deleteFollowingIfAtInsPoint(). Runs in this category are typically
3500 // not visible on screen, such as hyperlinks and bookmarks, and are deleted through the main
3501 // menu. Such runs must not be deleted inadvertedly when pressing delete/backpace. Just to
3502 // exaplain why: for example, in Word bookmarks inadvertedly disappear when the bookmarked
3503 // text is edited; this is extremely annoying if such bookmarks are referenced from page
3504 // reference and similar fields, particularly if the document is long and contains many such
3505 // fields -- imagine printing a 200+ page document, only to discover that on page 178 you
3506 // have 'error: bookmark not found' where a page number should have been -- we want to
3507 // minimise this happening and will only delete such runs when (a) the user explicitely asks
3508 // to, or (b) they are inside a selection.
3509 if(!curBlock)
3510 curBlock = _findBlockAtPosition(getPoint());
3511
3512 if(bForward && count == 1)
3513 {
3514 UT_return_if_fail( curBlock );
3515
3516 fp_Run * pRun = curBlock->findRunAtOffset(getPoint() - curBlock->getPosition());
3517
3518 UT_return_if_fail( pRun );
3519
3520 UT_uint32 iLength = 0;
3521 while(pRun && (pRun->deleteFollowingIfAtInsPoint() && (getPoint() == curBlock->getPosition() + pRun->getBlockOffset())))
3522 {
3523 iLength += pRun->getLength();
3524 pRun = pRun->getNextRun();
3525 }
3526
3527 _setPoint(m_iInsPoint + iLength);
3528
3529 }
3530 else if(!bForward && count == 1)
3531 {
3532 UT_return_if_fail( curBlock );
3533
3534 fp_Run * pRun = curBlock->findRunAtOffset(getPoint() - curBlock->getPosition());
3535
3536 UT_return_if_fail( pRun );
3537
3538 // back one further
3539 pRun = pRun->getPrevRun();
3540
3541 UT_uint32 iLength = 0;
3542 while(pRun && (pRun->deleteFollowingIfAtInsPoint() && (getPoint() == curBlock->getPosition() + pRun->getBlockOffset())) )
3543 {
3544 iLength += pRun->getLength();
3545 pRun = pRun->getPrevRun();
3546 }
3547
3548 _setPoint(m_iInsPoint - iLength);
3549
3550 }
3551
3552 // deal with character clusters, such as base char + vowel + tone mark in Thai
3553 UT_uint32 pos1 = getPoint();
3554 if(!bForward)
3555 {
3556 UT_ASSERT_HARMLESS( pos1 > count );
3557 pos1 -= count;
3558 }
3559
3560 _adjustDeletePosition(pos1, count);
3561
3562 if(bForward)
3563 _setPoint(pos1);
3564 else
3565 _setPoint(pos1 + count);
3566
3567
3568 // Code to deal with font boundary problem.
3569 // TODO: This should really be fixed by someone who understands
3570 // how this code works! In the meantime save current font to be
3571 // restored after character is deleted.
3572
3573 getCharFormat(&props_in);
3574 currentfont = UT_getAttribute("font-family",props_in);
3575 properties[1] = currentfont;
3576 xxx_UT_DEBUGMSG(("deleteSpan - 1: Inital pos %d count %d \n",getPoint(),count));
3577
3578 UT_uint32 amt = count;
3579 UT_uint32 posCur = getPoint();
3580 UT_uint32 nposCur = getPoint();
3581 bool fontFlag = false;
3582
3583 if (!bForward)
3584 {
3585
3586 if (!_charMotion(bForward,count, false))
3587 {
3588 UT_ASSERT(getPoint() <= posCur);
3589 xxx_UT_DEBUGMSG(("SEVIOR: posCur %d getPoint() %d \n",posCur,getPoint()));
3590 amt = posCur - getPoint();
3591 }
3592
3593 posCur = getPoint();
3594 // Code to deal with change of font boundaries:
3595 if((posCur == nposCur) && (posCur > 0))
3596 {
3597 fontFlag = true;
3598 posCur--;
3599 }
3600 }
3601 else
3602 {
3603 PT_DocPosition posEOD;
3604 UT_DebugOnly<bool> bRes;
3605
3606 bRes = getEditableBounds(true, posEOD);
3607 UT_ASSERT(bRes);
3608 UT_ASSERT(posCur <= posEOD);
3609
3610 if (posEOD < (posCur+amt))
3611 {
3612 amt = posEOD - posCur;
3613 }
3614 }
3615
3616 if(!curBlock)
3617 curBlock = _findBlockAtPosition(getPoint());
3618
3619 //
3620 // Code to check for a delete over a frame boundary.
3621 //
3622 if(isInFrame(posCur) && !isInFrame(posCur+amt))
3623 {
3624 fl_FrameLayout * pFL = getFrameLayout(posCur+amt);
3625 if(pFL != NULL)
3626 {
3627 //
3628 // Delete to edge of text box
3629 //
3630 PT_DocPosition posFrame = pFL->getPosition(true);
3631 amt = posFrame + pFL->getLength() - posCur;
3632 }
3633 return;
3634 }
3635 if(!isInFrame(posCur) && isInFrame(posCur+amt) && (amt > 1))
3636 {
3637 fl_FrameLayout * pFL = getFrameLayout(posCur+amt);
3638 if(pFL != NULL)
3639 {
3640 //
3641 // delete to start of text box
3642 //
3643 PT_DocPosition posFrame = pFL->getPosition(true);
3644 amt = posCur + amt + 1 - posFrame;
3645 }
3646 }
3647 //
3648 // isInFrame will return true if we're right at the frame strux or right
3649 // at the EndFrame strux. If we delete either we're screwed. Handle
3650 // the cases.
3651 //
3652 // Later we want to be clever about moving the frame into a valid position
3653 // in the new merged block. Just fix the crash for now.
3654 //
3655 if(m_pDoc->isFrameAtPos(posCur) && isInFrame(posCur+amt) )
3656 {
3657 return;
3658 }
3659
3660 if(m_pDoc->isEndFrameAtPos(posCur))
3661 {
3662 return;
3663 }
3664
3665 // Signal PieceTable Change
3666 if (!b_editStarted)
3667 {
3668 _saveAndNotifyPieceTableChange();
3669 b_editStarted = true;
3670 }
3671 if (amt > 0)
3672 {
3673 m_pDoc->disableListUpdates();
3674
3675 nBlock = _findBlockAtPosition(getPoint());
3676 fl_AutoNum * pAuto2 = nBlock->getAutoNum();
3677 if(pAuto2 != NULL )
3678 {
3679 pf_Frag_Strux* sdh = nBlock->getStruxDocHandle();
3680 if((bisList == true) && (pAuto2->getFirstItem() == sdh || pAuto2->getLastItem() == sdh))
3681 {
3682 m_pDoc->StopList(sdh);
3683 PT_DocPosition listPoint,posEOD;
3684 getEditableBounds(true, posEOD);
3685 listPoint = getPoint();
3686 fl_AutoNum * pAuto = nBlock->getAutoNum();
3687 if(pAuto != NULL)
3688 {
3689 if(listPoint + 2 <= posEOD)
3690 _setPoint(listPoint+2);
3691 else
3692 _setPoint(posEOD);
3693 }
3694 }
3695 else if(bisList == true)
3696 {
3697
3698 m_pDoc->deleteSpan(posCur, posCur+amt,NULL, iRealDeleteCount);
3699 nBlock->remItemFromList();
3700 }
3701 else
3702 {
3703 m_pDoc->deleteSpan(posCur, posCur+amt,NULL, iRealDeleteCount);
3704 }
3705 }
3706 else
3707 {
3708 UT_DEBUGMSG(("deleteSpan - 2: posCur %d amt %d \n",posCur,amt));
3709 m_pDoc->deleteSpan(posCur, posCur+amt,NULL, iRealDeleteCount);
3710 }
3711
3712 if(fontFlag)
3713 {
3714 _makePointLegal();
3715 setCharFormat(properties);
3716 }
3717 }
3718 //
3719 // Dont leave a List field - tab on a line.
3720 //
3721 if(isTabListAheadPoint())
3722 {
3723 UT_uint32 iRealDeleteCount2;
3724
3725 m_pDoc->deleteSpan(getPoint(), getPoint()+2,NULL,iRealDeleteCount2);
3726 iRealDeleteCount += iRealDeleteCount2;
3727 }
3728 else if(count == 1)
3729 {
3730 bSimple = true;
3731 }
3732 // restore updates and clean up dirty lists
3733 m_pDoc->enableListUpdates();
3734 m_pDoc->updateDirtyLists();
3735
3736 _generalUpdate();
3737 g_free(props_in);
3738
3739 _fixInsertionPointCoords();
3740 _ensureInsertionPointOnScreen();
3741
3742 //special handling is required for delete in revisions mode
3743 //where we have to move the insertion point
3744 // only if we are deleting forward; if deleting backwards, the
3745 // code above already moved the insertion point
3746 //
3747 // Tomas, Oct 28, 2003
3748 // do this if we deleted fewer than count characters
3749 if(bForward && isMarkRevisions() && (iRealDeleteCount < count))
3750 {
3751 UT_ASSERT( iRealDeleteCount <= count );
3752 _charMotion(bForward,count - iRealDeleteCount);
3753 }
3754 if (b_delBlockWithFrames)
3755 {
3756 m_pDoc->endUserAtomicGlob();
3757 }
3758 }
3759
3760 // Signal PieceTable Changes have finished
3761 _restorePieceTableState();
3762 _setPoint(getPoint());
3763 if(!bSimple)
3764 notifyListeners(AV_CHG_MOTION | AV_CHG_ALL);
3765 else
3766 notifyListeners(AV_CHG_MOTION);
3767
3768 }
3769
3770
3771
cmdScroll(AV_ScrollCmd cmd,UT_uint32 iPos)3772 void FV_View::cmdScroll(AV_ScrollCmd cmd, UT_uint32 iPos)
3773 {
3774
3775 #define HACK_LINE_HEIGHT 20 // TODO Fix this!!
3776
3777 UT_sint32 lineHeight = iPos;
3778 bool bVertical = false;
3779 bool bHorizontal = false;
3780
3781 if (lineHeight == 0)
3782 lineHeight = m_pG->tlu(HACK_LINE_HEIGHT);
3783
3784 UT_sint32 yoff = m_yScrollOffset;
3785 UT_sint32 xoff = m_xScrollOffset;
3786
3787 switch(cmd)
3788 {
3789 case AV_SCROLLCMD_PAGEDOWN:
3790 yoff += getWindowHeight();
3791 bVertical = true;
3792 break;
3793 case AV_SCROLLCMD_PAGEUP:
3794 yoff -= getWindowHeight();
3795 bVertical = true;
3796 break;
3797 case AV_SCROLLCMD_PAGELEFT:
3798 xoff -= getWindowWidth();
3799 bHorizontal = true;
3800 break;
3801 case AV_SCROLLCMD_PAGERIGHT:
3802 xoff += getWindowWidth();
3803 bHorizontal = true;
3804 break;
3805 case AV_SCROLLCMD_LINEDOWN:
3806 yoff += lineHeight;
3807 bVertical = true;
3808 break;
3809 case AV_SCROLLCMD_LINEUP:
3810 yoff -= lineHeight;
3811 bVertical = true;
3812 break;
3813 case AV_SCROLLCMD_LINELEFT:
3814 xoff -= lineHeight;
3815 bHorizontal = true;
3816 break;
3817 case AV_SCROLLCMD_LINERIGHT:
3818 xoff += lineHeight;
3819 bHorizontal = true;
3820 break;
3821 case AV_SCROLLCMD_TOTOP:
3822 yoff = 0;
3823 bVertical = true;
3824 break;
3825 case AV_SCROLLCMD_TOPOSITION:
3826 UT_ASSERT(UT_NOT_IMPLEMENTED);
3827 break;
3828 case AV_SCROLLCMD_TOBOTTOM:
3829 fp_Page* pPage = m_pLayout->getFirstPage();
3830 UT_sint32 iDocHeight = getPageViewTopMargin();
3831 while (pPage)
3832 {
3833 iDocHeight += pPage->getHeight() + getPageViewSep();
3834 pPage = pPage->getNext();
3835 }
3836 yoff = iDocHeight;
3837 bVertical = true;
3838 break;
3839 }
3840
3841 if (yoff < 0)
3842 yoff = 0;
3843
3844 bool bRedrawPoint = true;
3845
3846 if (bVertical && (yoff != m_yScrollOffset))
3847 {
3848 sendVerticalScrollEvent(yoff);
3849 if ((cmd != AV_SCROLLCMD_PAGEUP
3850 && cmd != AV_SCROLLCMD_PAGEDOWN))
3851 bRedrawPoint = false;
3852 // UT_ASSERT(m_yScrollOffset == m_pG->getPrevYOffset());
3853 }
3854
3855 if (xoff < 0)
3856 xoff = 0;
3857
3858 if (bHorizontal && (xoff != m_xScrollOffset))
3859 {
3860 sendHorizontalScrollEvent(xoff);
3861 bRedrawPoint = false;
3862 }
3863
3864 if (bRedrawPoint)
3865 _fixInsertionPointCoords();
3866
3867 }
3868
cmdSelectNoNotify(PT_DocPosition dpBeg,PT_DocPosition dpEnd)3869 bool FV_View::cmdSelectNoNotify(PT_DocPosition dpBeg, PT_DocPosition dpEnd)
3870 {
3871 if (!isSelectionEmpty())
3872 {
3873 _clearSelection();
3874 }
3875 _setPoint(dpBeg);
3876 _setSelectionAnchor();
3877 m_Selection.setSelectionLeftAnchor(dpBeg);
3878 if(dpBeg < dpEnd - 2)
3879 {
3880 if(m_pDoc->isTableAtPos(dpEnd) && m_pDoc->isEndTableAtPos(dpEnd-1))
3881 {
3882 dpEnd--;
3883 }
3884 if(m_pDoc->isCellAtPos(dpEnd))
3885 {
3886 dpEnd--;
3887 }
3888 }
3889 m_Selection.setSelectionRightAnchor(dpEnd);
3890 _setPoint (dpEnd);
3891 // This is no good in abicommand
3892 // UT_ASSERT(!isSelectionEmpty());
3893
3894 if (dpBeg == dpEnd)
3895 {
3896 return false;
3897 }
3898 return true;
3899 }
3900
cmdSelect(PT_DocPosition dpBeg,PT_DocPosition dpEnd)3901 void FV_View::cmdSelect(PT_DocPosition dpBeg, PT_DocPosition dpEnd)
3902 {
3903 if(cmdSelectNoNotify(dpBeg, dpEnd))
3904 {
3905 _drawSelection();
3906 notifyListeners(AV_CHG_EMPTYSEL);
3907 }
3908 }
3909
cmdSelect(const std::pair<PT_DocPosition,PT_DocPosition> & range)3910 void FV_View::cmdSelect( const std::pair< PT_DocPosition, PT_DocPosition >& range )
3911 {
3912 if( range.first == 0 && range.second == 0 )
3913 {
3914 cmdUnselectSelection();
3915 return;
3916 }
3917
3918 cmdSelect( range.first, range.second );
3919 }
3920
3921
3922
3923 #define IS_SELECTALL(a, b) ((a) == FV_DOCPOS_BOD && (b) == FV_DOCPOS_EOD)
3924
cmdSelect(UT_sint32 xPos,UT_sint32 yPos,FV_DocPos dpBeg,FV_DocPos dpEnd)3925 void FV_View::cmdSelect(UT_sint32 xPos, UT_sint32 yPos, FV_DocPos dpBeg, FV_DocPos dpEnd)
3926 {
3927 UT_DEBUGMSG(("Double click on mouse \n"));
3928
3929 warpInsPtToXY(xPos, yPos,true);
3930 PT_DocPosition iPosLeft = _getDocPos(dpBeg, false);
3931 PT_DocPosition iPosRight = _getDocPos(dpEnd, false);
3932 if(iPosLeft > iPosRight)
3933 {
3934 return;
3935 }
3936 if(!isInFrame(iPosLeft) && isInFrame(iPosRight))
3937 {
3938 fl_FrameLayout * pFL = getFrameLayout(iPosRight);
3939 iPosRight =pFL->getPosition(true)-1;
3940 }
3941 if(isInFrame(iPosLeft) && !isInFrame(iPosRight))
3942 {
3943 fl_FrameLayout * pFL = getFrameLayout(iPosLeft);
3944 iPosRight =pFL->getPosition(true) + pFL->getLength() -1;
3945 }
3946 if(iPosLeft == iPosRight) return;
3947 //
3948 // Code to select a paragraph break on selectLine if on first line of a Block.
3949 //
3950 bool bRedraw = false;
3951 if((dpBeg == FV_DOCPOS_BOL) || (dpBeg == FV_DOCPOS_BOP) || (dpBeg == FV_DOCPOS_BOD))
3952 {
3953 fl_BlockLayout * pBlock = _findBlockAtPosition(iPosLeft);
3954 if(pBlock)
3955 {
3956 UT_sint32 x, y, x2, y2, h;
3957 bool b;
3958 fp_Run* pRun = pBlock->findPointCoords(m_iInsPoint, false, x, y, x2, y2, h, b);
3959 if(pRun)
3960 {
3961 fp_Line * pLine = pRun->getLine();
3962 if(pLine == static_cast<fp_Line *>(pBlock->getFirstContainer()))
3963 {
3964 PT_DocPosition iPosNew = pBlock->getPosition() -1;
3965 if(iPosNew < iPosLeft)
3966 {
3967 iPosLeft = iPosNew;
3968 }
3969 bRedraw = true; // Need to trick a global redraw in
3970 // header/footer
3971 }
3972 }
3973 }
3974 }
3975 cmdSelect (iPosLeft, iPosRight);
3976 if(bRedraw && isHdrFtrEdit())
3977 {
3978 cmdSelect (iPosLeft+1, iPosRight);
3979 }
3980 }
3981
cmdHyperlinkJump(UT_sint32 xPos,UT_sint32 yPos)3982 void FV_View::cmdHyperlinkJump(UT_sint32 xPos, UT_sint32 yPos)
3983 {
3984 _clearSelection();
3985 warpInsPtToXY(xPos, yPos,true);
3986
3987 fl_BlockLayout * pBlock = getCurrentBlock();
3988 PT_DocPosition iRelPos = getPoint() - pBlock->getPosition(false);
3989
3990 fp_Run *pRun = pBlock->getFirstRun();
3991 while (pRun && pRun->getBlockOffset()+ pRun->getLength() < iRelPos)
3992 pRun= pRun->getNextRun();
3993
3994 UT_return_if_fail(pRun);
3995 pRun->getPrevRun();
3996
3997 UT_return_if_fail(pRun);
3998 #if 0
3999 if(pRun->getType()== FPRUN_FMTMARK || pRun->getType()== FPRUN_HYPERLINK || pRun->getType()== FPRUN_BOOKMARK)
4000 pRun = pRun->getNextRun();
4001
4002 UT_ASSERT(pRun);
4003 #endif
4004 fp_HyperlinkRun * pH = pRun->getHyperlink();
4005
4006 UT_return_if_fail(pH);
4007
4008 const gchar * pTarget = pH->getTarget();
4009
4010 if(*pTarget == '#')
4011 pTarget++;
4012
4013 UT_UCS4String pJump(pTarget);
4014
4015 gotoTarget(AP_JUMPTARGET_BOOKMARK, pJump.ucs4_str());
4016 }
4017
4018
cmdHyperlinkJump(PT_DocPosition pos)4019 void FV_View::cmdHyperlinkJump(PT_DocPosition pos)
4020 {
4021 fp_HyperlinkRun * pH = static_cast<fp_HyperlinkRun *>(getHyperLinkRun(pos));
4022 UT_return_if_fail(pH);
4023 if(pH->getHyperlinkType() == HYPERLINK_ANNOTATION)
4024 {
4025 fp_AnnotationRun * pAN = static_cast<fp_AnnotationRun *>(pH);
4026 if(!pAN->displayAnnotations())
4027 {
4028 UT_DEBUGMSG(("Can only directly edit if we in show annotation mode \n"));
4029 UT_DEBUGMSG(("Should pop up a dialog to say this, but not now \n?"));
4030 return;
4031 }
4032 UT_uint32 aid = pAN->getPID();
4033 fl_AnnotationLayout * pAL = getAnnotationLayout(aid);
4034 if(pAL == NULL)
4035 {
4036 return;
4037 }
4038 //
4039 // Put caret just past the annotation field
4040 //
4041 PT_DocPosition posAn = pAL->getPosition();
4042 setPoint(posAn);
4043 _fixInsertionPointCoords();
4044 _ensureInsertionPointOnScreen();
4045 notifyListeners(AV_CHG_MOTION);
4046 _generalUpdate();
4047 return;
4048 }
4049 const gchar * pTarget = pH->getTarget();
4050
4051 if(*pTarget == '#')
4052 pTarget++;
4053
4054 UT_UCS4String pJump(pTarget);
4055
4056 gotoTarget(AP_JUMPTARGET_BOOKMARK, pJump.ucs4_str());
4057 }
4058
cmdHyperlinkCopyLocation(PT_DocPosition pos)4059 void FV_View::cmdHyperlinkCopyLocation(PT_DocPosition pos)
4060 {
4061 fp_HyperlinkRun * pH = static_cast<fp_HyperlinkRun *>(getHyperLinkRun(pos));
4062 if(!pH)
4063 return;
4064
4065 const gchar * pTarget = pH->getTarget();
4066
4067 if(!pTarget || !*pTarget || !strcmp(pTarget,"#"))
4068 return;
4069
4070 //skip over internal anchors
4071 if(*pTarget == '#')
4072 pTarget++;
4073
4074 //copy the target to the clipboard
4075 copyTextToClipboard(pTarget, true);
4076 }
4077
4078
cmdUndo(UT_uint32 count)4079 void FV_View::cmdUndo(UT_uint32 count)
4080 {
4081 STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
4082
4083 if (!isSelectionEmpty())
4084 _clearSelection();
4085
4086 // Temporarily disable smart quotes
4087 // This allows the smart quote to be reverted by undo.
4088 m_bAllowSmartQuoteReplacement = false;
4089
4090 // Signal PieceTable Change
4091 m_pDoc->notifyPieceTableChangeStart();
4092
4093 // Turn off list updates
4094 m_pDoc->disableListUpdates();
4095
4096 // Don't update tables until finished
4097
4098 m_pDoc->setDontImmediatelyLayout(true);
4099
4100 // Remember the current position, We might need it later.
4101 rememberCurrentPosition();
4102 UT_DEBUGMSG(("SEVIOR: undoing %d operations \n",count));
4103 m_pDoc->undoCmd(count);
4104 allowChangeInsPoint();
4105 m_pDoc->setDontImmediatelyLayout(false);
4106
4107 //
4108 // Now do a general update to make everything look good again.
4109 //
4110 _generalUpdate();
4111
4112 notifyListeners(AV_CHG_DIRTY);
4113
4114 // Look to see if we need the saved insertion point after the undo
4115 // if(needSavedPosition())
4116 // {
4117 //
4118 // We do, so restore insertion point to that value.
4119 // _setPoint(getSavedPosition());
4120 // clearSavedPosition();
4121 // }
4122 // restore updates and clean up dirty lists
4123 m_pDoc->enableListUpdates();
4124 m_pDoc->updateDirtyLists();
4125
4126 // Signal PieceTable Changes have finished
4127 m_pDoc->notifyPieceTableChangeEnd();
4128 m_iPieceTableState = 0;
4129 // Move insertion point out of field run if it is in one
4130 //
4131 _charMotion(true, 0);
4132 //
4133 // Do a complete update coz who knows what happened in the undo!
4134 //
4135 notifyListeners(AV_CHG_ALL);
4136 PT_DocPosition posEnd = 0;
4137 PT_DocPosition posBOD = 0;
4138 getEditableBounds(true, posEnd);
4139 getEditableBounds(true, posBOD);
4140 bool bOK = true;
4141 while(bOK && !isPointLegal() && (getPoint() < posEnd))
4142 {
4143 bOK = _charMotion(true,1);
4144 }
4145
4146 bOK = true;
4147 while(bOK && !isPointLegal() && (getPoint() > posBOD))
4148 {
4149 bOK = _charMotion(false,1);
4150 }
4151 setCursorToContext();
4152
4153 _updateInsertionPoint();
4154
4155 // Reenable smart quotes
4156 m_bAllowSmartQuoteReplacement = true;
4157 }
4158
cmdRedo(UT_uint32 count)4159 void FV_View::cmdRedo(UT_uint32 count)
4160 {
4161 STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
4162
4163 if (!isSelectionEmpty())
4164 _clearSelection();
4165
4166 // Temporarily disable smart quotes
4167 // This allows the smart quote to be reverted by undo.
4168 m_bAllowSmartQuoteReplacement = false;
4169
4170 // Signal PieceTable Change
4171 m_pDoc->notifyPieceTableChangeStart();
4172
4173 // Turn off list updates
4174 m_pDoc->disableListUpdates();
4175 m_pDoc->setDontImmediatelyLayout(true);
4176
4177 // Remember the current position, We might need it later.
4178 rememberCurrentPosition();
4179
4180 m_pDoc->redoCmd(count);
4181 allowChangeInsPoint();
4182
4183 // Look to see if we need the saved insertion point after the undo
4184 // if(needSavedPosition())
4185 // {
4186 //
4187 // We do, so restore insertion point to that value.
4188 //
4189 // _setPoint(getSavedPosition());
4190 // clearSavedPosition();
4191 // }
4192 m_pDoc->setDontImmediatelyLayout(false);
4193
4194 // Signal PieceTable Changes have finished
4195 m_pDoc->notifyPieceTableChangeEnd();
4196 m_iPieceTableState = 0;
4197
4198 // restore updates and clean up dirty lists
4199 m_pDoc->enableListUpdates();
4200 m_pDoc->updateDirtyLists();
4201
4202 _generalUpdate();
4203
4204 //
4205 // Do a complete update coz who knows what happened in the undo!
4206 //
4207 PT_DocPosition posEnd = 0;
4208 getEditableBounds(true, posEnd);
4209 bool bOK = true;
4210 bool bMoved = false;
4211 while(bOK && !isPointLegal() && (getPoint() < posEnd))
4212 {
4213 bOK = _charMotion(true,1);
4214 bMoved = true;
4215 }
4216 if(getPoint() > posEnd)
4217 {
4218 setPoint(posEnd);
4219 bMoved = true;
4220 }
4221
4222 bOK = true;
4223 while(bOK && !isPointLegal() && (getPoint() > 2))
4224 {
4225 bOK = _charMotion(false,1);
4226 bMoved = true;
4227 }
4228 if(!bMoved && (getPoint() != posEnd) )
4229 {
4230 bOK = _charMotion(true,1);
4231 bOK = _charMotion(false,1);
4232 }
4233
4234 setCursorToContext();
4235 _updateInsertionPoint();
4236 notifyListeners(AV_CHG_ALL);
4237
4238 // Reenable smart quotes
4239 m_bAllowSmartQuoteReplacement = true;
4240 }
4241
cmdSave(void)4242 UT_Error FV_View::cmdSave(void)
4243 {
4244 // transfer any persistent properties into the doc
4245 const gchar ** ppProps = getViewPersistentProps();
4246 m_pDoc->setProperties(ppProps);
4247 _updateDatesBeforeSave(false);
4248
4249 UT_Error tmpVar;
4250 tmpVar = m_pDoc->save();
4251 if (!tmpVar)
4252 {
4253 notifyListeners(AV_CHG_SAVE);
4254 }
4255 return tmpVar;
4256 }
4257
cmdSaveAs(const char * szFilename,int ieft,bool cpy)4258 UT_Error FV_View::cmdSaveAs(const char * szFilename, int ieft, bool cpy)
4259 {
4260 // transfer any persistent properties into the doc
4261 const gchar ** ppProps = getViewPersistentProps();
4262 m_pDoc->setProperties(ppProps);
4263 _updateDatesBeforeSave(true);
4264
4265 UT_Error tmpVar;
4266 tmpVar = static_cast<AD_Document*>(m_pDoc)->saveAs(szFilename, ieft, cpy);
4267 if (!tmpVar && cpy)
4268 {
4269 notifyListeners(AV_CHG_SAVE);
4270 }
4271 return tmpVar;
4272 }
4273
cmdSaveAs(const char * szFilename,int ieft)4274 UT_Error FV_View::cmdSaveAs(const char * szFilename, int ieft)
4275 {
4276 return cmdSaveAs(szFilename, ieft, true);
4277 }
4278
4279
cmdCut(void)4280 void FV_View::cmdCut(void)
4281 {
4282 if (isSelectionEmpty())
4283 {
4284 // clipboard does nothing if there is no selection
4285 return;
4286 }
4287 if(m_Selection.getSelectionMode() == FV_SelectionMode_TableColumn)
4288 {
4289 PD_DocumentRange * pDR = m_Selection.getNthSelection(0);
4290 PT_DocPosition pos = 0;
4291 if(pDR)
4292 {
4293 pos = pDR->m_pos1 +1;
4294 }
4295 else
4296 {
4297 pos = getSelectionAnchor();
4298 if(pos > getPoint())
4299 {
4300 pos = getPoint();
4301 }
4302 }
4303 _clearSelection();
4304 cmdDeleteCol(pos);
4305 return;
4306 }
4307 if(m_Selection.getSelectionMode() == FV_SelectionMode_TableRow)
4308 {
4309 PD_DocumentRange * pDR = m_Selection.getNthSelection(0);
4310 PT_DocPosition pos = 0;
4311 if(pDR)
4312 {
4313 pos = pDR->m_pos1 +1;
4314 }
4315 else
4316 {
4317 pos = getSelectionAnchor();
4318 if(pos > getPoint())
4319 {
4320 pos = getPoint();
4321 }
4322 }
4323 _clearSelection();
4324 cmdDeleteRow(pos);
4325 return;
4326 }
4327 // Signal PieceTable Change
4328 m_pDoc->notifyPieceTableChangeStart();
4329
4330 //
4331 // Disable list updates until after we've finished
4332 //
4333 m_pDoc->disableListUpdates();
4334 cmdCopy(true);
4335 _deleteSelection();
4336
4337 // Signal PieceTable Changes have finished
4338 m_pDoc->notifyPieceTableChangeEnd();
4339 m_iPieceTableState = 0;
4340 _generalUpdate();
4341
4342 // restore updates and clean up dirty lists
4343 m_pDoc->enableListUpdates();
4344 m_pDoc->updateDirtyLists();
4345
4346 _setPoint(getPoint());
4347 _fixInsertionPointCoords();
4348 _ensureInsertionPointOnScreen();
4349 notifyListeners(AV_CHG_ALL);
4350
4351 m_SelectionHandles.hide();
4352 }
4353
4354 // bToClipboard is true if you want to copy to the CLIPBOARD
4355 // selection on UNIX, as opposed to some PRIMARY selection
cmdCopy(bool bToClipboard)4356 void FV_View::cmdCopy(bool bToClipboard)
4357 {
4358 if (isSelectionEmpty())
4359 {
4360 // clipboard does nothing if there is no selection
4361 return;
4362 }
4363
4364 PD_DocumentRange dr;
4365 getDocumentRangeOfCurrentSelection(&dr);
4366 m_pApp->copyToClipboard(&dr, bToClipboard);
4367 notifyListeners(AV_CHG_CLIPBOARD);
4368 }
4369
cmdPaste(bool bHonorFormatting)4370 void FV_View::cmdPaste(bool bHonorFormatting)
4371 {
4372 //
4373 // Look to see if should paste a table column or row
4374 //
4375
4376 STD_DOUBLE_BUFFERING_FOR_THIS_FUNCTION
4377
4378 if((m_Selection.getPrevSelectionMode() == FV_SelectionMode_TableColumn)
4379 || (m_Selection.getPrevSelectionMode() == FV_SelectionMode_TableRow))
4380 {
4381 if(isInTable())
4382 {
4383 fl_TableLayout * pTab = getTableAtPos(getPoint());
4384 if(pTab && pTab == m_Selection.getTableLayout())
4385 {
4386 m_Selection.pasteRowOrCol();
4387
4388 // FIXME does this section get affected
4389 // by scrolling too?
4390
4391 return;
4392 }
4393 }
4394 }
4395
4396 // set UAG markers around everything that the actual paste does
4397 // so that undo/redo will treat it as one step.
4398
4399 m_pDoc->beginUserAtomicGlob();
4400
4401 // Signal PieceTable Change
4402 m_pDoc->notifyPieceTableChangeStart();
4403
4404 //
4405 // Disable list updates until after we've finished
4406 //
4407 m_pDoc->disableListUpdates();
4408 m_pDoc->setDoingPaste();
4409 setCursorWait();
4410 m_pDoc->setDontImmediatelyLayout(true);
4411 _doPaste(true, bHonorFormatting);
4412 // restore updates and clean up dirty lists
4413 m_pDoc->enableListUpdates();
4414 m_pDoc->updateDirtyLists();
4415 clearCursorWait();
4416
4417 // Signal PieceTable Changes have finished
4418 m_pDoc->notifyPieceTableChangeEnd();
4419 m_iPieceTableState = 0;
4420
4421 m_pDoc->clearDoingPaste();
4422 m_pDoc->endUserAtomicGlob();
4423 m_iPieceTableState = 0;
4424 // Move insertion point out of field run if it is in one
4425 //
4426 _charMotion(true, 0);
4427 _makePointLegal();
4428 //
4429 // Do a complete update coz who knows what happened in the paste!
4430 //
4431
4432 // force update the screen before leaving the current view
4433
4434 _fixInsertionPointCoords();
4435 _ensureInsertionPointOnScreen();
4436 notifyListeners(AV_CHG_ALL);
4437
4438 }
4439
cmdPasteSelectionAt(UT_sint32 xPos,UT_sint32 yPos)4440 void FV_View::cmdPasteSelectionAt(UT_sint32 xPos, UT_sint32 yPos)
4441 {
4442 // this is intended for the X11 middle mouse paste trick.
4443 //
4444 // if this view has the selection, we need to remember it
4445 // before we warp to the given (x,y) -- or else there won't
4446 // be a selection to paste when get there. this is sort of
4447 // back door hack and should probably be re-thought.
4448
4449 // set UAG markers around everything that the actual paste does
4450 // so that undo/redo will treat it as one step.
4451
4452 m_pDoc->beginUserAtomicGlob();
4453
4454 // Signal PieceTable Change
4455 _saveAndNotifyPieceTableChange();
4456
4457 if (!isSelectionEmpty())
4458 m_pApp->cacheCurrentSelection(this);
4459 cmdCopy(false);
4460 warpInsPtToXY(xPos,yPos,true);
4461 _doPaste(false, true);
4462 m_pApp->cacheCurrentSelection(NULL);
4463
4464 // Signal PieceTable Changes have finished
4465 _restorePieceTableState();
4466 _fixInsertionPointCoords();
4467 _ensureInsertionPointOnScreen();
4468
4469 m_pDoc->endUserAtomicGlob();
4470 m_prevMouseContext = EV_EMC_TEXT;
4471 notifyListeners(AV_CHG_ALL);
4472 }
4473
cmdDeleteBookmark(const char * szName)4474 UT_Error FV_View::cmdDeleteBookmark(const char* szName)
4475 {
4476 return _deleteBookmark(szName, true);
4477 }
4478
cmdDeleteHyperlink()4479 UT_Error FV_View::cmdDeleteHyperlink()
4480 {
4481 PT_DocPosition pos = getPoint();
4482 UT_DEBUGMSG(("fv_View::cmdDeleteHyperlink: pos %d\n", pos));
4483 UT_Error err= _deleteHyperlink(pos,true);
4484 m_prevMouseContext = EV_EMC_TEXT;
4485 setCursorToContext();
4486 notifyListeners(AV_CHG_ALL);
4487 return err;
4488 }
4489
4490
cmdHyperlinkStatusBar(UT_sint32 xPos,UT_sint32 yPos)4491 UT_Error FV_View::cmdHyperlinkStatusBar(UT_sint32 xPos, UT_sint32 yPos)
4492 {
4493 UT_sint32 xClick, yClick;
4494 fp_Page* pPage = _getPageForXY(xPos, yPos, xClick, yClick);
4495
4496 PT_DocPosition pos;
4497 bool bBOL = false;
4498 bool bEOL = false;
4499 bool isTOC = false;
4500 pPage->mapXYToPosition(xClick, yClick, pos, bBOL, bEOL,isTOC);
4501
4502 // now get the run at the position and the hyperlink run
4503 fp_HyperlinkRun * pH1 = 0;
4504
4505 fl_BlockLayout *pBlock = _findBlockAtPosition(pos);
4506 PT_DocPosition curPos = pos - pBlock->getPosition(false);
4507
4508 fp_Run * pRun = pBlock->getFirstRun();
4509
4510 //find the run at pos1
4511 while(pRun && pRun->getBlockOffset() <= curPos)
4512 pRun = pRun->getNextRun();
4513
4514 // this sometimes happens, not sure why
4515 //UT_ASSERT(pRun);
4516 if(!pRun)
4517 return false;
4518
4519 // now we have the run immediately after the run in question, so
4520 // we step back
4521 pRun = pRun->getPrevRun();
4522 UT_ASSERT(pRun);
4523 if(!pRun)
4524 return false;
4525
4526 xxx_UT_DEBUGMSG(("fv_View::cmdHyperlinkStatusBar: run 0x%x, type %d\n", pRun,pRun->getType()));
4527 pH1 = pRun->getHyperlink();
4528
4529 // this happens after a deletion of a hyperlink
4530 // the mouse processing is in the state of belief
4531 // that the processing has not finished yet -- this is not specific
4532 // to hyperlinks, it happens with anything on the context menu, except
4533 // it goes unobserved since the cursor does not change
4534 //UT_ASSERT(pH1);
4535 if(!pH1)
4536 return false;
4537 xxx_UT_DEBUGMSG(("fv_View::cmdHyperlinkStatusBar: msg [%s]\n",pH1->getTarget()));
4538 XAP_Frame * pFrame = static_cast<XAP_Frame *> (getParentData());
4539 if(pH1->getHyperlinkType() == HYPERLINK_NORMAL)
4540 {
4541 UT_UTF8String url = pH1->getTarget();
4542 url.decodeURL();
4543 pFrame->setStatusMessage(url.utf8_str());
4544 }
4545 else
4546 {
4547 if(!isAnnotationPreviewActive())
4548 {
4549 UT_DEBUGMSG(("popup Annotation preview \n"));
4550 }
4551 }
4552 return true;
4553 }
4554
cmdEditAnnotationWithDialog(UT_uint32 aID)4555 bool FV_View::cmdEditAnnotationWithDialog(UT_uint32 aID)
4556 {
4557 // kill the annotation preview popup if needed
4558 if(isAnnotationPreviewActive())
4559 killAnnotationPreview();
4560
4561 //
4562 // Get the text fromt he annotation
4563 //
4564
4565 // TODO maybe we should not exit if annotation is not present (ex. auto-generated annotations may become not be editable!)
4566 std::string sText;
4567 std::string sTitle2;
4568 std::string sAuthor2;
4569 bool b = getAnnotationText(aID,sText);
4570 if(!b)
4571 return false;
4572
4573 // Optional fields
4574 getAnnotationTitle(aID,sTitle2);
4575 getAnnotationAuthor(aID,sAuthor2);
4576
4577 // edit annotation
4578
4579 XAP_Frame * pFrame = static_cast<XAP_Frame *> (getParentData());
4580 UT_return_val_if_fail(pFrame, false);
4581
4582 XAP_App * pApp = XAP_App::getApp();
4583 UT_return_val_if_fail (pApp, false);
4584
4585 pFrame->raise();
4586
4587 XAP_DialogFactory * pDialogFactory
4588 = static_cast<XAP_DialogFactory *>(pFrame->getDialogFactory());
4589
4590 AP_Dialog_Annotation * pDialog
4591 = static_cast<AP_Dialog_Annotation *>(pDialogFactory->requestDialog(AP_DIALOG_ID_ANNOTATION));
4592 UT_return_val_if_fail (pDialog, false);
4593
4594 // set initial annotation properties
4595 // TODO add support for all fields
4596 pDialog->setTitle(sTitle2);
4597 pDialog->setAuthor(sAuthor2);
4598 pDialog->setDescription(sText);
4599
4600 // run the dialog
4601
4602 UT_DEBUGMSG(("cmdEditAnnotationWithDialog: Drawing annotation dialog...\n"));
4603 pDialog->runModal(pFrame);
4604 bool bOK = (pDialog->getAnswer() == AP_Dialog_Annotation::a_OK);
4605 bool bApply = (pDialog->getAnswer() == AP_Dialog_Annotation::a_APPLY);
4606 fl_AnnotationLayout * pAL = NULL;
4607
4608 if (bOK)
4609 {
4610 UT_DEBUGMSG(("cmdEditAnnotationWithDialog: Annotation id(\"%d\") edited \n",aID));
4611
4612 for(UT_sint32 i = 0;i < pApp->getFrameCount();++i)
4613 {
4614 pApp->getFrame(i)->updateTitle ();
4615 }
4616
4617 const std::string & sDescr = pDialog->getDescription();
4618 const std::string & sTitle = pDialog->getTitle();
4619 const std::string & sAuthor = pDialog->getAuthor();
4620 // bool bReplaceSelection = false;
4621
4622 b = setAnnotationText(aID,sDescr,sAuthor,sTitle);
4623 }
4624 else if (bApply)
4625 {
4626 pAL = insertAnnotationDescription(aID, pDialog);
4627 UT_return_val_if_fail(pAL, false);
4628 }
4629 // release the dialog
4630 pDialogFactory->releaseDialog(pDialog);
4631 //
4632 // Select the text
4633 //
4634 pAL = getAnnotationLayout(aID);
4635 if(!pAL)
4636 return false;
4637 selectAnnotation(pAL);
4638
4639 return true;
4640 }
4641
insertAnnotationDescription(UT_uint32 aID,AP_Dialog_Annotation * pDialog)4642 fl_AnnotationLayout *FV_View::insertAnnotationDescription(UT_uint32 aID, AP_Dialog_Annotation *pDialog)
4643 {
4644 fl_AnnotationLayout *pAL = getAnnotationLayout(aID);
4645 UT_return_val_if_fail(pAL, NULL);
4646
4647 UT_UCS4String sDescr(pDialog->getDescription());
4648 pf_Frag_Strux *sdhAnn = pAL->getStruxDocHandle();
4649 pf_Frag_Strux *sdhEnd = NULL;
4650
4651 getDocument()->getNextStruxOfType(sdhAnn, PTX_EndAnnotation, &sdhEnd);
4652 UT_return_val_if_fail(sdhEnd, NULL);
4653
4654 // Start of the text covered by the annotations
4655 PT_DocPosition posStart = getDocument()->getStruxPosition(sdhEnd);
4656 posStart++;
4657
4658 fp_Run *pRun = getHyperLinkRun(posStart);
4659 UT_return_val_if_fail(pRun, NULL);
4660
4661 pRun = pRun->getNextRun();
4662 while (pRun && (pRun->getType() != FPRUN_HYPERLINK))
4663 pRun = pRun->getNextRun();
4664 UT_return_val_if_fail(pRun, NULL);
4665 UT_return_val_if_fail(pRun->getType() == FPRUN_HYPERLINK, NULL);
4666
4667 PT_DocPosition posEnd = pRun->getBlock()->getPosition(false) + pRun->getBlockOffset();
4668
4669 if(posStart > posEnd)
4670 posStart = posEnd;
4671
4672 cmdSelect(posStart, posEnd);
4673 cmdCharInsert(sDescr.ucs4_str(), sDescr.size());
4674
4675 return pAL;
4676 }
4677
cmdInsertHyperlink(const char * szName,const char * szTitle)4678 UT_Error FV_View::cmdInsertHyperlink(const char * szName, const char * szTitle)
4679 {
4680 bool bRet;
4681
4682 PT_DocPosition posStart = getPoint();
4683 PT_DocPosition posEnd = posStart;
4684 PT_DocPosition iPointOrig = posStart;
4685 PT_DocPosition iAnchorOrig = m_Selection.getSelectionAnchor();
4686
4687 if (!isSelectionEmpty())
4688 {
4689 if (m_Selection.getSelectionAnchor() < posStart)
4690 {
4691 posStart = m_Selection.getSelectionAnchor();
4692 }
4693 else
4694 {
4695 posEnd = m_Selection.getSelectionAnchor();
4696 }
4697
4698 }
4699 else
4700 {
4701 //No selection
4702 XAP_Frame * pFrame = static_cast<XAP_Frame *>(getParentData());
4703 UT_ASSERT((pFrame));
4704
4705 pFrame->showMessageBox(AP_STRING_ID_MSG_HyperlinkNoSelection, XAP_Dialog_MessageBox::b_O, XAP_Dialog_MessageBox::a_OK);
4706 return false;
4707 }
4708
4709 bool relLink = false;
4710 if (!UT_go_path_is_uri(szName))
4711 relLink = m_pDoc->isBookmarkRelativeLink(szName);
4712 // TODO: After strings freeze is lifted, we should
4713 // TODO: display a message if relLink is true but
4714 // TODO: szName does not stat.
4715
4716 if(!UT_go_path_is_uri(szName) && m_pDoc->isBookmarkUnique(szName) && !relLink)
4717 {
4718 //No bookmark of that name in document, tell user.
4719 XAP_Frame * pFrame = static_cast<XAP_Frame *>(getParentData());
4720 UT_ASSERT((pFrame));
4721
4722 pFrame->showMessageBox(AP_STRING_ID_MSG_HyperlinkNoBookmark,
4723 XAP_Dialog_MessageBox::b_O,
4724 XAP_Dialog_MessageBox::a_OK,
4725 szName);
4726 }
4727
4728 // Hack for bug 2940
4729 if (posStart == 1) posStart++;
4730
4731 // the selection has to be within a single block
4732 // we could implement hyperlinks spaning arbitrary part of the document
4733 // but then we could not use <a href=> </a> in the output and
4734 // I see no obvious need for hyperlinks to span more than a single block
4735 fl_BlockLayout * pBl1 = _findBlockAtPosition(posStart);
4736 fl_BlockLayout * pBl2 = _findBlockAtPosition(posEnd);
4737 //
4738 // Handle corner case of selection from outside the left column
4739 //
4740 if(isInFootnote(posStart))
4741 {
4742 if((pBl1 != NULL) && (pBl1->getPosition(true) == posStart))
4743 {
4744 if(posEnd > posStart+1)
4745 {
4746 posStart++;
4747 }
4748 }
4749 }
4750 if(isInEndnote(posStart))
4751 {
4752 if((pBl1 != NULL) && (pBl1->getPosition(true) == posStart))
4753 {
4754 if(posEnd > posStart+1)
4755 {
4756 posStart++;
4757 }
4758 }
4759 }
4760 if(pBl1 != pBl2)
4761 {
4762 XAP_Frame * pFrame = static_cast<XAP_Frame *>(getParentData());
4763 UT_ASSERT((pFrame));
4764
4765 pFrame->showMessageBox(AP_STRING_ID_MSG_HyperlinkCrossesBoundaries, XAP_Dialog_MessageBox::b_O, XAP_Dialog_MessageBox::a_OK);
4766
4767 return false;
4768 }
4769 if(isTOCSelected())
4770 {
4771 //
4772 // Fixme place message box here
4773 //
4774 return false;
4775
4776 }
4777 // Silently fail (TODO: pop up message) if we try to nest hyperlinks.
4778 if (_getHyperlinkInRange(posStart, posEnd) != NULL)
4779 return false;
4780 //
4781 // Under sum1 induced conditions posEnd could give the same block pointer
4782 // despite being past the end of the block. This extra fail-safe code
4783 // prevents this.
4784 //
4785 if((pBl1->getPosition() + pBl1->getLength() -1) < posEnd)
4786 {
4787 return false;
4788 }
4789
4790 std::string target;
4791
4792 if(UT_go_path_is_uri(szName) || relLink)
4793 {
4794 target = szName;
4795 }
4796 else
4797 {
4798 target = "#";
4799 target += szName;
4800 }
4801
4802 std::string title;
4803 if (szTitle && *szTitle)
4804 {
4805 title = szTitle;
4806 }
4807
4808 const gchar * pAttr[6];
4809 int attr = 0;
4810
4811 pAttr [attr++] = "xlink:href";
4812 pAttr [attr++] = target.c_str();
4813 if (szTitle && *szTitle)
4814 {
4815 pAttr [attr++] = "xlink:title";
4816 pAttr [attr++] = title.c_str();
4817 }
4818 pAttr[attr++] = 0;
4819 pAttr[attr++] = 0;
4820
4821 UT_DEBUGMSG(("fv_View::cmdInsertHyperlink: target \"%s\"\n", target.c_str()));
4822
4823 // Signal PieceTable Change
4824 _saveAndNotifyPieceTableChange();
4825
4826 // we first insert the end run, so that we can use it as a stop
4827 // after inserting the start run when marking the runs in between
4828 // as a hyperlink
4829 bRet = m_pDoc->insertObject(posEnd, PTO_Hyperlink, NULL, NULL);
4830
4831 if(bRet)
4832 {
4833 const gchar ** pAttrs = pAttr;
4834 const gchar ** pProps = 0;
4835 bRet = m_pDoc->insertObject(posStart, PTO_Hyperlink, pAttrs, pProps);
4836 }
4837
4838 if(bRet)
4839 {
4840 // because we have inserted two objects around the selection
4841 // boundaries the original insetion point and selection anchor
4842 // are now shifted, so we need to fix them
4843 setPoint(iPointOrig+1);
4844 m_Selection.setSelectionAnchor(iAnchorOrig + 1);
4845 }
4846
4847 // Signal piceTable is stable again
4848 _restorePieceTableState();
4849
4850 _generalUpdate();
4851
4852 return bRet;
4853
4854 }
4855
4856 /******************************************************************/
4857
getCmdInsertRangeVariables(PT_DocPosition & posStart,PT_DocPosition & posEnd,fl_BlockLayout * & pBL1,fl_BlockLayout * & pBL2)4858 void FV_View::getCmdInsertRangeVariables( PT_DocPosition& posStart,
4859 PT_DocPosition& posEnd,
4860 fl_BlockLayout*& pBL1,
4861 fl_BlockLayout*& pBL2 )
4862 {
4863 posStart = getPoint();
4864 posEnd = posStart;
4865
4866 if (!isSelectionEmpty())
4867 {
4868 if (m_Selection.getSelectionAnchor() < posStart)
4869 {
4870 posStart = m_Selection.getSelectionAnchor();
4871 }
4872 else
4873 {
4874 posEnd = m_Selection.getSelectionAnchor();
4875 }
4876 }
4877
4878 // we cannot bookmark lesser position than 2, because the bookmark object has to be located
4879 // withing a block; this was the cause of bug 7128
4880 // (we might consider one day to allow the bookmark object before the first block strux, but the
4881 // complications this would cause are possibly not worth it)
4882 if(posStart < 2)
4883 posStart = 2;
4884
4885 posEnd++;
4886
4887 pBL1 =_findBlockAtPosition(posStart);
4888 pBL2 =_findBlockAtPosition(posEnd);
4889
4890 //
4891 // Handle corner case of selection from outside the left column
4892 //
4893 if((pBL1!= NULL) && isInFootnote(posStart) && (pBL1->getPosition(true) == posStart))
4894 {
4895 if(posEnd > posStart+1)
4896 {
4897 posStart++;
4898 }
4899 }
4900 if((pBL1 != NULL) && isInEndnote(posStart) && (pBL1->getPosition(true) == posStart))
4901 {
4902 if(posEnd > posStart+1)
4903 {
4904 posStart++;
4905 }
4906 }
4907 }
4908
4909
cmdInsertBookmark(const char * szName)4910 UT_Error FV_View::cmdInsertBookmark(const char * szName)
4911 {
4912 // Signal PieceTable Change
4913 _saveAndNotifyPieceTableChange();
4914 bool bRet;
4915
4916 PT_DocPosition posStart = 0, posEnd = 0;
4917 fl_BlockLayout* pBL1 = 0;
4918 fl_BlockLayout* pBL2 = 0;
4919 getCmdInsertRangeVariables( posStart, posEnd, pBL1, pBL2 );
4920
4921 if(pBL1 != pBL2)
4922 {
4923 //
4924 // Fixme put message boxes here
4925 //
4926 _restorePieceTableState();
4927 return false;
4928 }
4929 if(isTOCSelected())
4930 {
4931 //
4932 // Fixme put message boxes here
4933 //
4934 _restorePieceTableState();
4935 return false;
4936 }
4937
4938 if(!m_pDoc->isBookmarkUnique(static_cast<const gchar*>(szName)))
4939 {
4940 XAP_Frame * pFrame = static_cast<XAP_Frame *>(getParentData());
4941 XAP_Dialog_MessageBox::tAnswer ans = XAP_Dialog_MessageBox::a_NO;
4942
4943 if(pFrame)
4944 ans = pFrame->showMessageBox(AP_STRING_ID_MSG_BookmarkAlreadyExists,
4945 XAP_Dialog_MessageBox::b_YN, XAP_Dialog_MessageBox::a_NO);
4946
4947 if(ans == XAP_Dialog_MessageBox::a_YES)
4948 {
4949 //bookmark already exists -- remove it and then reinsert
4950 UT_DEBUGMSG(("fv_View::cmdInsertBookmark: bookmark \"%s\" exists - removing\n", szName));
4951 _deleteBookmark(static_cast<const gchar*>(szName), false, &posStart, &posEnd);
4952 }
4953 else
4954 {
4955 xxx_UT_DEBUGMSG(("User canceled bookmark replacement\n"));
4956 return false;
4957 }
4958 }
4959
4960 const gchar* pAttr[6];
4961
4962 char name[BOOKMARK_NAME_SIZE + 1];
4963 strncpy(name, szName, BOOKMARK_NAME_SIZE);
4964 name[BOOKMARK_NAME_SIZE] = 0;
4965
4966 pAttr [0] = "name";
4967 pAttr [1] = name;
4968 pAttr [2] = "type";
4969 pAttr [3] = "start";
4970 pAttr [4] = 0;
4971 pAttr [5] = 0;
4972
4973 UT_DEBUGMSG(("fv_View::cmdInsertBookmark: szName \"%s\"\n", szName));
4974
4975 const gchar ** pProps = 0;
4976 bRet = m_pDoc->insertObject(posStart, PTO_Bookmark, pAttr, pProps);
4977
4978 if(bRet)
4979 {
4980 // override the type to mark the end.
4981 pAttr [3] = "end";
4982 bRet = m_pDoc->insertObject(posEnd, PTO_Bookmark, pAttr, pProps);
4983 }
4984
4985
4986 // Signal piceTable is stable again
4987 _restorePieceTableState();
4988 _generalUpdate();
4989
4990 return bRet;
4991
4992 }
4993
4994 UT_Error
cmdInsertXMLID(const std::string & xmlid)4995 FV_View::cmdInsertXMLID( const std::string& xmlid )
4996 {
4997 UT_DEBUGMSG(("fv_View::cmdInsertXMLID: xmlid:%s\n", xmlid.c_str()));
4998
4999 // Signal PieceTable Change
5000 _saveAndNotifyPieceTableChange();
5001 UT_Error ret;
5002
5003 PT_DocPosition posStart = 0, posEnd = 0;
5004 fl_BlockLayout* pBL1 = 0;
5005 fl_BlockLayout* pBL2 = 0;
5006 getCmdInsertRangeVariables( posStart, posEnd, pBL1, pBL2 );
5007 UT_DEBUGMSG(("fv_View::cmdInsertXMLID: posStart:%d posEnd:%d\n", posStart, posEnd ));
5008
5009 if(pBL1 != pBL2)
5010 {
5011 //
5012 // Fixme put message boxes here
5013 //
5014 UT_DEBUGMSG(("fv_View::cmdInsertXMLID: range contains different blocks! xmlid \"%s\"\n", xmlid.c_str()));
5015 _restorePieceTableState();
5016 return UT_ERROR;
5017 }
5018 if(isTOCSelected())
5019 {
5020 //
5021 // Fixme put message boxes here
5022 //
5023 UT_DEBUGMSG(("fv_View::cmdInsertXMLID: can't insert xmlid in TOC! xmlid \"%s\"\n", xmlid.c_str()));
5024 _restorePieceTableState();
5025 return UT_ERROR;
5026 }
5027
5028 PD_DocumentRDFHandle rdf = m_pDoc->getDocumentRDF();
5029 std::set< std::string > allIDs;
5030 rdf->getAllIDs( allIDs );
5031 if( allIDs.count( xmlid ))
5032 {
5033 UT_DEBUGMSG(("fv_View::cmdInsertXMLID: xmlid already in use... %s\n", xmlid.c_str()));
5034 XAP_Frame * pFrame = static_cast<XAP_Frame *>(getParentData());
5035 XAP_Dialog_MessageBox::tAnswer ans = XAP_Dialog_MessageBox::a_NO;
5036
5037 if(pFrame)
5038 ans = pFrame->showMessageBox(AP_STRING_ID_MSG_XMLIDAlreadyExists,
5039 XAP_Dialog_MessageBox::b_YN, XAP_Dialog_MessageBox::a_NO);
5040
5041 if(ans == XAP_Dialog_MessageBox::a_YES)
5042 {
5043 // already exists -- remove it and then reinsert
5044 UT_DEBUGMSG(("fv_View::cmdInsertXMLID: xmlid:%s exists - removing\n", xmlid.c_str()));
5045 _deleteXMLID( xmlid, false, posStart, posEnd );
5046 }
5047 else
5048 {
5049 xxx_UT_DEBUGMSG(("User canceled xmlid replacement\n"));
5050 return UT_OK;
5051 }
5052 }
5053
5054 const gchar* pa[10] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
5055 pa[0] = PT_XMLID;
5056 pa[1] = xmlid.c_str();
5057 // sanity check
5058 pa[2] = "this-is-an-rdf-anchor";
5059 pa[3] = "yes";
5060
5061 UT_DEBUGMSG(("fv_View::cmdInsertXMLID: inserting xmlid:%s at posStart:%d posEnd:%d\n",
5062 xmlid.c_str(), posStart, posEnd ));
5063
5064 const gchar ** pAttrs = const_cast<const gchar **>(pa);
5065 const gchar ** pProps = 0;
5066 bool bRet = m_pDoc->insertObject(posStart, PTO_RDFAnchor, pAttrs, pProps);
5067 if(bRet)
5068 {
5069 pa[4] = PT_RDF_END;
5070 pa[5] = "yes";
5071 bRet = m_pDoc->insertObject(posEnd, PTO_RDFAnchor, pAttrs, pProps);
5072 }
5073
5074 if( bRet ) ret = UT_OK;
5075 else ret = UT_ERROR;
5076
5077 // Signal piceTable is stable again
5078 _restorePieceTableState();
5079 _generalUpdate();
5080
5081 return ret;
5082 }
5083
5084 UT_Error
cmdDeleteXMLID(const std::string & xmlid)5085 FV_View::cmdDeleteXMLID( const std::string& xmlid )
5086 {
5087 return _deleteXMLID( xmlid, true);
5088 }
5089
5090
5091 /*****************************************************************/
5092
5093
cmdInsertTOC(void)5094 UT_Error FV_View::cmdInsertTOC(void)
5095 {
5096 // Signal PieceTable Change
5097 _saveAndNotifyPieceTableChange();
5098 m_pDoc->beginUserAtomicGlob();
5099 bool bRet = false; // was not initialised; since ret value is
5100 // UT_Error, false should correspond to OK. Tomas
5101
5102
5103 if (!isSelectionEmpty())
5104 {
5105 _deleteSelection();
5106 _generalUpdate();
5107 fl_BlockLayout * pBL = _findBlockAtPosition(getPoint());
5108 if(pBL != NULL)
5109 {
5110 fl_ContainerLayout * pCL = pBL->myContainingLayout();
5111 if(pCL->getContainerType() != FL_CONTAINER_DOCSECTION)
5112 {
5113 m_pDoc->endUserAtomicGlob();
5114
5115 // Signal piceTable is stable again
5116 _restorePieceTableState();
5117 _generalUpdate();
5118 notifyListeners(AV_CHG_MOTION | AV_CHG_ALL);
5119 return bRet;
5120 }
5121 }
5122 else
5123 {
5124 m_pDoc->endUserAtomicGlob();
5125
5126 // Signal piceTable is stable again
5127 _restorePieceTableState();
5128 _generalUpdate();
5129 notifyListeners(AV_CHG_MOTION | AV_CHG_ALL);
5130 return bRet;
5131 }
5132 }
5133 //
5134 // Check if there is a hyperlink here
5135 //
5136 if(getHyperLinkRun(getPoint()) != NULL)
5137 {
5138 return false;
5139 }
5140 if(!isPointLegal())
5141 {
5142 _charMotion(true,1);
5143 }
5144 PT_DocPosition posEnd = 0;
5145 getEditableBounds(true, posEnd);
5146 if(getPoint() >= posEnd && !isPointLegal())
5147 {
5148 _charMotion(false,1);
5149 }
5150 //
5151 // Close off the current block
5152 //
5153 insertParagraphBreak();
5154 //
5155 // insert just before this block to make the TOC gets inserted just BEFORE
5156 // the Block we just created.
5157 //
5158 // we want this sort of structure in the PT
5159 //
5160 // <Strux Block><Frag><frag><frag><TOC></TOC><Strux Block>|
5161 // |
5162 // Point is here after insert TOC-------------------------|
5163 //
5164 fl_BlockLayout * pBL = getCurrentBlock();
5165 PT_DocPosition pos = pBL->getPosition(true);
5166 if((pBL->getNext() == NULL) || (pBL->getPrev() == NULL))
5167 {
5168 insertParagraphBreak();
5169 pBL = getCurrentBlock();
5170 pos = pBL->getPosition(true);
5171 }
5172 if(pBL != NULL)
5173 {
5174 fl_ContainerLayout * pCL = pBL->myContainingLayout();
5175 if(pCL->getContainerType() != FL_CONTAINER_DOCSECTION)
5176 {
5177 // Signal piceTable is stable again
5178 _restorePieceTableState();
5179 _generalUpdate();
5180 m_pDoc->endUserAtomicGlob();
5181
5182 notifyListeners(AV_CHG_MOTION | AV_CHG_ALL);
5183 return bRet;
5184 }
5185 }
5186 else
5187 {
5188
5189 // Signal piceTable is stable again
5190 _restorePieceTableState();
5191 _generalUpdate();
5192 m_pDoc->endUserAtomicGlob();
5193 notifyListeners(AV_CHG_MOTION | AV_CHG_ALL);
5194 return bRet;
5195 }
5196 m_pDoc->insertStrux(pos,PTX_SectionTOC);
5197 pos++;
5198 m_pDoc->insertStrux(pos,PTX_EndTOC);
5199 setPoint(pos+1);
5200 insertParaBreakIfNeededAtPos(getPoint());
5201 //
5202 // Now move the point forward until we're in a legal position
5203 //
5204 _makePointLegal();
5205 // Signal piceTable is stable again
5206 _restorePieceTableState();
5207 _generalUpdate();
5208 m_pDoc->endUserAtomicGlob();
5209 notifyListeners(AV_CHG_MOTION | AV_CHG_ALL);
5210
5211 return bRet;
5212
5213 }
5214
5215
5216 /*****************************************************************/
cmdInsertField(const char * szName,const gchar ** extra_attrs,const gchar ** extra_props)5217 UT_Error FV_View::cmdInsertField(const char* szName, const gchar ** extra_attrs, const gchar ** extra_props)
5218 {
5219 bool bResult = true;
5220
5221 /*
5222 currently unused
5223 fl_BlockLayout* pBL = _findBlockAtPosition(getPoint());
5224 */
5225
5226 // Signal PieceTable Change
5227 _saveAndNotifyPieceTableChange();
5228 _insertField(szName, extra_attrs,extra_props);
5229
5230
5231 // Signal PieceTable Changes have finished
5232 _restorePieceTableState();
5233 _generalUpdate();
5234
5235 _fixInsertionPointCoords();
5236 if (!_ensureInsertionPointOnScreen())
5237 {
5238 //
5239 // Handle End of Paragraph case
5240 //
5241 PT_DocPosition posEOD;
5242 getEditableBounds(true, posEOD);
5243 if(getPoint() == posEOD)
5244 {
5245 m_bPointEOL = true;
5246 }
5247 _fixInsertionPointCoords();
5248 }
5249 return bResult;
5250 }
5251
cmdInsertGraphic(FG_Graphic * pFG)5252 UT_Error FV_View::cmdInsertGraphic(FG_Graphic* pFG)
5253 {
5254 bool bDidGlob = false;
5255
5256 // Signal PieceTable Change
5257 _saveAndNotifyPieceTableChange();
5258
5259 if (!isSelectionEmpty() && !m_FrameEdit.isActive())
5260 {
5261 bDidGlob = true;
5262 m_pDoc->beginUserAtomicGlob();
5263 _deleteSelection();
5264 }
5265 else if(m_FrameEdit.isActive())
5266 {
5267 m_FrameEdit.setPointInside();
5268 }
5269 /*
5270 Create a unique identifier for the data item.
5271 */
5272 UT_UUID *uuid = m_pDoc->getNewUUID();
5273 UT_return_val_if_fail(uuid != NULL, UT_ERROR);
5274 UT_UTF8String s;
5275 uuid->toString(s);
5276 DELETEP(uuid);
5277
5278 UT_Error errorCode = _insertGraphic(pFG, s.utf8_str());
5279 if(m_FrameEdit.isActive())
5280 {
5281 m_FrameEdit.setMode(FV_FrameEdit_NOT_ACTIVE);
5282 }
5283
5284 _restorePieceTableState();
5285
5286 _generalUpdate();
5287 if (bDidGlob)
5288 m_pDoc->endUserAtomicGlob();
5289 _updateInsertionPoint();
5290
5291 return errorCode;
5292 }
5293
cmdInsertPositionedGraphic(FG_Graphic * pFG)5294 UT_Error FV_View::cmdInsertPositionedGraphic(FG_Graphic* pFG)
5295 {
5296 fl_BlockLayout * pBlock = NULL;
5297 fp_Run * pRun = NULL;
5298 UT_sint32 xCaret, yCaret;
5299 UT_uint32 heightCaret;
5300 UT_sint32 xCaret2, yCaret2;
5301 bool bDirection;
5302 bool bEOL = false;
5303 _findPositionCoords(getPoint(), bEOL, xCaret, yCaret, xCaret2, yCaret2, heightCaret, bDirection, &pBlock, &pRun);
5304 UT_return_val_if_fail(pBlock,UT_ERROR);
5305 return cmdInsertPositionedGraphic(pFG,xCaret,yCaret);
5306
5307 }
5308
5309
cmdInsertPositionedGraphic(FG_Graphic * pFG,UT_sint32 mouseX,UT_sint32 mouseY)5310 UT_Error FV_View::cmdInsertPositionedGraphic(FG_Graphic* pFG,UT_sint32 mouseX, UT_sint32 mouseY)
5311 {
5312 m_pDoc->beginUserAtomicGlob();
5313
5314 // Signal PieceTable Change
5315 _saveAndNotifyPieceTableChange();
5316
5317 if (!isSelectionEmpty())
5318 {
5319 _clearSelection();
5320 }
5321
5322 /*
5323 Create a unique identifier for the data item.
5324 */
5325 UT_UUID *uuid = m_pDoc->getNewUUID();
5326 UT_return_val_if_fail(uuid != NULL, UT_ERROR);
5327 UT_UTF8String s;
5328 uuid->toString(s);
5329 //
5330 // Find a document position close to the requested position
5331 //
5332 PT_DocPosition pos = getDocPositionFromXY(mouseX,mouseY);
5333 fl_BlockLayout * pBlock = getBlockAtPosition(pos);
5334 fp_Run * pRun = NULL;
5335 bool bEOL,bDir;
5336 bEOL = false;
5337 UT_sint32 x1,y1,x2,y2,iHeight;
5338 if(pBlock)
5339 {
5340 pRun = pBlock->findPointCoords(pos,bEOL,x1,y1,x2,y2,iHeight,bDir);
5341 }
5342 fp_Line * pLine = pRun->getLine();
5343 if(pLine == NULL)
5344 {
5345 return false;
5346 }
5347
5348 // Also get max width, height
5349
5350 fl_DocSectionLayout * pDSL = pBlock->getDocSectionLayout();
5351 double maxW = static_cast<double>(pDSL->getActualColumnWidth())*0.5/UT_LAYOUT_RESOLUTION;
5352 double maxH = static_cast<double>(pDSL->getActualColumnHeight())*0.5/ UT_LAYOUT_RESOLUTION;
5353 //
5354 // OK calculate all the properties of this image
5355 //
5356 UT_String sWidth;
5357 UT_String sHeight;
5358 double ratw = 1.0;
5359 double rath = 1.0;
5360 double rat = 1.0;
5361 double dw = static_cast<double>(pFG->getWidth());
5362 double dh = static_cast<double>(pFG->getHeight());
5363
5364 if(dw > maxW/2.)
5365 {
5366 ratw = maxW/dw;
5367 }
5368 if(dh > maxH/2.)
5369 {
5370 rath = maxH/dh;
5371 }
5372 if(ratw < rath)
5373 {
5374 rat = ratw;
5375 }
5376 else
5377 {
5378 rat = rath;
5379 }
5380 // This preserves the aspect ratio and limits the size of the images
5381 dw = dw*rat;
5382 dh = dh*rat;
5383 sWidth = UT_formatDimensionedValue(dw,"in", NULL);
5384 sHeight = UT_formatDimensionedValue(dh,"in", NULL);
5385 //
5386 // Create a dataid for the object
5387 //
5388
5389 const char * dataID = pFG->createDataItem(m_pDoc,s.utf8_str());
5390 UT_String sFrameProps;
5391 UT_String sProp;
5392 UT_String sVal;
5393 sProp = "frame-type";
5394 sVal = "image";
5395 UT_String_setProperty(sFrameProps,sProp,sVal);
5396 //
5397 // Turn off the borders.
5398 //
5399 sProp = "top-style";
5400 sVal = "none";
5401 UT_String_setProperty(sFrameProps,sProp,sVal);
5402 sProp = "right-style";
5403 UT_String_setProperty(sFrameProps,sProp,sVal);
5404 sProp = "left-style";
5405 UT_String_setProperty(sFrameProps,sProp,sVal);
5406 sProp = "bot-style";
5407 UT_String_setProperty(sFrameProps,sProp,sVal);
5408 //
5409 // Set width/Height
5410 //
5411 sProp = "frame-width";
5412 sVal = sWidth;
5413 UT_String_setProperty(sFrameProps,sProp,sVal);
5414 sProp = "frame-height";
5415 sVal = sHeight;
5416 UT_String_setProperty(sFrameProps,sProp,sVal);
5417 double xpos = 0.0;
5418 double ypos= 0.0;
5419
5420 sProp = "position-to";
5421 sVal = "column-above-text";
5422 UT_String_setProperty(sFrameProps,sProp,sVal);
5423 if(isInHdrFtr(pos))
5424 {
5425 clearHdrFtrEdit();
5426 warpInsPtToXY(0,0,false);
5427 pos = getPoint();
5428 }
5429
5430 //
5431 // Now calculate the Y offset to the Column
5432 //
5433 fp_Column * pCol = static_cast<fp_Column *>(pLine->getColumn());
5434 UT_sint32 ixoff,iyoff;
5435 fp_Page * pPage = pCol->getPage();
5436 pPage->getScreenOffsets(static_cast<fp_Container *>(pCol),ixoff,iyoff);
5437 iHeight = static_cast<UT_sint32>(dh*UT_LAYOUT_RESOLUTION);
5438 UT_sint32 iposy = mouseY - iyoff - iHeight/2;
5439 ypos = static_cast<double>(iposy)/static_cast<double>(UT_LAYOUT_RESOLUTION);
5440 sProp = "frame-col-ypos";
5441 sVal = UT_formatDimensionedValue(ypos,"in", NULL);
5442 UT_String_setProperty(sFrameProps,sProp,sVal);
5443 sProp = "wrap-mode";
5444 sVal = "wrapped-both";
5445 UT_String_setProperty(sFrameProps,sProp,sVal);
5446 UT_sint32 iWidth = static_cast<UT_sint32>(dw*UT_LAYOUT_RESOLUTION);
5447 UT_sint32 iposx = mouseX - ixoff - iWidth/2;
5448 UT_sint32 iColW = static_cast<UT_sint32>(maxW*2.*UT_LAYOUT_RESOLUTION);
5449 if((iposx + iWidth) > (pCol->getX() + iColW))
5450 {
5451 iposx = iColW - iWidth - pCol->getX();
5452 }
5453 if(iposx < pCol->getX())
5454 {
5455 iposx = 0;
5456 }
5457
5458 UT_DEBUGMSG(("iposx %d pCol->getX() %d \n",iposx,pCol->getX()));
5459 xpos = static_cast<double>(iposx)/static_cast<double>(UT_LAYOUT_RESOLUTION);
5460
5461 sProp = "frame-col-xpos";
5462 sVal = UT_formatDimensionedValue(xpos,"in", NULL);
5463 UT_DEBUGMSG((" %s %s \n",sProp.c_str(),sVal.c_str()));
5464 UT_String_setProperty(sFrameProps,sProp,sVal);
5465 //
5466 // Wrapped Mode
5467 //
5468 sProp = "wrap-mode";
5469 sVal = "wrapped-both";
5470 UT_String_setProperty(sFrameProps,sProp,sVal);
5471 //
5472 // Now define the Frame attributes strux
5473 //
5474 const gchar * attributes[5] = {PT_STRUX_IMAGE_DATAID,
5475 NULL,"props",NULL,NULL};
5476 attributes[1] = dataID;
5477 attributes[3] = sFrameProps.c_str();
5478 //
5479 // This should place the the frame strux immediately after the block containing
5480 // position posXY.
5481 // It returns the Frag_Strux of the new frame.
5482 //
5483 fl_BlockLayout * pBL = pBlock;
5484 if((pBL == NULL) || (pRun == NULL))
5485 {
5486 return UT_ERROR;
5487 }
5488 fl_BlockLayout * pPrevBL = pBL;
5489 while(pBL && ((pBL->myContainingLayout()->getContainerType() == FL_CONTAINER_ENDNOTE) || (pBL->myContainingLayout()->getContainerType() == FL_CONTAINER_FOOTNOTE) || (pBL->myContainingLayout()->getContainerType() == FL_CONTAINER_TOC)|| (pBL->myContainingLayout()->getContainerType() == FL_CONTAINER_FRAME)))
5490 {
5491 UT_DEBUGMSG(("Skipping Block %p \n",pBL));
5492 pPrevBL = pBL;
5493 pBL = pBL->getPrevBlockInDocument();
5494 }
5495 if(pBL == NULL)
5496 {
5497 pBL = pPrevBL;
5498 }
5499 UT_ASSERT((pBL->myContainingLayout()->getContainerType() != FL_CONTAINER_HDRFTR)
5500 && (pBL->myContainingLayout()->getContainerType() != FL_CONTAINER_SHADOW));
5501 pos = pBL->getPosition();
5502 pf_Frag_Strux * pfFrame = NULL;
5503 m_pDoc->insertStrux(pos,PTX_SectionFrame,attributes,NULL,&pfFrame);
5504 PT_DocPosition posFrame = pfFrame->getPos();
5505 m_pDoc->insertStrux(posFrame+1,PTX_EndFrame);
5506 insertParaBreakIfNeededAtPos(posFrame+2);
5507
5508 // Signal PieceTable Changes have finished
5509 _restorePieceTableState();
5510 m_pDoc->endUserAtomicGlob();
5511 _generalUpdate();
5512 if(!isPointLegal())
5513 {
5514 _makePointLegal();
5515 }
5516 _ensureInsertionPointOnScreen();
5517 notifyListeners(AV_CHG_MOTION | AV_CHG_ALL);
5518 return UT_OK;
5519 }
5520
5521 /*!
5522 * This method inserts a MathML object and it's Latex representation
5523 * at the current insertion point.
5524 * It leaves the Object selected so it can be altered as needed.
5525 */
cmdInsertLatexMath(UT_UTF8String & sLatex,UT_UTF8String & sMath)5526 bool FV_View::cmdInsertLatexMath(UT_UTF8String & sLatex,
5527 UT_UTF8String & sMath)
5528 {
5529 //
5530 // First create the Data Items
5531 //
5532 UT_UTF8String sMathName;
5533 UT_UTF8String sLatexName;
5534 sMathName = "MathLatex";
5535 sLatexName = "LatexMath";
5536 /*
5537 Create a unique identifier for the data item.
5538 */
5539 UT_UUID *uuid = m_pDoc->getNewUUID();
5540 UT_return_val_if_fail(uuid != NULL, false);
5541 UT_UTF8String s;
5542 uuid->toString(s);
5543 sMathName += s;
5544 sLatexName += s;
5545 delete uuid;
5546 UT_DEBUGMSG(("Inserting latex id name %s \n",sLatexName.utf8_str()));
5547 //
5548 // Insert these into the Piece Table
5549 //
5550 UT_ByteBuf mathBuf;
5551 UT_ByteBuf latexBuf;
5552 mathBuf.ins(0,reinterpret_cast<const UT_Byte *>(sMath.utf8_str()),static_cast<UT_uint32>(sMath.size()));
5553 latexBuf.ins(0,reinterpret_cast<const UT_Byte *>(sLatex.utf8_str()),static_cast<UT_uint32>(sLatex.size()));
5554 m_pDoc->createDataItem(sMathName.utf8_str(),false,&mathBuf,"",NULL);
5555 m_pDoc->createDataItem(sLatexName.utf8_str(),false,&latexBuf,"",NULL);
5556 // OK Insert the MathML Object
5557 const gchar * atts[9]={"dataid",NULL,"latexid",NULL,"props",NULL,NULL,NULL,NULL};
5558 atts[1] = static_cast<const gchar *>(sMathName.utf8_str());
5559 atts[3] = static_cast<const gchar *>(sLatexName.utf8_str());
5560 const gchar *cur_style = NULL;
5561 getStyle(&cur_style);
5562 if((cur_style != NULL) && (*cur_style) && (strcmp(cur_style,"None") != 0))
5563 {
5564 atts[6] = PT_STYLE_ATTRIBUTE_NAME;
5565 atts[7] = cur_style;
5566 }
5567
5568 bool bDidGlob = false;
5569 const gchar ** props = NULL;
5570
5571 // Signal PieceTable Change
5572 _saveAndNotifyPieceTableChange();
5573 PT_DocPosition pos = getPoint();
5574 if (!isSelectionEmpty())
5575 {
5576 getCharFormat(&props,false,pos);
5577 bDidGlob = true;
5578 m_pDoc->beginUserAtomicGlob();
5579 _deleteSelection();
5580 }
5581 else
5582 {
5583 getCharFormat(&props,false,pos);
5584 }
5585 pos = getPoint();
5586 UT_UTF8String sNewProps;
5587 UT_UTF8String sProp;
5588 UT_UTF8String sVal;
5589 UT_sint32 i = 0;
5590 if(props)
5591 {
5592 while(props[i] != NULL)
5593 {
5594 sProp = props[i];
5595 sVal = props[i+1];
5596 UT_UTF8String_setProperty(sNewProps,sProp,sVal);
5597 i +=2;
5598 }
5599 g_free(props);
5600 }
5601 atts[5] = sNewProps.utf8_str();
5602 m_pDoc->insertObject(pos,PTO_Math,atts,NULL);
5603
5604 if (bDidGlob)
5605 m_pDoc->endUserAtomicGlob();
5606
5607 _generalUpdate();
5608 _restorePieceTableState();
5609 cmdSelect(pos,pos+1);
5610 return true;
5611 }
5612
5613 /*!
5614 * This method inserts a MathML object at the point presented.
5615 * It assumes that a data item with a name of the supplied filename has
5616 * already been inserted.
5617 */
cmdInsertMathML(const char * szUID,PT_DocPosition pos)5618 bool FV_View::cmdInsertMathML(const char * szUID,PT_DocPosition pos)
5619 {
5620 UT_DebugOnly<PT_DocPosition> posDebug = pos;
5621 UT_DEBUGMSG(("Insert Math Object at %d name %s \n",(PT_DocPosition)posDebug,szUID));
5622 const gchar * atts[5]={"dataid",NULL,NULL,NULL,NULL};
5623 atts[1] = szUID;
5624 const gchar *cur_style = NULL;
5625 getStyle(&cur_style);
5626 if((cur_style != NULL) && (*cur_style) && (strcmp(cur_style,"None") != 0))
5627 {
5628 atts[2] = PT_STYLE_ATTRIBUTE_NAME;
5629 atts[3] = cur_style;
5630 }
5631 bool bDidGlob = false;
5632 const gchar ** props = NULL;
5633
5634 // Signal PieceTable Change
5635 _saveAndNotifyPieceTableChange();
5636
5637 if (!isSelectionEmpty())
5638 {
5639 bDidGlob = true;
5640 m_pDoc->beginUserAtomicGlob();
5641 _deleteSelection();
5642 }
5643 _makePointLegal();
5644 getCharFormat(&props,false,getPoint());
5645 m_pDoc->insertObject(getPoint(),PTO_Math,atts,props);
5646
5647 if (bDidGlob)
5648 m_pDoc->endUserAtomicGlob();
5649
5650 _generalUpdate();
5651
5652 _restorePieceTableState();
5653 _updateInsertionPoint();
5654 return true;
5655 }
5656
5657
5658 /*!
5659 * This method inserts a Embed object at the point presented.
5660 * The calling routine should pass in a pointer to bytebuf that represents the
5661 * object.
5662 * Also needed are strings for the Mime-type and the type of Embeded object.
5663 *
5664 * eg for a GNOME-Office chart we'll have MIME-TYPE "application/chart+xml"
5665 * and sProps="embed-type: GOChart";
5666 */
cmdInsertEmbed(const UT_ByteBuf * pBuf,PT_DocPosition pos,const char * szMime,const char * szProps)5667 bool FV_View::cmdInsertEmbed(const UT_ByteBuf * pBuf,PT_DocPosition pos,const char * szMime,const char * szProps)
5668 {
5669
5670 const gchar * atts[7]={"dataid",NULL,"props",NULL,NULL,NULL,NULL};
5671 UT_UTF8String sUID="obj-", s;
5672 UT_UUID *uuid = m_pDoc->getNewUUID();
5673 UT_return_val_if_fail(uuid != NULL, false);
5674 uuid->toString(s);
5675 sUID += s;
5676 atts[1] = sUID.utf8_str();
5677 const gchar *cur_style = NULL;
5678 UT_String sBuf(reinterpret_cast<const char *>(pBuf->getPointer(0)),pBuf->getLength());
5679 UT_DEBUGMSG(("Chart text is... \n %s \n",sBuf.c_str()));
5680 bool result = m_pDoc->createDataItem(sUID.utf8_str(),false,pBuf, szMime, NULL);
5681 if(!result)
5682 {
5683 return result;
5684 }
5685 getStyle(&cur_style);
5686 if((cur_style != NULL) && (*cur_style) && (strcmp(cur_style,"None") != 0))
5687 {
5688 atts[4] = PT_STYLE_ATTRIBUTE_NAME;
5689 atts[5] = cur_style;
5690 }
5691 bool bDidGlob = false;
5692 const gchar ** props = NULL;
5693
5694 // Signal PieceTable Change
5695 _saveAndNotifyPieceTableChange();
5696
5697 if (!isSelectionEmpty())
5698 {
5699 bDidGlob = true;
5700 m_pDoc->beginUserAtomicGlob();
5701 _deleteSelection();
5702 // Reevaluate pos after deleting the selection
5703 pos = getPoint();
5704 }
5705 getCharFormat(&props,false,pos);
5706 UT_UTF8String sFullProps;
5707 UT_UTF8String sProp,sVal;
5708 UT_UTF8String sProps;
5709 UT_sint32 i = 0;
5710 if(props)
5711 {
5712 for(i=0;props[i] != NULL;i+=2)
5713 {
5714 sProp = props[i];
5715 sVal = props[i+1];
5716 UT_UTF8String_setProperty(sFullProps,sProp,sVal);
5717 }
5718 g_free(props);
5719 }
5720 sProps = szProps;
5721 UT_DEBUGMSG(("Supplied props %s \n",sProps.utf8_str()));
5722 UT_UTF8String_addPropertyString(sFullProps,sProps);
5723 UT_DEBUGMSG(("Property String at Update Object is %s \n",sFullProps.utf8_str()));
5724 atts[3]=sFullProps.utf8_str();
5725 m_pDoc->insertObject(pos,PTO_Embed,atts,NULL);
5726 if (bDidGlob)
5727 m_pDoc->endUserAtomicGlob();
5728
5729 _generalUpdate();
5730
5731 _restorePieceTableState();
5732 _updateInsertionPoint();
5733 cmdSelect(pos,pos+1);
5734 return true;
5735 }
5736
5737 /*!
5738 * This method updates the Embedded object currently selected with a new
5739 * object defined with the supplied bytebuffer, as well as strings to represent
5740 * the MIME/Type and Object type.
5741 *
5742 * eg for a GNOME-Office chart we'll have MIME-TYPE "application/chart+xml"
5743 * and sProps="embed-type: GOChart";
5744 */
cmdUpdateEmbed(const UT_ByteBuf * pBuf,const char * szMime,const char * szProps)5745 bool FV_View::cmdUpdateEmbed(const UT_ByteBuf * pBuf, const char * szMime, const char * szProps)
5746 {
5747 if (isSelectionEmpty())
5748 {
5749 return false;
5750 }
5751 PT_DocPosition pos1 = getPoint();
5752 PT_DocPosition pos2 = getSelectionAnchor();
5753 PT_DocPosition posTemp = 0;
5754 if(pos2 < pos1)
5755 {
5756 posTemp = pos2;
5757 pos2 = pos1;
5758 pos1 = posTemp;
5759 }
5760 fl_BlockLayout * pBL = getCurrentBlock();
5761 if(!pBL)
5762 return false;
5763 fp_Run * pRun;
5764 UT_sint32 xPoint,yPoint,xPoint2,yPoint2,iPointHeight;
5765 bool bDirection;
5766 pRun = pBL->findPointCoords(pos1, false, xPoint,
5767 yPoint, xPoint2, yPoint2,
5768 iPointHeight, bDirection);
5769 if(pRun && (pRun->getType() != FPRUN_EMBED) )
5770 {
5771 pos1 = pos2;
5772 }
5773 pRun = pBL->findPointCoords(pos1, false, xPoint,
5774 yPoint, xPoint2, yPoint2,
5775 iPointHeight, bDirection);
5776 if(pRun == NULL)
5777 {
5778 return false;
5779 }
5780 if(pRun->getType() != FPRUN_EMBED)
5781 {
5782 return false;
5783 }
5784 const gchar * atts[7]={"dataid",NULL,"props",NULL,NULL,NULL,NULL};
5785 UT_UTF8String sUID="obj-", s;
5786 UT_UUID *uuid = m_pDoc->getNewUUID();
5787 UT_return_val_if_fail(uuid != NULL, false);
5788 uuid->toString(s);
5789 sUID += s;
5790 atts[1] = sUID.utf8_str();
5791 bool bres = m_pDoc->createDataItem(sUID.utf8_str(),false,pBuf, szMime, NULL);
5792 UT_return_val_if_fail(bres,false)
5793 const gchar *cur_style = NULL;
5794 getStyle(&cur_style);
5795 if((cur_style != NULL) && (*cur_style) && (strcmp(cur_style,"None") != 0))
5796 {
5797 atts[4] = PT_STYLE_ATTRIBUTE_NAME;
5798 atts[5] = cur_style;
5799 }
5800 const gchar ** props = NULL;
5801
5802 // Signal PieceTable Change
5803 _saveAndNotifyPieceTableChange();
5804 m_pDoc->beginUserAtomicGlob();
5805 getCharFormat(&props,false,pos1);
5806 UT_UTF8String sFullProps;
5807 UT_UTF8String sProp,sVal;
5808 UT_UTF8String sProps;
5809 sProps = szProps;
5810 UT_sint32 i = 0;
5811 if(props)
5812 {
5813 for(i=0;props[i] != NULL;i+=2)
5814 {
5815 sProp = props[i];
5816 sVal = props[i+1];
5817 UT_DEBUGMSG(("Update Embed Prop %s val %s \n",props[i],props[i+1]));
5818 UT_UTF8String_setProperty(sFullProps,sProp,sVal);
5819 }
5820 g_free(props);
5821 }
5822 UT_DEBUGMSG(("Supplied props %s \n",sProps.utf8_str()));
5823 UT_UTF8String_addPropertyString(sFullProps,sProps);
5824 atts[3]=sFullProps.utf8_str();
5825 UT_DEBUGMSG(("Property String at Update Object is %s \n",atts[3]));
5826 _deleteSelection();
5827 m_pDoc->insertObject(pos1,PTO_Embed,atts,NULL);
5828 m_pDoc->endUserAtomicGlob();
5829
5830 _generalUpdate();
5831 _restorePieceTableState();
5832 _updateInsertionPoint();
5833 cmdSelect(pos1,pos1+1);
5834 return true;
5835 }
5836
5837 /*!
5838 * This method updates the Embedded object in pRun with a new
5839 * object defined with the supplied bytebuffer, as well as strings to represent
5840 * the MIME/Type and Object type.
5841 *
5842 * eg for a GNOME-Office chart we'll have MIME-TYPE "application/chart+xml"
5843 * and sProps="embed-type: GOChart";
5844 */
cmdUpdateEmbed(fp_Run * pRun,const UT_ByteBuf * pBuf,const char * szMime,const char * szProps)5845 bool FV_View::cmdUpdateEmbed(fp_Run * pRun, const UT_ByteBuf * pBuf, const char * szMime, const char * szProps)
5846 {
5847 if(pRun == NULL || pRun->getType() != FPRUN_EMBED)
5848 {
5849 return false;
5850 }
5851 PT_DocPosition pos;
5852 bool flag;
5853 pRun->mapXYToPosition(0, 0, pos, flag, flag, flag);
5854 cmdSelect (pos, pos+1);
5855 const gchar * atts[7]={"dataid",NULL,"props",NULL,NULL,NULL,NULL};
5856 UT_UTF8String sUID="obj-", s;
5857 UT_UUID *uuid = m_pDoc->getNewUUID();
5858 UT_return_val_if_fail(uuid != NULL, false);
5859 uuid->toString(s);
5860 sUID += s;
5861 atts[1] = sUID.utf8_str();
5862 bool bres = m_pDoc->createDataItem(sUID.utf8_str(),false,pBuf, szMime, NULL);
5863 UT_return_val_if_fail(bres,false)
5864 const gchar *cur_style = NULL;
5865 getStyle(&cur_style);
5866 if((cur_style != NULL) && (*cur_style) && (strcmp(cur_style,"None") != 0))
5867 {
5868 atts[4] = PT_STYLE_ATTRIBUTE_NAME;
5869 atts[5] = cur_style;
5870 }
5871 const gchar ** props = NULL;
5872
5873 // Signal PieceTable Change
5874 _saveAndNotifyPieceTableChange();
5875 m_pDoc->beginUserAtomicGlob();
5876 getCharFormat(&props,false,pos);
5877 UT_UTF8String sFullProps;
5878 UT_UTF8String sProp,sVal;
5879 UT_UTF8String sProps;
5880 sProps = szProps;
5881 UT_sint32 i = 0;
5882 if(props)
5883 {
5884 for(i=0;props[i] != NULL;i+=2)
5885 {
5886 sProp = props[i];
5887 // Filter out size properties
5888 if (sProp == "width" || sProp == "height" || sProp == "descent"
5889 || sProp == "ascent")
5890 sVal=NULL;
5891 else
5892 sVal = props[i+1];
5893 UT_DEBUGMSG(("Update Embed Prop %s val %s \n",props[i],props[i+1]));
5894 UT_UTF8String_setProperty(sFullProps,sProp,sVal);
5895 }
5896 g_free(props);
5897 }
5898 UT_DEBUGMSG(("Supplied props %s \n",sProps.utf8_str()));
5899 UT_UTF8String_addPropertyString(sFullProps,sProps);
5900 atts[3]=sFullProps.utf8_str();
5901 UT_DEBUGMSG(("Property String at Update Object is %s \n",atts[3]));
5902 m_pDoc->changeSpanFmt(PTC_AddFmt, pos, pos+1, atts, NULL);
5903 m_pDoc->endUserAtomicGlob();
5904
5905 _generalUpdate();
5906 _restorePieceTableState();
5907 _updateInsertionPoint();
5908 cmdSelect(pos,pos+1);
5909 return true;
5910 }
5911
5912 /*!
5913 * This method deletes the Embedded object in pRun.
5914 */
cmdDeleteEmbed(fp_Run * pRun)5915 bool FV_View::cmdDeleteEmbed(fp_Run * pRun)
5916 {
5917 if(pRun == NULL || pRun->getType() != FPRUN_EMBED)
5918 {
5919 return false;
5920 }
5921 PT_DocPosition pos;
5922 bool flag;
5923 pRun->mapXYToPosition(0, 0, pos, flag, flag, flag);
5924 cmdSelect (pos, pos+1);
5925 _saveAndNotifyPieceTableChange();
5926 m_pDoc->beginUserAtomicGlob();
5927 _deleteSelection();
5928 m_pDoc->endUserAtomicGlob();
5929
5930 _generalUpdate();
5931 _restorePieceTableState();
5932 _updateInsertionPoint();
5933 cmdSelect(pos,pos);
5934 return true;
5935 }
5936
5937 /*!
5938 * This method inserts an image at the strux of type iStruxType at the
5939 * point given by ipos.
5940 * This is useful for speficifying images as backgrounds to pages and cells.
5941 */
cmdInsertGraphicAtStrux(FG_Graphic * pFG,PT_DocPosition iPos,PTStruxType iStruxType)5942 UT_Error FV_View::cmdInsertGraphicAtStrux(FG_Graphic* pFG, PT_DocPosition iPos, PTStruxType iStruxType)
5943 {
5944 bool bDidGlob = false;
5945
5946 // Signal PieceTable Change
5947 _saveAndNotifyPieceTableChange();
5948
5949 /*
5950 Create a unique identifier for the data item.
5951 */
5952 UT_UUID *uuid = m_pDoc->getNewUUID();
5953 UT_return_val_if_fail(uuid != NULL, UT_ERROR);
5954 UT_UTF8String s;
5955 uuid->toString(s);
5956
5957 UT_Error errorCode = pFG->insertAtStrux(m_pDoc,
5958 m_pG->getDeviceResolution(),
5959 iPos,
5960 iStruxType, s.utf8_str());
5961
5962 _restorePieceTableState();
5963
5964 _generalUpdate();
5965 if (bDidGlob)
5966 m_pDoc->endUserAtomicGlob();
5967 _updateInsertionPoint();
5968
5969 return errorCode;
5970 }
5971
5972 #ifdef ENABLE_SPELL
cmdContextSuggest(UT_uint32 ndx,fl_BlockLayout * ppBL,const fl_PartOfBlockPtr & ppPOB)5973 void FV_View::cmdContextSuggest(UT_uint32 ndx, fl_BlockLayout * ppBL,
5974 const fl_PartOfBlockPtr& ppPOB)
5975 {
5976 // locate the squiggle
5977 PT_DocPosition pos = getPoint();
5978 fl_BlockLayout* pBL;
5979 fl_PartOfBlockPtr pPOB;
5980
5981 if (!ppBL)
5982 pBL = _findBlockAtPosition(pos);
5983 else
5984 pBL = ppBL;
5985 UT_ASSERT(pBL);
5986
5987 if (!ppPOB)
5988 pPOB = pBL->getSpellSquiggles()->get(pos - pBL->getPosition());
5989 else
5990 pPOB = ppPOB;
5991 UT_ASSERT(pPOB);
5992
5993 // grab the suggestion
5994 UT_UCSChar * replace = _lookupSuggestion(pBL, pPOB, ndx);
5995
5996 if (!replace)
5997 return;
5998
5999 // make the change
6000 UT_ASSERT(isSelectionEmpty());
6001
6002 moveInsPtTo(static_cast<PT_DocPosition>(pBL->getPosition() + pPOB->getOffset()));
6003 extSelHorizontal(true, pPOB->getPTLength());
6004
6005 UT_UCSChar * selection;
6006 getSelectionText(selection);
6007 getDictForSelection ()->correctWord (selection, UT_UCS4_strlen (selection),
6008 replace, UT_UCS4_strlen (replace));
6009 cmdCharInsert(replace, UT_UCS4_strlen(replace));
6010 FREEP(selection);
6011 FREEP(replace);
6012 }
6013
cmdContextIgnoreAll(void)6014 void FV_View::cmdContextIgnoreAll(void)
6015 {
6016 // locate the squiggle
6017 PT_DocPosition pos = getPoint();
6018 fl_BlockLayout* pBL = _findBlockAtPosition(pos);
6019 UT_return_if_fail(pBL);
6020 const fl_PartOfBlockPtr& pPOB = pBL->getSpellSquiggles()->get(pos - pBL->getPosition());
6021 if(!pPOB) // this can happen with very rapid right-clicks
6022 {
6023 return;
6024 }
6025
6026 // grab a copy of the word
6027 UT_GrowBuf pgb(1024);
6028 bool bRes = pBL->getBlockBuf(&pgb);
6029 UT_ASSERT(bRes);
6030 if(!bRes)
6031 {
6032 UT_WARNINGMSG(("getBlockBuf() failed in %s:%d",
6033 __FILE__, __LINE__));
6034 }
6035
6036 const UT_UCSChar * pBuf;
6037 UT_sint32 iLength, iPTLength, iBlockPos;
6038
6039 fl_BlockSpellIterator BSI(pBL, pPOB->getOffset());
6040 BSI.nextWordForSpellChecking(pBuf, iLength, iBlockPos, iPTLength);
6041
6042 // make the change
6043 getDictForSelection ()->ignoreWord ((const UT_UCSChar *)pBuf, (size_t)iLength);
6044 {
6045 // remove the squiggles, too
6046 fl_DocSectionLayout * pSL = m_pLayout->getFirstSection();
6047 if(pSL)
6048 {
6049 fl_BlockLayout* b = pSL->getNextBlockInDocument();
6050 while (b)
6051 {
6052 // TODO: just check and remove matching squiggles
6053 // for now, destructively recheck the whole thing
6054 m_pLayout->queueBlockForBackgroundCheck(FL_DocLayout::bgcrSpelling, b);
6055 b = static_cast<fl_BlockLayout *>(b->getNextBlockInDocument());
6056 }
6057 }
6058 }
6059 }
6060
cmdContextAdd(void)6061 void FV_View::cmdContextAdd(void)
6062 {
6063 // locate the squiggle
6064 PT_DocPosition pos = getPoint();
6065 fl_BlockLayout* pBL = _findBlockAtPosition(pos);
6066 UT_return_if_fail(pBL);
6067 const fl_PartOfBlockPtr& pPOB = pBL->getSpellSquiggles()->get(pos - pBL->getPosition());
6068 if(!pPOB) // this can happen with very rapid right-clicks
6069 {
6070 return;
6071 }
6072
6073 // grab a copy of the word
6074 UT_GrowBuf pgb(1024);
6075 bool bRes = pBL->getBlockBuf(&pgb);
6076 UT_ASSERT(bRes);
6077 if(!bRes)
6078 {
6079 UT_WARNINGMSG(("getBlockBuf() failed in %s:%d",
6080 __FILE__, __LINE__));
6081 }
6082
6083 const UT_UCSChar * pBuf;
6084 UT_sint32 iLength, iPTLength, iBlockPos;
6085
6086 fl_BlockSpellIterator BSI(pBL, pPOB->getOffset());
6087 BSI.nextWordForSpellChecking(pBuf, iLength, iBlockPos, iPTLength);
6088
6089 // make the change
6090 if (getDictForSelection ()->addToCustomDict (pBuf, iLength))
6091 {
6092 // remove the squiggles, too
6093 fl_DocSectionLayout * pSL = m_pLayout->getFirstSection();
6094 if(pSL)
6095 {
6096 fl_BlockLayout* b = pSL->getNextBlockInDocument();
6097 while (b)
6098 {
6099 // TODO: just check and remove matching squiggles
6100 // for now, destructively recheck the whole thing
6101 if(b->getContainerType() == FL_CONTAINER_BLOCK)
6102 {
6103 m_pLayout->queueBlockForBackgroundCheck(FL_DocLayout::bgcrSpelling, b);
6104 b = static_cast<fl_BlockLayout *>(b->getNextBlockInDocument());
6105 }
6106 else
6107 {
6108 b = static_cast<fl_BlockLayout *>(b->getNext());
6109 }
6110 }
6111 }
6112 }
6113 }
6114 #endif
6115
6116
6117 /*!
6118 * Remove all the Headers or footers from the section owning the current Page.
6119 \param bool isHeader remove the header if true, the footer if false.
6120 */
cmdRemoveHdrFtr(bool isHeader)6121 void FV_View::cmdRemoveHdrFtr( bool isHeader)
6122 {
6123 //
6124 // Branch to Header/Footer sections.
6125 //
6126 fp_ShadowContainer * pHFCon = NULL;
6127 fl_HdrFtrShadow * pShadow = NULL;
6128 fl_HdrFtrSectionLayout * pHdrFtr = NULL;
6129
6130 if(isHeader)
6131 {
6132 fp_Page * pPage = getCurrentPage();
6133 pHFCon = pPage->getHdrFtrP(FL_HDRFTR_HEADER);
6134 if(pHFCon == NULL)
6135 {
6136 return;
6137 }
6138 //
6139 // Now see if we are in the header to be removed. If so, jump out.
6140 //
6141 if (!isSelectionEmpty())
6142 _clearSelection();
6143 if(isHdrFtrEdit())
6144 {
6145 clearHdrFtrEdit();
6146 _setPoint(pPage->getFirstLastPos(true));
6147 }
6148 }
6149 else
6150 {
6151 fp_Page * pPage = getCurrentPage();
6152 pHFCon = pPage->getHdrFtrP(FL_HDRFTR_FOOTER);
6153 if(pHFCon == NULL)
6154 {
6155 return;
6156 }
6157 //
6158 // Now see if we are in the Footer to be removed. If so, jump out.
6159 //
6160 if (!isSelectionEmpty())
6161 _clearSelection();
6162 if(isHdrFtrEdit())
6163 {
6164 clearHdrFtrEdit();
6165 _setPoint(pPage->getFirstLastPos(false));
6166 }
6167 }
6168 pShadow = pHFCon->getShadow();
6169 UT_return_if_fail(pShadow);
6170
6171 m_pDoc->beginUserAtomicGlob();
6172
6173 _saveAndNotifyPieceTableChange();
6174 //
6175 // Save current document position.
6176 //
6177 PT_DocPosition curPoint = getPoint();
6178 //
6179 // Get the hdrftrSectionLayout
6180 // Get it's position.
6181 // Find the last run in the Section and get it's position.
6182 //
6183 // Need code here to remove all the header/footers.
6184 //
6185 pHdrFtr = pShadow->getHdrFtrSectionLayout();
6186 fl_DocSectionLayout * pDSL = pHdrFtr->getDocSectionLayout();
6187 //
6188 // Repeat this code 4 times to remove all the DocSection Layouts.
6189 //
6190 setCursorWait();
6191 if(isHeader)
6192 {
6193 pHdrFtr = pDSL->getHeader();
6194 if(pHdrFtr)
6195 {
6196 _removeThisHdrFtr(pHdrFtr);
6197 }
6198 pHdrFtr = pDSL->getHeaderEven();
6199 if(pHdrFtr)
6200 {
6201 _removeThisHdrFtr(pHdrFtr);
6202 }
6203 pHdrFtr = pDSL->getHeaderFirst();
6204 if(pHdrFtr)
6205 {
6206 _removeThisHdrFtr(pHdrFtr);
6207 }
6208 pHdrFtr = pDSL->getHeaderLast();
6209 if(pHdrFtr)
6210 {
6211 _removeThisHdrFtr(pHdrFtr);
6212 }
6213 }
6214 else
6215 {
6216 pHdrFtr = pDSL->getFooter();
6217 if(pHdrFtr)
6218 {
6219 _removeThisHdrFtr(pHdrFtr);
6220 }
6221 pHdrFtr = pDSL->getFooterEven();
6222 if(pHdrFtr)
6223 {
6224 _removeThisHdrFtr(pHdrFtr);
6225 }
6226 pHdrFtr = pDSL->getFooterFirst();
6227 if(pHdrFtr)
6228 {
6229 _removeThisHdrFtr(pHdrFtr);
6230 }
6231 pHdrFtr = pDSL->getFooterLast();
6232 if(pHdrFtr)
6233 {
6234 _removeThisHdrFtr(pHdrFtr);
6235 }
6236 }
6237 //
6238 // After erarsing the cursor, Restore to the point before all this mess started.
6239 //
6240 _setPoint(curPoint);
6241
6242 // Signal PieceTable Changes have finished
6243 _restorePieceTableState();
6244
6245 _generalUpdate();
6246 updateScreen (); // fix 1803, force screen update/redraw
6247
6248 _updateInsertionPoint();
6249 m_pDoc->endUserAtomicGlob();
6250 clearCursorWait();
6251 notifyListeners (AV_CHG_HDRFTR | AV_CHG_FMTSECTION);
6252 }
6253
6254 /*!
6255 * Start edit header mode. If there is no header one will be inserted.
6256 * otherwise start editing the header on the current page.
6257 */
cmdEditHeader(void)6258 void FV_View::cmdEditHeader(void)
6259 {
6260 _cmdEditHdrFtr(FL_HDRFTR_HEADER);
6261 notifyListeners (AV_CHG_HDRFTR | AV_CHG_FMTSECTION);
6262 }
6263
6264 /*!
6265 * Start edit footer mode. If there is no footer one will be inserted.
6266 * otherwise start editing the footer on the current page.
6267 */
cmdEditFooter(void)6268 void FV_View::cmdEditFooter(void)
6269 {
6270 _cmdEditHdrFtr(FL_HDRFTR_FOOTER);
6271 notifyListeners (AV_CHG_HDRFTR | AV_CHG_FMTSECTION);
6272 }
6273
cmdAcceptRejectRevision(bool bReject,UT_sint32 xPos,UT_sint32 yPos)6274 void FV_View::cmdAcceptRejectRevision(bool bReject, UT_sint32 xPos, UT_sint32 yPos)
6275 {
6276 UT_DEBUGMSG(( "FV_View::cmdAcceptRejectRevision [bReject=%d]\n",bReject ));
6277
6278 PT_DocPosition iStart, iEnd;
6279 fl_BlockLayout * pBlock = NULL;
6280 fp_Run *pRun = NULL;
6281
6282 // Signal PieceTable Change
6283 _saveAndNotifyPieceTableChange();
6284
6285 if(isSelectionEmpty())
6286 {
6287 if(xPos || yPos) // if given 0,0 use current position
6288 {
6289 warpInsPtToXY(xPos, yPos,true);
6290 }
6291
6292 pBlock = getCurrentBlock();
6293 PT_DocPosition iRelPos = getPoint() - pBlock->getPosition(false);
6294
6295 pRun = pBlock->getFirstRun();
6296 while (pRun && pRun->getNextRun() && pRun->getBlockOffset()+ pRun->getLength() <= iRelPos)
6297 pRun= pRun->getNextRun();
6298
6299 UT_return_if_fail(pRun);
6300
6301 iStart = pBlock->getPosition(false) + pRun->getBlockOffset();
6302 iEnd = pBlock->getPosition(false) + pRun->getBlockOffset() + pRun->getLength();
6303
6304 }
6305 else
6306 {
6307 iStart = getPoint();
6308 iEnd = getSelectionAnchor();
6309 }
6310
6311 // remove the selection, since things will get inserted, deleted, etc.
6312 _clearSelection();
6313
6314 m_pDoc->acceptRejectRevision(bReject,iStart,iEnd,m_iViewRevision);
6315 _restorePieceTableState();
6316 _generalUpdate();
6317 }
6318
cmdSetRevisionLevel(UT_uint32 i)6319 void FV_View::cmdSetRevisionLevel(UT_uint32 i)
6320 {
6321 UT_return_if_fail( i <= PD_MAX_REVISION );
6322 // first set the same level in Doc; we do this unconditionally,
6323 // this way the doc will always save the level the user last used
6324 // NB: the doc id and the view id can be differnt if the user
6325 // changed it in some other view
6326 m_pDoc->setShowRevisionId(i);
6327
6328 if(m_iViewRevision != i)
6329 {
6330 m_iViewRevision = i;
6331
6332 // need to rebuild the doc to reflect the new level ...
6333 m_pLayout->rebuildFromHere(static_cast<fl_DocSectionLayout *>(m_pLayout->getFirstSection()));
6334
6335 // we have to force redraw here, see bug 10486
6336 draw(NULL);
6337 }
6338 }
6339
6340 /*!
6341 finds the next/previous revision and sets selection to it
6342 TODO the selection will not cross block boundaries; it probably should
6343
6344 \param bNext: if true the search is carried out in forward direction
6345 \return returns true on succes
6346 */
cmdFindRevision(bool bNext,UT_sint32 xPos,UT_sint32 yPos)6347 bool FV_View::cmdFindRevision(bool bNext, UT_sint32 xPos, UT_sint32 yPos)
6348 {
6349 if(xPos || yPos)
6350 {
6351 // this is the case we were called from context menu ...
6352 warpInsPtToXY(xPos, yPos,true);
6353 }
6354
6355 if(!isSelectionEmpty())
6356 {
6357 _moveToSelectionEnd(bNext);
6358 }
6359
6360 fl_BlockLayout * pBL = getCurrentBlock();
6361
6362 if(!pBL)
6363 return false;
6364
6365 fl_DocSectionLayout * pSL = pBL->getDocSectionLayout();
6366
6367 if(!pSL)
6368 return false;
6369
6370 fp_Run * pRun;
6371 UT_sint32 xPoint,yPoint,xPoint2,yPoint2,iPointHeight;
6372 bool bDirection;
6373
6374 pRun = pBL->findPointCoords(getPoint(), false, xPoint,
6375 yPoint, xPoint2, yPoint2,
6376 iPointHeight, bDirection);
6377
6378 if(!pRun)
6379 return false;
6380
6381 if(bNext)
6382 {
6383 pRun = pRun->getNextRun();
6384
6385 while(pSL)
6386 {
6387 while(pBL)
6388 {
6389 while(pRun)
6390 {
6391 if(pRun->containsRevisions() && !pRun->isHidden())
6392 {
6393 goto move_point;
6394 }
6395
6396 pRun = pRun->getNextRun();
6397 }
6398
6399 pBL = pBL->getNextBlockInDocument();
6400 }
6401
6402 pSL = pSL->getNextDocSection();
6403 }
6404 }
6405 else
6406 {
6407 pRun = pRun->getPrevRun();
6408
6409 while(pSL)
6410 {
6411 while(pBL)
6412 {
6413 while(pRun)
6414 {
6415 if(pRun->containsRevisions() && !pRun->isHidden())
6416 {
6417 goto move_point;
6418 }
6419
6420 pRun = pRun->getPrevRun();
6421 }
6422
6423 pBL = pBL->getPrevBlockInDocument();
6424 }
6425
6426 pSL = pSL->getPrevDocSection();
6427 }
6428 }
6429
6430 return false;
6431
6432 move_point:
6433 UT_return_val_if_fail(pRun && pBL, false);
6434
6435 // we want to span the selection not only over this run, but also
6436 // all subesequent runs that contain the same revions
6437 // TODO: probably should do this across block/section boundaries
6438 fp_Run * pRun2 = bNext ? pRun->getNextRun() : pRun->getPrevRun();
6439 fp_Run * pOldRun2 = pRun;
6440
6441 PP_RevisionAttr * pR1 = pRun->getRevisions();
6442
6443 while(pRun2)
6444 {
6445 if(pRun2->containsRevisions() && !pRun2->isHidden())
6446 {
6447 // test the two runs, if their revions are the same
6448 // include this one as well
6449 PP_RevisionAttr * pR2 = pRun2->getRevisions();
6450
6451 if(!(*pR1 == *pR2))
6452 break;
6453 }
6454 else
6455 {
6456 break;
6457 }
6458
6459 pOldRun2 = pRun2;
6460 pRun2 = bNext ? pRun2->getNextRun() : pRun2->getPrevRun();
6461 }
6462
6463 // backtrack (we want pRun2 to be the last run in the selection
6464 pRun2 = pOldRun2;
6465 UT_return_val_if_fail(pRun2, false);
6466
6467 PT_DocPosition dpos1, dpos2;
6468
6469 if(bNext)
6470 {
6471 dpos1 = pBL->getPosition() + pRun->getBlockOffset();
6472 dpos2 = pRun2->getBlock()->getPosition() + pRun2->getBlockOffset() + pRun2->getLength();
6473 }
6474 else
6475 {
6476 dpos1 = pRun2->getBlock()->getPosition() + pRun2->getBlockOffset();
6477 dpos2 = pBL->getPosition() + pRun->getBlockOffset() + pRun->getLength();
6478 }
6479
6480 cmdSelect(dpos1, dpos2);
6481
6482 return true;
6483 }
6484
_updateDatesBeforeSave(bool bOverwriteCreated)6485 void FV_View::_updateDatesBeforeSave(bool bOverwriteCreated)
6486 {
6487 time_t now = time(NULL);
6488 std::string timeStr = ctime(&now);
6489
6490 if (bOverwriteCreated)
6491 {
6492 m_pDoc->setMetaDataProp(PD_META_KEY_DATE, timeStr);
6493 } else
6494 {
6495 std::string metaValue;
6496 if(!m_pDoc->getMetaDataProp(PD_META_KEY_DATE, metaValue))
6497 {
6498 m_pDoc->setMetaDataProp(PD_META_KEY_DATE, timeStr);
6499 }
6500 }
6501
6502 m_pDoc->setMetaDataProp(PD_META_KEY_DATE_LAST_CHANGED, timeStr);
6503 }
6504
6505