Normal view patch version 0.2 (cvs-ready?)

Aaron Lehmann (aaronl@vitelus.com)
Mon, 19 Jul 1999 10:27:01 +0000 (GMT)


Hi Abis,

I did quite a bit of work on my normal view patch today. Thanks to your
help, I got the menu items working. Hint: Don't run this release with
debugging enabled. The rulers don't like my changes and make lots of
asssets. This has been tested on Linux i386 only, I don't have access to
any of the other platforms. But as it is all xp code it _should_ work on
all three platforms.

Anyway, here's what it can do now:

* Be buggy :-)
* Add menu items for switching between modes. An outline mode is
available which brings up a dialog asking the user to send a patch :).
* Successfully switch modes on the fly
* Normal view no longer has margins! and rulers actually display
accordingly (if you refresh them :( ).
* Uses a more generic architecture than the previous release which makes
it easier to add new modes and especially switch modes on the fly.

And what it can't do yet:

* Be free of bugs :-)
* Print while in normal mode (crashes immediately - I suspect it's due to
the non-standard fp_Page size.)
* Automatically refresh the rulers when changing modes (I can't figure out
how to get a pointer to either ruler from FV_View).
* Not assert when scrolling (that's the ruler's fault, not mine. To get
arround it, comment out the relevent assert in the ruler code. I didn't
do it as I don't want to start commenting out asserts that trigger
because of my code)
* Not have a serrious bug where sometimes phantom page breaks appear while
scrolling (this appears to happen only when you type more than a page in
Page Layout mode and then switch to Normal)
* Have WYSIWYG columns. I remember one of the AbiSource employees
mentioning this as essensial in a normal view mode. I haven't even taken a
look at the column code, but I have a feeling that having all of the text
in one column while the document is still divided into 2 or 3 (and prints
that way!) is non-trivial compared to the rest of the stuff to do in the
normal mode. Any ideas where to start?

Don't worry, I'm working on the shortcommings that I can understand.

I was wondering if this could be put into CVS. It has quite a few bugs,
but none of them seem to affect the standard Page Layout mode. Normal
could be there for the adventurous and it would get more stable over time.
If you don't accept code of such low quality into CVS, I definately
understand :-). I just worry about waking up one day and finding that the
CVS tree became incompatible with my patch and having to tediously patch
everything by hand just to keep it current.

Now about the diff, diff - in its infinite wisdom, decided not to
intelligently handle my changes. It repetitively put ALL of fv_View.cpp
(~5000 lines) into the diff. Don't mind it. If it doesn't apply for some
reason, just patch the constructor, _draw* functions, getViewMode and
setViewMode by hand. Sorry for flooding the list with this gigantic,
repetitive diff.

Here it is:

diff -ur abi.vanilla/src/text/fmt/xp/fl_DocLayout.cpp abi/src/text/fmt/xp/fl_DocLayout.cpp
--- abi.vanilla/src/text/fmt/xp/fl_DocLayout.cpp Tue Jun 1 21:05:33 1999
+++ abi/src/text/fmt/xp/fl_DocLayout.cpp Mon Jul 19 00:12:09 1999
@@ -128,8 +128,8 @@
if (m_pG->queryProperties(GR_Graphics::DGP_SCREEN))
{
// add page view dimensions
- iHeight += fl_PAGEVIEW_PAGE_SEP * (count - 1);
- iHeight += fl_PAGEVIEW_MARGIN_Y * 2;
+ iHeight += m_pView->getPageViewPageSep() * (count - 1);
+ iHeight += m_pView->getPageViewTopMargin() * 2;
}

return iHeight;
@@ -152,7 +152,7 @@
if (m_pG->queryProperties(GR_Graphics::DGP_SCREEN))
{
// add page view dimensions
- iWidth += fl_PAGEVIEW_MARGIN_X * 2;
+ iWidth += m_pView->getPageViewLeftMargin() * 2;
}

return iWidth;
@@ -247,7 +247,7 @@
m_vecPages.deleteNthItem(ndx);
delete pPage;

- // let the view know that we created a new page,
+ // let the view know that we deleted a page,
// so that it can update the scroll bar ranges
// and whatever else it needs to do.

diff -ur abi.vanilla/src/text/fmt/xp/fl_DocLayout.h abi/src/text/fmt/xp/fl_DocLayout.h
--- abi.vanilla/src/text/fmt/xp/fl_DocLayout.h Wed Apr 7 13:46:43 1999
+++ abi/src/text/fmt/xp/fl_DocLayout.h Mon Jul 19 00:52:08 1999
@@ -40,12 +40,6 @@
class fl_PartOfBlock;


-// the following get used by view and layout code,
-// since they're private to the formatter, we stick 'em here
-#define fl_PAGEVIEW_PAGE_SEP 20 // must be <= MARGIN_Y
-#define fl_PAGEVIEW_MARGIN_X 25
-#define fl_PAGEVIEW_MARGIN_Y 25
-
// ----------------------------------------------------------------
/*
FL_DocLayout is a formatted representation of a specific PD_Document,
diff -ur abi.vanilla/src/text/fmt/xp/fl_SectionLayout.h abi/src/text/fmt/xp/fl_SectionLayout.h
--- abi.vanilla/src/text/fmt/xp/fl_SectionLayout.h Fri Apr 23 07:25:15 1999
+++ abi/src/text/fmt/xp/fl_SectionLayout.h Sun Jul 18 23:35:02 1999
@@ -167,6 +167,11 @@
inline UT_sint32 getBottomMargin(void) const { return m_iBottomMargin; }
inline UT_sint32 getSpaceAfter(void) const { return m_iSpaceAfter; }

+ void setLeftMargin(UT_sint32 iM) { m_iLeftMargin = iM; }
+ void setRightMargin(UT_sint32 iM) { m_iRightMargin = iM; }
+ void setTopMargin(UT_sint32 iM) { m_iTopMargin = iM; }
+ void setBottomMargin(UT_sint32 iM) { m_iBottomMargin = iM; }
+
UT_uint32 getNumColumns(void) const;
UT_uint32 getColumnGap(void) const;

diff -ur abi.vanilla/src/text/fmt/xp/fp_Page.h abi/src/text/fmt/xp/fp_Page.h
--- abi.vanilla/src/text/fmt/xp/fp_Page.h Tue Apr 6 13:19:04 1999
+++ abi/src/text/fmt/xp/fp_Page.h Mon Jul 19 00:38:57 1999
@@ -49,6 +49,8 @@

UT_sint32 getWidth(void) const;
UT_sint32 getHeight(void) const;
+ void setWidth(UT_sint32 iD) { m_iWidth = iD; }
+ void setHeight(UT_sint32 iD) { m_iHeight = iD; }
UT_sint32 getBottom(void) const;
fp_Page* getNext(void) const;
fp_Page* getPrev(void) const;
@@ -76,6 +78,8 @@

fp_HdrFtrContainer* getHeaderContainer(fl_HdrFtrSectionLayout*);
fp_HdrFtrContainer* getFooterContainer(fl_HdrFtrSectionLayout*);
+
+ void reformat (void) { _reformat(); }

#ifdef FMT_TEST
void __dump(FILE * fp) const;
@@ -103,3 +107,6 @@
};

#endif /* PAGE_H */
+
+
+
diff -ur abi.vanilla/src/text/fmt/xp/fv_View.cpp abi/src/text/fmt/xp/fv_View.cpp
--- abi.vanilla/src/text/fmt/xp/fv_View.cpp Fri Jul 2 09:10:35 1999
+++ abi/src/text/fmt/xp/fv_View.cpp Mon Jul 19 02:38:21 1999
@@ -110,6 +110,10 @@

m_wrappedEnd = UT_FALSE;
m_startPosition = 0;
+
+ m_ViewTypeChanged = UT_FALSE;
+ setViewType (FV_VIEWTYPE_PGLAYOUT);
+
}

FV_View::~FV_View()
@@ -142,3327 +146,3575 @@
UT_Bool bUndo = canDo(UT_TRUE);
UT_Bool bRedo = canDo(UT_FALSE);

- if ((m_chg.bUndo == bUndo) && (m_chg.bRedo == bRedo))
- {
- mask ^= AV_CHG_DO;
- }
- else
- {
- if (m_chg.bUndo != bUndo)
- m_chg.bUndo = bUndo;
- if (m_chg.bRedo != bRedo)
- m_chg.bRedo = bRedo;
- }
- }
-
- if (mask & AV_CHG_DIRTY)
- {
- UT_Bool bDirty = m_pDoc->isDirty();
+ if ((m_chg.bUndo == bUndo) && (m_chg.bRedo == bRedo))
+ {
+ mask ^= AV_CHG_DO;
+ }
+ else
+ {
+ if (m_chg.bUndo != bUndo)
+ m_chg.bUndo = bUndo;
+ if (m_chg.bRedo != bRedo)
+ m_chg.bRedo = bRedo;
+ }
+ }
+
+ if (mask & AV_CHG_DIRTY)
+ {
+ UT_Bool bDirty = m_pDoc->isDirty();
+
+ if (m_chg.bDirty != bDirty)
+ {
+ m_chg.bDirty = bDirty;
+ }
+ else
+ {
+ mask ^= AV_CHG_DIRTY;
+ }
+ }
+
+ if (mask & AV_CHG_EMPTYSEL)
+ {
+ UT_Bool bSel = !isSelectionEmpty();
+
+ if (m_chg.bSelection != bSel)
+ m_chg.bSelection = bSel;
+ else
+ mask ^= AV_CHG_EMPTYSEL;
+ }
+
+ if (mask & AV_CHG_FILENAME)
+ {
+ // NOTE: we don't attempt to filter this
+ }
+
+ if (mask & AV_CHG_FMTBLOCK)
+ {
+ /*
+ The following brute-force solution works, but is atrociously
+ expensive, so we should avoid using it whenever feasible.
+ */
+ const XML_Char ** propsBlock = NULL;
+ getBlockFormat(&propsBlock);
+
+ UT_Bool bMatch = UT_FALSE;
+
+ if (propsBlock && m_chg.propsBlock)
+ {
+ bMatch = UT_TRUE;
+
+ int i=0;
+
+ while (bMatch)
+ {
+ if (!propsBlock[i] || !m_chg.propsBlock[i])
+ {
+ bMatch = (propsBlock[i] == m_chg.propsBlock[i]);
+ break;
+ }
+
+ if (UT_stricmp(propsBlock[i], m_chg.propsBlock[i]))
+ {
+ bMatch = UT_FALSE;
+ break;
+ }
+
+ i++;
+ }
+ }
+
+ if (!bMatch)
+ {
+ FREEP(m_chg.propsBlock);
+ m_chg.propsBlock = propsBlock;
+ }
+ else
+ {
+ FREEP(propsBlock);
+ mask ^= AV_CHG_FMTBLOCK;
+ }
+ }
+
+ if (mask & AV_CHG_FMTCHAR)
+ {
+ /*
+ The following brute-force solution works, but is atrociously
+ expensive, so we should avoid using it whenever feasible.
+
+ TODO: devise special case logic for (at minimum) char motion
+ */
+ const XML_Char ** propsChar = NULL;
+ getCharFormat(&propsChar);
+
+ UT_Bool bMatch = UT_FALSE;
+
+ if (propsChar && m_chg.propsChar)
+ {
+ bMatch = UT_TRUE;
+
+ int i=0;
+
+ while (bMatch)
+ {
+ if (!propsChar[i] || !m_chg.propsChar[i])
+ {
+ bMatch = (propsChar[i] == m_chg.propsChar[i]);
+ break;
+ }
+
+ if (UT_stricmp(propsChar[i], m_chg.propsChar[i]))
+ {
+ bMatch = UT_FALSE;
+ break;
+ }
+
+ i++;
+ }
+ }
+
+ if (!bMatch)
+ {
+ FREEP(m_chg.propsChar);
+ m_chg.propsChar = propsChar;
+ }
+ else
+ {
+ FREEP(propsChar);
+ mask ^= AV_CHG_FMTCHAR;
+ }
+ }
+
+ if (mask & AV_CHG_FMTSECTION)
+ {
+ /*
+ The following brute-force solution works, but is atrociously
+ expensive, so we should avoid using it whenever feasible.
+ */
+ const XML_Char ** propsSection = NULL;
+ getSectionFormat(&propsSection);
+
+ UT_Bool bMatch = UT_FALSE;
+
+ if (propsSection && m_chg.propsSection)
+ {
+ bMatch = UT_TRUE;
+
+ int i=0;
+
+ while (bMatch)
+ {
+ if (!propsSection[i] || !m_chg.propsSection[i])
+ {
+ bMatch = (propsSection[i] == m_chg.propsSection[i]);
+ break;
+ }
+
+ if (UT_stricmp(propsSection[i], m_chg.propsSection[i]))
+ {
+ bMatch = UT_FALSE;
+ break;
+ }
+
+ i++;
+ }
+ }
+
+ if (!bMatch)
+ {
+ FREEP(m_chg.propsSection);
+ m_chg.propsSection = propsSection;
+ }
+ else
+ {
+ FREEP(propsSection);
+ mask ^= AV_CHG_FMTSECTION;
+ }
+ }
+
+ if (mask & AV_CHG_FMTSTYLE)
+ {
+ // NOTE: we don't attempt to filter this
+ // TODO: we probably should
+ }
+
+ if (mask & AV_CHG_PAGECOUNT)
+ {
+ // NOTE: we don't attempt to filter this
+ }
+
+ if (mask & AV_CHG_COLUMN)
+ {
+ // computing which column the cursor is in is rather expensive,
+ // i'm not sure it's worth the effort here...
+
+ fp_Run * pRun;
+ UT_sint32 xCaret, yCaret;
+ UT_uint32 heightCaret;
+
+ _findPositionCoords(getPoint(), m_bPointEOL, xCaret, yCaret, heightCaret, NULL, &pRun);
+
+ fp_Container * pContainer = pRun->getLine()->getContainer();
+
+ if (pContainer->getType() == FP_CONTAINER_COLUMN)
+ {
+ fp_Column* pColumn = (fp_Column*) pContainer;
+
+ UT_uint32 nCol=0;
+ fp_Column * pNthColumn = pColumn->getLeader();
+ while (pNthColumn && (pNthColumn != pColumn))
+ {
+ nCol++;
+ pNthColumn = pNthColumn->getFollower();
+ }
+
+ if (nCol != m_chg.iColumn)
+ {
+ m_chg.iColumn = nCol;
+ }
+ else
+ {
+ mask ^= AV_CHG_COLUMN;
+ }
+ }
+ }

- if (m_chg.bDirty != bDirty)
- {
- m_chg.bDirty = bDirty;
- }
- else
- {
- mask ^= AV_CHG_DIRTY;
- }
- }
+ // base class does the rest
+ return AV_View::notifyListeners(mask);
+ }

- if (mask & AV_CHG_EMPTYSEL)
- {
- UT_Bool bSel = !isSelectionEmpty();
+ void FV_View::_swapSelectionOrientation(void)
+ {
+ // reverse the direction of the current selection
+ // without changing the screen.

- if (m_chg.bSelection != bSel)
- m_chg.bSelection = bSel;
- else
- mask ^= AV_CHG_EMPTYSEL;
- }
+ UT_ASSERT(!isSelectionEmpty());
+ PT_DocPosition curPos = getPoint();
+ UT_ASSERT(curPos != m_iSelectionAnchor);
+ _setPoint(m_iSelectionAnchor);
+ m_iSelectionAnchor = curPos;
+ }

- if (mask & AV_CHG_FILENAME)
- {
- // NOTE: we don't attempt to filter this
- }
+ void FV_View::_moveToSelectionEnd(UT_Bool bForward)
+ {
+ // move to the requested end of the current selection.
+ // NOTE: this must clear the selection.
+ // NOTE: we do not draw the insertion point
+ // after clearing the selection.

- if (mask & AV_CHG_FMTBLOCK)
- {
- /*
- The following brute-force solution works, but is atrociously
- expensive, so we should avoid using it whenever feasible.
- */
- const XML_Char ** propsBlock = NULL;
- getBlockFormat(&propsBlock);
+ UT_ASSERT(!isSelectionEmpty());

- UT_Bool bMatch = UT_FALSE;
+ PT_DocPosition curPos = getPoint();

- if (propsBlock && m_chg.propsBlock)
- {
- bMatch = UT_TRUE;
+ UT_ASSERT(curPos != m_iSelectionAnchor);
+ UT_Bool bForwardSelection = (m_iSelectionAnchor < curPos);

- int i=0;
+ if (bForward != bForwardSelection)
+ {
+ _swapSelectionOrientation();
+ }

- while (bMatch)
- {
- if (!propsBlock[i] || !m_chg.propsBlock[i])
- {
- bMatch = (propsBlock[i] == m_chg.propsBlock[i]);
- break;
- }
+ _clearSelection();

- if (UT_stricmp(propsBlock[i], m_chg.propsBlock[i]))
- {
- bMatch = UT_FALSE;
- break;
- }
+ return;
+ }

- i++;
- }
- }
+ void FV_View::_eraseSelection(void)
+ {
+ if (!m_bSelection)
+ {
+ _resetSelection();
+ return;
+ }
+
+ UT_uint32 iPos1, iPos2;
+
+ if (m_iSelectionAnchor < getPoint())
+ {
+ iPos1 = m_iSelectionAnchor;
+ iPos2 = getPoint();
+ }
+ else
+ {
+ iPos1 = getPoint();
+ iPos2 = m_iSelectionAnchor;
+ }

- if (!bMatch)
- {
- FREEP(m_chg.propsBlock);
- m_chg.propsBlock = propsBlock;
- }
- else
- {
- FREEP(propsBlock);
- mask ^= AV_CHG_FMTBLOCK;
- }
- }
+ _clearBetweenPositions(iPos1, iPos2, UT_TRUE);
+ }

- if (mask & AV_CHG_FMTCHAR)
- {
- /*
- The following brute-force solution works, but is atrociously
- expensive, so we should avoid using it whenever feasible.
+ void FV_View::_clearSelection(void)
+ {
+ if (!m_bSelection)
+ {
+ _resetSelection();
+ return;
+ }
+
+ UT_uint32 iPos1, iPos2;
+
+ if (m_iSelectionAnchor < getPoint())
+ {
+ iPos1 = m_iSelectionAnchor;
+ iPos2 = getPoint();
+ }
+ else
+ {
+ iPos1 = getPoint();
+ iPos2 = m_iSelectionAnchor;
+ }

- TODO: devise special case logic for (at minimum) char motion
- */
- const XML_Char ** propsChar = NULL;
- getCharFormat(&propsChar);
+ _clearBetweenPositions(iPos1, iPos2, UT_TRUE);

- UT_Bool bMatch = UT_FALSE;
+ _resetSelection();

- if (propsChar && m_chg.propsChar)
- {
- bMatch = UT_TRUE;
+ _drawBetweenPositions(iPos1, iPos2);
+ }

- int i=0;
+ void FV_View::_resetSelection(void)
+ {
+ m_bSelection = UT_FALSE;
+ m_iSelectionAnchor = getPoint();
+ }

- while (bMatch)
- {
- if (!propsChar[i] || !m_chg.propsChar[i])
- {
- bMatch = (propsChar[i] == m_chg.propsChar[i]);
- break;
- }
+ void FV_View::_drawSelection()
+ {
+ UT_ASSERT(!isSelectionEmpty());

- if (UT_stricmp(propsChar[i], m_chg.propsChar[i]))
- {
- bMatch = UT_FALSE;
- break;
- }
+ if (m_iSelectionAnchor < getPoint())
+ {
+ _drawBetweenPositions(m_iSelectionAnchor, getPoint());
+ }
+ else
+ {
+ _drawBetweenPositions(getPoint(), m_iSelectionAnchor);
+ }
+ }

- i++;
- }
- }
+ void FV_View::_setSelectionAnchor(void)
+ {
+ m_bSelection = UT_TRUE;
+ m_iSelectionAnchor = getPoint();
+ }

- if (!bMatch)
- {
- FREEP(m_chg.propsChar);
- m_chg.propsChar = propsChar;
- }
- else
- {
- FREEP(propsChar);
- mask ^= AV_CHG_FMTCHAR;
- }
- }
+ void FV_View::_deleteSelection(void)
+ {
+ // delete the current selection.
+ // NOTE: this must clear the selection.

- if (mask & AV_CHG_FMTSECTION)
- {
- /*
- The following brute-force solution works, but is atrociously
- expensive, so we should avoid using it whenever feasible.
- */
- const XML_Char ** propsSection = NULL;
- getSectionFormat(&propsSection);
+ UT_ASSERT(!isSelectionEmpty());

- UT_Bool bMatch = UT_FALSE;
+ PT_DocPosition iPoint = getPoint();
+ UT_ASSERT(iPoint != m_iSelectionAnchor);

- if (propsSection && m_chg.propsSection)
- {
- bMatch = UT_TRUE;
+ UT_uint32 iSelAnchor = m_iSelectionAnchor;
+
+ _eraseSelection();
+ _resetSelection();
+
+ UT_Bool bForward = (iPoint < iSelAnchor);
+ if (bForward)
+ {
+ m_pDoc->deleteSpan(iPoint, iSelAnchor);
+ }
+ else
+ {
+ m_pDoc->deleteSpan(iSelAnchor, iPoint);
+ }
+ }

- int i=0;
+ UT_Bool FV_View::isSelectionEmpty()
+ {
+ if (!m_bSelection)
+ {
+ return UT_TRUE;
+ }
+
+ PT_DocPosition curPos = getPoint();
+ if (curPos == m_iSelectionAnchor)
+ {
+ return UT_TRUE;
+ }

- while (bMatch)
- {
- if (!propsSection[i] || !m_chg.propsSection[i])
- {
- bMatch = (propsSection[i] == m_chg.propsSection[i]);
- break;
- }
+ return UT_FALSE;
+ }

- if (UT_stricmp(propsSection[i], m_chg.propsSection[i]))
- {
- bMatch = UT_FALSE;
+ PT_DocPosition FV_View::_getDocPos(FV_DocPos dp, UT_Bool bKeepLooking)
+ {
+ return _getDocPosFromPoint(getPoint(),dp,bKeepLooking);
+ }
+
+ PT_DocPosition FV_View::_getDocPosFromPoint(PT_DocPosition iPoint, FV_DocPos dp, UT_Bool bKeepLooking)
+ {
+ UT_sint32 xPoint;
+ UT_sint32 yPoint;
+ UT_sint32 iPointHeight;
+
+ PT_DocPosition iPos;
+
+ // this gets called from ctor, so get out quick
+ if (dp == FV_DOCPOS_BOD)
+ {
+ UT_Bool bRes = m_pDoc->getBounds(UT_FALSE, iPos);
+ UT_ASSERT(bRes);
+
+ return iPos;
+ }
+
+ // TODO: could cache these to save a lookup if point doesn't change
+ fl_BlockLayout* pBlock = _findBlockAtPosition(iPoint);
+ fp_Run* pRun = pBlock->findPointCoords(iPoint, m_bPointEOL,
+ xPoint, yPoint, iPointHeight);
+ fp_Line* pLine = pRun->getLine();
+
+ // be pessimistic
+ iPos = iPoint;
+
+ switch (dp)
+ {
+ case FV_DOCPOS_BOL:
+ {
+ fp_Run* pFirstRun = pLine->getFirstRun();
+
+ iPos = pFirstRun->getBlockOffset() + pBlock->getPosition();
+ }
+ break;
+
+ case FV_DOCPOS_EOL:
+ {
+ fp_Run* pLastRun = pLine->getLastRun();
+
+ while (!pLastRun->isFirstRunOnLine() && pLastRun->isForcedBreak())
+ {
+ pLastRun = pLastRun->getPrev();
+ }
+
+ if(pLastRun->isForcedBreak())
+ {
+ iPos = pBlock->getPosition() + pLastRun->getBlockOffset();
+ }
+ else
+ {
+ iPos = pBlock->getPosition() + pLastRun->getBlockOffset() + pLastRun->getLength();
+ }
+ }
+ break;
+
+ case FV_DOCPOS_EOD:
+ {
+ UT_Bool bRes = m_pDoc->getBounds(UT_TRUE, iPos);
+ UT_ASSERT(bRes);
+ }
+ break;
+
+ case FV_DOCPOS_BOB:
+ {
+ #if 0
+ // TODO this piece of code attempts to go back
+ // TODO to the previous block if we are on the
+ // TODO edge. this causes bug #92 (double clicking
+ // TODO on the first line of a paragraph selects
+ // TODO current paragraph and the previous paragraph).
+ // TODO i'm not sure why it is here.
+ // TODO
+ // TODO it's here because it makes control-up-arrow
+ // TODO when at the beginning of paragraph work. this
+ // TODO problem is logged as bug #403.
+ // TODO
+ // are we already there?
+ if (iPos == pBlock->getPosition())
+ {
+ // yep. is there a prior block?
+ if (!pBlock->getPrevBlockInDocument())
+ break;
+
+ // yep. look there instead
+ pBlock = pBlock->getPrevBlockInDocument();
+ }
+ #endif /* 0 */
+
+ iPos = pBlock->getPosition();
+ }
+ break;
+
+ case FV_DOCPOS_EOB:
+ {
+ if (pBlock->getNextBlockInDocument())
+ {
+ // BOB for next block
+ pBlock = pBlock->getNextBlockInDocument();
+ iPos = pBlock->getPosition();
+ }
+ else
+ {
+ // EOD
+ UT_Bool bRes = m_pDoc->getBounds(UT_TRUE, iPos);
+ UT_ASSERT(bRes);
+ }
+ }
+ break;
+
+ case FV_DOCPOS_BOW:
+ {
+ UT_GrowBuf pgb(1024);
+
+ UT_Bool bRes = pBlock->getBlockBuf(&pgb);
+ UT_ASSERT(bRes);
+
+ const UT_UCSChar* pSpan = pgb.getPointer(0);
+
+ UT_ASSERT(iPos >= pBlock->getPosition());
+ UT_uint32 offset = iPos - pBlock->getPosition();
+ UT_ASSERT(offset <= pgb.getLength());
+
+ if (offset == 0)
+ {
+ if (!bKeepLooking)
+ break;
+
+ // is there a prior block?
+ pBlock = pBlock->getPrevBlockInDocument();
+
+ if (!pBlock)
+ break;
+
+ // yep. look there instead
+ pgb.truncate(0);
+ bRes = pBlock->getBlockBuf(&pgb);
+ UT_ASSERT(bRes);
+
+ pSpan = pgb.getPointer(0);
+ offset = pgb.getLength();
+
+ if (offset == 0)
+ {
+ iPos = pBlock->getPosition();
+ break;
+ }
+ }
+
+ UT_Bool bInWord = !UT_isWordDelimiter(pSpan[bKeepLooking ? offset-1 : offset]);
+
+ for (offset--; offset > 0; offset--)
+ {
+ if (UT_isWordDelimiter(pSpan[offset]))
+ {
+ if (bInWord)
+ break;
+ }
+ else
+ bInWord = UT_TRUE;
+ }
+
+ if ((offset > 0) && (offset < pgb.getLength()))
+ offset++;
+
+ iPos = offset + pBlock->getPosition();
+ }
+ break;
+
+ case FV_DOCPOS_EOW:
+ {
+ UT_GrowBuf pgb(1024);
+
+ UT_Bool bRes = pBlock->getBlockBuf(&pgb);
+ UT_ASSERT(bRes);
+
+ const UT_UCSChar* pSpan = pgb.getPointer(0);
+
+ UT_ASSERT(iPos >= pBlock->getPosition());
+ UT_uint32 offset = iPos - pBlock->getPosition();
+ UT_ASSERT(offset <= pgb.getLength());
+
+ if (offset == pgb.getLength())
+ {
+ if (!bKeepLooking)
+ break;
+
+ // is there a next block?
+ pBlock = pBlock->getNextBlockInDocument();
+
+ if (!pBlock)
+ break;
+
+ // yep. look there instead
+ pgb.truncate(0);
+ bRes = pBlock->getBlockBuf(&pgb);
+ UT_ASSERT(bRes);
+
+ pSpan = pgb.getPointer(0);
+ offset = 0;
+
+ if (pgb.getLength() == 0)
+ {
+ iPos = pBlock->getPosition();
+ break;
+ }
+ }
+
+ UT_Bool bBetween = UT_isWordDelimiter(pSpan[offset]);
+
+ // Needed so ctrl-right arrow will work
+ for (; offset < pgb.getLength(); offset++)
+ {
+ if (!UT_isWordDelimiter(pSpan[offset]))
+ break;
+ }
+
+ for (; offset < pgb.getLength(); offset++)
+ {
+ if (!UT_isWordDelimiter(pSpan[offset]))
+ {
+ if (bBetween)
+ break;
+ }
+ else if (pSpan[offset] != ' ')
break;
- }
+ else
+ bBetween = UT_TRUE;
+ }
+
+ iPos = offset + pBlock->getPosition();
+ }
+ break;
+
+ case FV_DOCPOS_BOS:
+ case FV_DOCPOS_EOS:
+ UT_ASSERT(UT_TODO);
+ break;
+
+ default:
+ UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
+ break;
+ }

- i++;
- }
- }
+ return iPos;
+ }

- if (!bMatch)
- {
- FREEP(m_chg.propsSection);
- m_chg.propsSection = propsSection;
- }
- else
- {
- FREEP(propsSection);
- mask ^= AV_CHG_FMTSECTION;
- }
- }
+ void FV_View::moveInsPtTo(FV_DocPos dp)
+ {
+ if (!isSelectionEmpty())
+ _clearSelection();
+ else
+ _eraseInsertionPoint();
+
+ PT_DocPosition iPos = _getDocPos(dp);
+
+ if (iPos != getPoint())
+ {
+ UT_Bool bPointIsValid = (getPoint() >= _getDocPos(FV_DOCPOS_BOD));
+ if (bPointIsValid)
+ _clearIfAtFmtMark(getPoint());
+ }
+
+ _setPoint(iPos, (dp == FV_DOCPOS_EOL));
+
+ if (!_ensureThatInsertionPointIsOnScreen())
+ {
+ _fixInsertionPointCoords();
+ _drawInsertionPoint();
+ }

- if (mask & AV_CHG_FMTSTYLE)
- {
- // NOTE: we don't attempt to filter this
- // TODO: we probably should
- }
+ notifyListeners(AV_CHG_MOTION);
+ }

- if (mask & AV_CHG_PAGECOUNT)
- {
- // NOTE: we don't attempt to filter this
- }
+ void FV_View::moveInsPtTo(PT_DocPosition dp)
+ {
+ if (!isSelectionEmpty())
+ _clearSelection();
+ else
+ _eraseInsertionPoint();
+
+ if (dp != getPoint())
+ _clearIfAtFmtMark(getPoint());
+
+ _setPoint(dp, /* (dp == FV_DOCPOS_EOL) */ UT_FALSE); // is this bool correct?
+
+ if (!_ensureThatInsertionPointIsOnScreen())
+ {
+ _fixInsertionPointCoords();
+ _drawInsertionPoint();
+ }

- if (mask & AV_CHG_COLUMN)
- {
- // computing which column the cursor is in is rather expensive,
- // i'm not sure it's worth the effort here...
-
- fp_Run * pRun;
- UT_sint32 xCaret, yCaret;
- UT_uint32 heightCaret;
+ notifyListeners(AV_CHG_MOTION);
+ }

- _findPositionCoords(getPoint(), m_bPointEOL, xCaret, yCaret, heightCaret, NULL, &pRun);

- fp_Container * pContainer = pRun->getLine()->getContainer();
+ void FV_View::cmdCharMotion(UT_Bool bForward, UT_uint32 count)
+ {
+ if (!isSelectionEmpty())
+ {
+ _moveToSelectionEnd(bForward);
+ // Note: _moveToSelectionEnd() clears the selection
+ // but does not redraw the insertion point.
+ _drawInsertionPoint();
+ }
+
+ PT_DocPosition iPoint = getPoint();
+ if (!_charMotion(bForward, count))
+ _setPoint(iPoint);
+ else
+ _updateInsertionPoint();

- if (pContainer->getType() == FP_CONTAINER_COLUMN)
- {
- fp_Column* pColumn = (fp_Column*) pContainer;
-
- UT_uint32 nCol=0;
- fp_Column * pNthColumn = pColumn->getLeader();
- while (pNthColumn && (pNthColumn != pColumn))
- {
- nCol++;
- pNthColumn = pNthColumn->getFollower();
- }
+ notifyListeners(AV_CHG_MOTION);
+ }

- if (nCol != m_chg.iColumn)
- {
- m_chg.iColumn = nCol;
- }
- else
- {
- mask ^= AV_CHG_COLUMN;
- }
- }
- }
-
- // base class does the rest
- return AV_View::notifyListeners(mask);
-}
+ fl_BlockLayout* FV_View::_findBlockAtPosition(PT_DocPosition pos) const
+ {
+ return m_pLayout->findBlockAtPosition(pos);
+ }

-void FV_View::_swapSelectionOrientation(void)
-{
- // reverse the direction of the current selection
- // without changing the screen.
+ UT_Bool FV_View::cmdCharInsert(UT_UCSChar * text, UT_uint32 count)
+ {
+ UT_Bool bResult;

- UT_ASSERT(!isSelectionEmpty());
- PT_DocPosition curPos = getPoint();
- UT_ASSERT(curPos != m_iSelectionAnchor);
- _setPoint(m_iSelectionAnchor);
- m_iSelectionAnchor = curPos;
-}
-
-void FV_View::_moveToSelectionEnd(UT_Bool bForward)
-{
- // move to the requested end of the current selection.
- // NOTE: this must clear the selection.
- // NOTE: we do not draw the insertion point
- // after clearing the selection.
+ if (!isSelectionEmpty())
+ {
+ m_pDoc->beginUserAtomicGlob();
+ _deleteSelection();
+ bResult = m_pDoc->insertSpan(getPoint(), text, count);
+ m_pDoc->endUserAtomicGlob();
+ }
+ else
+ {
+ _eraseInsertionPoint();
+ bResult = m_pDoc->insertSpan(getPoint(), text, count);
+ }
+
+ _generalUpdate();
+
+ if (!_ensureThatInsertionPointIsOnScreen())
+ {
+ _fixInsertionPointCoords();
+ _drawInsertionPoint();
+ }

- UT_ASSERT(!isSelectionEmpty());
-
- PT_DocPosition curPos = getPoint();
-
- UT_ASSERT(curPos != m_iSelectionAnchor);
- UT_Bool bForwardSelection = (m_iSelectionAnchor < curPos);
-
- if (bForward != bForwardSelection)
- {
- _swapSelectionOrientation();
- }
+ return bResult;
+ }

- _clearSelection();
+ void FV_View::insertSectionBreak(void)
+ {
+ m_pDoc->beginUserAtomicGlob();

- return;
-}
+ if (!isSelectionEmpty())
+ {
+ _deleteSelection();
+ }
+ else
+ {
+ _eraseInsertionPoint();
+ }
+
+ // insert a new paragraph with the same attributes/properties
+ // as the previous (or none if the first paragraph in the section).
+ // before inserting a section break, we insert a block break
+ UT_uint32 iPoint = getPoint();
+
+ m_pDoc->insertStrux(iPoint, PTX_Block);
+ m_pDoc->insertStrux(iPoint, PTX_Section);
+
+ m_pDoc->endUserAtomicGlob();
+
+ _generalUpdate();
+
+ if (!_ensureThatInsertionPointIsOnScreen())
+ {
+ _fixInsertionPointCoords();
+ _drawInsertionPoint();
+ }
+ }

-void FV_View::_eraseSelection(void)
-{
- if (!m_bSelection)
- {
- _resetSelection();
- return;
- }
+ void FV_View::insertParagraphBreak(void)
+ {
+ UT_Bool bDidGlob = UT_FALSE;

- UT_uint32 iPos1, iPos2;
+ if (!isSelectionEmpty())
+ {
+ bDidGlob = UT_TRUE;
+ m_pDoc->beginUserAtomicGlob();
+ _deleteSelection();
+ }
+ else
+ {
+ _eraseInsertionPoint();
+ }
+
+ // insert a new paragraph with the same attributes/properties
+ // as the previous (or none if the first paragraph in the section).
+
+ m_pDoc->insertStrux(getPoint(), PTX_Block);
+
+ if (bDidGlob)
+ m_pDoc->endUserAtomicGlob();
+
+ _generalUpdate();
+
+ if (!_ensureThatInsertionPointIsOnScreen())
+ {
+ _fixInsertionPointCoords();
+ _drawInsertionPoint();
+ }
+ }

- if (m_iSelectionAnchor < getPoint())
- {
- iPos1 = m_iSelectionAnchor;
- iPos2 = getPoint();
- }
- else
- {
- iPos1 = getPoint();
- iPos2 = m_iSelectionAnchor;
- }
+ UT_Bool FV_View::setStyle(const XML_Char * style)
+ {
+ UT_Bool bRet;

- _clearBetweenPositions(iPos1, iPos2, UT_TRUE);
-}
+ PT_DocPosition posStart = getPoint();
+ PT_DocPosition posEnd = posStart;

-void FV_View::_clearSelection(void)
-{
- if (!m_bSelection)
- {
- _resetSelection();
- return;
- }
+ if (!isSelectionEmpty())
+ {
+ if (m_iSelectionAnchor < posStart)
+ {
+ posStart = m_iSelectionAnchor;
+ }
+ else
+ {
+ posEnd = m_iSelectionAnchor;
+ }
+ }
+
+ // lookup the current style
+ PD_Style * pStyle = NULL;
+ m_pDoc->getStyle(style, &pStyle);
+ if (!pStyle)
+ {
+ UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
+ return UT_FALSE;
+ }
+
+ UT_Bool bCharStyle = pStyle->isCharStyle();
+
+ const XML_Char * attribs[] = { PT_STYLE_ATTRIBUTE_NAME, 0, 0 };
+ attribs[1] = style;
+
+ if (bCharStyle)
+ {
+ // set character-level style
+ if (isSelectionEmpty())
+ {
+ _eraseInsertionPoint();
+ }
+
+ _clearIfAtFmtMark(getPoint()); // TODO is this correct ??
+ _eraseSelection();
+
+ bRet = m_pDoc->changeSpanFmt(PTC_AddStyle,posStart,posEnd,attribs,NULL);
+ }
+ else
+ {
+ // set block-level style
+ _eraseInsertionPoint();
+
+ _clearIfAtFmtMark(getPoint()); // TODO is this correct ??
+
+ // NB: clear explicit props at both block and char levels
+ bRet = m_pDoc->changeStruxFmt(PTC_AddStyle,posStart,posEnd,attribs,NULL,PTX_Block);
+ }
+
+ _generalUpdate();
+
+ if (isSelectionEmpty())
+ {
+ _fixInsertionPointCoords();
+ _drawInsertionPoint();
+ }
+ return bRet;
+ }

- UT_uint32 iPos1, iPos2;

- if (m_iSelectionAnchor < getPoint())
- {
- iPos1 = m_iSelectionAnchor;
- iPos2 = getPoint();
- }
- else
- {
- iPos1 = getPoint();
- iPos2 = m_iSelectionAnchor;
- }
+ static const XML_Char * x_getStyle(const PP_AttrProp * pAP, UT_Bool bBlock)
+ {
+ UT_ASSERT(pAP);
+ const XML_Char* sz = NULL;

- _clearBetweenPositions(iPos1, iPos2, UT_TRUE);
-
- _resetSelection();
+ pAP->getAttribute(PT_STYLE_ATTRIBUTE_NAME, sz);

- _drawBetweenPositions(iPos1, iPos2);
-}
+ // TODO: should we have an explicit default for char styles?
+ if (!sz && bBlock)
+ sz = "Normal";

-void FV_View::_resetSelection(void)
-{
- m_bSelection = UT_FALSE;
- m_iSelectionAnchor = getPoint();
-}
+ return sz;
+ }

-void FV_View::_drawSelection()
-{
- UT_ASSERT(!isSelectionEmpty());
+ UT_Bool FV_View::getStyle(const XML_Char ** style)
+ {
+ UT_Bool bCharStyle = UT_FALSE;
+ const XML_Char * szChar = NULL;
+ const XML_Char * szBlock = NULL;
+
+ const PP_AttrProp * pBlockAP = NULL;
+
+ /*
+ IDEA: We want to know the style, iff it's constant across the
+ entire selection. Usually, this will be a block-level style.
+ However, if the entire span has the same char-level style,
+ we'll report that instead.
+ */
+ PT_DocPosition posStart = getPoint();
+ PT_DocPosition posEnd = posStart;
+ UT_Bool bSelEmpty = isSelectionEmpty();
+
+ if (!bSelEmpty)
+ {
+ if (m_iSelectionAnchor < posStart)
+ posStart = m_iSelectionAnchor;
+ else
+ posEnd = m_iSelectionAnchor;
+ }
+
+ // 1. get block style at insertion point
+ fl_BlockLayout* pBlock = _findBlockAtPosition(posStart);
+ pBlock->getAttrProp(&pBlockAP);
+
+ szBlock = x_getStyle(pBlockAP, UT_TRUE);
+
+ // 2. prune if block style varies across selection
+ if (!bSelEmpty)
+ {
+ fl_BlockLayout* pBlockEnd = _findBlockAtPosition(posEnd);
+
+ while (pBlock && (pBlock != pBlockEnd))
+ {
+ const PP_AttrProp * pAP;
+ UT_Bool bCheck = UT_FALSE;
+
+ pBlock = pBlock->getNextBlockInDocument();
+
+ if (!pBlock)
+ {
+ // at EOD, so just bail
+ break;
+ }

- if (m_iSelectionAnchor < getPoint())
- {
- _drawBetweenPositions(m_iSelectionAnchor, getPoint());
- }
- else
- {
- _drawBetweenPositions(getPoint(), m_iSelectionAnchor);
- }
-}
+ // did block format change?
+ pBlock->getAttrProp(&pAP);
+ if (pBlockAP != pAP)
+ {
+ pBlockAP = pAP;
+ bCheck = UT_TRUE;
+ }
+
+ if (bCheck)
+ {
+ const XML_Char* sz = x_getStyle(pBlockAP, UT_TRUE);
+
+ if (UT_stricmp(sz, szBlock))
+ {
+ // doesn't match, so stop looking
+ szBlock = NULL;
+ pBlock = NULL;
+ break;
+ }
+ }
+ }
+ }
+
+ // NOTE: if block style varies, no need to check char style
+
+ if (szBlock && szBlock[0])
+ {
+ const PP_AttrProp * pSpanAP = NULL;
+
+ // 3. locate char style at insertion point
+ UT_sint32 xPoint;
+ UT_sint32 yPoint;
+ UT_sint32 iPointHeight;
+
+ fl_BlockLayout* pBlock = _findBlockAtPosition(posStart);
+ UT_uint32 blockPosition = pBlock->getPosition();
+ fp_Run* pRun = pBlock->findPointCoords(posStart, UT_FALSE,
+ xPoint, yPoint, iPointHeight);
+ UT_Bool bLeftSide = UT_TRUE;
+
+ // TODO consider adding indexAP from change record to the
+ // TODO runs so that we can just use it here.
+
+ if (!bSelEmpty)
+ {
+ // we want the interior of the selection -- and not the
+ // format to the left of the start of the selection.
+ bLeftSide = UT_FALSE;
+
+ /*
+ Likewise, findPointCoords will return the run to the right
+ of the specified position, so we need to stop looking one
+ position to the left.
+ */
+ posEnd--;
+ }
+
+ pBlock->getSpanAttrProp( (posStart - blockPosition), bLeftSide, &pSpanAP);
+
+ if (pSpanAP)
+ {
+ szChar = x_getStyle(pSpanAP, UT_FALSE);
+ bCharStyle = (szChar && szChar[0]);
+ }
+
+ // 4. prune if char style varies across selection
+ if (!bSelEmpty)
+ {
+ fl_BlockLayout* pBlockEnd = _findBlockAtPosition(posEnd);
+ fp_Run* pRunEnd = pBlockEnd->findPointCoords(posEnd, UT_FALSE,
+ xPoint, yPoint, iPointHeight);
+ while (pRun && (pRun != pRunEnd))
+ {
+ const PP_AttrProp * pAP;
+ UT_Bool bCheck = UT_FALSE;
+
+ pRun = pRun->getNext();
+ if (!pRun)
+ {
+ // go to first run of next block
+ pBlock = pBlock->getNextBlockInDocument();
+ if (!pBlock) // at EOD, so just bail
+ break;
+ pRun = pBlock->getFirstRun();
+ }
+
+ // did span format change?
+
+ pAP = NULL;
+ pBlock->getSpanAttrProp(pRun->getBlockOffset()+pRun->getLength(),UT_TRUE,&pAP);
+ if (pAP && (pSpanAP != pAP))
+ {
+ pSpanAP = pAP;
+ bCheck = UT_TRUE;
+ }
+
+ if (bCheck)
+ {
+ const XML_Char* sz = x_getStyle(pSpanAP, UT_TRUE);
+ UT_Bool bHere = (sz && sz[0]);
+
+ if ((bCharStyle != bHere) || (UT_stricmp(sz, szChar)))
+ {
+ // doesn't match, so stop looking
+ bCharStyle = UT_FALSE;
+ szChar = NULL;
+ pRun = NULL;
+ break;
+ }
+ }
+ }
+ }
+ }

-void FV_View::_setSelectionAnchor(void)
-{
- m_bSelection = UT_TRUE;
- m_iSelectionAnchor = getPoint();
-}
+ *style = (bCharStyle ? szChar : szBlock);

-void FV_View::_deleteSelection(void)
-{
- // delete the current selection.
- // NOTE: this must clear the selection.
+ return UT_TRUE;
+ }

- UT_ASSERT(!isSelectionEmpty());
+ UT_Bool FV_View::setCharFormat(const XML_Char * properties[])
+ {
+ UT_Bool bRet;

- PT_DocPosition iPoint = getPoint();
- UT_ASSERT(iPoint != m_iSelectionAnchor);
+ if (isSelectionEmpty())
+ {
+ _eraseInsertionPoint();
+ }
+
+ PT_DocPosition posStart = getPoint();
+ PT_DocPosition posEnd = posStart;
+
+ if (!isSelectionEmpty())
+ {
+ if (m_iSelectionAnchor < posStart)
+ {
+ posStart = m_iSelectionAnchor;
+ }
+ else
+ {
+ posEnd = m_iSelectionAnchor;
+ }
+ }
+
+ _eraseSelection();
+
+ bRet = m_pDoc->changeSpanFmt(PTC_AddFmt,posStart,posEnd,NULL,properties);
+
+ _generalUpdate();
+
+ if (isSelectionEmpty())
+ {
+ _fixInsertionPointCoords();
+ _drawInsertionPoint();
+ }

- UT_uint32 iSelAnchor = m_iSelectionAnchor;
-
- _eraseSelection();
- _resetSelection();
+ return bRet;
+ }

- UT_Bool bForward = (iPoint < iSelAnchor);
- if (bForward)
- {
- m_pDoc->deleteSpan(iPoint, iSelAnchor);
- }
- else
- {
- m_pDoc->deleteSpan(iSelAnchor, iPoint);
- }
-}
+ UT_Bool FV_View::getCharFormat(const XML_Char *** pProps, UT_Bool bExpandStyles)
+ {
+ const PP_AttrProp * pSpanAP = NULL;
+ const PP_AttrProp * pBlockAP = NULL;
+ const PP_AttrProp * pSectionAP = NULL; // TODO do we care about section-level inheritance
+ UT_Vector v;
+ UT_uint32 i;
+ _fmtPair * f;
+
+ /*
+ IDEA: We want to know character-level formatting properties, iff
+ they're constant across the entire selection. To do so, we start
+ at the beginning of the selection, load 'em all into a vector, and
+ then prune any property that collides.
+ */
+ PT_DocPosition posStart = getPoint();
+ PT_DocPosition posEnd = posStart;
+ UT_Bool bSelEmpty = isSelectionEmpty();
+
+ if (!bSelEmpty)
+ {
+ if (m_iSelectionAnchor < posStart)
+ posStart = m_iSelectionAnchor;
+ else
+ posEnd = m_iSelectionAnchor;
+ }
+
+ // 1. assemble complete set at insertion point
+ UT_sint32 xPoint;
+ UT_sint32 yPoint;
+ UT_sint32 iPointHeight;
+
+ fl_BlockLayout* pBlock = _findBlockAtPosition(posStart);
+ UT_uint32 blockPosition = pBlock->getPosition();
+ fp_Run* pRun = pBlock->findPointCoords(posStart, UT_FALSE,
+ xPoint, yPoint, iPointHeight);
+ UT_Bool bLeftSide = UT_TRUE;
+
+ // TODO consider adding indexAP from change record to the
+ // TODO runs so that we can just use it here.
+
+ if (!bSelEmpty)
+ {
+ // we want the interior of the selection -- and not the
+ // format to the left of the start of the selection.
+ bLeftSide = UT_FALSE;
+
+ /*
+ Likewise, findPointCoords will return the run to the right
+ of the specified position, so we need to stop looking one
+ position to the left.
+ */
+ posEnd--;
+ }
+
+ pBlock->getSpanAttrProp( (posStart - blockPosition), bLeftSide, &pSpanAP);
+
+ pBlock->getAttrProp(&pBlockAP);
+
+ v.addItem(new _fmtPair("font-family", pSpanAP,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
+ v.addItem(new _fmtPair("font-size", pSpanAP,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
+ v.addItem(new _fmtPair("font-weight", pSpanAP,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
+ v.addItem(new _fmtPair("font-style", pSpanAP,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
+ v.addItem(new _fmtPair("text-decoration",pSpanAP,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
+ v.addItem(new _fmtPair("color", pSpanAP,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
+
+ // 2. prune 'em as they vary across selection
+ if (!bSelEmpty)
+ {
+ fl_BlockLayout* pBlockEnd = _findBlockAtPosition(posEnd);
+ fp_Run* pRunEnd = pBlockEnd->findPointCoords(posEnd, UT_FALSE,
+ xPoint, yPoint, iPointHeight);
+ while (pRun && (pRun != pRunEnd))
+ {
+ const PP_AttrProp * pAP;
+ UT_Bool bCheck = UT_FALSE;
+
+ pRun = pRun->getNext();
+ if (!pRun)
+ {
+ // go to first run of next block
+ pBlock = pBlock->getNextBlockInDocument();
+
+ if (!pBlock) // at EOD, so just bail
+ break;
+
+ // did block format change?
+ pBlock->getAttrProp(&pAP);
+ if (pBlockAP != pAP)
+ {
+ pBlockAP = pAP;
+ bCheck = UT_TRUE;
+ }
+
+ pRun = pBlock->getFirstRun();
+ }
+
+ // did span format change?
+
+ pAP = NULL;
+ pBlock->getSpanAttrProp(pRun->getBlockOffset()+pRun->getLength(),UT_TRUE,&pAP);
+ if (pSpanAP != pAP)
+ {
+ pSpanAP = pAP;
+ bCheck = UT_TRUE;
+ }
+
+ if (bCheck)
+ {
+ i = v.getItemCount();
+
+ while (i > 0)
+ {
+ f = (_fmtPair *)v.getNthItem(i-1);
+
+ const XML_Char * value = PP_evalProperty(f->m_prop,pSpanAP,pBlockAP,pSectionAP,m_pDoc,bExpandStyles);
+ UT_ASSERT(value);
+
+ // prune anything that doesn't match
+ if (UT_stricmp(f->m_val, value))
+ {
+ DELETEP(f);
+ v.deleteNthItem(i-1);
+ }
+
+ i--;
+ }
+
+ // when vector is empty, stop looking
+ if (0 == v.getItemCount())
+ {
+ pRun = NULL;
+ break;
+ }
+ }
+ }
+ }
+
+ // 3. export whatever's left
+ UT_uint32 count = v.getItemCount()*2 + 1;
+
+ // NOTE: caller must free this, but not the referenced contents
+ const XML_Char ** props = (const XML_Char **) calloc(count, sizeof(XML_Char *));
+ if (!props)
+ return UT_FALSE;
+
+ const XML_Char ** p = props;
+
+ i = v.getItemCount();
+
+ while (i > 0)
+ {
+ f = (_fmtPair *)v.getNthItem(i-1);
+ i--;
+
+ p[0] = f->m_prop;
+ p[1] = f->m_val;
+ p += 2;
+ }

-UT_Bool FV_View::isSelectionEmpty()
-{
- if (!m_bSelection)
- {
- return UT_TRUE;
- }
-
- PT_DocPosition curPos = getPoint();
- if (curPos == m_iSelectionAnchor)
- {
- return UT_TRUE;
- }
+ UT_VECTOR_PURGEALL(_fmtPair *,v);

- return UT_FALSE;
-}
+ *pProps = props;

-PT_DocPosition FV_View::_getDocPos(FV_DocPos dp, UT_Bool bKeepLooking)
-{
- return _getDocPosFromPoint(getPoint(),dp,bKeepLooking);
-}
+ return UT_TRUE;
+ }

-PT_DocPosition FV_View::_getDocPosFromPoint(PT_DocPosition iPoint, FV_DocPos dp, UT_Bool bKeepLooking)
-{
- UT_sint32 xPoint;
- UT_sint32 yPoint;
- UT_sint32 iPointHeight;
+ UT_Bool FV_View::setBlockFormat(const XML_Char * properties[])
+ {
+ UT_Bool bRet;

- PT_DocPosition iPos;
+ _clearIfAtFmtMark(getPoint());

- // this gets called from ctor, so get out quick
- if (dp == FV_DOCPOS_BOD)
- {
- UT_Bool bRes = m_pDoc->getBounds(UT_FALSE, iPos);
- UT_ASSERT(bRes);
+ _eraseInsertionPoint();

- return iPos;
- }
+ PT_DocPosition posStart = getPoint();
+ PT_DocPosition posEnd = posStart;

- // TODO: could cache these to save a lookup if point doesn't change
- fl_BlockLayout* pBlock = _findBlockAtPosition(iPoint);
- fp_Run* pRun = pBlock->findPointCoords(iPoint, m_bPointEOL,
- xPoint, yPoint, iPointHeight);
- fp_Line* pLine = pRun->getLine();
+ if (!isSelectionEmpty())
+ {
+ if (m_iSelectionAnchor < posStart)
+ {
+ posStart = m_iSelectionAnchor;
+ }
+ else
+ {
+ posEnd = m_iSelectionAnchor;
+ }
+ }
+
+ bRet = m_pDoc->changeStruxFmt(PTC_AddFmt,posStart,posEnd,NULL,properties,PTX_Block);
+
+ _generalUpdate();
+
+ if (isSelectionEmpty())
+ {
+ _fixInsertionPointCoords();
+ _drawInsertionPoint();
+ }

- // be pessimistic
- iPos = iPoint;
+ return bRet;
+ }

- switch (dp)
- {
- case FV_DOCPOS_BOL:
- {
- fp_Run* pFirstRun = pLine->getFirstRun();
+ UT_Bool FV_View::getSectionFormat(const XML_Char ***pProps)
+ {
+ const PP_AttrProp * pBlockAP = NULL;
+ const PP_AttrProp * pSectionAP = NULL;
+ UT_Vector v;
+ UT_uint32 i;
+ _fmtPair * f;
+
+ /*
+ IDEA: We want to know block-level formatting properties, iff
+ they're constant across the entire selection. To do so, we start
+ at the beginning of the selection, load 'em all into a vector, and
+ then prune any property that collides.
+ */
+ PT_DocPosition posStart = getPoint();
+ PT_DocPosition posEnd = posStart;
+
+ if (!isSelectionEmpty())
+ {
+ if (m_iSelectionAnchor < posStart)
+ posStart = m_iSelectionAnchor;
+ else
+ posEnd = m_iSelectionAnchor;
+ }
+
+ // 1. assemble complete set at insertion point
+ fl_BlockLayout* pBlock = _findBlockAtPosition(posStart);
+ fl_SectionLayout* pSection = pBlock->getSectionLayout();
+ pSection->getAttrProp(&pSectionAP);
+
+ v.addItem(new _fmtPair("columns", NULL,pBlockAP,pSectionAP,m_pDoc,UT_FALSE));
+ v.addItem(new _fmtPair("column-gap",NULL,pBlockAP,pSectionAP,m_pDoc,UT_FALSE));
+
+ // 2. prune 'em as they vary across selection
+ if (!isSelectionEmpty())
+ {
+ fl_BlockLayout* pBlockEnd = _findBlockAtPosition(posEnd);
+ fl_SectionLayout *pSectionEnd = pBlockEnd->getSectionLayout();
+
+ while (pSection && (pSection != pSectionEnd))
+ {
+ const PP_AttrProp * pAP;
+ UT_Bool bCheck = UT_FALSE;

- iPos = pFirstRun->getBlockOffset() + pBlock->getPosition();
- }
- break;
-
- case FV_DOCPOS_EOL:
- {
- fp_Run* pLastRun = pLine->getLastRun();
+ pSection = pSection->getNext();
+ if (!pSection) // at EOD, so just bail
+ break;

- while (!pLastRun->isFirstRunOnLine() && pLastRun->isForcedBreak())
- {
- pLastRun = pLastRun->getPrev();
- }
+ // did block format change?
+ pSection->getAttrProp(&pAP);
+ if (pSectionAP != pAP)
+ {
+ pSectionAP = pAP;
+ bCheck = UT_TRUE;
+ }
+
+ if (bCheck)
+ {
+ i = v.getItemCount();
+
+ while (i > 0)
+ {
+ f = (_fmtPair *)v.getNthItem(i-1);
+
+ const XML_Char * value = PP_evalProperty(f->m_prop,NULL,pBlockAP,pSectionAP,m_pDoc,UT_FALSE);
+ UT_ASSERT(value);
+
+ // prune anything that doesn't match
+ if (UT_stricmp(f->m_val, value))
+ {
+ DELETEP(f);
+ v.deleteNthItem(i-1);
+ }
+
+ i--;
+ }
+
+ // when vector is empty, stop looking
+ if (0 == v.getItemCount())
+ {
+ pSection = NULL;
+ break;
+ }
+ }
+ }
+ }
+
+ // 3. export whatever's left
+ UT_uint32 count = v.getItemCount()*2 + 1;
+
+ // NOTE: caller must free this, but not the referenced contents
+ const XML_Char ** props = (const XML_Char **) calloc(count, sizeof(XML_Char *));
+ if (!props)
+ return UT_FALSE;
+
+ const XML_Char ** p = props;
+
+ i = v.getItemCount();
+
+ while (i > 0)
+ {
+ f = (_fmtPair *)v.getNthItem(i-1);
+ i--;
+
+ p[0] = f->m_prop;
+ p[1] = f->m_val;
+ p += 2;
+ }

- if(pLastRun->isForcedBreak())
- {
- iPos = pBlock->getPosition() + pLastRun->getBlockOffset();
- }
- else
- {
- iPos = pBlock->getPosition() + pLastRun->getBlockOffset() + pLastRun->getLength();
- }
- }
- break;
+ UT_VECTOR_PURGEALL(_fmtPair *,v);

- case FV_DOCPOS_EOD:
- {
- UT_Bool bRes = m_pDoc->getBounds(UT_TRUE, iPos);
- UT_ASSERT(bRes);
- }
- break;
+ *pProps = props;

- case FV_DOCPOS_BOB:
- {
-#if 0
-// TODO this piece of code attempts to go back
-// TODO to the previous block if we are on the
-// TODO edge. this causes bug #92 (double clicking
-// TODO on the first line of a paragraph selects
-// TODO current paragraph and the previous paragraph).
-// TODO i'm not sure why it is here.
-// TODO
-// TODO it's here because it makes control-up-arrow
-// TODO when at the beginning of paragraph work. this
-// TODO problem is logged as bug #403.
-// TODO
- // are we already there?
- if (iPos == pBlock->getPosition())
- {
- // yep. is there a prior block?
- if (!pBlock->getPrevBlockInDocument())
- break;
+ return UT_TRUE;
+ }

- // yep. look there instead
- pBlock = pBlock->getPrevBlockInDocument();
- }
-#endif /* 0 */
-
- iPos = pBlock->getPosition();
- }
- break;
+ UT_Bool FV_View::getBlockFormat(const XML_Char *** pProps,UT_Bool bExpandStyles)
+ {
+ const PP_AttrProp * pBlockAP = NULL;
+ const PP_AttrProp * pSectionAP = NULL; // TODO do we care about section-level inheritance?
+ UT_Vector v;
+ UT_uint32 i;
+ _fmtPair * f;
+
+ /*
+ IDEA: We want to know block-level formatting properties, iff
+ they're constant across the entire selection. To do so, we start
+ at the beginning of the selection, load 'em all into a vector, and
+ then prune any property that collides.
+ */
+ PT_DocPosition posStart = getPoint();
+ PT_DocPosition posEnd = posStart;
+
+ if (!isSelectionEmpty())
+ {
+ if (m_iSelectionAnchor < posStart)
+ posStart = m_iSelectionAnchor;
+ else
+ posEnd = m_iSelectionAnchor;
+ }
+
+ // 1. assemble complete set at insertion point
+ fl_BlockLayout* pBlock = _findBlockAtPosition(posStart);
+ pBlock->getAttrProp(&pBlockAP);
+
+ v.addItem(new _fmtPair("text-align", NULL,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
+ v.addItem(new _fmtPair("text-indent", NULL,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
+ v.addItem(new _fmtPair("margin-left", NULL,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
+ v.addItem(new _fmtPair("margin-right", NULL,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
+ v.addItem(new _fmtPair("margin-top", NULL,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
+ v.addItem(new _fmtPair("margin-bottom", NULL,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
+ v.addItem(new _fmtPair("line-height", NULL,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
+ v.addItem(new _fmtPair("tabstops", NULL,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
+ v.addItem(new _fmtPair("default-tab-interval",NULL,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
+
+ // 2. prune 'em as they vary across selection
+ if (!isSelectionEmpty())
+ {
+ fl_BlockLayout* pBlockEnd = _findBlockAtPosition(posEnd);
+
+ while (pBlock && (pBlock != pBlockEnd))
+ {
+ const PP_AttrProp * pAP;
+ UT_Bool bCheck = UT_FALSE;

- case FV_DOCPOS_EOB:
- {
- if (pBlock->getNextBlockInDocument())
- {
- // BOB for next block
- pBlock = pBlock->getNextBlockInDocument();
- iPos = pBlock->getPosition();
- }
- else
- {
- // EOD
- UT_Bool bRes = m_pDoc->getBounds(UT_TRUE, iPos);
- UT_ASSERT(bRes);
- }
- }
- break;
+ pBlock = pBlock->getNextBlockInDocument();
+ if (!pBlock) // at EOD, so just bail
+ break;

- case FV_DOCPOS_BOW:
- {
- UT_GrowBuf pgb(1024);
+ // did block format change?
+ pBlock->getAttrProp(&pAP);
+ if (pBlockAP != pAP)
+ {
+ pBlockAP = pAP;
+ bCheck = UT_TRUE;
+ }
+
+ if (bCheck)
+ {
+ i = v.getItemCount();
+
+ while (i > 0)
+ {
+ f = (_fmtPair *)v.getNthItem(i-1);
+
+ const XML_Char * value = PP_evalProperty(f->m_prop,NULL,pBlockAP,pSectionAP,m_pDoc,bExpandStyles);
+ UT_ASSERT(value);
+
+ // prune anything that doesn't match
+ if (UT_stricmp(f->m_val, value))
+ {
+ DELETEP(f);
+ v.deleteNthItem(i-1);
+ }
+
+ i--;
+ }
+
+ // when vector is empty, stop looking
+ if (0 == v.getItemCount())
+ {
+ pBlock = NULL;
+ break;
+ }
+ }
+ }
+ }
+
+ // 3. export whatever's left
+ UT_uint32 count = v.getItemCount()*2 + 1;
+
+ // NOTE: caller must free this, but not the referenced contents
+ const XML_Char ** props = (const XML_Char **) calloc(count, sizeof(XML_Char *));
+ if (!props)
+ return UT_FALSE;
+
+ const XML_Char ** p = props;
+
+ i = v.getItemCount();
+
+ while (i > 0)
+ {
+ f = (_fmtPair *)v.getNthItem(i-1);
+ i--;
+
+ p[0] = f->m_prop;
+ p[1] = f->m_val;
+ p += 2;
+ }

- UT_Bool bRes = pBlock->getBlockBuf(&pgb);
- UT_ASSERT(bRes);
+ UT_VECTOR_PURGEALL(_fmtPair *,v);

- const UT_UCSChar* pSpan = pgb.getPointer(0);
+ *pProps = props;

- UT_ASSERT(iPos >= pBlock->getPosition());
- UT_uint32 offset = iPos - pBlock->getPosition();
- UT_ASSERT(offset <= pgb.getLength());
+ return UT_TRUE;
+ }

- if (offset == 0)
- {
- if (!bKeepLooking)
- break;
+ void FV_View::delTo(FV_DocPos dp)
+ {
+ PT_DocPosition iPos = _getDocPos(dp);

- // is there a prior block?
- pBlock = pBlock->getPrevBlockInDocument();
+ if (iPos == getPoint())
+ {
+ return;
+ }

- if (!pBlock)
- break;
+ _extSelToPos(iPos);
+ _deleteSelection();

- // yep. look there instead
- pgb.truncate(0);
- bRes = pBlock->getBlockBuf(&pgb);
- UT_ASSERT(bRes);
+ _fixInsertionPointCoords();
+ _drawInsertionPoint();
+ }

- pSpan = pgb.getPointer(0);
- offset = pgb.getLength();
+ /*
+ This function is somewhat of a compromise. It will return a new
+ range of memory (destroy with free()) full of what's in the selection,
+ but it will not cross block boundaries. This is for convenience
+ in implementation, but could probably be accomplished without
+ too much more effort. However, since an edit entry in a dialog
+ box (1) only allows a bit of text and (2) has no concept of a
+ block break anyway, I don't see a reason to make this behave
+ differently.
+ */
+ UT_UCSChar * FV_View::getSelectionText(void)
+ {
+ UT_ASSERT(!isSelectionEmpty());

- if (offset == 0)
- {
- iPos = pBlock->getPosition();
- break;
- }
- }
+ UT_GrowBuf buffer;

- UT_Bool bInWord = !UT_isWordDelimiter(pSpan[bKeepLooking ? offset-1 : offset]);
+ UT_uint32 selLength = labs(m_iInsPoint - m_iSelectionAnchor);

- for (offset--; offset > 0; offset--)
- {
- if (UT_isWordDelimiter(pSpan[offset]))
- {
- if (bInWord)
- break;
- }
- else
- bInWord = UT_TRUE;
- }
+ PT_DocPosition low;
+ if (m_iInsPoint > m_iSelectionAnchor)
+ {
+ low = m_iSelectionAnchor;
+ }
+ else
+ {
+ low = m_iInsPoint;
+ }

- if ((offset > 0) && (offset < pgb.getLength()))
- offset++;
+ // get the current block the insertion point is in
+ fl_BlockLayout * block = m_pLayout->findBlockAtPosition(low);

- iPos = offset + pBlock->getPosition();
- }
- break;
+ if (block)
+ {
+ block->getBlockBuf(&buffer);

- case FV_DOCPOS_EOW:
- {
- UT_GrowBuf pgb(1024);
+ UT_UCSChar * bufferSegment = NULL;

- UT_Bool bRes = pBlock->getBlockBuf(&pgb);
- UT_ASSERT(bRes);
+ PT_DocPosition offset = low - block->getPosition(UT_FALSE);

- const UT_UCSChar* pSpan = pgb.getPointer(0);
+ // allow no more than the rest of the block
+ if (offset + selLength > buffer.getLength())
+ selLength = buffer.getLength() - offset;

- UT_ASSERT(iPos >= pBlock->getPosition());
- UT_uint32 offset = iPos - pBlock->getPosition();
- UT_ASSERT(offset <= pgb.getLength());
+ // give us space for our new chunk of selected text, add 1 so it
+ // terminates itself
+ bufferSegment = (UT_UCSChar *) calloc(selLength + 1, sizeof(UT_UCSChar));

- if (offset == pgb.getLength())
- {
- if (!bKeepLooking)
- break;
+ // copy it out
+ memmove(bufferSegment, buffer.getPointer(offset), selLength * sizeof(UT_UCSChar));

- // is there a next block?
- pBlock = pBlock->getNextBlockInDocument();
+ return bufferSegment;
+ }

- if (!pBlock)
- break;
+ return NULL;
+ }

- // yep. look there instead
- pgb.truncate(0);
- bRes = pBlock->getBlockBuf(&pgb);
- UT_ASSERT(bRes);
+ void FV_View::cmdCharDelete(UT_Bool bForward, UT_uint32 count)
+ {
+ if (!isSelectionEmpty())
+ {
+ _deleteSelection();
+
+ _generalUpdate();
+
+ if (!_ensureThatInsertionPointIsOnScreen())
+ {
+ _fixInsertionPointCoords();
+ _drawInsertionPoint();
+ }
+ }
+ else
+ {
+ _eraseInsertionPoint();
+
+ UT_uint32 amt = count;
+ UT_uint32 posCur = getPoint();
+
+ if (!bForward)
+ {
+
+ if (!_charMotion(bForward,count))
+ {
+ UT_ASSERT(getPoint() <= posCur);
+ amt = posCur - getPoint();
+ }
+
+ posCur = getPoint();
+ }
+ else
+ {
+ PT_DocPosition posEOD;
+ UT_Bool bRes;
+
+ bRes = m_pDoc->getBounds(UT_TRUE, posEOD);
+ UT_ASSERT(bRes);
+ UT_ASSERT(posCur <= posEOD);
+
+ if (posEOD < (posCur+amt))
+ {
+ amt = posEOD - posCur;
+ }
+ }
+
+ if (amt > 0)
+ {
+ m_pDoc->deleteSpan(posCur, posCur+amt);
+ }
+
+ _generalUpdate();
+
+ if (!_ensureThatInsertionPointIsOnScreen())
+ {
+ _fixInsertionPointCoords();
+ _drawInsertionPoint();
+ }
+ }
+ }

- pSpan = pgb.getPointer(0);
- offset = 0;
+ void FV_View::_moveInsPtNextPrevLine(UT_Bool bNext)
+ {
+ UT_sint32 xPoint;
+ UT_sint32 yPoint;
+ UT_sint32 iPointHeight, iLineHeight;
+
+ /*
+ This function moves the IP up or down one line, attempting to get
+ as close as possible to the prior "sticky" x position. The notion
+ of "next" is strictly physical, not logical.
+
+ For example, instead of always moving from the last line of one block
+ to the first line of the next, you might wind up skipping over a
+ bunch of blocks to wind up in the first line of the second column.
+ */
+ UT_sint32 xOldSticky = m_xPointSticky;
+
+ // first, find the line we are on now
+ UT_uint32 iOldPoint = getPoint();
+
+ fl_BlockLayout* pOldBlock = _findBlockAtPosition(iOldPoint);
+ fp_Run* pOldRun = pOldBlock->findPointCoords(getPoint(), m_bPointEOL, xPoint, yPoint, iPointHeight);
+ fl_SectionLayout* pOldSL = pOldBlock->getSectionLayout();
+ fp_Line* pOldLine = pOldRun->getLine();
+ fp_Container* pOldContainer = pOldLine->getContainer();
+ fp_Page* pOldPage = pOldContainer->getPage();
+ UT_Bool bDocSection = (pOldSL->getType() == FL_SECTION_DOC);
+
+ fp_Column* pOldLeader = NULL;
+ if (bDocSection)
+ {
+ pOldLeader = ((fp_Column*) (pOldContainer))->getLeader();
+ }
+
+ UT_sint32 iPageOffset;
+ getPageYOffset(pOldPage, iPageOffset);
+
+ UT_sint32 iLineX = 0;
+ UT_sint32 iLineY = 0;
+
+ pOldContainer->getOffsets(pOldLine, iLineX, iLineY);
+ yPoint = iLineY;
+
+ iLineHeight = pOldLine->getHeight();
+
+ UT_Bool bNOOP = UT_FALSE;
+
+ if (bNext)
+ {
+ if (pOldLine != pOldContainer->getLastLine())
+ {
+ // just move off this line
+ yPoint += (iLineHeight + pOldLine->getMarginAfter());
+ }
+ else if (bDocSection && (((fp_Column*) (pOldSL->getLastContainer()))->getLeader() == pOldLeader))
+ {
+ // move to next section
+ fl_SectionLayout* pSL = pOldSL->getNext();
+ if (pSL)
+ {
+ yPoint = pSL->getFirstContainer()->getY();
+ }
+ else
+ {
+ bNOOP = UT_TRUE;
+ }
+ }
+ else
+ {
+ // move to next page
+ fp_Page* pPage = pOldPage->getNext();
+ if (pPage)
+ {
+ getPageYOffset(pPage, iPageOffset);
+ yPoint = 0;
+ }
+ else
+ {
+ bNOOP = UT_TRUE;
+ }
+ }
+ }
+ else
+ {
+ if (pOldLine != pOldContainer->getFirstLine())
+ {
+ // just move off this line
+ yPoint -= (pOldLine->getMarginBefore() + 1);
+ }
+ else if (bDocSection && (pOldSL->getFirstContainer() == pOldLeader))
+ {
+ // move to prev section
+ fl_SectionLayout* pSL = pOldSL->getPrev();
+ if (pSL)
+ {
+ fp_Column* pTmpCol = ((fp_Column*) (pSL->getLastContainer()))->getLeader();
+ yPoint = pTmpCol->getY();
+
+ UT_sint32 iMostHeight = 0;
+ while (pTmpCol)
+ {
+ iMostHeight = UT_MAX(iMostHeight, pTmpCol->getHeight());
+
+ pTmpCol = pTmpCol->getFollower();
+ }
+
+ yPoint += (iMostHeight - 1);
+ }
+ else
+ {
+ bNOOP = UT_TRUE;
+ }
+ }
+ else
+ {
+ // move to prev page
+ fp_Page* pPage = pOldPage->getPrev();
+ if (pPage)
+ {
+ getPageYOffset(pPage, iPageOffset);
+ yPoint = pPage->getBottom();
+ }
+ else
+ {
+ bNOOP = UT_TRUE;
+ }
+ }
+ }
+
+ if (bNOOP)
+ {
+ // cannot move. should we beep?
+ _drawInsertionPoint();
+ return;
+ }
+
+ // change to screen coordinates
+ xPoint = m_xPointSticky - m_xScrollOffset + fl_PAGEVIEW_MARGIN_X;
+ yPoint += iPageOffset - m_yScrollOffset;
+
+ // hit-test to figure out where that puts us
+ UT_sint32 xClick, yClick;
+ fp_Page* pPage = _getPageForXY(xPoint, yPoint, xClick, yClick);
+
+ PT_DocPosition iNewPoint;
+ UT_Bool bBOL, bEOL;
+ pPage->mapXYToPosition(xClick, yClick, iNewPoint, bBOL, bEOL);
+
+ UT_ASSERT(iNewPoint != iOldPoint);
+
+ _setPoint(iNewPoint, bEOL);
+
+ if (!_ensureThatInsertionPointIsOnScreen())
+ {
+ _fixInsertionPointCoords();
+ _drawInsertionPoint();
+ }

- if (pgb.getLength() == 0)
- {
- iPos = pBlock->getPosition();
- break;
- }
- }
+ // this is the only place where we override changes to m_xPointSticky
+ m_xPointSticky = xOldSticky;
+ }

- UT_Bool bBetween = UT_isWordDelimiter(pSpan[offset]);
-
- // Needed so ctrl-right arrow will work
- for (; offset < pgb.getLength(); offset++)
- {
- if (!UT_isWordDelimiter(pSpan[offset]))
- break;
- }
-
- for (; offset < pgb.getLength(); offset++)
- {
- if (!UT_isWordDelimiter(pSpan[offset]))
- {
- if (bBetween)
- break;
- }
- else if (pSpan[offset] != ' ')
- break;
- else
- bBetween = UT_TRUE;
- }
+ UT_Bool FV_View::_ensureThatInsertionPointIsOnScreen(void)
+ {
+ UT_Bool bRet = UT_FALSE;

- iPos = offset + pBlock->getPosition();
- }
- break;
+ if (m_iWindowHeight <= 0)
+ {
+ return UT_FALSE;
+ }
+
+ _fixInsertionPointCoords();
+
+ //UT_DEBUGMSG(("_ensure: [xp %ld][yp %ld][ph %ld] [w %ld][h %ld]\n",m_xPoint,m_yPoint,m_iPointHeight,m_iWindowWidth,m_iWindowHeight));
+
+ if (m_yPoint < 0)
+ {
+ cmdScroll(AV_SCROLLCMD_LINEUP, (UT_uint32) (-(m_yPoint)));
+ bRet = UT_TRUE;
+ }
+ else if (((UT_uint32) (m_yPoint + m_iPointHeight)) >= ((UT_uint32) m_iWindowHeight))
+ {
+ cmdScroll(AV_SCROLLCMD_LINEDOWN, (UT_uint32)(m_yPoint + m_iPointHeight - m_iWindowHeight));
+ bRet = UT_TRUE;
+ }
+
+ /*
+ TODO: we really ought to try to do better than this.
+ */
+ if (m_xPoint < 0)
+ {
+ cmdScroll(AV_SCROLLCMD_LINELEFT, (UT_uint32) (-(m_xPoint)));
+ bRet = UT_TRUE;
+ }
+ else if (((UT_uint32) (m_xPoint)) >= ((UT_uint32) m_iWindowWidth))
+ {
+ cmdScroll(AV_SCROLLCMD_LINERIGHT, (UT_uint32)(m_xPoint - m_iWindowWidth));
+ bRet = UT_TRUE;
+ }

- case FV_DOCPOS_BOS:
- case FV_DOCPOS_EOS:
- UT_ASSERT(UT_TODO);
- break;
+ return bRet;
+ }

- default:
- UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
- break;
- }
+ void FV_View::warpInsPtNextPrevLine(UT_Bool bNext)
+ {
+ if (!isSelectionEmpty())
+ _moveToSelectionEnd(bNext);
+ else
+ _eraseInsertionPoint();
+
+ _resetSelection();
+ _clearIfAtFmtMark(getPoint());
+ _moveInsPtNextPrevLine(bNext);
+ notifyListeners(AV_CHG_MOTION);
+ }

- return iPos;
-}
+ void FV_View::extSelNextPrevLine(UT_Bool bNext)
+ {
+ if (isSelectionEmpty())
+ {
+ _setSelectionAnchor();
+ _clearIfAtFmtMark(getPoint());
+ _moveInsPtNextPrevLine(bNext);
+ if (isSelectionEmpty())
+ {
+ _fixInsertionPointCoords();
+ _drawInsertionPoint();
+ }
+ else
+ {
+ _drawSelection();
+ }
+ }
+ else
+ {
+ PT_DocPosition iOldPoint = getPoint();
+ _moveInsPtNextPrevLine(bNext);
+ PT_DocPosition iNewPoint = getPoint();
+
+ // top/bottom of doc - nowhere to go
+ if (iOldPoint == iNewPoint)
+ return;
+
+ _extSel(iOldPoint);
+
+ if (isSelectionEmpty())
+ {
+ _resetSelection();
+ _fixInsertionPointCoords();
+ _drawInsertionPoint();
+ }
+ }

-void FV_View::moveInsPtTo(FV_DocPos dp)
-{
- if (!isSelectionEmpty())
- _clearSelection();
- else
- _eraseInsertionPoint();
-
- PT_DocPosition iPos = _getDocPos(dp);
+ notifyListeners(AV_CHG_MOTION);
+ }

- if (iPos != getPoint())
- {
- UT_Bool bPointIsValid = (getPoint() >= _getDocPos(FV_DOCPOS_BOD));
- if (bPointIsValid)
- _clearIfAtFmtMark(getPoint());
- }
+ void FV_View::extSelHorizontal(UT_Bool bForward, UT_uint32 count)
+ {
+ if (isSelectionEmpty())
+ {
+ _eraseInsertionPoint();
+ _setSelectionAnchor();
+ _charMotion(bForward, count);
+ }
+ else
+ {
+ PT_DocPosition iOldPoint = getPoint();
+
+ if (_charMotion(bForward, count) == UT_FALSE)
+ {
+ _setPoint(iOldPoint);
+ return;
+ }
+
+ _extSel(iOldPoint);
+ }
+
+ _ensureThatInsertionPointIsOnScreen();
+
+ /*
+ It IS possible for the selection to be empty, even
+ after extending it. If the charMotion fails, for example,
+ because we are at the end of a document, then the selection
+ will end up empty once again.
+ */
+ if (isSelectionEmpty())
+ {
+ _resetSelection();
+ _fixInsertionPointCoords();
+ _drawInsertionPoint();
+ }
+ else
+ {
+ _drawSelection();
+ }

- _setPoint(iPos, (dp == FV_DOCPOS_EOL));
+ notifyListeners(AV_CHG_MOTION);
+ }

- if (!_ensureThatInsertionPointIsOnScreen())
- {
- _fixInsertionPointCoords();
- _drawInsertionPoint();
- }
+ void FV_View::extSelTo(FV_DocPos dp)
+ {
+ PT_DocPosition iPos = _getDocPos(dp);

- notifyListeners(AV_CHG_MOTION);
-}
+ _extSelToPos(iPos);

-void FV_View::moveInsPtTo(PT_DocPosition dp)
-{
- if (!isSelectionEmpty())
- _clearSelection();
- else
- _eraseInsertionPoint();
-
- if (dp != getPoint())
- _clearIfAtFmtMark(getPoint());
+ if (!_ensureThatInsertionPointIsOnScreen())
+ {
+ if (isSelectionEmpty())
+ {
+ _fixInsertionPointCoords();
+ _drawInsertionPoint();
+ }
+ }

- _setPoint(dp, /* (dp == FV_DOCPOS_EOL) */ UT_FALSE); // is this bool correct?
+ notifyListeners(AV_CHG_MOTION);
+ }

- if (!_ensureThatInsertionPointIsOnScreen())
- {
- _fixInsertionPointCoords();
- _drawInsertionPoint();
- }
+ #define AUTO_SCROLL_MSECS 100

- notifyListeners(AV_CHG_MOTION);
-}
+ void FV_View::_autoScroll(UT_Timer * pTimer)
+ {
+ UT_ASSERT(pTimer);

+ // this is a static callback method and does not have a 'this' pointer.

-void FV_View::cmdCharMotion(UT_Bool bForward, UT_uint32 count)
-{
- if (!isSelectionEmpty())
- {
- _moveToSelectionEnd(bForward);
- // Note: _moveToSelectionEnd() clears the selection
- // but does not redraw the insertion point.
- _drawInsertionPoint();
- }
+ FV_View * pView = (FV_View *) pTimer->getInstanceData();
+ UT_ASSERT(pView);

- PT_DocPosition iPoint = getPoint();
- if (!_charMotion(bForward, count))
- _setPoint(iPoint);
- else
- _updateInsertionPoint();
+ PT_DocPosition iOldPoint = pView->getPoint();

- notifyListeners(AV_CHG_MOTION);
-}
+ /*
+ NOTE: We update the selection here, so that the timer can keep
+ triggering autoscrolls even if the mouse doesn't move.
+ */
+ pView->extSelToXY(pView->m_xLastMouse, pView->m_yLastMouse, UT_FALSE);
+
+ if (pView->getPoint() != iOldPoint)
+ {
+ // do the autoscroll
+ if (!pView->_ensureThatInsertionPointIsOnScreen())
+ {
+ pView->_fixInsertionPointCoords();
+ // pView->_drawInsertionPoint();
+ }
+ }
+ else
+ {
+ // not far enough to change the selection ... do we still need to scroll?
+ UT_sint32 xPos = pView->m_xLastMouse;
+ UT_sint32 yPos = pView->m_yLastMouse;
+
+ // TODO: clamp xPos, yPos to viewable area??
+
+ UT_Bool bOnScreen = UT_TRUE;
+
+ if ((xPos < 0 || xPos > pView->m_iWindowWidth) ||
+ (yPos < 0 || yPos > pView->m_iWindowHeight))
+ bOnScreen = UT_FALSE;
+
+ if (!bOnScreen)
+ {
+ // yep, do it manually
+
+ // TODO currently we blindly send these auto scroll events without regard
+ // TODO to whether the window can scroll any further in that direction.
+ // TODO we could optimize this a bit and check the scroll range before we
+ // TODO fire them, but that knowledge is only stored in the frame and we
+ // TODO don't have a backpointer to it.
+ // UT_DEBUGMSG(("_auto: [xp %ld][yp %ld] [w %ld][h %ld]\n",
+ // xPos,yPos,pView->m_iWindowWidth,pView->m_iWindowHeight));
+
+ if (yPos < 0)
+ {
+ pView->cmdScroll(AV_SCROLLCMD_LINEUP, (UT_uint32) (-(yPos)));
+ }
+ else if (((UT_uint32) (yPos)) >= ((UT_uint32) pView->m_iWindowHeight))
+ {
+ pView->cmdScroll(AV_SCROLLCMD_LINEDOWN, (UT_uint32)(yPos - pView->m_iWindowHeight));
+ }
+
+ if (xPos < 0)
+ {
+ pView->cmdScroll(AV_SCROLLCMD_LINELEFT, (UT_uint32) (-(xPos)));
+ }
+ else if (((UT_uint32) (xPos)) >= ((UT_uint32) pView->m_iWindowWidth))
+ {
+ pView->cmdScroll(AV_SCROLLCMD_LINERIGHT, (UT_uint32)(xPos - pView->m_iWindowWidth));
+ }
+ }
+ }
+ }

-fl_BlockLayout* FV_View::_findBlockAtPosition(PT_DocPosition pos) const
-{
- return m_pLayout->findBlockAtPosition(pos);
-}

-UT_Bool FV_View::cmdCharInsert(UT_UCSChar * text, UT_uint32 count)
-{
- UT_Bool bResult;
+ fp_Page* FV_View::_getPageForXY(UT_sint32 xPos, UT_sint32 yPos, UT_sint32& xClick, UT_sint32& yClick)
+ {
+ xClick = xPos + m_xScrollOffset - fl_PAGEVIEW_MARGIN_X;
+ yClick = yPos + m_yScrollOffset - fl_PAGEVIEW_MARGIN_Y;
+ fp_Page* pPage = m_pLayout->getFirstPage();
+ while (pPage)
+ {
+ UT_sint32 iPageHeight = pPage->getHeight();
+ if (yClick < iPageHeight)
+ {
+ // found it
+ break;
+ }
+ else
+ {
+ yClick -= iPageHeight + fl_PAGEVIEW_PAGE_SEP;
+ }
+ pPage = pPage->getNext();
+ }
+
+ if (!pPage)
+ {
+ // we're below the last page
+ pPage = m_pLayout->getLastPage();
+
+ UT_sint32 iPageHeight = pPage->getHeight();
+ yClick += iPageHeight + fl_PAGEVIEW_PAGE_SEP;
+ }

- if (!isSelectionEmpty())
- {
- m_pDoc->beginUserAtomicGlob();
- _deleteSelection();
- bResult = m_pDoc->insertSpan(getPoint(), text, count);
- m_pDoc->endUserAtomicGlob();
- }
- else
- {
- _eraseInsertionPoint();
- bResult = m_pDoc->insertSpan(getPoint(), text, count);
- }
+ return pPage;
+ }

- _generalUpdate();
-
- if (!_ensureThatInsertionPointIsOnScreen())
- {
- _fixInsertionPointCoords();
- _drawInsertionPoint();
- }
+ void FV_View::extSelToXY(UT_sint32 xPos, UT_sint32 yPos, UT_Bool bDrag)
+ {
+ /*
+ Figure out which page we clicked on.
+ Pass the click down to that page.
+ */
+ UT_sint32 xClick, yClick;
+ fp_Page* pPage = _getPageForXY(xPos, yPos, xClick, yClick);
+
+ PT_DocPosition iNewPoint;
+ UT_Bool bBOL, bEOL;
+ pPage->mapXYToPosition(xClick, yClick, iNewPoint, bBOL, bEOL);
+
+ UT_Bool bPostpone = UT_FALSE;
+
+ if (bDrag)
+ {
+ // figure out whether we're still on screen
+ UT_Bool bOnScreen = UT_TRUE;
+
+ if ((xPos < 0 || xPos > m_iWindowWidth) ||
+ (yPos < 0 || yPos > m_iWindowHeight))
+ bOnScreen = UT_FALSE;
+
+ // is autoscroll timer set properly?
+ if (bOnScreen)
+ {
+ if (m_pAutoScrollTimer)
+ {
+ // timer not needed any more, so stop it
+ m_pAutoScrollTimer->stop();
+ }
+ }
+ else
+ {
+ // remember where mouse is
+ m_xLastMouse = xPos;
+ m_yLastMouse = yPos;
+
+ // offscreen ==> make sure it's set
+ if (!m_pAutoScrollTimer)
+ {
+ m_pAutoScrollTimer = UT_Timer::static_constructor(_autoScroll, this, m_pG);
+ if (m_pAutoScrollTimer)
+ m_pAutoScrollTimer->set(AUTO_SCROLL_MSECS);
+ }
+ else
+ {
+ m_pAutoScrollTimer->start();
+ }
+
+ // postpone selection until timer fires
+ bPostpone = UT_TRUE;
+ }
+ }
+
+ if (!bPostpone)
+ {
+ _extSelToPos(iNewPoint);
+ notifyListeners(AV_CHG_MOTION);
+ }
+ }

- return bResult;
-}
+ void FV_View::extSelToXYword(UT_sint32 xPos, UT_sint32 yPos, UT_Bool bDrag)
+ {
+ // extend the current selection to
+ // include the WORD at the given XY.
+ // this should behave just like extSelToXY()
+ // but with WORD-level granularity.
+
+ /*
+ Figure out which page we clicked on.
+ Pass the click down to that page.
+ */
+ UT_sint32 xClick, yClick;
+ fp_Page* pPage = _getPageForXY(xPos, yPos, xClick, yClick);
+
+ PT_DocPosition iNewPoint;
+ UT_Bool bBOL, bEOL;
+ pPage->mapXYToPosition(xClick, yClick, iNewPoint, bBOL, bEOL);
+
+ //UT_ASSERT(!isSelectionEmpty());
+
+ if (iNewPoint <= m_iSelectionLeftAnchor) {
+ m_iSelectionAnchor = m_iSelectionRightAnchor;
+ }
+ else {
+ m_iSelectionAnchor = m_iSelectionLeftAnchor;
+ }
+
+ PT_DocPosition iNewPointWord;
+ if (iNewPoint > m_iSelectionAnchor)
+ iNewPointWord = _getDocPosFromPoint(iNewPoint,FV_DOCPOS_EOW,UT_FALSE);
+ else
+ iNewPointWord = _getDocPosFromPoint(iNewPoint,FV_DOCPOS_BOW,UT_FALSE);
+
+ UT_Bool bPostpone = UT_FALSE;
+
+ if (bDrag)
+ {
+ // figure out whether we're still on screen
+ UT_Bool bOnScreen = UT_TRUE;
+
+ if ((xPos < 0 || xPos > m_iWindowWidth) ||
+ (yPos < 0 || yPos > m_iWindowHeight))
+ bOnScreen = UT_FALSE;
+
+ // is autoscroll timer set properly?
+ if (bOnScreen)
+ {
+ if (m_pAutoScrollTimer)
+ {
+ // timer not needed any more, so stop it
+ m_pAutoScrollTimer->stop();
+ }
+ }
+ else
+ {
+ // remember where mouse is
+ m_xLastMouse = xPos;
+ m_yLastMouse = yPos;
+
+ // offscreen ==> make sure it's set
+ if (!m_pAutoScrollTimer)
+ {
+ m_pAutoScrollTimer = UT_Timer::static_constructor(_autoScroll, this, m_pG);
+ if (m_pAutoScrollTimer)
+ m_pAutoScrollTimer->set(AUTO_SCROLL_MSECS);
+ }
+ else
+ {
+ m_pAutoScrollTimer->start();
+ }
+
+ // postpone selection until timer fires
+ bPostpone = UT_TRUE;
+ }
+ }
+
+ if (!bPostpone)
+ {
+ _extSelToPos(iNewPointWord);
+ notifyListeners(AV_CHG_MOTION);
+ }
+ }

-void FV_View::insertSectionBreak(void)
-{
- m_pDoc->beginUserAtomicGlob();
+ void FV_View::endDrag(UT_sint32 xPos, UT_sint32 yPos)
+ {
+ if (!m_pAutoScrollTimer)
+ return;

- if (!isSelectionEmpty())
- {
- _deleteSelection();
- }
- else
- {
- _eraseInsertionPoint();
- }
+ // figure out whether we're still on screen
+ UT_Bool bOnScreen = UT_TRUE;

- // insert a new paragraph with the same attributes/properties
- // as the previous (or none if the first paragraph in the section).
- // before inserting a section break, we insert a block break
- UT_uint32 iPoint = getPoint();
-
- m_pDoc->insertStrux(iPoint, PTX_Block);
- m_pDoc->insertStrux(iPoint, PTX_Section);
+ if ((xPos < 0 || xPos > m_iWindowWidth) ||
+ (yPos < 0 || yPos > m_iWindowHeight))
+ bOnScreen = UT_FALSE;
+
+ if (!bOnScreen)
+ {
+ // remember where mouse is
+ m_xLastMouse = xPos;
+ m_yLastMouse = yPos;
+
+ // finish pending autoscroll
+ m_pAutoScrollTimer->fire();
+ }

- m_pDoc->endUserAtomicGlob();
+ // timer not needed any more, so stop it
+ m_pAutoScrollTimer->stop();
+ }

- _generalUpdate();
-
- if (!_ensureThatInsertionPointIsOnScreen())
- {
- _fixInsertionPointCoords();
- _drawInsertionPoint();
- }
-}
+ // ---------------- start goto ---------------

-void FV_View::insertParagraphBreak(void)
-{
- UT_Bool bDidGlob = UT_FALSE;
+ UT_Bool FV_View::gotoTarget(FV_JumpTarget /* type */, UT_UCSChar * /* data */)
+ {
+ UT_ASSERT(UT_NOT_IMPLEMENTED);

- if (!isSelectionEmpty())
- {
- bDidGlob = UT_TRUE;
- m_pDoc->beginUserAtomicGlob();
- _deleteSelection();
- }
- else
- {
- _eraseInsertionPoint();
- }
+ UT_ASSERT(m_pLayout);

- // insert a new paragraph with the same attributes/properties
- // as the previous (or none if the first paragraph in the section).
+ // TODO: We need a Unicode atol/strtol.

- m_pDoc->insertStrux(getPoint(), PTX_Block);
+ /*
+ char * numberString = (char *) calloc(UT_UCS_strlen(m_targetData) + 1, sizeof(char));
+ UT_ASSERT(numberString);

- if (bDidGlob)
- m_pDoc->endUserAtomicGlob();
-
- _generalUpdate();
-
- if (!_ensureThatInsertionPointIsOnScreen())
- {
- _fixInsertionPointCoords();
- _drawInsertionPoint();
- }
-}
+ UT_UCS_strcpy_to_char(numberString, m_targetData);

-UT_Bool FV_View::setStyle(const XML_Char * style)
-{
- UT_Bool bRet;
+ UT_uint32 pageNumber = atol(numberString);
+ FREEP(numberString);
+ */

- PT_DocPosition posStart = getPoint();
- PT_DocPosition posEnd = posStart;
+ // check for range
+ // if (pageNumber < 0 || pageNumber > (UT_uint32) m_pLayout->countPages())
+ // return UT_FALSE;

- if (!isSelectionEmpty())
- {
- if (m_iSelectionAnchor < posStart)
- {
- posStart = m_iSelectionAnchor;
- }
- else
- {
- posEnd = m_iSelectionAnchor;
- }
- }
+ // get the right page
+ // fp_Page * page = m_pLayout->getNthPage(pageNumber);
+ // UT_ASSERT(page);

- // lookup the current style
- PD_Style * pStyle = NULL;
- m_pDoc->getStyle(style, &pStyle);
- if (!pStyle)
- {
- UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
- return UT_FALSE;
- }
+ // peek inside the page
+ // ...

- UT_Bool bCharStyle = pStyle->isCharStyle();
+ return UT_FALSE;
+ }

- const XML_Char * attribs[] = { PT_STYLE_ATTRIBUTE_NAME, 0, 0 };
- attribs[1] = style;
+ // ---------------- start find and replace ---------------

- if (bCharStyle)
- {
- // set character-level style
- if (isSelectionEmpty())
- {
- _eraseInsertionPoint();
- }
+ UT_Bool FV_View::findNext(const UT_UCSChar * find, UT_Bool matchCase, UT_Bool * bDoneEntireDocument)
+ {
+ if (!isSelectionEmpty())
+ {
+ _clearSelection();
+ }
+ else
+ {
+ _eraseInsertionPoint();
+ }
+
+ UT_Bool bRes = _findNext(find, matchCase, bDoneEntireDocument);
+
+ if (isSelectionEmpty())
+ {
+ if (!_ensureThatInsertionPointIsOnScreen())
+ {
+ _fixInsertionPointCoords();
+ _drawInsertionPoint();
+ }
+ }
+ else
+ {
+ _ensureThatInsertionPointIsOnScreen();
+ _drawSelection();
+ }

- _clearIfAtFmtMark(getPoint()); // TODO is this correct ??
- _eraseSelection();
-
- bRet = m_pDoc->changeSpanFmt(PTC_AddStyle,posStart,posEnd,attribs,NULL);
- }
- else
- {
- // set block-level style
- _eraseInsertionPoint();
+ // TODO do we need to do a notifyListeners(AV_CHG_MOTION) ??
+ return bRes;
+ }

- _clearIfAtFmtMark(getPoint()); // TODO is this correct ??
+ UT_Bool FV_View::_findNext(const UT_UCSChar * find, UT_Bool matchCase, UT_Bool * bDoneEntireDocument)
+ {
+ UT_ASSERT(find);

- // NB: clear explicit props at both block and char levels
- bRet = m_pDoc->changeStruxFmt(PTC_AddStyle,posStart,posEnd,attribs,NULL,PTX_Block);
- }
+ fl_BlockLayout * block = NULL;
+ PT_DocPosition offset = 0;

- _generalUpdate();
-
- if (isSelectionEmpty())
- {
- _fixInsertionPointCoords();
- _drawInsertionPoint();
- }
- return bRet;
-}
+ block = _findGetCurrentBlock();
+ offset = _findGetCurrentOffset();

+ UT_UCSChar * buffer = NULL;
+
+ while ((buffer = _findGetNextBlockBuffer(&block, &offset)))
+ {
+ // magic number; range of UT_sint32 falls short of extremely large docs
+ UT_sint32 foundAt = -1;
+
+ // Change the ordering of searches to accomodate new searches (like
+ // regular expressions, case-sensitive, or reverse searches).
+ // Right now we just work off case searches.
+ if (matchCase == UT_TRUE)
+ {
+ // this search will do case-sensitive work
+ foundAt = _findBlockSearchDumbCase(buffer, find);
+ }
+ else if (matchCase == UT_FALSE)
+ {
+ // do the case-insensitive search
+ foundAt = _findBlockSearchDumbNoCase(buffer, find);
+ }
+
+
+ if (foundAt != -1)
+ {
+ _setPoint(block->getPosition(UT_FALSE) + offset + foundAt);
+ _setSelectionAnchor();
+ _charMotion(UT_TRUE, UT_UCS_strlen(find));
+
+ m_doneFind = UT_TRUE;
+
+ FREEP(buffer);
+ return UT_TRUE;
+ }
+
+ // didn't find anything, so set the offset to the end
+ // of the current area
+ offset += UT_UCS_strlen(buffer);
+
+ // must clean up buffer returned for search
+ FREEP(buffer);
+ }
+
+ if (bDoneEntireDocument)
+ {
+ *bDoneEntireDocument = UT_TRUE;
+ }

-static const XML_Char * x_getStyle(const PP_AttrProp * pAP, UT_Bool bBlock)
-{
- UT_ASSERT(pAP);
- const XML_Char* sz = NULL;
+ // reset wrap for next time
+ m_wrappedEnd = UT_FALSE;

- pAP->getAttribute(PT_STYLE_ATTRIBUTE_NAME, sz);
+ return UT_FALSE;
+ }

- // TODO: should we have an explicit default for char styles?
- if (!sz && bBlock)
- sz = "Normal";
+ void FV_View::findSetStartAtInsPoint(void)
+ {
+ m_startPosition = m_iInsPoint;
+ m_wrappedEnd = UT_FALSE;
+ m_doneFind = UT_FALSE;
+ }

- return sz;
-}
+ PT_DocPosition FV_View::_BlockOffsetToPos(fl_BlockLayout * block, PT_DocPosition offset)
+ {
+ UT_ASSERT(block);
+ return block->getPosition(UT_FALSE) + offset;
+ }

-UT_Bool FV_View::getStyle(const XML_Char ** style)
-{
- UT_Bool bCharStyle = UT_FALSE;
- const XML_Char * szChar = NULL;
- const XML_Char * szBlock = NULL;
+ UT_UCSChar * FV_View::_findGetNextBlockBuffer(fl_BlockLayout ** block, PT_DocPosition * offset)
+ {
+ UT_ASSERT(m_pLayout);

- const PP_AttrProp * pBlockAP = NULL;
+ // this assert doesn't work, since the startPosition CAN legitimately be zero
+ UT_ASSERT(m_startPosition >= 2); // the beginning of the first block in any document

- /*
- IDEA: We want to know the style, iff it's constant across the
- entire selection. Usually, this will be a block-level style.
- However, if the entire span has the same char-level style,
- we'll report that instead.
- */
- PT_DocPosition posStart = getPoint();
- PT_DocPosition posEnd = posStart;
- UT_Bool bSelEmpty = isSelectionEmpty();
+ UT_ASSERT(block);
+ UT_ASSERT(*block);

- if (!bSelEmpty)
- {
- if (m_iSelectionAnchor < posStart)
- posStart = m_iSelectionAnchor;
- else
- posEnd = m_iSelectionAnchor;
- }
+ UT_ASSERT(offset);
+
+ fl_BlockLayout * newBlock = NULL;
+ PT_DocPosition newOffset = 0;
+
+ UT_uint32 bufferLength = 0;
+
+ UT_GrowBuf buffer;
+
+ // check early for completion, from where we left off last, and bail
+ // if we are now at or past the start position
+ if (m_wrappedEnd && _BlockOffsetToPos(*block, *offset) >= m_startPosition)
+ {
+ // we're done
+ return NULL;
+ }
+
+ if (!(*block)->getBlockBuf(&buffer))
+ {
+ UT_DEBUGMSG(("Block %p has no associated buffer.\n", *block));
+ UT_ASSERT(0);
+ }
+
+ // have we already searched all the text in this buffer?
+ if (*offset >= buffer.getLength())
+ {
+ // then return a fresh new block's buffer
+ newBlock = (*block)->getNextBlockInDocument();
+
+ // are we at the end of the document?
+ if (!newBlock)
+ {
+ // then wrap (fetch the first block in the doc)
+ PT_DocPosition startOfDoc;
+ m_pDoc->getBounds(UT_FALSE, startOfDoc);
+
+ newBlock = m_pLayout->findBlockAtPosition(startOfDoc);
+
+ m_wrappedEnd = UT_TRUE;
+
+ UT_ASSERT(newBlock);
+ }
+
+ // re-assign the buffer contents for our new block
+ buffer.truncate(0);
+ // the offset starts at 0 for a fresh buffer
+ newOffset = 0;
+
+ if (!newBlock->getBlockBuf(&buffer))
+ {
+ UT_DEBUGMSG(("Block %p (a ->next block) has no buffer.\n", newBlock));
+ UT_ASSERT(0);
+ }
+
+ // good to go with a full buffer for our new block
+ }
+ else // we have some left to go in this buffer
+ {
+ // buffer is still valid, just copy pointers
+ newBlock = *block;
+ newOffset = *offset;
+ }
+
+ // are we going to run into the start position in this buffer?
+ // if so, we need to size our length accordingly
+ if (m_wrappedEnd && _BlockOffsetToPos(newBlock, newOffset) + buffer.getLength() >= m_startPosition)
+ {
+ bufferLength = (m_startPosition - (newBlock)->getPosition(UT_FALSE)) - newOffset;
+ }
+ else
+ {
+ bufferLength = buffer.getLength() - newOffset;
+ }
+
+ // clone a buffer (this could get really slow on large buffers!)
+ UT_UCSChar * bufferSegment = NULL;
+
+ // remember, the caller gets to free this memory
+ bufferSegment = (UT_UCSChar *) calloc(bufferLength + 1,
+ sizeof(UT_UCSChar));
+ UT_ASSERT(bufferSegment);
+
+ memmove(bufferSegment, buffer.getPointer(newOffset),
+ (bufferLength) * sizeof(UT_UCSChar));
+
+ // before we bail, hold up our block stuff for next round
+ *block = newBlock;
+ *offset = newOffset;

- // 1. get block style at insertion point
- fl_BlockLayout* pBlock = _findBlockAtPosition(posStart);
- pBlock->getAttrProp(&pBlockAP);
+ return bufferSegment;
+ }

- szBlock = x_getStyle(pBlockAP, UT_TRUE);
+ UT_Bool FV_View::findSetNextString(UT_UCSChar * string, UT_Bool matchCase)
+ {
+ UT_ASSERT(string);

- // 2. prune if block style varies across selection
- if (!bSelEmpty)
- {
- fl_BlockLayout* pBlockEnd = _findBlockAtPosition(posEnd);
+ // update case matching
+ _m_matchCase = matchCase;

- while (pBlock && (pBlock != pBlockEnd))
- {
- const PP_AttrProp * pAP;
- UT_Bool bCheck = UT_FALSE;
+ // update string
+ FREEP(_m_findNextString);
+ return UT_UCS_cloneString(&_m_findNextString, string);
+ }

- pBlock = pBlock->getNextBlockInDocument();
+ UT_Bool FV_View::findAgain()
+ {
+ if (_m_findNextString && *_m_findNextString)
+ {
+ UT_Bool bRes = findNext(_m_findNextString, _m_matchCase, NULL);
+ if (bRes)
+ {
+ _drawSelection();
+ }

- if (!pBlock)
- {
- // at EOD, so just bail
- break;
- }
-
- // did block format change?
- pBlock->getAttrProp(&pAP);
- if (pBlockAP != pAP)
- {
- pBlockAP = pAP;
- bCheck = UT_TRUE;
- }
-
- if (bCheck)
- {
- const XML_Char* sz = x_getStyle(pBlockAP, UT_TRUE);
-
- if (UT_stricmp(sz, szBlock))
- {
- // doesn't match, so stop looking
- szBlock = NULL;
- pBlock = NULL;
- break;
- }
- }
- }
- }
-
- // NOTE: if block style varies, no need to check char style
-
- if (szBlock && szBlock[0])
- {
- const PP_AttrProp * pSpanAP = NULL;
-
- // 3. locate char style at insertion point
- UT_sint32 xPoint;
- UT_sint32 yPoint;
- UT_sint32 iPointHeight;
-
- fl_BlockLayout* pBlock = _findBlockAtPosition(posStart);
- UT_uint32 blockPosition = pBlock->getPosition();
- fp_Run* pRun = pBlock->findPointCoords(posStart, UT_FALSE,
- xPoint, yPoint, iPointHeight);
- UT_Bool bLeftSide = UT_TRUE;
-
- // TODO consider adding indexAP from change record to the
- // TODO runs so that we can just use it here.
-
- if (!bSelEmpty)
- {
- // we want the interior of the selection -- and not the
- // format to the left of the start of the selection.
- bLeftSide = UT_FALSE;
-
- /*
- Likewise, findPointCoords will return the run to the right
- of the specified position, so we need to stop looking one
- position to the left.
- */
- posEnd--;
- }
-
- pBlock->getSpanAttrProp( (posStart - blockPosition), bLeftSide, &pSpanAP);
-
- if (pSpanAP)
- {
- szChar = x_getStyle(pSpanAP, UT_FALSE);
- bCharStyle = (szChar && szChar[0]);
- }
-
- // 4. prune if char style varies across selection
- if (!bSelEmpty)
- {
- fl_BlockLayout* pBlockEnd = _findBlockAtPosition(posEnd);
- fp_Run* pRunEnd = pBlockEnd->findPointCoords(posEnd, UT_FALSE,
- xPoint, yPoint, iPointHeight);
- while (pRun && (pRun != pRunEnd))
- {
- const PP_AttrProp * pAP;
- UT_Bool bCheck = UT_FALSE;
+ return bRes;
+ }

- pRun = pRun->getNext();
- if (!pRun)
- {
- // go to first run of next block
- pBlock = pBlock->getNextBlockInDocument();
- if (!pBlock) // at EOD, so just bail
- break;
- pRun = pBlock->getFirstRun();
- }
+ return UT_FALSE;
+ }

- // did span format change?
+ UT_Bool FV_View::findReplace(const UT_UCSChar * find, const UT_UCSChar * replace,
+ UT_Bool matchCase, UT_Bool * bDoneEntireDocument)
+ {
+ UT_ASSERT(find && replace);

- pAP = NULL;
- pBlock->getSpanAttrProp(pRun->getBlockOffset()+pRun->getLength(),UT_TRUE,&pAP);
- if (pAP && (pSpanAP != pAP))
- {
- pSpanAP = pAP;
- bCheck = UT_TRUE;
- }
+ UT_Bool bRes = _findReplace(find, replace, matchCase, bDoneEntireDocument);

- if (bCheck)
- {
- const XML_Char* sz = x_getStyle(pSpanAP, UT_TRUE);
- UT_Bool bHere = (sz && sz[0]);
+ updateScreen();

- if ((bCharStyle != bHere) || (UT_stricmp(sz, szChar)))
- {
- // doesn't match, so stop looking
- bCharStyle = UT_FALSE;
- szChar = NULL;
- pRun = NULL;
- break;
- }
- }
- }
- }
- }
+ if (isSelectionEmpty())
+ {
+ if (!_ensureThatInsertionPointIsOnScreen())
+ {
+ _fixInsertionPointCoords();
+ _drawInsertionPoint();
+ }
+ }
+ else
+ {
+ _ensureThatInsertionPointIsOnScreen();
+ }

- *style = (bCharStyle ? szChar : szBlock);
+ return bRes;
+ }

- return UT_TRUE;
-}
+ UT_Bool FV_View::_findReplace(const UT_UCSChar * find, const UT_UCSChar * replace,
+ UT_Bool matchCase, UT_Bool * bDoneEntireDocument)
+ {
+ UT_ASSERT(find && replace);

-UT_Bool FV_View::setCharFormat(const XML_Char * properties[])
-{
- UT_Bool bRet;
+ // if we have done a find, and there is a selection, then replace what's in the
+ // selection and move on to next find (batch run, the common case)
+ if ((m_doneFind == UT_TRUE) && (!isSelectionEmpty()))
+ {
+ UT_Bool result = UT_TRUE;
+
+ if (!isSelectionEmpty())
+ {
+ _deleteSelection();
+ }
+ else
+ {
+ _eraseInsertionPoint();
+ }
+
+ // if we have a string with length, do an insert, else let it hang
+ // from the delete above
+ if (*replace)
+ result = m_pDoc->insertSpan(getPoint(), replace, UT_UCS_strlen(replace));
+
+ // if we've wrapped around once, and we're doing work before we've
+ // hit the point at which we started, then we adjust the start
+ // position so that we stop at the right spot.
+ if (m_wrappedEnd && !*bDoneEntireDocument)
+ m_startPosition += ((long) UT_UCS_strlen(replace) - (long) UT_UCS_strlen(find));
+
+ UT_ASSERT(m_startPosition >= 2);
+
+ // do not increase the insertion point index, since the insert span will
+ // leave us at the correct place.
+
+ _findNext(find, matchCase, bDoneEntireDocument);
+ return result;
+ }
+
+ // if we have done a find, but there is no selection, do a find for them
+ // but no replace
+ if (m_doneFind == UT_TRUE && isSelectionEmpty() == UT_TRUE)
+ {
+ _findNext(find, matchCase, bDoneEntireDocument);
+ return UT_FALSE;
+ }
+
+ // if we haven't done a find yet, do a find for them
+ if (m_doneFind == UT_FALSE)
+ {
+ _findNext(find, matchCase, bDoneEntireDocument);
+ return UT_FALSE;
+ }

- if (isSelectionEmpty())
- {
- _eraseInsertionPoint();
- }
+ UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
+ return UT_FALSE;
+ }

- PT_DocPosition posStart = getPoint();
- PT_DocPosition posEnd = posStart;
+ /*
+ After most editing commands, it is necessary to call this method,
+ _generalUpdate, in order to fix everything.
+ */
+ void FV_View::_generalUpdate(void)
+ {
+ m_pDoc->signalListeners(PD_SIGNAL_UPDATE_LAYOUT);

- if (!isSelectionEmpty())
- {
- if (m_iSelectionAnchor < posStart)
- {
- posStart = m_iSelectionAnchor;
- }
- else
- {
- posEnd = m_iSelectionAnchor;
- }
- }
+ /*
+ TODO note that we are far too heavy handed with the mask we
+ send here. I ripped out all the individual calls to notifyListeners
+ which appeared within fl_BlockLayout, and they all now go through
+ here. For that reason, I made the following mask into the union
+ of all the masks I found. I assume that this is inefficient, but
+ functionally correct.
+
+ TODO WRONG! WRONG! WRONG! notifyListener() must be called in
+ TODO WRONG! WRONG! WRONG! fl_BlockLayout in response to a change
+ TODO WRONG! WRONG! WRONG! notification and not here. this call
+ TODO WRONG! WRONG! WRONG! will only update the current window.
+ TODO WRONG! WRONG! WRONG! having the notification in fl_BlockLayout
+ TODO WRONG! WRONG! WRONG! will get each view on the document.
+ */
+ notifyListeners(AV_CHG_TYPING | AV_CHG_FMTCHAR | AV_CHG_FMTBLOCK);
+ }

- _eraseSelection();
-
- bRet = m_pDoc->changeSpanFmt(PTC_AddFmt,posStart,posEnd,NULL,properties);
+ UT_uint32 FV_View::findReplaceAll(const UT_UCSChar * find, const UT_UCSChar * replace,
+ UT_Bool matchCase)
+ {
+ UT_uint32 numReplaced = 0;
+ m_pDoc->beginUserAtomicGlob();

- _generalUpdate();
-
- if (isSelectionEmpty())
- {
- _fixInsertionPointCoords();
- _drawInsertionPoint();
- }
+ UT_Bool bDoneEntireDocument = UT_FALSE;

- return bRet;
-}
+ // prime it with a find
+ if (!_findNext(find, matchCase, &bDoneEntireDocument))
+ {
+ // can't find a single thing, we're done
+ m_pDoc->endUserAtomicGlob();
+ return numReplaced;
+ }
+
+ // while we've still got buffer
+ while (bDoneEntireDocument == UT_FALSE)
+ {
+ // if it returns false, it found nothing more before
+ // it hit the end of the document
+ if (!_findReplace(find, replace, matchCase, &bDoneEntireDocument))
+ {
+ m_pDoc->endUserAtomicGlob();
+ return numReplaced;
+ }
+ numReplaced++;
+ }
+
+ m_pDoc->endUserAtomicGlob();
+
+ _generalUpdate();
+
+ if (isSelectionEmpty())
+ {
+ if (!_ensureThatInsertionPointIsOnScreen())
+ {
+ _fixInsertionPointCoords();
+ _drawInsertionPoint();
+ }
+ }
+ else
+ {
+ _ensureThatInsertionPointIsOnScreen();
+ }

-UT_Bool FV_View::getCharFormat(const XML_Char *** pProps, UT_Bool bExpandStyles)
-{
- const PP_AttrProp * pSpanAP = NULL;
- const PP_AttrProp * pBlockAP = NULL;
- const PP_AttrProp * pSectionAP = NULL; // TODO do we care about section-level inheritance
- UT_Vector v;
- UT_uint32 i;
- _fmtPair * f;
+ return numReplaced;
+ }

- /*
- IDEA: We want to know character-level formatting properties, iff
- they're constant across the entire selection. To do so, we start
- at the beginning of the selection, load 'em all into a vector, and
- then prune any property that collides.
- */
- PT_DocPosition posStart = getPoint();
- PT_DocPosition posEnd = posStart;
- UT_Bool bSelEmpty = isSelectionEmpty();
+ fl_BlockLayout * FV_View::_findGetCurrentBlock(void)
+ {
+ return m_pLayout->findBlockAtPosition(m_iInsPoint);
+ }

- if (!bSelEmpty)
- {
- if (m_iSelectionAnchor < posStart)
- posStart = m_iSelectionAnchor;
- else
- posEnd = m_iSelectionAnchor;
- }
+ PT_DocPosition FV_View::_findGetCurrentOffset(void)
+ {
+ return (m_iInsPoint - _findGetCurrentBlock()->getPosition(UT_FALSE));
+ }

- // 1. assemble complete set at insertion point
- UT_sint32 xPoint;
- UT_sint32 yPoint;
- UT_sint32 iPointHeight;
+ /*
+ A simple strstr search of the buffer.
+ */
+ UT_sint32 FV_View::_findBlockSearchDumbCase(const UT_UCSChar * haystack, const UT_UCSChar * needle)
+ {
+ UT_ASSERT(haystack);
+ UT_ASSERT(needle);

- fl_BlockLayout* pBlock = _findBlockAtPosition(posStart);
- UT_uint32 blockPosition = pBlock->getPosition();
- fp_Run* pRun = pBlock->findPointCoords(posStart, UT_FALSE,
- xPoint, yPoint, iPointHeight);
- UT_Bool bLeftSide = UT_TRUE;
-
- // TODO consider adding indexAP from change record to the
- // TODO runs so that we can just use it here.
-
- if (!bSelEmpty)
- {
- // we want the interior of the selection -- and not the
- // format to the left of the start of the selection.
- bLeftSide = UT_FALSE;
+ UT_UCSChar * at = UT_UCS_strstr(haystack, needle);

- /*
- Likewise, findPointCoords will return the run to the right
- of the specified position, so we need to stop looking one
- position to the left.
- */
- posEnd--;
- }
+ return (at) ? (at - haystack) : -1;
+ }

- pBlock->getSpanAttrProp( (posStart - blockPosition), bLeftSide, &pSpanAP);
+ /*
+ Pierre Sarrazin <ps@cam.org> supplied the Unicode stricmp comparison function,
+ which works for Latin-1 at the moment.
+ */

- pBlock->getAttrProp(&pBlockAP);
+ UT_sint32 FV_View::_findBlockSearchDumbNoCase(const UT_UCSChar * haystack, const UT_UCSChar * needle)
+ {
+ UT_ASSERT(haystack);
+ UT_ASSERT(needle);

- v.addItem(new _fmtPair("font-family", pSpanAP,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
- v.addItem(new _fmtPair("font-size", pSpanAP,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
- v.addItem(new _fmtPair("font-weight", pSpanAP,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
- v.addItem(new _fmtPair("font-style", pSpanAP,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
- v.addItem(new _fmtPair("text-decoration",pSpanAP,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
- v.addItem(new _fmtPair("color", pSpanAP,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
+ UT_UCSChar * at = UT_UCS_stristr(haystack, needle);

- // 2. prune 'em as they vary across selection
- if (!bSelEmpty)
- {
- fl_BlockLayout* pBlockEnd = _findBlockAtPosition(posEnd);
- fp_Run* pRunEnd = pBlockEnd->findPointCoords(posEnd, UT_FALSE,
- xPoint, yPoint, iPointHeight);
- while (pRun && (pRun != pRunEnd))
- {
- const PP_AttrProp * pAP;
- UT_Bool bCheck = UT_FALSE;
+ return (at) ? (at - haystack) : -1;
+ }

- pRun = pRun->getNext();
- if (!pRun)
- {
- // go to first run of next block
- pBlock = pBlock->getNextBlockInDocument();

- if (!pBlock) // at EOD, so just bail
- break;
+ /*
+ Any takers?
+ */

- // did block format change?
- pBlock->getAttrProp(&pAP);
- if (pBlockAP != pAP)
- {
- pBlockAP = pAP;
- bCheck = UT_TRUE;
- }
+ UT_sint32 FV_View::_findBlockSearchRegexp(const UT_UCSChar * /* haystack */, const UT_UCSChar * /* needle */)
+ {
+ UT_ASSERT(UT_NOT_IMPLEMENTED);

- pRun = pBlock->getFirstRun();
- }
+ return -1;
+ }

- // did span format change?
+ // ---------------- end find and replace ---------------

- pAP = NULL;
- pBlock->getSpanAttrProp(pRun->getBlockOffset()+pRun->getLength(),UT_TRUE,&pAP);
- if (pSpanAP != pAP)
- {
- pSpanAP = pAP;
- bCheck = UT_TRUE;
- }
+ void FV_View::_extSel(UT_uint32 iOldPoint)
+ {
+ /*
+ We need to calculate the differences between the old
+ selection and new one.
+
+ Anything which was selected, and now is not, should
+ be fixed on screen, back to normal.
+
+ Anything which was NOT selected, and now is, should
+ be fixed on screen, to show it in selected state.
+
+ Anything which was selected, and is still selected,
+ should NOT be touched.
+
+ And, obviously, anything which was not selected, and
+ is still not selected, should not be touched.
+ */
+
+ UT_uint32 iNewPoint = getPoint();
+
+ if (iNewPoint == iOldPoint)
+ {
+ return;
+ }
+
+ if (iNewPoint < iOldPoint)
+ {
+ if (iNewPoint < m_iSelectionAnchor)
+ {
+ if (iOldPoint < m_iSelectionAnchor)
+ {
+ /*
+ N O A
+ The selection got bigger. Both points are
+ left of the anchor.
+ */
+ _drawBetweenPositions(iNewPoint, iOldPoint);
+ }
+ else
+ {
+ /*
+ N A O
+ The selection flipped across the anchor to the left.
+ */
+ _clearBetweenPositions(m_iSelectionAnchor, iOldPoint, UT_TRUE);
+ _drawBetweenPositions(iNewPoint, iOldPoint);
+ }
+ }
+ else
+ {
+ UT_ASSERT(iOldPoint >= m_iSelectionAnchor);
+
+ /*
+ A N O
+ The selection got smaller. Both points are to the
+ right of the anchor
+ */
+
+ _clearBetweenPositions(iNewPoint, iOldPoint, UT_TRUE);
+ _drawBetweenPositions(iNewPoint, iOldPoint);
+ }
+ }
+ else
+ {
+ UT_ASSERT(iNewPoint > iOldPoint);
+
+ if (iNewPoint < m_iSelectionAnchor)
+ {
+ UT_ASSERT(iOldPoint <= m_iSelectionAnchor);
+
+ /*
+ O N A
+ The selection got smaller. Both points are
+ left of the anchor.
+ */
+
+ _clearBetweenPositions(iOldPoint, iNewPoint, UT_TRUE);
+ _drawBetweenPositions(iOldPoint, iNewPoint);
+ }
+ else
+ {
+ if (iOldPoint < m_iSelectionAnchor)
+ {
+ /*
+ O A N
+ The selection flipped across the anchor to the right.
+ */
+
+ _clearBetweenPositions(iOldPoint, m_iSelectionAnchor, UT_TRUE);
+ _drawBetweenPositions(iOldPoint, iNewPoint);
+ }
+ else
+ {
+ /*
+ A O N
+ The selection got bigger. Both points are to the
+ right of the anchor
+ */
+ _drawBetweenPositions(iOldPoint, iNewPoint);
+ }
+ }
+ }
+ }

- if (bCheck)
- {
- i = v.getItemCount();
+ void FV_View::_extSelToPos(PT_DocPosition iNewPoint)
+ {
+ PT_DocPosition iOldPoint = getPoint();
+ if (iNewPoint == iOldPoint)
+ return;
+
+ if (isSelectionEmpty())
+ {
+ _eraseInsertionPoint();
+ _clearIfAtFmtMark(getPoint());
+ _setSelectionAnchor();
+ }
+
+ _setPoint(iNewPoint);
+ _extSel(iOldPoint);
+
+ if (isSelectionEmpty())
+ {
+ _resetSelection();
+ _drawInsertionPoint();
+ }

- while (i > 0)
- {
- f = (_fmtPair *)v.getNthItem(i-1);
+ notifyListeners(AV_CHG_MOTION);
+ }

- const XML_Char * value = PP_evalProperty(f->m_prop,pSpanAP,pBlockAP,pSectionAP,m_pDoc,bExpandStyles);
- UT_ASSERT(value);
+ void FV_View::warpInsPtToXY(UT_sint32 xPos, UT_sint32 yPos)
+ {
+ /*
+ Figure out which page we clicked on.
+ Pass the click down to that page.
+ */
+ UT_sint32 xClick, yClick;
+ fp_Page* pPage = _getPageForXY(xPos, yPos, xClick, yClick);
+
+ if (!isSelectionEmpty())
+ _clearSelection();
+ else
+ _eraseInsertionPoint();
+
+ PT_DocPosition pos;
+ UT_Bool bBOL, bEOL;
+
+ pPage->mapXYToPosition(xClick, yClick, pos, bBOL, bEOL);
+
+ if (pos != getPoint())
+ _clearIfAtFmtMark(getPoint());
+
+ _setPoint(pos, bEOL);
+ _fixInsertionPointCoords();
+ _drawInsertionPoint();

- // prune anything that doesn't match
- if (UT_stricmp(f->m_val, value))
- {
- DELETEP(f);
- v.deleteNthItem(i-1);
- }
+ notifyListeners(AV_CHG_MOTION);
+ }

- i--;
- }
+ void FV_View::getPageScreenOffsets(fp_Page* pThePage, UT_sint32& xoff,
+ UT_sint32& yoff)
+ {
+ UT_uint32 y = fl_PAGEVIEW_MARGIN_Y;

- // when vector is empty, stop looking
- if (0 == v.getItemCount())
- {
- pRun = NULL;
- break;
- }
- }
- }
- }
+ fp_Page* pPage = m_pLayout->getFirstPage();
+ while (pPage)
+ {
+ if (pPage == pThePage)
+ {
+ break;
+ }
+ y += pPage->getHeight() + fl_PAGEVIEW_PAGE_SEP;

- // 3. export whatever's left
- UT_uint32 count = v.getItemCount()*2 + 1;
+ pPage = pPage->getNext();
+ }

- // NOTE: caller must free this, but not the referenced contents
- const XML_Char ** props = (const XML_Char **) calloc(count, sizeof(XML_Char *));
- if (!props)
- return UT_FALSE;
+ yoff = y - m_yScrollOffset;
+ xoff = fl_PAGEVIEW_MARGIN_Y - m_xScrollOffset;
+ }

- const XML_Char ** p = props;
+ void FV_View::getPageYOffset(fp_Page* pThePage, UT_sint32& yoff)
+ {
+ UT_uint32 y = fl_PAGEVIEW_MARGIN_Y;

- i = v.getItemCount();
+ fp_Page* pPage = m_pLayout->getFirstPage();
+ while (pPage)
+ {
+ if (pPage == pThePage)
+ {
+ break;
+ }
+ y += pPage->getHeight() + fl_PAGEVIEW_PAGE_SEP;

- while (i > 0)
- {
- f = (_fmtPair *)v.getNthItem(i-1);
- i--;
+ pPage = pPage->getNext();
+ }

- p[0] = f->m_prop;
- p[1] = f->m_val;
- p += 2;
- }
+ yoff = y;
+ }

- UT_VECTOR_PURGEALL(_fmtPair *,v);
+ UT_uint32 FV_View::getPageViewLeftMargin(void) const
+ {
+ // return the amount of gray-space we draw to the left
+ // of the paper in "Page View". return zero if not in
+ // "Page View".

- *pProps = props;
+ return fl_PAGEVIEW_MARGIN_X;
+ }

- return UT_TRUE;
-}
+ UT_uint32 FV_View::getPageViewTopMargin(void) const
+ {
+ // return the amount of gray-space we draw above the top
+ // of the paper in "Page View". return zero if not in
+ // "Page View".

-UT_Bool FV_View::setBlockFormat(const XML_Char * properties[])
+ return fl_PAGEVIEW_MARGIN_Y;
+ }
+
+UT_uint32 FV_View::getPageViewPageSep(void) const
{
- UT_Bool bRet;
-
- _clearIfAtFmtMark(getPoint());
-
- _eraseInsertionPoint();
-
- PT_DocPosition posStart = getPoint();
- PT_DocPosition posEnd = posStart;
-
- if (!isSelectionEmpty())
- {
- if (m_iSelectionAnchor < posStart)
- {
- posStart = m_iSelectionAnchor;
- }
- else
- {
- posEnd = m_iSelectionAnchor;
- }
- }
-
- bRet = m_pDoc->changeStruxFmt(PTC_AddFmt,posStart,posEnd,NULL,properties,PTX_Block);
-
- _generalUpdate();
-
- if (isSelectionEmpty())
- {
- _fixInsertionPointCoords();
- _drawInsertionPoint();
- }
-
- return bRet;
+ return fl_PAGEVIEW_PAGE_SEP;
}

-UT_Bool FV_View::getSectionFormat(const XML_Char ***pProps)
-{
- const PP_AttrProp * pBlockAP = NULL;
- const PP_AttrProp * pSectionAP = NULL;
- UT_Vector v;
- UT_uint32 i;
- _fmtPair * f;
-
- /*
- IDEA: We want to know block-level formatting properties, iff
- they're constant across the entire selection. To do so, we start
- at the beginning of the selection, load 'em all into a vector, and
- then prune any property that collides.
- */
- PT_DocPosition posStart = getPoint();
- PT_DocPosition posEnd = posStart;
-
- if (!isSelectionEmpty())
- {
- if (m_iSelectionAnchor < posStart)
- posStart = m_iSelectionAnchor;
- else
- posEnd = m_iSelectionAnchor;
- }
-
- // 1. assemble complete set at insertion point
- fl_BlockLayout* pBlock = _findBlockAtPosition(posStart);
- fl_SectionLayout* pSection = pBlock->getSectionLayout();
- pSection->getAttrProp(&pSectionAP);
-
- v.addItem(new _fmtPair("columns", NULL,pBlockAP,pSectionAP,m_pDoc,UT_FALSE));
- v.addItem(new _fmtPair("column-gap",NULL,pBlockAP,pSectionAP,m_pDoc,UT_FALSE));
-
- // 2. prune 'em as they vary across selection
- if (!isSelectionEmpty())
- {
- fl_BlockLayout* pBlockEnd = _findBlockAtPosition(posEnd);
- fl_SectionLayout *pSectionEnd = pBlockEnd->getSectionLayout();
+ /*
+ This method simply iterates over every run between two doc positions
+ and draws each one.
+ */
+ void FV_View::_drawBetweenPositions(PT_DocPosition iPos1, PT_DocPosition iPos2)
+ {
+ UT_ASSERT(iPos1 < iPos2);

- while (pSection && (pSection != pSectionEnd))
- {
- const PP_AttrProp * pAP;
- UT_Bool bCheck = UT_FALSE;
+ fp_Run* pRun1;
+ fp_Run* pRun2;
+ UT_sint32 xoff;
+ UT_sint32 yoff;
+ UT_uint32 uheight;
+
+ {
+ UT_sint32 x;
+ UT_sint32 y;
+ fl_BlockLayout* pBlock1;
+ fl_BlockLayout* pBlock2;
+
+ /*
+ we don't really care about the coords. We're calling these
+ to get the Run pointer
+ */
+ _findPositionCoords(iPos1, UT_FALSE, x, y, uheight, &pBlock1, &pRun1);
+ _findPositionCoords(iPos2, UT_FALSE, x, y, uheight, &pBlock2, &pRun2);
+ }
+
+ UT_Bool bDone = UT_FALSE;
+ fp_Run* pCurRun = pRun1;
+
+ while (!bDone)
+ {
+ if (pCurRun == pRun2)
+ {
+ bDone = UT_TRUE;
+ }
+
+ fl_BlockLayout* pBlock = pCurRun->getBlock();
+ UT_ASSERT(pBlock);
+
+ fp_Line* pLine = pCurRun->getLine();
+
+ pLine->getScreenOffsets(pCurRun, xoff, yoff);
+
+ dg_DrawArgs da;
+
+ da.pG = m_pG;
+ da.xoff = xoff;
+ da.yoff = yoff + pLine->getAscent();
+
+ pCurRun->draw(&da);
+
+ pCurRun = pCurRun->getNext();
+ if (!pCurRun)
+ {
+ fl_BlockLayout* pNextBlock;
+
+ pNextBlock = pBlock->getNextBlockInDocument();
+ if (pNextBlock)
+ {
+ pCurRun = pNextBlock->getFirstRun();
+ }
+ }
+ }
+ }

- pSection = pSection->getNext();
- if (!pSection) // at EOD, so just bail
- break;
+ /*
+ This method simply iterates over every run between two doc positions
+ and draws each one.
+ */
+ void FV_View::_clearBetweenPositions(PT_DocPosition iPos1, PT_DocPosition iPos2, UT_Bool bFullLineHeightRect)
+ {
+ if (iPos1 >= iPos2)
+ {
+ return;
+ }
+
+ fp_Run* pRun1;
+ fp_Run* pRun2;
+ UT_uint32 uheight;
+
+ {
+ UT_sint32 x;
+ UT_sint32 y;
+ fl_BlockLayout* pBlock1;
+ fl_BlockLayout* pBlock2;
+
+ /*
+ we don't really care about the coords. We're calling these
+ to get the Run pointer
+ */
+ _findPositionCoords(iPos1, UT_FALSE, x, y, uheight, &pBlock1, &pRun1);
+ _findPositionCoords(iPos2, UT_FALSE, x, y, uheight, &pBlock2, &pRun2);
+ }
+
+ if (!pRun1 && !pRun2)
+ {
+ // no formatting info for either block, so just bail
+ // this can happen during spell, when we're trying to invalidate
+ // a new squiggle before the block has been formatted
+ return;
+ }
+
+ UT_ASSERT(pRun1 && pRun2);
+
+ UT_Bool bDone = UT_FALSE;
+ fp_Run* pCurRun = pRun1;
+
+
+ while (!bDone)
+ {
+ if (pCurRun == pRun2)
+ {
+ bDone = UT_TRUE;
+ }
+
+ pCurRun->clearScreen(bFullLineHeightRect);
+
+ if (pCurRun->getNext())
+ {
+ pCurRun = pCurRun->getNext();
+ }
+ else
+ {
+ fl_BlockLayout* pNextBlock;
+
+ fl_BlockLayout* pBlock = pCurRun->getBlock();
+ UT_ASSERT(pBlock);
+
+ pNextBlock = pBlock->getNextBlockInDocument();
+ if (pNextBlock)
+ {
+ pCurRun = pNextBlock->getFirstRun();
+ }
+ }
+ }
+ }

- // did block format change?
- pSection->getAttrProp(&pAP);
- if (pSectionAP != pAP)
- {
- pSectionAP = pAP;
- bCheck = UT_TRUE;
- }
+ void FV_View::_findPositionCoords(PT_DocPosition pos,
+ UT_Bool bEOL,
+ UT_sint32& x,
+ UT_sint32& y,
+ UT_uint32& height,
+ fl_BlockLayout** ppBlock,
+ fp_Run** ppRun)
+ {
+ UT_sint32 xPoint;
+ UT_sint32 yPoint;
+ UT_sint32 iPointHeight;
+
+ fl_BlockLayout* pBlock = _findBlockAtPosition(pos);
+ UT_ASSERT(pBlock);
+ fp_Run* pRun = pBlock->findPointCoords(pos, bEOL, xPoint, yPoint, iPointHeight);
+
+ // NOTE prior call will fail if the block isn't currently formatted,
+ // NOTE so we won't be able to figure out more specific geometry
+
+ if (pRun)
+ {
+ // we now have coords relative to the page containing the ins pt
+ fp_Page* pPointPage = pRun->getLine()->getContainer()->getPage();
+
+ UT_sint32 iPageOffset;
+ getPageYOffset(pPointPage, iPageOffset);
+ yPoint += iPageOffset;
+ xPoint += fl_PAGEVIEW_MARGIN_X;
+
+ // now, we have coords absolute, as if all pages were stacked vertically
+ xPoint -= m_xScrollOffset;
+ yPoint -= m_yScrollOffset;
+
+ // now, return the results
+ x = xPoint;
+ y = yPoint;
+ height = iPointHeight;
+ }
+
+ if (ppBlock)
+ {
+ *ppBlock = pBlock;
+ }
+
+ if (ppRun)
+ {
+ *ppRun = pRun;
+ }
+ }

- if (bCheck)
- {
- i = v.getItemCount();
+ void FV_View::_fixInsertionPointCoords()
+ {
+ _findPositionCoords(getPoint(), m_bPointEOL, m_xPoint, m_yPoint, m_iPointHeight, NULL, NULL);

- while (i > 0)
- {
- f = (_fmtPair *)v.getNthItem(i-1);
+ // hang onto this for _moveInsPtNextPrevLine()
+ m_xPointSticky = m_xPoint + m_xScrollOffset - fl_PAGEVIEW_MARGIN_X;
+ }

- const XML_Char * value = PP_evalProperty(f->m_prop,NULL,pBlockAP,pSectionAP,m_pDoc,UT_FALSE);
- UT_ASSERT(value);
+ void FV_View::_updateInsertionPoint()
+ {
+ if (isSelectionEmpty())
+ {
+ _eraseInsertionPoint();
+
+ if (!_ensureThatInsertionPointIsOnScreen())
+ {
+ _fixInsertionPointCoords();
+ _drawInsertionPoint();
+ }
+ }
+ }

- // prune anything that doesn't match
- if (UT_stricmp(f->m_val, value))
- {
- DELETEP(f);
- v.deleteNthItem(i-1);
- }
+ void FV_View::_xorInsertionPoint()
+ {
+ if (m_iPointHeight > 0)
+ {
+ UT_RGBColor clr(255,255,255);
+
+ m_pG->setColor(clr);
+ m_pG->xorLine(m_xPoint, m_yPoint, m_xPoint, m_yPoint + m_iPointHeight);
+ }
+ }

- i--;
- }
+ void FV_View::_eraseInsertionPoint()
+ {
+ if (!isSelectionEmpty())
+ {
+ return;
+ }

- // when vector is empty, stop looking
- if (0 == v.getItemCount())
- {
- pSection = NULL;
- break;
- }
- }
- }
- }
+ _xorInsertionPoint();
+ }

- // 3. export whatever's left
- UT_uint32 count = v.getItemCount()*2 + 1;
+ void FV_View::_drawInsertionPoint()
+ {
+ if (m_iWindowHeight <= 0)
+ {
+ return;
+ }
+
+ if (!isSelectionEmpty())
+ {
+ return;
+ }

- // NOTE: caller must free this, but not the referenced contents
- const XML_Char ** props = (const XML_Char **) calloc(count, sizeof(XML_Char *));
- if (!props)
- return UT_FALSE;
+ _xorInsertionPoint();
+ }

- const XML_Char ** p = props;
+ void FV_View::setXScrollOffset(UT_sint32 v)
+ {
+ UT_sint32 dx = v - m_xScrollOffset;

- i = v.getItemCount();
+ if (dx == 0)
+ return;

- while (i > 0)
- {
- f = (_fmtPair *)v.getNthItem(i-1);
- i--;
+ m_pG->scroll(dx, 0);
+ m_xScrollOffset = v;

- p[0] = f->m_prop;
- p[1] = f->m_val;
- p += 2;
+ if (dx > 0)
+ {
+ if (dx >= m_iWindowWidth)
+ {
+ _draw(0, 0, m_iWindowWidth, m_iWindowHeight, UT_FALSE, UT_TRUE);
+ }
+ else
+ {
+ _draw(m_iWindowWidth - dx, 0, m_iWindowWidth, m_iWindowHeight, UT_FALSE, UT_TRUE);
+ }
+ }
+ else
+ {
+ if (dx <= -m_iWindowWidth)
+ {
+ _draw(0, 0, m_iWindowWidth, m_iWindowHeight, UT_FALSE, UT_TRUE);
+ }
+ else
+ {
+ _draw(0, 0, -dx, m_iWindowHeight, UT_FALSE, UT_TRUE);
+ }
}
+ }

- UT_VECTOR_PURGEALL(_fmtPair *,v);
-
- *pProps = props;
-
- return UT_TRUE;
-}
+ void FV_View::setYScrollOffset(UT_sint32 v)
+ {
+ UT_sint32 dy = v - m_yScrollOffset;

-UT_Bool FV_View::getBlockFormat(const XML_Char *** pProps,UT_Bool bExpandStyles)
-{
- const PP_AttrProp * pBlockAP = NULL;
- const PP_AttrProp * pSectionAP = NULL; // TODO do we care about section-level inheritance?
- UT_Vector v;
- UT_uint32 i;
- _fmtPair * f;
+ if (dy == 0)
+ return;

- /*
- IDEA: We want to know block-level formatting properties, iff
- they're constant across the entire selection. To do so, we start
- at the beginning of the selection, load 'em all into a vector, and
- then prune any property that collides.
- */
- PT_DocPosition posStart = getPoint();
- PT_DocPosition posEnd = posStart;
+ m_pG->scroll(0, dy);
+ m_yScrollOffset = v;

- if (!isSelectionEmpty())
- {
- if (m_iSelectionAnchor < posStart)
- posStart = m_iSelectionAnchor;
- else
- posEnd = m_iSelectionAnchor;
+ if (dy > 0)
+ {
+ if (dy >= m_iWindowHeight)
+ {
+ _draw(0, 0, m_iWindowWidth, m_iWindowHeight, UT_FALSE, UT_TRUE);
+ }
+ else
+ {
+ _draw(0, m_iWindowHeight - dy, m_iWindowWidth, dy, UT_FALSE, UT_TRUE);
+ }
+ }
+ else
+ {
+ if (dy <= -m_iWindowHeight)
+ {
+ _draw(0, 0, m_iWindowWidth, m_iWindowHeight, UT_FALSE, UT_TRUE);
+ }
+ else
+ {
+ _draw(0, 0, m_iWindowWidth, -dy, UT_FALSE, UT_TRUE);
+ }
}
+ }

- // 1. assemble complete set at insertion point
- fl_BlockLayout* pBlock = _findBlockAtPosition(posStart);
- pBlock->getAttrProp(&pBlockAP);
-
- v.addItem(new _fmtPair("text-align", NULL,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
- v.addItem(new _fmtPair("text-indent", NULL,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
- v.addItem(new _fmtPair("margin-left", NULL,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
- v.addItem(new _fmtPair("margin-right", NULL,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
- v.addItem(new _fmtPair("margin-top", NULL,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
- v.addItem(new _fmtPair("margin-bottom", NULL,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
- v.addItem(new _fmtPair("line-height", NULL,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
- v.addItem(new _fmtPair("tabstops", NULL,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
- v.addItem(new _fmtPair("default-tab-interval",NULL,pBlockAP,pSectionAP,m_pDoc,bExpandStyles));
+ void FV_View::draw(int page, dg_DrawArgs* da)
+ {
+ xxx_UT_DEBUGMSG(("FV_View::draw_1: [page %ld]\n",page));

- // 2. prune 'em as they vary across selection
- if (!isSelectionEmpty())
- {
- fl_BlockLayout* pBlockEnd = _findBlockAtPosition(posEnd);
-
- while (pBlock && (pBlock != pBlockEnd))
- {
- const PP_AttrProp * pAP;
- UT_Bool bCheck = UT_FALSE;
-
- pBlock = pBlock->getNextBlockInDocument();
- if (!pBlock) // at EOD, so just bail
- break;
-
- // did block format change?
- pBlock->getAttrProp(&pAP);
- if (pBlockAP != pAP)
- {
- pBlockAP = pAP;
- bCheck = UT_TRUE;
- }
-
- if (bCheck)
- {
- i = v.getItemCount();
-
- while (i > 0)
- {
- f = (_fmtPair *)v.getNthItem(i-1);
-
- const XML_Char * value = PP_evalProperty(f->m_prop,NULL,pBlockAP,pSectionAP,m_pDoc,bExpandStyles);
- UT_ASSERT(value);
-
- // prune anything that doesn't match
- if (UT_stricmp(f->m_val, value))
- {
- DELETEP(f);
- v.deleteNthItem(i-1);
- }
-
- i--;
- }
-
- // when vector is empty, stop looking
- if (0 == v.getItemCount())
- {
- pBlock = NULL;
- break;
- }
- }
- }
- }
-
- // 3. export whatever's left
- UT_uint32 count = v.getItemCount()*2 + 1;
-
- // NOTE: caller must free this, but not the referenced contents
- const XML_Char ** props = (const XML_Char **) calloc(count, sizeof(XML_Char *));
- if (!props)
- return UT_FALSE;
-
- const XML_Char ** p = props;
-
- i = v.getItemCount();
-
- while (i > 0)
- {
- f = (_fmtPair *)v.getNthItem(i-1);
- i--;
-
- p[0] = f->m_prop;
- p[1] = f->m_val;
- p += 2;
- }
-
- UT_VECTOR_PURGEALL(_fmtPair *,v);
-
- *pProps = props;
-
- return UT_TRUE;
-}
-
-void FV_View::delTo(FV_DocPos dp)
-{
- PT_DocPosition iPos = _getDocPos(dp);
-
- if (iPos == getPoint())
- {
- return;
- }
-
- _extSelToPos(iPos);
- _deleteSelection();
-
- _fixInsertionPointCoords();
- _drawInsertionPoint();
-}
-
-/*
- This function is somewhat of a compromise. It will return a new
- range of memory (destroy with free()) full of what's in the selection,
- but it will not cross block boundaries. This is for convenience
- in implementation, but could probably be accomplished without
- too much more effort. However, since an edit entry in a dialog
- box (1) only allows a bit of text and (2) has no concept of a
- block break anyway, I don't see a reason to make this behave
- differently.
-*/
-UT_UCSChar * FV_View::getSelectionText(void)
-{
- UT_ASSERT(!isSelectionEmpty());
-
- UT_GrowBuf buffer;
-
- UT_uint32 selLength = labs(m_iInsPoint - m_iSelectionAnchor);
-
- PT_DocPosition low;
- if (m_iInsPoint > m_iSelectionAnchor)
- {
- low = m_iSelectionAnchor;
- }
- else
- {
- low = m_iInsPoint;
- }
-
- // get the current block the insertion point is in
- fl_BlockLayout * block = m_pLayout->findBlockAtPosition(low);
-
- if (block)
- {
- block->getBlockBuf(&buffer);
-
- UT_UCSChar * bufferSegment = NULL;
-
- PT_DocPosition offset = low - block->getPosition(UT_FALSE);
-
- // allow no more than the rest of the block
- if (offset + selLength > buffer.getLength())
- selLength = buffer.getLength() - offset;
-
- // give us space for our new chunk of selected text, add 1 so it
- // terminates itself
- bufferSegment = (UT_UCSChar *) calloc(selLength + 1, sizeof(UT_UCSChar));
-
- // copy it out
- memmove(bufferSegment, buffer.getPointer(offset), selLength * sizeof(UT_UCSChar));
-
- return bufferSegment;
- }
-
- return NULL;
-}
-
-void FV_View::cmdCharDelete(UT_Bool bForward, UT_uint32 count)
-{
- if (!isSelectionEmpty())
- {
- _deleteSelection();
-
- _generalUpdate();
-
- if (!_ensureThatInsertionPointIsOnScreen())
- {
- _fixInsertionPointCoords();
- _drawInsertionPoint();
- }
- }
- else
- {
- _eraseInsertionPoint();
-
- UT_uint32 amt = count;
- UT_uint32 posCur = getPoint();
-
- if (!bForward)
- {
-
- if (!_charMotion(bForward,count))
- {
- UT_ASSERT(getPoint() <= posCur);
- amt = posCur - getPoint();
- }
-
- posCur = getPoint();
- }
- else
- {
- PT_DocPosition posEOD;
- UT_Bool bRes;
-
- bRes = m_pDoc->getBounds(UT_TRUE, posEOD);
- UT_ASSERT(bRes);
- UT_ASSERT(posCur <= posEOD);
-
- if (posEOD < (posCur+amt))
- {
- amt = posEOD - posCur;
- }
- }
-
- if (amt > 0)
- {
- m_pDoc->deleteSpan(posCur, posCur+amt);
- }
-
- _generalUpdate();
-
- if (!_ensureThatInsertionPointIsOnScreen())
- {
- _fixInsertionPointCoords();
- _drawInsertionPoint();
- }
- }
-}
-
-void FV_View::_moveInsPtNextPrevLine(UT_Bool bNext)
-{
- UT_sint32 xPoint;
- UT_sint32 yPoint;
- UT_sint32 iPointHeight, iLineHeight;
-
- /*
- This function moves the IP up or down one line, attempting to get
- as close as possible to the prior "sticky" x position. The notion
- of "next" is strictly physical, not logical.
-
- For example, instead of always moving from the last line of one block
- to the first line of the next, you might wind up skipping over a
- bunch of blocks to wind up in the first line of the second column.
- */
- UT_sint32 xOldSticky = m_xPointSticky;
-
- // first, find the line we are on now
- UT_uint32 iOldPoint = getPoint();
-
- fl_BlockLayout* pOldBlock = _findBlockAtPosition(iOldPoint);
- fp_Run* pOldRun = pOldBlock->findPointCoords(getPoint(), m_bPointEOL, xPoint, yPoint, iPointHeight);
- fl_SectionLayout* pOldSL = pOldBlock->getSectionLayout();
- fp_Line* pOldLine = pOldRun->getLine();
- fp_Container* pOldContainer = pOldLine->getContainer();
- fp_Page* pOldPage = pOldContainer->getPage();
- UT_Bool bDocSection = (pOldSL->getType() == FL_SECTION_DOC);
-
- fp_Column* pOldLeader = NULL;
- if (bDocSection)
- {
- pOldLeader = ((fp_Column*) (pOldContainer))->getLeader();
- }
-
- UT_sint32 iPageOffset;
- getPageYOffset(pOldPage, iPageOffset);
-
- UT_sint32 iLineX = 0;
- UT_sint32 iLineY = 0;
-
- pOldContainer->getOffsets(pOldLine, iLineX, iLineY);
- yPoint = iLineY;
-
- iLineHeight = pOldLine->getHeight();
-
- UT_Bool bNOOP = UT_FALSE;
-
- if (bNext)
- {
- if (pOldLine != pOldContainer->getLastLine())
- {
- // just move off this line
- yPoint += (iLineHeight + pOldLine->getMarginAfter());
- }
- else if (bDocSection && (((fp_Column*) (pOldSL->getLastContainer()))->getLeader() == pOldLeader))
- {
- // move to next section
- fl_SectionLayout* pSL = pOldSL->getNext();
- if (pSL)
- {
- yPoint = pSL->getFirstContainer()->getY();
- }
- else
- {
- bNOOP = UT_TRUE;
- }
- }
- else
- {
- // move to next page
- fp_Page* pPage = pOldPage->getNext();
- if (pPage)
- {
- getPageYOffset(pPage, iPageOffset);
- yPoint = 0;
- }
- else
- {
- bNOOP = UT_TRUE;
- }
- }
- }
- else
- {
- if (pOldLine != pOldContainer->getFirstLine())
- {
- // just move off this line
- yPoint -= (pOldLine->getMarginBefore() + 1);
- }
- else if (bDocSection && (pOldSL->getFirstContainer() == pOldLeader))
- {
- // move to prev section
- fl_SectionLayout* pSL = pOldSL->getPrev();
- if (pSL)
- {
- fp_Column* pTmpCol = ((fp_Column*) (pSL->getLastContainer()))->getLeader();
- yPoint = pTmpCol->getY();
-
- UT_sint32 iMostHeight = 0;
- while (pTmpCol)
- {
- iMostHeight = UT_MAX(iMostHeight, pTmpCol->getHeight());
-
- pTmpCol = pTmpCol->getFollower();
- }
-
- yPoint += (iMostHeight - 1);
- }
- else
- {
- bNOOP = UT_TRUE;
- }
- }
- else
- {
- // move to prev page
- fp_Page* pPage = pOldPage->getPrev();
- if (pPage)
- {
- getPageYOffset(pPage, iPageOffset);
- yPoint = pPage->getBottom();
- }
- else
- {
- bNOOP = UT_TRUE;
- }
- }
- }
-
- if (bNOOP)
- {
- // cannot move. should we beep?
- _drawInsertionPoint();
- return;
- }
-
- // change to screen coordinates
- xPoint = m_xPointSticky - m_xScrollOffset + fl_PAGEVIEW_MARGIN_X;
- yPoint += iPageOffset - m_yScrollOffset;
-
- // hit-test to figure out where that puts us
- UT_sint32 xClick, yClick;
- fp_Page* pPage = _getPageForXY(xPoint, yPoint, xClick, yClick);
-
- PT_DocPosition iNewPoint;
- UT_Bool bBOL, bEOL;
- pPage->mapXYToPosition(xClick, yClick, iNewPoint, bBOL, bEOL);
-
- UT_ASSERT(iNewPoint != iOldPoint);
-
- _setPoint(iNewPoint, bEOL);
-
- if (!_ensureThatInsertionPointIsOnScreen())
- {
- _fixInsertionPointCoords();
- _drawInsertionPoint();
- }
-
- // this is the only place where we override changes to m_xPointSticky
- m_xPointSticky = xOldSticky;
-}
-
-UT_Bool FV_View::_ensureThatInsertionPointIsOnScreen(void)
-{
- UT_Bool bRet = UT_FALSE;
-
- if (m_iWindowHeight <= 0)
- {
- return UT_FALSE;
- }
-
- _fixInsertionPointCoords();
-
- //UT_DEBUGMSG(("_ensure: [xp %ld][yp %ld][ph %ld] [w %ld][h %ld]\n",m_xPoint,m_yPoint,m_iPointHeight,m_iWindowWidth,m_iWindowHeight));
-
- if (m_yPoint < 0)
- {
- cmdScroll(AV_SCROLLCMD_LINEUP, (UT_uint32) (-(m_yPoint)));
- bRet = UT_TRUE;
- }
- else if (((UT_uint32) (m_yPoint + m_iPointHeight)) >= ((UT_uint32) m_iWindowHeight))
- {
- cmdScroll(AV_SCROLLCMD_LINEDOWN, (UT_uint32)(m_yPoint + m_iPointHeight - m_iWindowHeight));
- bRet = UT_TRUE;
- }
-
- /*
- TODO: we really ought to try to do better than this.
- */
- if (m_xPoint < 0)
- {
- cmdScroll(AV_SCROLLCMD_LINELEFT, (UT_uint32) (-(m_xPoint)));
- bRet = UT_TRUE;
- }
- else if (((UT_uint32) (m_xPoint)) >= ((UT_uint32) m_iWindowWidth))
- {
- cmdScroll(AV_SCROLLCMD_LINERIGHT, (UT_uint32)(m_xPoint - m_iWindowWidth));
- bRet = UT_TRUE;
- }
-
- return bRet;
-}
-
-void FV_View::warpInsPtNextPrevLine(UT_Bool bNext)
-{
- if (!isSelectionEmpty())
- _moveToSelectionEnd(bNext);
- else
- _eraseInsertionPoint();
-
- _resetSelection();
- _clearIfAtFmtMark(getPoint());
- _moveInsPtNextPrevLine(bNext);
- notifyListeners(AV_CHG_MOTION);
-}
-
-void FV_View::extSelNextPrevLine(UT_Bool bNext)
-{
- if (isSelectionEmpty())
- {
- _setSelectionAnchor();
- _clearIfAtFmtMark(getPoint());
- _moveInsPtNextPrevLine(bNext);
- if (isSelectionEmpty())
- {
- _fixInsertionPointCoords();
- _drawInsertionPoint();
- }
- else
- {
- _drawSelection();
- }
- }
- else
- {
- PT_DocPosition iOldPoint = getPoint();
- _moveInsPtNextPrevLine(bNext);
- PT_DocPosition iNewPoint = getPoint();
-
- // top/bottom of doc - nowhere to go
- if (iOldPoint == iNewPoint)
- return;
-
- _extSel(iOldPoint);
-
- if (isSelectionEmpty())
- {
- _resetSelection();
- _fixInsertionPointCoords();
- _drawInsertionPoint();
- }
- }
-
- notifyListeners(AV_CHG_MOTION);
-}
-
-void FV_View::extSelHorizontal(UT_Bool bForward, UT_uint32 count)
-{
- if (isSelectionEmpty())
- {
- _eraseInsertionPoint();
- _setSelectionAnchor();
- _charMotion(bForward, count);
- }
- else
- {
- PT_DocPosition iOldPoint = getPoint();
-
- if (_charMotion(bForward, count) == UT_FALSE)
- {
- _setPoint(iOldPoint);
- return;
- }
-
- _extSel(iOldPoint);
- }
-
- _ensureThatInsertionPointIsOnScreen();
-
- /*
- It IS possible for the selection to be empty, even
- after extending it. If the charMotion fails, for example,
- because we are at the end of a document, then the selection
- will end up empty once again.
- */
- if (isSelectionEmpty())
- {
- _resetSelection();
- _fixInsertionPointCoords();
- _drawInsertionPoint();
- }
- else
- {
- _drawSelection();
- }
-
- notifyListeners(AV_CHG_MOTION);
-}
-
-void FV_View::extSelTo(FV_DocPos dp)
-{
- PT_DocPosition iPos = _getDocPos(dp);
-
- _extSelToPos(iPos);
-
- if (!_ensureThatInsertionPointIsOnScreen())
- {
- if (isSelectionEmpty())
- {
- _fixInsertionPointCoords();
- _drawInsertionPoint();
- }
- }
-
- notifyListeners(AV_CHG_MOTION);
-}
-
-#define AUTO_SCROLL_MSECS 100
-
-void FV_View::_autoScroll(UT_Timer * pTimer)
-{
- UT_ASSERT(pTimer);
-
- // this is a static callback method and does not have a 'this' pointer.
-
- FV_View * pView = (FV_View *) pTimer->getInstanceData();
- UT_ASSERT(pView);
-
- PT_DocPosition iOldPoint = pView->getPoint();
-
- /*
- NOTE: We update the selection here, so that the timer can keep
- triggering autoscrolls even if the mouse doesn't move.
- */
- pView->extSelToXY(pView->m_xLastMouse, pView->m_yLastMouse, UT_FALSE);
-
- if (pView->getPoint() != iOldPoint)
- {
- // do the autoscroll
- if (!pView->_ensureThatInsertionPointIsOnScreen())
- {
- pView->_fixInsertionPointCoords();
-// pView->_drawInsertionPoint();
- }
- }
- else
- {
- // not far enough to change the selection ... do we still need to scroll?
- UT_sint32 xPos = pView->m_xLastMouse;
- UT_sint32 yPos = pView->m_yLastMouse;
-
- // TODO: clamp xPos, yPos to viewable area??
-
- UT_Bool bOnScreen = UT_TRUE;
-
- if ((xPos < 0 || xPos > pView->m_iWindowWidth) ||
- (yPos < 0 || yPos > pView->m_iWindowHeight))
- bOnScreen = UT_FALSE;
-
- if (!bOnScreen)
- {
- // yep, do it manually
-
- // TODO currently we blindly send these auto scroll events without regard
- // TODO to whether the window can scroll any further in that direction.
- // TODO we could optimize this a bit and check the scroll range before we
- // TODO fire them, but that knowledge is only stored in the frame and we
- // TODO don't have a backpointer to it.
- // UT_DEBUGMSG(("_auto: [xp %ld][yp %ld] [w %ld][h %ld]\n",
- // xPos,yPos,pView->m_iWindowWidth,pView->m_iWindowHeight));
-
- if (yPos < 0)
- {
- pView->cmdScroll(AV_SCROLLCMD_LINEUP, (UT_uint32) (-(yPos)));
- }
- else if (((UT_uint32) (yPos)) >= ((UT_uint32) pView->m_iWindowHeight))
- {
- pView->cmdScroll(AV_SCROLLCMD_LINEDOWN, (UT_uint32)(yPos - pView->m_iWindowHeight));
- }
-
- if (xPos < 0)
- {
- pView->cmdScroll(AV_SCROLLCMD_LINELEFT, (UT_uint32) (-(xPos)));
- }
- else if (((UT_uint32) (xPos)) >= ((UT_uint32) pView->m_iWindowWidth))
- {
- pView->cmdScroll(AV_SCROLLCMD_LINERIGHT, (UT_uint32)(xPos - pView->m_iWindowWidth));
- }
- }
- }
-}
-
-
-fp_Page* FV_View::_getPageForXY(UT_sint32 xPos, UT_sint32 yPos, UT_sint32& xClick, UT_sint32& yClick)
-{
- xClick = xPos + m_xScrollOffset - fl_PAGEVIEW_MARGIN_X;
- yClick = yPos + m_yScrollOffset - fl_PAGEVIEW_MARGIN_Y;
- fp_Page* pPage = m_pLayout->getFirstPage();
- while (pPage)
- {
- UT_sint32 iPageHeight = pPage->getHeight();
- if (yClick < iPageHeight)
- {
- // found it
- break;
- }
- else
- {
- yClick -= iPageHeight + fl_PAGEVIEW_PAGE_SEP;
- }
- pPage = pPage->getNext();
- }
-
- if (!pPage)
- {
- // we're below the last page
- pPage = m_pLayout->getLastPage();
-
- UT_sint32 iPageHeight = pPage->getHeight();
- yClick += iPageHeight + fl_PAGEVIEW_PAGE_SEP;
- }
-
- return pPage;
-}
-
-void FV_View::extSelToXY(UT_sint32 xPos, UT_sint32 yPos, UT_Bool bDrag)
-{
- /*
- Figure out which page we clicked on.
- Pass the click down to that page.
- */
- UT_sint32 xClick, yClick;
- fp_Page* pPage = _getPageForXY(xPos, yPos, xClick, yClick);
-
- PT_DocPosition iNewPoint;
- UT_Bool bBOL, bEOL;
- pPage->mapXYToPosition(xClick, yClick, iNewPoint, bBOL, bEOL);
-
- UT_Bool bPostpone = UT_FALSE;
-
- if (bDrag)
- {
- // figure out whether we're still on screen
- UT_Bool bOnScreen = UT_TRUE;
-
- if ((xPos < 0 || xPos > m_iWindowWidth) ||
- (yPos < 0 || yPos > m_iWindowHeight))
- bOnScreen = UT_FALSE;
-
- // is autoscroll timer set properly?
- if (bOnScreen)
- {
- if (m_pAutoScrollTimer)
- {
- // timer not needed any more, so stop it
- m_pAutoScrollTimer->stop();
- }
- }
- else
- {
- // remember where mouse is
- m_xLastMouse = xPos;
- m_yLastMouse = yPos;
-
- // offscreen ==> make sure it's set
- if (!m_pAutoScrollTimer)
- {
- m_pAutoScrollTimer = UT_Timer::static_constructor(_autoScroll, this, m_pG);
- if (m_pAutoScrollTimer)
- m_pAutoScrollTimer->set(AUTO_SCROLL_MSECS);
- }
- else
- {
- m_pAutoScrollTimer->start();
- }
-
- // postpone selection until timer fires
- bPostpone = UT_TRUE;
- }
- }
-
- if (!bPostpone)
- {
- _extSelToPos(iNewPoint);
- notifyListeners(AV_CHG_MOTION);
- }
-}
-
-void FV_View::extSelToXYword(UT_sint32 xPos, UT_sint32 yPos, UT_Bool bDrag)
-{
- // extend the current selection to
- // include the WORD at the given XY.
- // this should behave just like extSelToXY()
- // but with WORD-level granularity.
-
- /*
- Figure out which page we clicked on.
- Pass the click down to that page.
- */
- UT_sint32 xClick, yClick;
- fp_Page* pPage = _getPageForXY(xPos, yPos, xClick, yClick);
-
- PT_DocPosition iNewPoint;
- UT_Bool bBOL, bEOL;
- pPage->mapXYToPosition(xClick, yClick, iNewPoint, bBOL, bEOL);
-
- //UT_ASSERT(!isSelectionEmpty());
-
- if (iNewPoint <= m_iSelectionLeftAnchor) {
- m_iSelectionAnchor = m_iSelectionRightAnchor;
- }
- else {
- m_iSelectionAnchor = m_iSelectionLeftAnchor;
- }
-
- PT_DocPosition iNewPointWord;
- if (iNewPoint > m_iSelectionAnchor)
- iNewPointWord = _getDocPosFromPoint(iNewPoint,FV_DOCPOS_EOW,UT_FALSE);
- else
- iNewPointWord = _getDocPosFromPoint(iNewPoint,FV_DOCPOS_BOW,UT_FALSE);
-
- UT_Bool bPostpone = UT_FALSE;
-
- if (bDrag)
- {
- // figure out whether we're still on screen
- UT_Bool bOnScreen = UT_TRUE;
-
- if ((xPos < 0 || xPos > m_iWindowWidth) ||
- (yPos < 0 || yPos > m_iWindowHeight))
- bOnScreen = UT_FALSE;
-
- // is autoscroll timer set properly?
- if (bOnScreen)
- {
- if (m_pAutoScrollTimer)
- {
- // timer not needed any more, so stop it
- m_pAutoScrollTimer->stop();
- }
- }
- else
- {
- // remember where mouse is
- m_xLastMouse = xPos;
- m_yLastMouse = yPos;
-
- // offscreen ==> make sure it's set
- if (!m_pAutoScrollTimer)
- {
- m_pAutoScrollTimer = UT_Timer::static_constructor(_autoScroll, this, m_pG);
- if (m_pAutoScrollTimer)
- m_pAutoScrollTimer->set(AUTO_SCROLL_MSECS);
- }
- else
- {
- m_pAutoScrollTimer->start();
- }
-
- // postpone selection until timer fires
- bPostpone = UT_TRUE;
- }
- }
-
- if (!bPostpone)
- {
- _extSelToPos(iNewPointWord);
- notifyListeners(AV_CHG_MOTION);
- }
-}
-
-void FV_View::endDrag(UT_sint32 xPos, UT_sint32 yPos)
-{
- if (!m_pAutoScrollTimer)
- return;
-
- // figure out whether we're still on screen
- UT_Bool bOnScreen = UT_TRUE;
-
- if ((xPos < 0 || xPos > m_iWindowWidth) ||
- (yPos < 0 || yPos > m_iWindowHeight))
- bOnScreen = UT_FALSE;
-
- if (!bOnScreen)
- {
- // remember where mouse is
- m_xLastMouse = xPos;
- m_yLastMouse = yPos;
-
- // finish pending autoscroll
- m_pAutoScrollTimer->fire();
- }
-
- // timer not needed any more, so stop it
- m_pAutoScrollTimer->stop();
-}
-
-// ---------------- start goto ---------------
-
-UT_Bool FV_View::gotoTarget(FV_JumpTarget /* type */, UT_UCSChar * /* data */)
-{
- UT_ASSERT(UT_NOT_IMPLEMENTED);
-
- UT_ASSERT(m_pLayout);
-
- // TODO: We need a Unicode atol/strtol.
-
- /*
- char * numberString = (char *) calloc(UT_UCS_strlen(m_targetData) + 1, sizeof(char));
- UT_ASSERT(numberString);
-
- UT_UCS_strcpy_to_char(numberString, m_targetData);
-
- UT_uint32 pageNumber = atol(numberString);
- FREEP(numberString);
- */
-
- // check for range
-// if (pageNumber < 0 || pageNumber > (UT_uint32) m_pLayout->countPages())
-// return UT_FALSE;
-
- // get the right page
-// fp_Page * page = m_pLayout->getNthPage(pageNumber);
-// UT_ASSERT(page);
-
- // peek inside the page
- // ...
-
- return UT_FALSE;
-}
-
-// ---------------- start find and replace ---------------
-
-UT_Bool FV_View::findNext(const UT_UCSChar * find, UT_Bool matchCase, UT_Bool * bDoneEntireDocument)
-{
- if (!isSelectionEmpty())
- {
- _clearSelection();
- }
- else
- {
- _eraseInsertionPoint();
- }
-
- UT_Bool bRes = _findNext(find, matchCase, bDoneEntireDocument);
-
- if (isSelectionEmpty())
- {
- if (!_ensureThatInsertionPointIsOnScreen())
- {
- _fixInsertionPointCoords();
- _drawInsertionPoint();
- }
- }
- else
- {
- _ensureThatInsertionPointIsOnScreen();
- _drawSelection();
- }
-
- // TODO do we need to do a notifyListeners(AV_CHG_MOTION) ??
- return bRes;
-}
-
-UT_Bool FV_View::_findNext(const UT_UCSChar * find, UT_Bool matchCase, UT_Bool * bDoneEntireDocument)
-{
- UT_ASSERT(find);
-
- fl_BlockLayout * block = NULL;
- PT_DocPosition offset = 0;
-
- block = _findGetCurrentBlock();
- offset = _findGetCurrentOffset();
-
- UT_UCSChar * buffer = NULL;
-
- while ((buffer = _findGetNextBlockBuffer(&block, &offset)))
- {
- // magic number; range of UT_sint32 falls short of extremely large docs
- UT_sint32 foundAt = -1;
-
- // Change the ordering of searches to accomodate new searches (like
- // regular expressions, case-sensitive, or reverse searches).
- // Right now we just work off case searches.
- if (matchCase == UT_TRUE)
- {
- // this search will do case-sensitive work
- foundAt = _findBlockSearchDumbCase(buffer, find);
- }
- else if (matchCase == UT_FALSE)
- {
- // do the case-insensitive search
- foundAt = _findBlockSearchDumbNoCase(buffer, find);
- }
-
-
- if (foundAt != -1)
- {
- _setPoint(block->getPosition(UT_FALSE) + offset + foundAt);
- _setSelectionAnchor();
- _charMotion(UT_TRUE, UT_UCS_strlen(find));
-
- m_doneFind = UT_TRUE;
-
- FREEP(buffer);
- return UT_TRUE;
- }
-
- // didn't find anything, so set the offset to the end
- // of the current area
- offset += UT_UCS_strlen(buffer);
-
- // must clean up buffer returned for search
- FREEP(buffer);
- }
-
- if (bDoneEntireDocument)
- {
- *bDoneEntireDocument = UT_TRUE;
- }
-
- // reset wrap for next time
- m_wrappedEnd = UT_FALSE;
-
- return UT_FALSE;
-}
-
-void FV_View::findSetStartAtInsPoint(void)
-{
- m_startPosition = m_iInsPoint;
- m_wrappedEnd = UT_FALSE;
- m_doneFind = UT_FALSE;
-}
-
-PT_DocPosition FV_View::_BlockOffsetToPos(fl_BlockLayout * block, PT_DocPosition offset)
-{
- UT_ASSERT(block);
- return block->getPosition(UT_FALSE) + offset;
-}
-
-UT_UCSChar * FV_View::_findGetNextBlockBuffer(fl_BlockLayout ** block, PT_DocPosition * offset)
-{
- UT_ASSERT(m_pLayout);
-
- // this assert doesn't work, since the startPosition CAN legitimately be zero
- UT_ASSERT(m_startPosition >= 2); // the beginning of the first block in any document
-
- UT_ASSERT(block);
- UT_ASSERT(*block);
-
- UT_ASSERT(offset);
-
- fl_BlockLayout * newBlock = NULL;
- PT_DocPosition newOffset = 0;
-
- UT_uint32 bufferLength = 0;
-
- UT_GrowBuf buffer;
-
- // check early for completion, from where we left off last, and bail
- // if we are now at or past the start position
- if (m_wrappedEnd && _BlockOffsetToPos(*block, *offset) >= m_startPosition)
- {
- // we're done
- return NULL;
- }
-
- if (!(*block)->getBlockBuf(&buffer))
- {
- UT_DEBUGMSG(("Block %p has no associated buffer.\n", *block));
- UT_ASSERT(0);
- }
-
- // have we already searched all the text in this buffer?
- if (*offset >= buffer.getLength())
- {
- // then return a fresh new block's buffer
- newBlock = (*block)->getNextBlockInDocument();
-
- // are we at the end of the document?
- if (!newBlock)
- {
- // then wrap (fetch the first block in the doc)
- PT_DocPosition startOfDoc;
- m_pDoc->getBounds(UT_FALSE, startOfDoc);
-
- newBlock = m_pLayout->findBlockAtPosition(startOfDoc);
-
- m_wrappedEnd = UT_TRUE;
-
- UT_ASSERT(newBlock);
- }
-
- // re-assign the buffer contents for our new block
- buffer.truncate(0);
- // the offset starts at 0 for a fresh buffer
- newOffset = 0;
-
- if (!newBlock->getBlockBuf(&buffer))
- {
- UT_DEBUGMSG(("Block %p (a ->next block) has no buffer.\n", newBlock));
- UT_ASSERT(0);
- }
-
- // good to go with a full buffer for our new block
- }
- else // we have some left to go in this buffer
- {
- // buffer is still valid, just copy pointers
- newBlock = *block;
- newOffset = *offset;
- }
-
- // are we going to run into the start position in this buffer?
- // if so, we need to size our length accordingly
- if (m_wrappedEnd && _BlockOffsetToPos(newBlock, newOffset) + buffer.getLength() >= m_startPosition)
- {
- bufferLength = (m_startPosition - (newBlock)->getPosition(UT_FALSE)) - newOffset;
- }
- else
- {
- bufferLength = buffer.getLength() - newOffset;
- }
-
- // clone a buffer (this could get really slow on large buffers!)
- UT_UCSChar * bufferSegment = NULL;
-
- // remember, the caller gets to free this memory
- bufferSegment = (UT_UCSChar *) calloc(bufferLength + 1,
- sizeof(UT_UCSChar));
- UT_ASSERT(bufferSegment);
-
- memmove(bufferSegment, buffer.getPointer(newOffset),
- (bufferLength) * sizeof(UT_UCSChar));
-
- // before we bail, hold up our block stuff for next round
- *block = newBlock;
- *offset = newOffset;
-
- return bufferSegment;
-}
-
-UT_Bool FV_View::findSetNextString(UT_UCSChar * string, UT_Bool matchCase)
-{
- UT_ASSERT(string);
-
- // update case matching
- _m_matchCase = matchCase;
-
- // update string
- FREEP(_m_findNextString);
- return UT_UCS_cloneString(&_m_findNextString, string);
-}
-
-UT_Bool FV_View::findAgain()
-{
- if (_m_findNextString && *_m_findNextString)
- {
- UT_Bool bRes = findNext(_m_findNextString, _m_matchCase, NULL);
- if (bRes)
- {
- _drawSelection();
- }
-
- return bRes;
- }
-
- return UT_FALSE;
-}
-
-UT_Bool FV_View::findReplace(const UT_UCSChar * find, const UT_UCSChar * replace,
- UT_Bool matchCase, UT_Bool * bDoneEntireDocument)
-{
- UT_ASSERT(find && replace);
-
- UT_Bool bRes = _findReplace(find, replace, matchCase, bDoneEntireDocument);
-
- updateScreen();
-
- if (isSelectionEmpty())
- {
- if (!_ensureThatInsertionPointIsOnScreen())
- {
- _fixInsertionPointCoords();
- _drawInsertionPoint();
- }
- }
- else
- {
- _ensureThatInsertionPointIsOnScreen();
- }
-
- return bRes;
-}
-
-UT_Bool FV_View::_findReplace(const UT_UCSChar * find, const UT_UCSChar * replace,
- UT_Bool matchCase, UT_Bool * bDoneEntireDocument)
-{
- UT_ASSERT(find && replace);
-
- // if we have done a find, and there is a selection, then replace what's in the
- // selection and move on to next find (batch run, the common case)
- if ((m_doneFind == UT_TRUE) && (!isSelectionEmpty()))
- {
- UT_Bool result = UT_TRUE;
-
- if (!isSelectionEmpty())
- {
- _deleteSelection();
- }
- else
- {
- _eraseInsertionPoint();
- }
-
- // if we have a string with length, do an insert, else let it hang
- // from the delete above
- if (*replace)
- result = m_pDoc->insertSpan(getPoint(), replace, UT_UCS_strlen(replace));
-
- // if we've wrapped around once, and we're doing work before we've
- // hit the point at which we started, then we adjust the start
- // position so that we stop at the right spot.
- if (m_wrappedEnd && !*bDoneEntireDocument)
- m_startPosition += ((long) UT_UCS_strlen(replace) - (long) UT_UCS_strlen(find));
-
- UT_ASSERT(m_startPosition >= 2);
-
- // do not increase the insertion point index, since the insert span will
- // leave us at the correct place.
-
- _findNext(find, matchCase, bDoneEntireDocument);
- return result;
- }
-
- // if we have done a find, but there is no selection, do a find for them
- // but no replace
- if (m_doneFind == UT_TRUE && isSelectionEmpty() == UT_TRUE)
- {
- _findNext(find, matchCase, bDoneEntireDocument);
- return UT_FALSE;
- }
-
- // if we haven't done a find yet, do a find for them
- if (m_doneFind == UT_FALSE)
- {
- _findNext(find, matchCase, bDoneEntireDocument);
- return UT_FALSE;
- }
-
- UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
- return UT_FALSE;
-}
-
-/*
- After most editing commands, it is necessary to call this method,
- _generalUpdate, in order to fix everything.
-*/
-void FV_View::_generalUpdate(void)
-{
- m_pDoc->signalListeners(PD_SIGNAL_UPDATE_LAYOUT);
-
- /*
- TODO note that we are far too heavy handed with the mask we
- send here. I ripped out all the individual calls to notifyListeners
- which appeared within fl_BlockLayout, and they all now go through
- here. For that reason, I made the following mask into the union
- of all the masks I found. I assume that this is inefficient, but
- functionally correct.
-
- TODO WRONG! WRONG! WRONG! notifyListener() must be called in
- TODO WRONG! WRONG! WRONG! fl_BlockLayout in response to a change
- TODO WRONG! WRONG! WRONG! notification and not here. this call
- TODO WRONG! WRONG! WRONG! will only update the current window.
- TODO WRONG! WRONG! WRONG! having the notification in fl_BlockLayout
- TODO WRONG! WRONG! WRONG! will get each view on the document.
- */
- notifyListeners(AV_CHG_TYPING | AV_CHG_FMTCHAR | AV_CHG_FMTBLOCK);
-}
-
-UT_uint32 FV_View::findReplaceAll(const UT_UCSChar * find, const UT_UCSChar * replace,
- UT_Bool matchCase)
-{
- UT_uint32 numReplaced = 0;
- m_pDoc->beginUserAtomicGlob();
-
- UT_Bool bDoneEntireDocument = UT_FALSE;
-
- // prime it with a find
- if (!_findNext(find, matchCase, &bDoneEntireDocument))
- {
- // can't find a single thing, we're done
- m_pDoc->endUserAtomicGlob();
- return numReplaced;
- }
-
- // while we've still got buffer
- while (bDoneEntireDocument == UT_FALSE)
- {
- // if it returns false, it found nothing more before
- // it hit the end of the document
- if (!_findReplace(find, replace, matchCase, &bDoneEntireDocument))
- {
- m_pDoc->endUserAtomicGlob();
- return numReplaced;
- }
- numReplaced++;
- }
-
- m_pDoc->endUserAtomicGlob();
-
- _generalUpdate();
-
- if (isSelectionEmpty())
- {
- if (!_ensureThatInsertionPointIsOnScreen())
- {
- _fixInsertionPointCoords();
- _drawInsertionPoint();
- }
- }
- else
- {
- _ensureThatInsertionPointIsOnScreen();
- }
-
- return numReplaced;
-}
-
-fl_BlockLayout * FV_View::_findGetCurrentBlock(void)
-{
- return m_pLayout->findBlockAtPosition(m_iInsPoint);
-}
-
-PT_DocPosition FV_View::_findGetCurrentOffset(void)
-{
- return (m_iInsPoint - _findGetCurrentBlock()->getPosition(UT_FALSE));
-}
-
-/*
- A simple strstr search of the buffer.
-*/
-UT_sint32 FV_View::_findBlockSearchDumbCase(const UT_UCSChar * haystack, const UT_UCSChar * needle)
-{
- UT_ASSERT(haystack);
- UT_ASSERT(needle);
-
- UT_UCSChar * at = UT_UCS_strstr(haystack, needle);
-
- return (at) ? (at - haystack) : -1;
-}
-
-/*
- Pierre Sarrazin <ps@cam.org> supplied the Unicode stricmp comparison function,
- which works for Latin-1 at the moment.
-*/
-
-UT_sint32 FV_View::_findBlockSearchDumbNoCase(const UT_UCSChar * haystack, const UT_UCSChar * needle)
-{
- UT_ASSERT(haystack);
- UT_ASSERT(needle);
-
- UT_UCSChar * at = UT_UCS_stristr(haystack, needle);
-
- return (at) ? (at - haystack) : -1;
-}
-
-
-/*
- Any takers?
-*/
-
-UT_sint32 FV_View::_findBlockSearchRegexp(const UT_UCSChar * /* haystack */, const UT_UCSChar * /* needle */)
-{
- UT_ASSERT(UT_NOT_IMPLEMENTED);
-
- return -1;
-}
-
-// ---------------- end find and replace ---------------
-
-void FV_View::_extSel(UT_uint32 iOldPoint)
-{
- /*
- We need to calculate the differences between the old
- selection and new one.
-
- Anything which was selected, and now is not, should
- be fixed on screen, back to normal.
-
- Anything which was NOT selected, and now is, should
- be fixed on screen, to show it in selected state.
-
- Anything which was selected, and is still selected,
- should NOT be touched.
-
- And, obviously, anything which was not selected, and
- is still not selected, should not be touched.
- */
-
- UT_uint32 iNewPoint = getPoint();
-
- if (iNewPoint == iOldPoint)
- {
- return;
- }
-
- if (iNewPoint < iOldPoint)
- {
- if (iNewPoint < m_iSelectionAnchor)
- {
- if (iOldPoint < m_iSelectionAnchor)
- {
- /*
- N O A
- The selection got bigger. Both points are
- left of the anchor.
- */
- _drawBetweenPositions(iNewPoint, iOldPoint);
- }
- else
- {
- /*
- N A O
- The selection flipped across the anchor to the left.
- */
- _clearBetweenPositions(m_iSelectionAnchor, iOldPoint, UT_TRUE);
- _drawBetweenPositions(iNewPoint, iOldPoint);
- }
- }
- else
- {
- UT_ASSERT(iOldPoint >= m_iSelectionAnchor);
-
- /*
- A N O
- The selection got smaller. Both points are to the
- right of the anchor
- */
-
- _clearBetweenPositions(iNewPoint, iOldPoint, UT_TRUE);
- _drawBetweenPositions(iNewPoint, iOldPoint);
- }
- }
- else
- {
- UT_ASSERT(iNewPoint > iOldPoint);
-
- if (iNewPoint < m_iSelectionAnchor)
- {
- UT_ASSERT(iOldPoint <= m_iSelectionAnchor);
-
- /*
- O N A
- The selection got smaller. Both points are
- left of the anchor.
- */
-
- _clearBetweenPositions(iOldPoint, iNewPoint, UT_TRUE);
- _drawBetweenPositions(iOldPoint, iNewPoint);
- }
- else
- {
- if (iOldPoint < m_iSelectionAnchor)
- {
- /*
- O A N
- The selection flipped across the anchor to the right.
- */
-
- _clearBetweenPositions(iOldPoint, m_iSelectionAnchor, UT_TRUE);
- _drawBetweenPositions(iOldPoint, iNewPoint);
- }
- else
- {
- /*
- A O N
- The selection got bigger. Both points are to the
- right of the anchor
- */
- _drawBetweenPositions(iOldPoint, iNewPoint);
- }
- }
- }
-}
-
-void FV_View::_extSelToPos(PT_DocPosition iNewPoint)
-{
- PT_DocPosition iOldPoint = getPoint();
- if (iNewPoint == iOldPoint)
- return;
-
- if (isSelectionEmpty())
- {
- _eraseInsertionPoint();
- _clearIfAtFmtMark(getPoint());
- _setSelectionAnchor();
- }
-
- _setPoint(iNewPoint);
- _extSel(iOldPoint);
-
- if (isSelectionEmpty())
- {
- _resetSelection();
- _drawInsertionPoint();
- }
-
- notifyListeners(AV_CHG_MOTION);
-}
-
-void FV_View::warpInsPtToXY(UT_sint32 xPos, UT_sint32 yPos)
-{
- /*
- Figure out which page we clicked on.
- Pass the click down to that page.
- */
- UT_sint32 xClick, yClick;
- fp_Page* pPage = _getPageForXY(xPos, yPos, xClick, yClick);
-
- if (!isSelectionEmpty())
- _clearSelection();
- else
- _eraseInsertionPoint();
-
- PT_DocPosition pos;
- UT_Bool bBOL, bEOL;
-
- pPage->mapXYToPosition(xClick, yClick, pos, bBOL, bEOL);
-
- if (pos != getPoint())
- _clearIfAtFmtMark(getPoint());
-
- _setPoint(pos, bEOL);
- _fixInsertionPointCoords();
- _drawInsertionPoint();
-
- notifyListeners(AV_CHG_MOTION);
-}
-
-void FV_View::getPageScreenOffsets(fp_Page* pThePage, UT_sint32& xoff,
- UT_sint32& yoff)
-{
- UT_uint32 y = fl_PAGEVIEW_MARGIN_Y;
-
- fp_Page* pPage = m_pLayout->getFirstPage();
- while (pPage)
- {
- if (pPage == pThePage)
- {
- break;
- }
- y += pPage->getHeight() + fl_PAGEVIEW_PAGE_SEP;
-
- pPage = pPage->getNext();
- }
-
- yoff = y - m_yScrollOffset;
- xoff = fl_PAGEVIEW_MARGIN_Y - m_xScrollOffset;
-}
-
-void FV_View::getPageYOffset(fp_Page* pThePage, UT_sint32& yoff)
-{
- UT_uint32 y = fl_PAGEVIEW_MARGIN_Y;
-
- fp_Page* pPage = m_pLayout->getFirstPage();
- while (pPage)
- {
- if (pPage == pThePage)
- {
- break;
- }
- y += pPage->getHeight() + fl_PAGEVIEW_PAGE_SEP;
-
- pPage = pPage->getNext();
- }
-
- yoff = y;
-}
-
-UT_uint32 FV_View::getPageViewLeftMargin(void) const
-{
- // return the amount of gray-space we draw to the left
- // of the paper in "Page View". return zero if not in
- // "Page View".
-
- return fl_PAGEVIEW_MARGIN_X;
-}
-
-UT_uint32 FV_View::getPageViewTopMargin(void) const
-{
- // return the amount of gray-space we draw above the top
- // of the paper in "Page View". return zero if not in
- // "Page View".
-
- return fl_PAGEVIEW_MARGIN_Y;
-}
-
-/*
- This method simply iterates over every run between two doc positions
- and draws each one.
-*/
-void FV_View::_drawBetweenPositions(PT_DocPosition iPos1, PT_DocPosition iPos2)
-{
- UT_ASSERT(iPos1 < iPos2);
-
- fp_Run* pRun1;
- fp_Run* pRun2;
- UT_sint32 xoff;
- UT_sint32 yoff;
- UT_uint32 uheight;
-
- {
- UT_sint32 x;
- UT_sint32 y;
- fl_BlockLayout* pBlock1;
- fl_BlockLayout* pBlock2;
-
- /*
- we don't really care about the coords. We're calling these
- to get the Run pointer
- */
- _findPositionCoords(iPos1, UT_FALSE, x, y, uheight, &pBlock1, &pRun1);
- _findPositionCoords(iPos2, UT_FALSE, x, y, uheight, &pBlock2, &pRun2);
- }
-
- UT_Bool bDone = UT_FALSE;
- fp_Run* pCurRun = pRun1;
-
- while (!bDone)
- {
- if (pCurRun == pRun2)
- {
- bDone = UT_TRUE;
- }
-
- fl_BlockLayout* pBlock = pCurRun->getBlock();
- UT_ASSERT(pBlock);
-
- fp_Line* pLine = pCurRun->getLine();
-
- pLine->getScreenOffsets(pCurRun, xoff, yoff);
-
- dg_DrawArgs da;
-
- da.pG = m_pG;
- da.xoff = xoff;
- da.yoff = yoff + pLine->getAscent();
-
- pCurRun->draw(&da);
-
- pCurRun = pCurRun->getNext();
- if (!pCurRun)
- {
- fl_BlockLayout* pNextBlock;
-
- pNextBlock = pBlock->getNextBlockInDocument();
- if (pNextBlock)
- {
- pCurRun = pNextBlock->getFirstRun();
- }
- }
- }
-}
-
-/*
- This method simply iterates over every run between two doc positions
- and draws each one.
-*/
-void FV_View::_clearBetweenPositions(PT_DocPosition iPos1, PT_DocPosition iPos2, UT_Bool bFullLineHeightRect)
-{
- if (iPos1 >= iPos2)
- {
- return;
- }
-
- fp_Run* pRun1;
- fp_Run* pRun2;
- UT_uint32 uheight;
-
- {
- UT_sint32 x;
- UT_sint32 y;
- fl_BlockLayout* pBlock1;
- fl_BlockLayout* pBlock2;
-
- /*
- we don't really care about the coords. We're calling these
- to get the Run pointer
- */
- _findPositionCoords(iPos1, UT_FALSE, x, y, uheight, &pBlock1, &pRun1);
- _findPositionCoords(iPos2, UT_FALSE, x, y, uheight, &pBlock2, &pRun2);
- }
-
- if (!pRun1 && !pRun2)
- {
- // no formatting info for either block, so just bail
- // this can happen during spell, when we're trying to invalidate
- // a new squiggle before the block has been formatted
- return;
- }
-
- UT_ASSERT(pRun1 && pRun2);
-
- UT_Bool bDone = UT_FALSE;
- fp_Run* pCurRun = pRun1;
+ da->pG = m_pG;
+ fp_Page* pPage = m_pLayout->getNthPage(page);
+ if (pPage)
+ {
+ pPage->draw(da);
+ }
+ }


- while (!bDone)
- {
- if (pCurRun == pRun2)
- {
- bDone = UT_TRUE;
- }
-
- pCurRun->clearScreen(bFullLineHeightRect);
-
- if (pCurRun->getNext())
- {
- pCurRun = pCurRun->getNext();
- }
- else
- {
- fl_BlockLayout* pNextBlock;
-
- fl_BlockLayout* pBlock = pCurRun->getBlock();
- UT_ASSERT(pBlock);
-
- pNextBlock = pBlock->getNextBlockInDocument();
- if (pNextBlock)
- {
- pCurRun = pNextBlock->getFirstRun();
- }
- }
- }
-}
-
-void FV_View::_findPositionCoords(PT_DocPosition pos,
- UT_Bool bEOL,
- UT_sint32& x,
- UT_sint32& y,
- UT_uint32& height,
- fl_BlockLayout** ppBlock,
- fp_Run** ppRun)
-{
- UT_sint32 xPoint;
- UT_sint32 yPoint;
- UT_sint32 iPointHeight;
-
- fl_BlockLayout* pBlock = _findBlockAtPosition(pos);
- UT_ASSERT(pBlock);
- fp_Run* pRun = pBlock->findPointCoords(pos, bEOL, xPoint, yPoint, iPointHeight);
-
- // NOTE prior call will fail if the block isn't currently formatted,
- // NOTE so we won't be able to figure out more specific geometry
-
- if (pRun)
- {
- // we now have coords relative to the page containing the ins pt
- fp_Page* pPointPage = pRun->getLine()->getContainer()->getPage();
-
- UT_sint32 iPageOffset;
- getPageYOffset(pPointPage, iPageOffset);
- yPoint += iPageOffset;
- xPoint += fl_PAGEVIEW_MARGIN_X;
-
- // now, we have coords absolute, as if all pages were stacked vertically
- xPoint -= m_xScrollOffset;
- yPoint -= m_yScrollOffset;
-
- // now, return the results
- x = xPoint;
- y = yPoint;
- height = iPointHeight;
- }
-
- if (ppBlock)
- {
- *ppBlock = pBlock;
- }
-
- if (ppRun)
- {
- *ppRun = pRun;
- }
-}
-
-void FV_View::_fixInsertionPointCoords()
-{
- _findPositionCoords(getPoint(), m_bPointEOL, m_xPoint, m_yPoint, m_iPointHeight, NULL, NULL);
-
- // hang onto this for _moveInsPtNextPrevLine()
- m_xPointSticky = m_xPoint + m_xScrollOffset - fl_PAGEVIEW_MARGIN_X;
-}
-
-void FV_View::_updateInsertionPoint()
-{
- if (isSelectionEmpty())
- {
- _eraseInsertionPoint();
-
- if (!_ensureThatInsertionPointIsOnScreen())
- {
- _fixInsertionPointCoords();
- _drawInsertionPoint();
- }
- }
-}
+ void FV_View::draw(const UT_Rect* pClipRect)
+ {
+ if (pClipRect)
+ {
+ _draw(pClipRect->left,pClipRect->top,pClipRect->width,pClipRect->height,UT_FALSE,UT_TRUE);
+ }
+ else
+ {
+ _draw(0,0,m_iWindowWidth,m_iWindowHeight,UT_FALSE,UT_FALSE);
+ }
+ }

-void FV_View::_xorInsertionPoint()
-{
- if (m_iPointHeight > 0)
- {
- UT_RGBColor clr(255,255,255);
+ void FV_View::updateScreen(void)
+ {
+ _draw(0,0,m_iWindowWidth,m_iWindowHeight,UT_TRUE,UT_FALSE);
+ }

- m_pG->setColor(clr);
- m_pG->xorLine(m_xPoint, m_yPoint, m_xPoint, m_yPoint + m_iPointHeight);
- }
+void FV_View::_draw(UT_sint32 x, UT_sint32 y,
+ UT_sint32 width, UT_sint32 height,
+ UT_Bool bDirtyRunsOnly, UT_Bool bClip)
+{
+ switch (m_ViewType)
+ {
+ case FV_VIEWTYPE_PGLAYOUT:
+ _draw_pglayout (x, y, width, height, bDirtyRunsOnly, bClip);
+ break;
+ case FV_VIEWTYPE_NORMAL:
+ _draw_normal (x, y, width, height, bDirtyRunsOnly, bClip);
+ break;
+ case FV_VIEWTYPE_OUTLINE:
+ _draw_outline (x, y, width, height, bDirtyRunsOnly, bClip);
+ break;
+ default:
+ UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
+ }
}

-void FV_View::_eraseInsertionPoint()
+void FV_View::_draw_pglayout(UT_sint32 x, UT_sint32 y,
+ UT_sint32 width, UT_sint32 height,
+ UT_Bool bDirtyRunsOnly, UT_Bool bClip)
{
- if (!isSelectionEmpty())
+ xxx_UT_DEBUGMSG(("FV_View::draw_3 [x %ld][y %ld][w %ld][h %ld][bClip %ld]\n"
+ "\t\twith [yScrollOffset %ld][windowHeight %ld]\n",
+ x,y,width,height,bClip,
+ m_yScrollOffset,m_iWindowHeight));
+
+ // this can happen when the frame size is decreased and
+ // only the toolbars show...
+ if ((m_iWindowWidth <= 0) || (m_iWindowHeight <= 0))
{
+ UT_DEBUGMSG(("fv_View::draw() called with zero drawing area.\n"));
return;
}

- _xorInsertionPoint();
-}
-
-void FV_View::_drawInsertionPoint()
-{
- if (m_iWindowHeight <= 0)
+ if ((width <= 0) || (height <= 0))
{
+ UT_DEBUGMSG(("fv_View::draw() called with zero width or height expose.\n"));
return;
}
-
- if (!isSelectionEmpty())
+
+ if (bClip)
{
- return;
+ UT_Rect r;
+
+ r.left = x;
+ r.top = y;
+ r.width = width;
+ r.height = height;
+
+ m_pG->setClipRect(&r);
}

- _xorInsertionPoint();
-}
+ // figure out where pages go, based on current window dimensions
+ // TODO: don't calc for every draw
+ // HYP: cache calc results at scroll/size time
+ UT_sint32 iDocHeight = m_pLayout->getHeight();

-void FV_View::setXScrollOffset(UT_sint32 v)
-{
- UT_sint32 dx = v - m_xScrollOffset;
+ // TODO: handle positioning within oversized viewport
+ // TODO: handle variable-size pages (envelope, landscape, etc.)

- if (dx == 0)
- return;
-
- m_pG->scroll(dx, 0);
- m_xScrollOffset = v;
-
- if (dx > 0)
- {
- if (dx >= m_iWindowWidth)
- {
- _draw(0, 0, m_iWindowWidth, m_iWindowHeight, UT_FALSE, UT_TRUE);
- }
- else
- {
- _draw(m_iWindowWidth - dx, 0, m_iWindowWidth, m_iWindowHeight, UT_FALSE, UT_TRUE);
- }
- }
- else
- {
- if (dx <= -m_iWindowWidth)
+ /*
+ In page view mode, so draw outside decorations first, then each
+ page with its decorations.
+ */
+
+ UT_RGBColor clrMargin(127,127,127); // dark gray
+
+ if (!bDirtyRunsOnly)
+ {
+ if (m_xScrollOffset < fl_PAGEVIEW_MARGIN_X)
{
- _draw(0, 0, m_iWindowWidth, m_iWindowHeight, UT_FALSE, UT_TRUE);
+ // fill left margin
+ m_pG->fillRect(clrMargin, 0, 0, fl_PAGEVIEW_MARGIN_X - m_xScrollOffset, m_iWindowHeight);
}
- else
+
+ if (m_yScrollOffset < fl_PAGEVIEW_MARGIN_Y)
{
- _draw(0, 0, -dx, m_iWindowHeight, UT_FALSE, UT_TRUE);
+ // fill top margin
+ m_pG->fillRect(clrMargin, 0, 0, m_iWindowWidth, fl_PAGEVIEW_MARGIN_Y - m_yScrollOffset);
}
- }
-}
+ }

-void FV_View::setYScrollOffset(UT_sint32 v)
-{
- UT_sint32 dy = v - m_yScrollOffset;
+ UT_sint32 curY = fl_PAGEVIEW_MARGIN_Y;
+ fp_Page* pPage = m_pLayout->getFirstPage();
+ while (pPage)
+ {
+ UT_sint32 iPageWidth = pPage->getWidth();
+ UT_sint32 iPageHeight = pPage->getHeight();
+ UT_sint32 adjustedTop = curY - m_yScrollOffset;
+ UT_sint32 adjustedBottom = adjustedTop + iPageHeight + fl_PAGEVIEW_PAGE_SEP;
+ if (adjustedTop > m_iWindowHeight)
+ {
+ // the start of this page is past the bottom
+ // of the window, so we don't need to draw it.

- if (dy == 0)
- return;
-
- m_pG->scroll(0, dy);
- m_yScrollOffset = v;
+ xxx_UT_DEBUGMSG(("not drawing page A: iPageHeight=%d curY=%d nPos=%d m_iWindowHeight=%d\n",
+ iPageHeight,
+ curY,
+ m_yScrollOffset,
+ m_iWindowHeight));

- if (dy > 0)
- {
- if (dy >= m_iWindowHeight)
+ // since all other pages are below this one, we
+ // don't need to draw them either. exit loop now.
+ break;
+ }
+ else if (adjustedBottom < 0)
{
- _draw(0, 0, m_iWindowWidth, m_iWindowHeight, UT_FALSE, UT_TRUE);
+ // the end of this page is above the top of
+ // the window, so we don't need to draw it.
+
+ xxx_UT_DEBUGMSG(("not drawing page B: iPageHeight=%d curY=%d nPos=%d m_iWindowHeight=%d\n",
+ iPageHeight,
+ curY,
+ m_yScrollOffset,
+ m_iWindowHeight));
}
- else
+ else if (adjustedTop > y + height)
{
- _draw(0, m_iWindowHeight - dy, m_iWindowWidth, dy, UT_FALSE, UT_TRUE);
+ // the top of this page is beyond the end
+ // of the clipping region, so we don't need
+ // to draw it.
+
+ xxx_UT_DEBUGMSG(("not drawing page C: iPageHeight=%d curY=%d nPos=%d m_iWindowHeight=%d y=%d h=%d\n",
+ iPageHeight,
+ curY,
+ m_yScrollOffset,
+ m_iWindowHeight,
+ y,height));
}
- }
- else
- {
- if (dy <= -m_iWindowHeight)
+ else if (adjustedBottom < y)
{
- _draw(0, 0, m_iWindowWidth, m_iWindowHeight, UT_FALSE, UT_TRUE);
+ // the bottom of this page is above the top
+ // of the clipping region, so we don't need
+ // to draw it.
+
+ xxx_UT_DEBUGMSG(("not drawing page D: iPageHeight=%d curY=%d nPos=%d m_iWindowHeight=%d y=%d h=%d\n",
+ iPageHeight,
+ curY,
+ m_yScrollOffset,
+ m_iWindowHeight,
+ y,height));
}
else
{
- _draw(0, 0, m_iWindowWidth, -dy, UT_FALSE, UT_TRUE);
+ // this page is on screen and intersects the clipping region,
+ // so we *DO* draw it.
+
+ xxx_UT_DEBUGMSG(("drawing page E: iPageHeight=%d curY=%d nPos=%d m_iWindowHeight=%d y=%d h=%d\n",
+ iPageHeight,curY,m_yScrollOffset,m_iWindowHeight,y,height));
+
+ dg_DrawArgs da;
+
+ da.bDirtyRunsOnly = bDirtyRunsOnly;
+ da.pG = m_pG;
+ da.xoff = fl_PAGEVIEW_MARGIN_X - m_xScrollOffset;
+ da.yoff = adjustedTop;
+
+ UT_sint32 adjustedLeft = fl_PAGEVIEW_MARGIN_X - m_xScrollOffset;
+ UT_sint32 adjustedRight = adjustedLeft + iPageWidth;
+
+ adjustedBottom -= fl_PAGEVIEW_PAGE_SEP;
+
+ if (!bDirtyRunsOnly || pPage->needsRedraw())
+ {
+ UT_RGBColor clrPaper(255,255,255);
+ m_pG->fillRect(clrPaper,adjustedLeft+1,adjustedTop+1,iPageWidth-1,iPageHeight-1);
+ }
+
+ pPage->draw(&da);
+
+ // draw page decorations
+ UT_RGBColor clr(0,0,0); // black
+ m_pG->setColor(clr);
+
+ // one pixel border
+ m_pG->drawLine(adjustedLeft, adjustedTop, adjustedRight, adjustedTop);
+ m_pG->drawLine(adjustedRight, adjustedTop, adjustedRight, adjustedBottom);
+ m_pG->drawLine(adjustedRight, adjustedBottom, adjustedLeft, adjustedBottom);
+ m_pG->drawLine(adjustedLeft, adjustedBottom, adjustedLeft, adjustedTop);
+
+ // fill to right of page
+ m_pG->fillRect(clrMargin, adjustedRight + 1, adjustedTop, m_iWindowWidth - (adjustedRight + 1), iPageHeight + 1);
+
+ // fill separator below page
+ m_pG->fillRect(clrMargin, adjustedLeft, adjustedBottom + 1, m_iWindowWidth - adjustedLeft, fl_PAGEVIEW_PAGE_SEP);
+
+ // two pixel drop shadow
+ adjustedLeft += 3;
+ adjustedBottom += 1;
+ m_pG->drawLine(adjustedLeft, adjustedBottom, adjustedRight+1, adjustedBottom);
+ adjustedBottom += 1;
+ m_pG->drawLine(adjustedLeft, adjustedBottom, adjustedRight+1, adjustedBottom);
+
+ adjustedTop += 3;
+ adjustedRight += 1;
+ m_pG->drawLine(adjustedRight, adjustedTop, adjustedRight, adjustedBottom+1);
+ adjustedRight += 1;
+ m_pG->drawLine(adjustedRight, adjustedTop, adjustedRight, adjustedBottom+1);
}
- }
-}

-void FV_View::draw(int page, dg_DrawArgs* da)
-{
- xxx_UT_DEBUGMSG(("FV_View::draw_1: [page %ld]\n",page));
+ curY += iPageHeight + fl_PAGEVIEW_PAGE_SEP;
+
+ pPage = pPage->getNext();
+ }

- da->pG = m_pG;
- fp_Page* pPage = m_pLayout->getNthPage(page);
- if (pPage)
+ if (curY < iDocHeight)
{
- pPage->draw(da);
+ // fill below bottom of document
+ UT_sint32 y = curY - m_yScrollOffset + 1;
+ UT_sint32 h = m_iWindowHeight - y;
+
+ m_pG->fillRect(clrMargin, 0, y, m_iWindowWidth, h);
}
-}

+ if (!bDirtyRunsOnly)
+ {
+ _fixInsertionPointCoords();
+ _drawInsertionPoint();
+ }

-void FV_View::draw(const UT_Rect* pClipRect)
-{
- if (pClipRect)
+ if (bClip)
{
- _draw(pClipRect->left,pClipRect->top,pClipRect->width,pClipRect->height,UT_FALSE,UT_TRUE);
+ m_pG->setClipRect(NULL);
}
- else
+
+#if 0
{
- _draw(0,0,m_iWindowWidth,m_iWindowHeight,UT_FALSE,UT_FALSE);
+ // Some test code for the graphics interface.
+ UT_RGBColor clrRed(255,0,0);
+ m_pG->setColor(clrRed);
+ m_pG->drawLine(10,10,20,10);
+ m_pG->drawLine(20,11,30,11);
+ m_pG->fillRect(clrRed,50,10,10,10);
+ m_pG->fillRect(clrRed,60,20,10,10);
}
-}
+#endif

-void FV_View::updateScreen(void)
-{
- _draw(0,0,m_iWindowWidth,m_iWindowHeight,UT_TRUE,UT_FALSE);
}

-void FV_View::_draw(UT_sint32 x, UT_sint32 y,
- UT_sint32 width, UT_sint32 height,
- UT_Bool bDirtyRunsOnly, UT_Bool bClip)
+
+void FV_View::_draw_normal(UT_sint32 x, UT_sint32 y,
+ UT_sint32 width, UT_sint32 height,
+ UT_Bool bDirtyRunsOnly, UT_Bool bClip)
{
- xxx_UT_DEBUGMSG(("FV_View::draw_3 [x %ld][y %ld][w %ld][h %ld][bClip %ld]\n"
+ xxx_UT_DEBUGMSG(("FV_View::draw_3 [x %ld][y %ld][w %ld][h %ld][bClip %ld]\n"
"\t\twith [yScrollOffset %ld][windowHeight %ld]\n",
x,y,width,height,bClip,
m_yScrollOffset,m_iWindowHeight));
@@ -3603,32 +3855,33 @@

adjustedBottom -= fl_PAGEVIEW_PAGE_SEP;

+ UT_RGBColor clrPaper(255,255,255);
+
if (!bDirtyRunsOnly || pPage->needsRedraw())
{
- UT_RGBColor clrPaper(255,255,255);
m_pG->fillRect(clrPaper,adjustedLeft+1,adjustedTop+1,iPageWidth-1,iPageHeight-1);
}

pPage->draw(&da);

// draw page decorations
- UT_RGBColor clr(0,0,0); // black
- m_pG->setColor(clr);
-
+ UT_RGBColor clr(0,0,0), clrLG(211,211,211); // black
+ m_pG->setColor(clrLG);
// one pixel border
m_pG->drawLine(adjustedLeft, adjustedTop, adjustedRight, adjustedTop);
m_pG->drawLine(adjustedRight, adjustedTop, adjustedRight, adjustedBottom);
- m_pG->drawLine(adjustedRight, adjustedBottom, adjustedLeft, adjustedBottom);
m_pG->drawLine(adjustedLeft, adjustedBottom, adjustedLeft, adjustedTop);
+ m_pG->drawLine(adjustedRight, adjustedBottom, adjustedLeft, adjustedBottom);
+ m_pG->setColor(clr);

// fill to right of page
- m_pG->fillRect(clrMargin, adjustedRight + 1, adjustedTop, m_iWindowWidth - (adjustedRight + 1), iPageHeight + 1);
+ m_pG->fillRect(clrPaper, adjustedRight + 1, adjustedTop, m_iWindowWidth - (adjustedRight + 1), iPageHeight + 1);

// fill separator below page
m_pG->fillRect(clrMargin, adjustedLeft, adjustedBottom + 1, m_iWindowWidth - adjustedLeft, fl_PAGEVIEW_PAGE_SEP);

// two pixel drop shadow
- adjustedLeft += 3;
+ /*adjustedLeft += 3;
adjustedBottom += 1;
m_pG->drawLine(adjustedLeft, adjustedBottom, adjustedRight+1, adjustedBottom);
adjustedBottom += 1;
@@ -3638,7 +3891,7 @@
adjustedRight += 1;
m_pG->drawLine(adjustedRight, adjustedTop, adjustedRight, adjustedBottom+1);
adjustedRight += 1;
- m_pG->drawLine(adjustedRight, adjustedTop, adjustedRight, adjustedBottom+1);
+ m_pG->drawLine(adjustedRight, adjustedTop, adjustedRight, adjustedBottom+1);*/
}

curY += iPageHeight + fl_PAGEVIEW_PAGE_SEP;
@@ -3680,6 +3933,15 @@

}

+
+void FV_View::_draw_outline(UT_sint32 x, UT_sint32 y,
+ UT_sint32 width, UT_sint32 height,
+ UT_Bool bDirtyRunsOnly, UT_Bool bClip)
+{
+ UT_ASSERT(UT_NOT_IMPLEMENTED);
+}
+
+
void FV_View::cmdScroll(AV_ScrollCmd cmd, UT_uint32 iPos)
{
#define HACK_LINE_HEIGHT 20 // TODO Fix this!!
@@ -4684,4 +4946,114 @@
{
m_pDoc->clearIfAtFmtMark(dpos);
_generalUpdate();
+}
+
+
+FVViewType FV_View::getViewType()
+{
+ return m_ViewType;
+}
+
+void FV_View::setViewType(FVViewType inViewType)
+{
+ UT_uint32 count, iNumPages = m_pLayout -> countPages();
+ fp_Page * iPage;
+
+ switch (inViewType)
+ {
+ case FV_VIEWTYPE_PGLAYOUT:
+ if (m_ViewType != inViewType || !m_ViewTypeChanged)
+ {
+ if (m_ViewTypeChanged && m_ViewType == FV_VIEWTYPE_NORMAL)
+ {
+ fl_DocSectionLayout * iCurrSection = m_pLayout -> getFirstSection();
+ UT_ASSERT (iCurrSection);
+
+ while (iCurrSection)
+ {
+ iCurrSection -> setTopMargin(100);
+ iCurrSection -> setBottomMargin(100);
+ iCurrSection -> setRightMargin(100);
+ iCurrSection -> setLeftMargin (100);
+ iCurrSection = iCurrSection -> getNextDocSection ();
+ }
+
+ for (count=0; count != iNumPages; ++count)
+ {
+ UT_sint32 iPageWidth, iPageHeight;
+ fp_Page * pPage;
+
+ pPage = m_pLayout -> getNthPage (count);
+ UT_ASSERT (pPage);
+
+ iPageWidth = pPage -> getWidth ();
+ iPageHeight = pPage -> getHeight ();
+
+ pPage -> setWidth (iPageWidth + (m_iRightMargin * 2) - NORMAL_VIEW_MARGIN_L);
+ pPage -> setHeight (iPageHeight + m_iTopMargin + m_iBottomMargin);
+
+ pPage -> reformat();
+ }
+ }
+ fl_PAGEVIEW_MARGIN_X = 25;
+ fl_PAGEVIEW_MARGIN_Y = 25;
+ fl_PAGEVIEW_PAGE_SEP = 20;
+ }
+ break;
+
+ case FV_VIEWTYPE_NORMAL:
+ if (m_ViewType != inViewType)
+ {
+ fl_DocSectionLayout * iCurrSection = m_pLayout -> getFirstSection();
+
+ fl_PAGEVIEW_MARGIN_X = 0;
+ fl_PAGEVIEW_MARGIN_Y = 0;
+ fl_PAGEVIEW_PAGE_SEP = 0;
+
+ UT_ASSERT (iCurrSection);
+
+ if (m_ViewType == FV_VIEWTYPE_PGLAYOUT)
+ {
+ m_iTopMargin = iCurrSection -> getTopMargin();
+ m_iBottomMargin = iCurrSection -> getBottomMargin();
+ m_iLeftMargin = iCurrSection -> getLeftMargin();
+ m_iRightMargin = iCurrSection -> getRightMargin();
+ }
+
+ while (iCurrSection)
+ {
+ iCurrSection -> setTopMargin(0);
+ iCurrSection -> setBottomMargin(0);
+ iCurrSection -> setRightMargin(0);
+ iCurrSection -> setLeftMargin (NORMAL_VIEW_MARGIN_L);
+ iCurrSection = iCurrSection -> getNextDocSection ();
+ }
+
+ for (count=0; count != iNumPages; ++count)
+ {
+ UT_sint32 iPageWidth, iPageHeight;
+ fp_Page * pPage;
+
+ pPage = m_pLayout -> getNthPage (count);
+ UT_ASSERT (pPage);
+
+ iPageWidth = pPage -> getWidth ();
+ iPageHeight = pPage -> getHeight ();
+
+ pPage -> setWidth (iPageWidth - (m_iRightMargin * 2) + NORMAL_VIEW_MARGIN_L);
+ pPage -> setHeight (iPageHeight - m_iTopMargin - m_iBottomMargin);
+
+ pPage -> reformat();
+ }
+ }
+ break;
+ case FV_VIEWTYPE_OUTLINE:
+ UT_ASSERT(UT_NOT_IMPLEMENTED);
+ break;
+ default:
+ UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
+ }
+ m_ViewType = inViewType;
+ draw(NULL);
+ m_ViewTypeChanged = UT_TRUE;
}
diff -ur abi.vanilla/src/text/fmt/xp/fv_View.h abi/src/text/fmt/xp/fv_View.h
--- abi.vanilla/src/text/fmt/xp/fv_View.h Fri Jul 2 09:10:36 1999
+++ abi/src/text/fmt/xp/fv_View.h Mon Jul 19 02:37:58 1999
@@ -47,6 +47,8 @@
class AP_LeftRulerInfo;


+#define NORMAL_VIEW_MARGIN_L 15
+
typedef enum _FVDocPos
{
FV_DOCPOS_BOB, FV_DOCPOS_EOB, // block
@@ -62,6 +64,13 @@
FV_JUMPTARGET_LINE // beginning of line
} FV_JumpTarget;

+typedef enum _FVViewType
+{
+ FV_VIEWTYPE_PGLAYOUT, // The default "page layout" view
+ FV_VIEWTYPE_NORMAL, // A "normal" less-WYSIWYG view that does not show margins or individual pages
+ FV_VIEWTYPE_OUTLINE // An outline view. Currently unimplemented.
+} FVViewType;
+
struct fv_ChangeState
{
UT_Bool bUndo;
@@ -119,6 +128,9 @@
UT_uint32 getCurrentPageNumForStatusBar(void) const;
fp_Page* getCurrentPage(void) const;

+ FVViewType getViewType();
+ void setViewType(FVViewType inViewType);
+
void draw(int page, dg_DrawArgs* da);

// TODO some of these functions should move into protected
@@ -127,7 +139,7 @@
void getPageYOffset(fp_Page* pPage, UT_sint32& yoff);
virtual UT_uint32 getPageViewLeftMargin(void) const;
virtual UT_uint32 getPageViewTopMargin(void) const;
-
+ virtual UT_uint32 getPageViewPageSep(void) const;
UT_Bool setSectionFormat(const XML_Char * properties[]);
UT_Bool getSectionFormat(const XML_Char *** properties);

@@ -206,9 +220,15 @@

protected:
void _generalUpdate(void);
-
+
+ // _draw() is now a function that just calls the appropriate view-specific one.
void _draw(UT_sint32, UT_sint32, UT_sint32, UT_sint32, UT_Bool bDirtyRunsOnly, UT_Bool bClip=UT_FALSE);
-
+
+ // The following three functions draw the view. The right one is called by _draw().
+ void _draw_pglayout(UT_sint32, UT_sint32, UT_sint32, UT_sint32, UT_Bool bDirtyRunsOnly, UT_Bool bClip=UT_FALSE);
+ void _draw_normal(UT_sint32, UT_sint32, UT_sint32, UT_sint32, UT_Bool bDirtyRunsOnly, UT_Bool bClip=UT_FALSE);
+ void _draw_outline(UT_sint32, UT_sint32, UT_sint32, UT_sint32, UT_Bool bDirtyRunsOnly, UT_Bool bClip=UT_FALSE);
+
void _drawBetweenPositions(PT_DocPosition left, PT_DocPosition right);
void _clearBetweenPositions(PT_DocPosition left, PT_DocPosition right, UT_Bool bFullLineHeightRect);

@@ -304,6 +324,15 @@
UT_sint32 _findBlockSearchDumbCase(const UT_UCSChar * haystack, const UT_UCSChar * needle);
UT_sint32 _findBlockSearchDumbNoCase(const UT_UCSChar * haystack, const UT_UCSChar * needle);
UT_sint32 _findBlockSearchRegexp(const UT_UCSChar * haystack, const UT_UCSChar * needle);
+
+ FVViewType m_ViewType;
+
+ UT_uint32 fl_PAGEVIEW_MARGIN_X, fl_PAGEVIEW_MARGIN_Y, fl_PAGEVIEW_PAGE_SEP;
+
+ UT_Bool m_ViewTypeChanged;
+
+ UT_sint32 m_iTopMargin, m_iBottomMargin, m_iLeftMargin, m_iRightMargin;
+
};

#endif /* FV_VIEW_H */
diff -ur abi.vanilla/src/wp/ap/xp/ap_EditMethods.cpp abi/src/wp/ap/xp/ap_EditMethods.cpp
--- abi.vanilla/src/wp/ap/xp/ap_EditMethods.cpp Mon Jul 12 09:22:31 1999
+++ abi/src/wp/ap/xp/ap_EditMethods.cpp Sun Jul 18 21:55:10 1999
@@ -14,7 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
+ * 02111-130, USA.
*/

#include <stdio.h>
@@ -204,6 +204,9 @@
static EV_EditMethod_Fn replace;
static EV_EditMethod_Fn dlgOptions;

+ static EV_EditMethod_Fn viewPageLayout;
+ static EV_EditMethod_Fn viewNormal;
+ static EV_EditMethod_Fn viewOutline;
static EV_EditMethod_Fn viewStd;
static EV_EditMethod_Fn viewFormat;
static EV_EditMethod_Fn viewRuler;
@@ -457,6 +460,10 @@
EV_EditMethod(NF(replace), 0, ""),
EV_EditMethod(NF(dlgOptions), 0, ""),

+ EV_EditMethod(NF(viewPageLayout), 0, ""),
+ EV_EditMethod(NF(viewNormal), 0, ""),
+ EV_EditMethod(NF(viewOutline), 0, ""),
+
EV_EditMethod(NF(viewStd), 0, ""),
EV_EditMethod(NF(viewFormat), 0, ""),
EV_EditMethod(NF(viewRuler), 0, ""),
@@ -3988,4 +3995,27 @@
{
//copy current line
return ( EX(warpInsPtBOL) && EX(extSelEOL) && EX(copy) );
+}
+
+Defun1(viewPageLayout)
+{
+ ABIWORD_VIEW;
+ pView->setViewType(FV_VIEWTYPE_PGLAYOUT);
+ return UT_TRUE;
+}
+
+Defun1(viewNormal)
+{
+ ABIWORD_VIEW;
+ pView->setViewType(FV_VIEWTYPE_NORMAL);
+ return UT_TRUE;
+}
+
+Defun1(viewOutline)
+{
+ XAP_Frame * pFrame = (XAP_Frame *) pAV_View->getParentData();
+ UT_ASSERT(pFrame);
+
+ s_TellNotImplemented(pFrame, "Outline view", __LINE__);
+ return UT_TRUE;
}
diff -ur abi.vanilla/src/wp/ap/xp/ap_Menu_ActionSet.cpp abi/src/wp/ap/xp/ap_Menu_ActionSet.cpp
--- abi.vanilla/src/wp/ap/xp/ap_Menu_ActionSet.cpp Sat May 22 11:43:50 1999
+++ abi/src/wp/ap/xp/ap_Menu_ActionSet.cpp Sun Jul 18 21:19:13 1999
@@ -100,6 +100,9 @@
_s(AP_MENU_ID_EDIT_OPTIONS, 0,1,0, "dlgOptions", NULL, NULL);

_s(AP_MENU_ID_VIEW, 1,0,0, NULL, NULL, NULL);
+ _s(AP_MENU_ID_VIEW_PGLAYOUT, 0,0,0, "viewPageLayout", NULL, NULL);
+ _s(AP_MENU_ID_VIEW_NORMAL, 0,0,0, "viewNormal", NULL, NULL);
+ _s(AP_MENU_ID_VIEW_OUTLINE, 0,0,0, "viewOutline", NULL, NULL);
_s(AP_MENU_ID_VIEW_TOOLBARS, 1,0,0, NULL, NULL, NULL);
_s(AP_MENU_ID_VIEW_TB_STD, 0,0,1, "viewStd", ap_GetState_Bars, NULL);
_s(AP_MENU_ID_VIEW_TB_FORMAT, 0,0,1, "viewFormat", ap_GetState_Bars, NULL);
diff -ur abi.vanilla/src/wp/ap/xp/ap_Menu_Id.h abi/src/wp/ap/xp/ap_Menu_Id.h
--- abi.vanilla/src/wp/ap/xp/ap_Menu_Id.h Sat May 22 11:43:50 1999
+++ abi/src/wp/ap/xp/ap_Menu_Id.h Sun Jul 18 18:09:09 1999
@@ -70,6 +70,9 @@
AP_MENU_ID_EDIT_OPTIONS,

AP_MENU_ID_VIEW,
+ AP_MENU_ID_VIEW_PGLAYOUT,
+ AP_MENU_ID_VIEW_NORMAL,
+ AP_MENU_ID_VIEW_OUTLINE,
AP_MENU_ID_VIEW_TOOLBARS,
AP_MENU_ID_VIEW_TB_STD,
AP_MENU_ID_VIEW_TB_FORMAT,
diff -ur abi.vanilla/src/wp/ap/xp/ap_Menu_LabelSet_EnUS.h abi/src/wp/ap/xp/ap_Menu_LabelSet_EnUS.h
--- abi.vanilla/src/wp/ap/xp/ap_Menu_LabelSet_EnUS.h Sat May 22 11:43:50 1999
+++ abi/src/wp/ap/xp/ap_Menu_LabelSet_EnUS.h Sun Jul 18 21:39:47 1999
@@ -68,6 +68,9 @@
MenuLabel(AP_MENU_ID_EDIT_OPTIONS, "&Options", "Set options")

MenuLabel(AP_MENU_ID_VIEW, "&View", NULL)
+ MenuLabel(AP_MENU_ID_VIEW_PGLAYOUT, "&Page Layout", "Switch to the Page Layout view mode.")
+ MenuLabel(AP_MENU_ID_VIEW_NORMAL, "&Normal", "Switch to the Normal view mode.")
+ MenuLabel(AP_MENU_ID_VIEW_OUTLINE, "&Outline", "Switch to the Outline view mode.")
MenuLabel(AP_MENU_ID_VIEW_TOOLBARS, "&Toolbars", NULL)
MenuLabel(AP_MENU_ID_VIEW_TB_STD, "&Standard", "Show or hide the standard toolbar")
MenuLabel(AP_MENU_ID_VIEW_TB_FORMAT, "&Formatting", "Show or hide the formatting toolbar")
diff -ur abi.vanilla/src/wp/ap/xp/ap_Menu_Layouts_MainMenu.h abi/src/wp/ap/xp/ap_Menu_Layouts_MainMenu.h
--- abi.vanilla/src/wp/ap/xp/ap_Menu_Layouts_MainMenu.h Sat May 22 11:43:50 1999
+++ abi/src/wp/ap/xp/ap_Menu_Layouts_MainMenu.h Sun Jul 18 18:11:04 1999
@@ -68,6 +68,10 @@
EndSubMenu()

BeginSubMenu(AP_MENU_ID_VIEW)
+ MenuItem(AP_MENU_ID_VIEW_PGLAYOUT)
+ MenuItem(AP_MENU_ID_VIEW_NORMAL)
+ MenuItem(AP_MENU_ID_VIEW_OUTLINE)
+ Separator()
BeginSubMenu(AP_MENU_ID_VIEW_TOOLBARS)
MenuItem(AP_MENU_ID_VIEW_TB_STD)
MenuItem(AP_MENU_ID_VIEW_TB_FORMAT)



This archive was generated by hypermail 1.03b2.