VIEW.C
资源名称:MSDN_VC98.zip [点击查看]
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:44k
源码类别:
Windows编程
开发平台:
Visual C++
- /******************************************************************************
- * This is a part of the Microsoft Source Code Samples.
- * Copyright (C) 1993-1997 Microsoft Corporation.
- * All rights reserved.
- * This source code is only intended as a supplement to
- * Microsoft Development Tools and/or WinHelp documentation.
- * See these sources for detailed information regarding the
- * Microsoft samples programs.
- ******************************************************************************/
- /****************************** Module Header *******************************
- * Module Name: VIEW.C
- *
- * Maps rows in window to items in COMPLIST
- *
- * Functions:
- *
- * view_new()
- * view_setcomplist()
- * view_getcomplist()
- * view_close()
- * view_delete()
- * view_outline()
- * view_expand()
- * view_gettext()
- * view_getlinenr_left()
- * view_getlinenr_right()
- * view_getwidth()
- * view_getrowcount()
- * view_getstate()
- * view_getitem()
- * view_isexpanded()
- * view_getcurrenttag()
- * view_newitem()
- * view_changeviewoptions()
- * view_changediffoptions()
- * view_findchange()
- * view_outline_opt()
- * view_freemappings()
- * view_findrow()
- * view_expand_item()
- *
- * Comments:
- *
- * A view owns a COMPLIST, and talks to a table window. The table window
- * shows 3 columns: line nr, tag and text. We also need to supply a state
- * for each row (used to select colour scheme).
- *
- * The COMPLIST can give us a list of its COMPITEMs. Each of these can give
- * us a tag (eg the filenames compared) and the text (usually the compare
- * result), and the state. We make the line number from the
- * COMPITEM's place in the list.
- *
- * If we are asked to switch to 'expand' mode, we ask the selected COMPITEM
- * for its composite section list. We can then get the state (and thus
- * the tag) from each SECTION, and the line nr and text from the LINEs within
- * each section.
- *
- * When moving between expand and outline, and when refreshing the view
- * for some option change, we have to be careful to keep the current row
- * and the selected row in the table what the user would expect.
- *
- * Functions in this module can be called from the UI thread (to refresh
- * the display) and simultaneously from a worker thread to update the
- * view mapping (view_setcomplist, view_newitem). We use a critical section
- * to manage the synchronisation. We need to protect all access/modification
- * to the view structure elements (particularly bExpand, rows, pLines and
- * pItems), BUT we must not hold the critical section over any calls
- * to SendMessage.
- *
- * We use the global options in windiff.h, and we allocate memory from the
- * heap hHeap which has been initialised elsewhere. Points in time-intensive
- * loops call Poll() defined elsewhere.
- *
- ****************************************************************************/
- #include <windows.h>
- #include <stdlib.h>
- #include <commdlg.h>
- #include "gutils.h"
- #include "table.h"
- #include "state.h"
- #include "windiff.h"
- #include "wdiffrc.h"
- #include "list.h"
- #include "line.h"
- #include "scandir.h"
- #include "file.h"
- #include "section.h"
- #include "compitem.h"
- #include "complist.h"
- #include "view.h"
- /*
- * data structures
- */
- /* in expand mode, we keep an array of one of these per screen line. */
- typedef struct viewline {
- LINE line; /* handle to LINE for this row */
- SECTION section; /* handle to section containing this line */
- int nr_left; /* line nr in left file */
- int nr_right; /* line nr in right file */
- } VIEWLINE, FAR * PVIEWLINE;
- /*
- * The users VIEW handle is in fact a pointer to this structure
- */
- struct view {
- HWND hwnd; /* the table window to send notifies to */
- COMPLIST cl; /* the complist that we own */
- BOOL bExpand; /* true if we are in expand mode */
- COMPITEM ciSelect; /* selected compitem (in expand mode) */
- int rows; /* number of rows in this view */
- char nrtext[12]; /* we use this in view_gettext for the line
- * number column. overwritten on each call
- */
- int maxtag, maxrest;/* column widths in characters for cols 1, 2 */
- /* if we are in outline mode, we map the row number to one entry
- * in this array of COMPITEM handles. this pointer will
- * be NULL in expand mode
- */
- COMPITEM FAR * pItems;
- /* in expand mode we use this array of line and section handles */
- PVIEWLINE pLines;
- };
- CRITICAL_SECTION CSView;
- static BOOL bDoneInit = FALSE;
- #define ViewEnter() EnterCriticalSection(&CSView);
- #define ViewLeave() LeaveCriticalSection(&CSView);
- void view_outline_opt(VIEW view, BOOL bRedraw);
- void view_freemappings(VIEW view);
- int view_findrow(VIEW view, int number, BOOL bRight);
- BOOL view_expand_item(VIEW view, COMPITEM ci);
- /***************************************************************************
- * Function: view_new
- *
- * Purpose:
- *
- * Create a new view. At this point, we are told the table window handle,
- * and nothing else.
- *
- */
- VIEW
- view_new(HWND hwndTable)
- {
- VIEW view;
- if (!bDoneInit) {
- InitializeCriticalSection(&CSView);
- bDoneInit = TRUE;
- }
- /* alloc the view from the heap */
- view = (VIEW) gmem_get(hHeap, sizeof(struct view));
- /* set the default fields */
- view->hwnd = hwndTable;
- view->cl = NULL;
- view->bExpand = FALSE;
- view->ciSelect = NULL;
- view->rows = 0;
- view->pItems = NULL;
- view->pLines = NULL;
- return(view);
- }
- /***************************************************************************
- * Function: view_setcomplist
- *
- * Purpose:
- *
- * We have to separate view_new and view_setcomplist because we need
- * to give the view handle to the complist and the complist handle to the
- * view. So do a view_new to create a null view; then complist_new() to
- * which you pass a view handle. The complist will then register itself
- * with the view by calling this function. During the build of the complist,
- * it will also update us by calling view_additem, so that we can refresh
- * the display.
- *
- * Here we should initialise an outline view of the complist.
- *
- * We also talk to the status bar using SetNames to set the names of
- * the two items.
- */
- BOOL
- view_setcomplist(VIEW view, COMPLIST cl)
- {
- LPSTR left, right, both;
- if (view == NULL) {
- return(FALSE);
- }
- /* there can be only one call to this per VIEW */
- if (view->cl != NULL) {
- return (FALSE);
- }
- ViewEnter();
- view->cl = cl;
- /* set names on status bar to root names of left and right trees */
- left = complist_getroot_left(cl);
- right = complist_getroot_right(cl);
- both = gmem_get(hHeap, lstrlen(left) + lstrlen(right) +4);
- wsprintf((LPTSTR)both, "%s : %s", left, right);
- ViewLeave();
- SetNames(both);
- ViewEnter();
- gmem_free(hHeap, both, lstrlen(both)+1);
- complist_freeroot_left(cl, left);
- complist_freeroot_right(cl, right);
- ViewLeave();
- view_outline(view);
- }
- /***************************************************************************
- * Function: view_getcomplist
- *
- * Purpose:
- *
- * Return a handle to the complist owned by this view
- */
- COMPLIST
- view_getcomplist(VIEW view)
- {
- if (view == NULL) {
- return(NULL);
- }
- return(view->cl);
- }
- /***************************************************************************
- * Function: view_close
- *
- * Purpose:
- *
- * Close a view. Notify the table window that this view should be
- * closed. When the table window has finished with it, it will send
- * a TQ_CLOSE notify that should result in view_delete being called
- * and the memory being freed.
- */
- void
- view_close(VIEW view)
- {
- if (view == NULL) {
- return;
- }
- SendMessage(view->hwnd, TM_NEWID, 0, 0);
- }
- /***************************************************************************
- * Function: view_delete
- *
- * Purpose:
- *
- * Delete a view and all associated data.
- *
- * This function should only be called in response to the table window
- * sending a TQ_CLOSE message. To close the view, call view_close and
- * wait for the TQ_CLOSE before calling this.
- *
- * We delete the associated COMPLIST and all its associated structures.
- */
- void
- view_delete(VIEW view)
- {
- if (view == NULL) {
- return;
- }
- /* we have two arrays that are used for the mapping - an array
- * of compitem handles in outline mode, and an array of
- * VIEWLINE structures in expand mode
- */
- view_freemappings(view);
- complist_delete(view->cl);
- gmem_free(hHeap, (LPSTR) view, sizeof(struct view));
- }
- /***************************************************************************
- * Function: view_outline
- *
- * Purpose:
- *
- * Build an outline mode mapping where one row represents one COMPITEM in
- * the list. Check the global option flag outline_include to see which items
- * we should include.
- *
- * If we were in expand mode, then set as the selection the row in outline mode
- * that we were expanding. Also remember to free up the expand mode mapping
- * array
- *
- * Once we have built the new mapping, notify the table window to
- * redraw itself.
- */
- void
- view_outline(VIEW view)
- {
- if (view == NULL) {
- return;
- }
- /* all work done by view_outline_opt - this function
- * gives us the option of not updating the display
- */
- view_outline_opt(view, TRUE);
- }
- /***************************************************************************
- * Function: view_expand
- *
- * Purpose:
- *
- * Switch to expand mode, expanding the given row into a view
- * of the differences in that file.
- *
- * Map the given row nr into a compitem handle, and then
- * call the internal function with that.
- */
- BOOL
- view_expand(VIEW view, long row)
- {
- COMPITEM ci;
- BOOL bRet;
- ViewEnter();
- if ((view == NULL) || (view->bExpand)) {
- /* no view, or already expanded */
- ViewLeave();
- return(FALSE);
- }
- if (row >= view->rows) {
- /* no such row */
- ViewLeave();
- return FALSE;
- }
- /* remember the compitem we are expanding */
- ci = view->pItems[row];
- bRet = view_expand_item(view, ci);
- // view_expand_item does the...
- // ViewLeave();
- return(bRet);
- }
- /***************************************************************************
- * Function: view_gettext
- *
- * Purpose:
- *
- * Return the text associated with a given column of a given row.
- * Return a pointer that does not need to be freed after use - ie
- * a pointer into our data somewhere, not a copy
- */
- LPSTR
- view_gettext(VIEW view, long row, int col)
- {
- int line;
- int state;
- LPSTR pstr;
- if (view == NULL) {
- return (NULL);
- }
- ViewEnter();
- if (row >= view->rows) {
- ViewLeave();
- return(NULL);
- }
- if (view->bExpand) {
- /* we are in expand mode */
- state = section_getstate(view->pLines[row].section);
- switch(col) {
- case 0:
- /* row nr */
- /* line numbers can be from either original file
- * this is a menu-selectable option
- */
- switch(line_numbers) {
- case IDM_NONRS:
- pstr = NULL;
- break;
- case IDM_LNRS:
- line = view->pLines[row].nr_left;
- if (state == STATE_MOVEDRIGHT) {
- line = -line;
- }
- break;
- case IDM_RNRS:
- line = view->pLines[row].nr_right;
- if (state == STATE_MOVEDLEFT) {
- line = -line;
- }
- break;
- }
- if (line == 0) {
- ViewLeave();
- return(NULL);
- }
- if (line < 0) {
- /* lines that are moved appear twice.
- * show the correct-sequence line nr
- * for the out-of-seq. copy in brackets.
- */
- wsprintf((LPTSTR)view->nrtext, "(%d)", abs(line));
- } else {
- wsprintf((LPTSTR)view->nrtext, "%d", line);
- }
- pstr = view->nrtext;
- break;
- case 1:
- /* tag text - represents the state of the line */
- switch(state) {
- case STATE_SAME:
- pstr = " ";
- break;
- case STATE_LEFTONLY:
- pstr = " <! ";
- break;
- case STATE_RIGHTONLY:
- pstr = " !> ";
- break;
- case STATE_MOVEDLEFT:
- pstr = " <- ";
- break;
- case STATE_MOVEDRIGHT:
- pstr = " -> ";
- break;
- }
- break;
- case 2:
- /* main text - line */
- pstr = line_gettext(view->pLines[row].line);
- break;
- }
- } else {
- /* outline mode */
- switch(col) {
- case 0:
- /* row number - just the line number */
- wsprintf((LPTSTR)view->nrtext, "%d", row+1);
- pstr = view->nrtext;
- break;
- case 1:
- /* tag */
- pstr = compitem_gettext_tag(view->pItems[row]);
- break;
- case 2:
- /* result text */
- pstr = compitem_gettext_result(view->pItems[row]);
- break;
- }
- }
- ViewLeave();
- return(pstr);
- }
- /***************************************************************************
- * Function: view_getlinenr_left
- *
- * Purpose:
- *
- * Return the line number that this row had in the original left
- * file. 0 if not in expand mode. 0 if this row was not in the left file.
- * -(linenr) if this row is a MOVED line, and this is the right file
- * copy
- */
- int
- view_getlinenr_left(VIEW view, long row)
- {
- int state, line;
- if ((view == NULL) || (row >= view->rows) || !view->bExpand) {
- return 0;
- }
- ViewEnter();
- state = section_getstate(view->pLines[row].section);
- line = view->pLines[row].nr_left;
- if (state == STATE_MOVEDRIGHT) {
- line = -line;
- }
- ViewLeave();
- return(line);
- }
- /***************************************************************************
- * Function: view_getlinenr_right
- *
- * Purpose:
- *
- * Return the line number that this row had in the original right
- * file. 0 if not in expand mode. 0 if this row was not in the right file.
- * -(linenr) if this row is a MOVED line, and this is the left file
- * copy
- */
- int
- view_getlinenr_right(VIEW view, long row)
- {
- int state, line;
- if ((view == NULL) || (row > view->rows) || !view->bExpand) {
- return 0;
- }
- ViewEnter();
- state = section_getstate(view->pLines[row].section);
- line = view->pLines[row].nr_right;
- if (state == STATE_MOVEDLEFT) {
- line = -line;
- }
- ViewLeave();
- return(line);
- }
- /***************************************************************************
- * Function: view_getwidth
- *
- * Purpose:
- *
- * Find the maximum width in characters for the given column
- */
- int
- view_getwidth(VIEW view, int col)
- {
- if (view == NULL) {
- return(0);
- }
- switch(col) {
- case 0:
- /* line nr column - always 5 characters wide */
- return(5);
- case 1:
- /* this is a proportional font field, so add on a margin
- * for error
- */
- return(view->maxtag + (view->maxtag / 20));
- case 2:
- /* this now includes the tab expansion allowance */
- return(view->maxrest);
- default:
- return(0);
- }
- }
- /***************************************************************************
- * Function: view_getrowcount
- *
- * Purpose:
- *
- * How many rows are there in this view ?
- */
- long
- view_getrowcount(VIEW view)
- {
- if (view == NULL) {
- return(0);
- }
- return(view->rows);
- }
- /***************************************************************************
- * Function: view_getstate
- *
- * Purpose:
- *
- * Return the state for the current row. This is used
- * to select the text colour for the row
- *
- * States for sections are obtained from section_getstate (and apply, and
- * to all lines in that section. States for compitems are obtained
- * from compitem_getstate.
- */
- int
- view_getstate(VIEW view, long row)
- {
- int state;
- if (view == NULL) {
- return(0);
- }
- ViewEnter();
- if (row >= view->rows) {
- state = 0;
- } else if (view->bExpand) {
- /* its a line state that's needed */
- state = section_getstate(view->pLines[row].section);
- } else {
- /* its a compitem state */
- state = compitem_getstate(view->pItems[row]);
- }
- ViewLeave();
- return(state);
- }
- /***************************************************************************
- * Function: view_gethandle
- *
- * Purpose:
- *
- * Return a handle to the current compitem. In expand mode,
- * returns the handle to the compitem we are expanding. In outline
- * mode, returns the handle to the compitem for the given row, if valid,
- * or NULL otherwise. row is only used if not in expand mode.
- */
- COMPITEM
- view_getitem(VIEW view, long row)
- {
- COMPITEM ci;
- if (view == NULL) {
- return(NULL);
- }
- ViewEnter();
- if (!view->bExpand) {
- if ((row >= 0) && (row < view->rows)) {
- ci = view->pItems[row];
- } else {
- ci = NULL;
- }
- } else {
- ci = view->ciSelect;
- }
- ViewLeave();
- return(ci);
- }
- /***************************************************************************
- * Function: view_isexpanded
- *
- * Purpose:
- *
- * Return TRUE if the current mapping is expanded mode
- */
- BOOL
- view_isexpanded(VIEW view)
- {
- if (view == NULL) {
- return(FALSE);
- }
- return(view->bExpand);
- }
- /***************************************************************************
- * Function: view_getcurrenttag
- *
- * Purpose:
- *
- * Return a text string describing the view. This is NULL in outline mode,
- * or the tag text for the current compitem in expanded mode
- */
- LPSTR
- view_getcurrenttag(VIEW view)
- {
- LPSTR str;
- if ((view == NULL) || (!view->bExpand)) {
- return(NULL);
- } else {
- ViewEnter();
- str = compitem_gettext_tag(view->ciSelect);
- ViewLeave();
- return(str);
- }
- }
- /***************************************************************************
- * Function: view_newitem
- *
- * Purpose:
- *
- * Notify that CompItems have been added to the complist.
- *
- * Rebuild the view (if in outline mode), and refresh the table. Use
- * the table message TM_APPEND if possible (if column widths have not
- * change). If we have to do TM_NEWLAYOUT, then ensure we scroll
- * back to the right row afterwards.
- *
- * This causes a Poll() to take place. We return TRUE if an abort is
- * pending - in this case, the caller should abandon the scan loop.
- *
- * Enter the critical section for this function since this can be
- * called from the worker thread while the UI thread is using the
- * view that we are about to change.
- *
- * EXCEPT THAT WE DON'T DARE. We cannot ever call SendMessage from the
- * worker thread within CSView. If there is conflict, it will hang.
- */
- BOOL
- view_newitem(VIEW view)
- {
- int maxtag, maxrest;
- long rownr;
- if ((view == NULL) || (view->bExpand)) {
- /* not in outline mode - nothing to do */
- return(Poll());
- }
- /* save some state about the present mapping */
- maxtag = view->maxtag;
- maxrest = view->maxrest;
- /* re-do the outline mapping, but don't tell the table
- * class.
- */
- view_outline_opt(view, FALSE);
- /* have the column widths changed ? */
- if ((maxtag < view->maxtag) || (maxrest < view->maxrest)) {
- /* yes - need complete redraw */
- /* find the row at the top of the window */
- rownr = SendMessage(view->hwnd, TM_TOPROW, FALSE, 0);
- /* switch to new mapping */
- SendMessage(view->hwnd, TM_NEWLAYOUT, 0, (DWORD) view);
- /* return to old row if possible - we know
- * that row is still there since we have only added
- * rows, and not changed any of the existing mapping
- *
- * Alas this is no longer true. However the table class
- * will defend itself against calls for a bogus top row.
- */
- if (rownr >= 0) {
- SendMessage(view->hwnd, TM_TOPROW, TRUE, rownr);
- }
- } else {
- /* no - we can just append */
- /*
- * The mapping may have
- * changed since we released the critsec. however we are still
- * safe. The table will not allow us to reduce the number of
- * rows, so the worst that can happen is that the table will
- * think there are too many rows, and the table message handler
- * will handle this correctly (return null for the text).
- * The only visible effect is therefore that the scrollbar
- * position is wrong.
- */
- SendMessage(view->hwnd, TM_APPEND, view->rows, (DWORD) view);
- }
- /* Poll to keep the UI updated on NT. Returns true if abort pending.
- */
- return(Poll());
- }
- /***************************************************************************
- * Function: view_changeviewoptions
- *
- * Purpose:
- *
- * The view mapping options (eg outline_include, expand_mode) have changed -
- * re-do the mapping and then scroll back to the same position in the window
- * if possible.
- */
- void
- view_changeviewoptions(VIEW view)
- {
- long row;
- int state, number;
- BOOL bRight;
- if (view == NULL) {
- return;
- }
- /* find what row we are currently on. Do this BEFORE we enter CSView */
- row = SendMessage(view->hwnd, TM_TOPROW, FALSE, 0);
- ViewEnter();
- if (!view->bExpand) {
- /* outline mode. maintaining current position is
- * unimportant
- */
- view_outline(view);
- ViewLeave();
- return;
- }
- /* expanded mode */
- /* save the line number on one side (and remember which side) */
- if (row >= view->rows) {
- number = -1;
- } else {
- state = section_getstate(view->pLines[row].section);
- if ((state == STATE_MOVEDRIGHT) ||
- (state == STATE_RIGHTONLY)) {
- bRight = TRUE;
- number = view->pLines[row].nr_right;
- } else {
- bRight = FALSE;
- number = view->pLines[row].nr_left;
- }
- }
- /* make the new mapping */
- view_expand_item(view, view->ciSelect);
- /* find the nearest row in the new view */
- if (number >= 0) {
- ViewEnter();
- row = view_findrow(view, number, bRight);
- ViewLeave();
- /* scroll this row to top of window */
- if (row >= 0) {
- SendMessage(view->hwnd, TM_TOPROW, TRUE, row);
- return;
- }
- }
- }
- /***************************************************************************
- * Function: view_changediffoptions
- *
- * Purpose:
- *
- * The compare options have changed - re-do the compare completely
- * and make the new mapping. Retain current position in the file.
- */
- void
- view_changediffoptions(VIEW view)
- {
- int state, number;
- long row;
- BOOL bRight;
- LIST li;
- COMPITEM ci;
- if (view == NULL) {
- return;
- }
- /*
- * get current row before entering critsec.
- */
- row = SendMessage(view->hwnd, TM_TOPROW, FALSE, 0);
- ViewEnter();
- /* find the current line number so we can go back to it
- * (only if we are in expanded mode
- */
- if (view->bExpand) {
- state = section_getstate(view->pLines[row].section);
- if ((state == STATE_MOVEDRIGHT) ||
- (state == STATE_RIGHTONLY)) {
- bRight = TRUE;
- number = view->pLines[row].nr_right;
- } else {
- bRight = FALSE;
- number = view->pLines[row].nr_left;
- }
- }
- /* To force a recompare using the new options, we must
- * tell each compitem to discard its current compare result.
- * We need to traverse the list of compitems calling this
- * for each compare.
- */
- li = complist_getitems(view->cl);
- for (ci = (COMPITEM) List_First(li); ci != NULL; ci = (COMPITEM) List_Next(ci)) {
- compitem_discardsections(ci);
- }
- /* if we are in outline mode, we have nothing more to do */
- if (!view->bExpand) {
- ViewLeave();
- return;
- }
- view_expand_item(view, view->ciSelect);
- /* find the nearest row in the new view */
- ViewEnter();
- row = view_findrow(view, number, bRight);
- ViewLeave();
- /* scroll this row to top of window */
- if (row >= 0) {
- SendMessage(view->hwnd, TM_TOPROW, TRUE, row);
- }
- }
- /***************************************************************************
- * Function: view_findchange
- *
- * Purpose:
- *
- * Find the next changed - ie non-same - row in a given direction.
- * For outline mode we find the next STATE_DIFFER. For expand mode, we
- * find the next section
- */
- long
- view_findchange(VIEW view, long startrow, BOOL bForward)
- {
- long i;
- if (view == NULL) {
- return(0);
- }
- ViewEnter();
- if (bForward) {
- if (startrow >= view->rows) {
- ViewLeave();
- return(-1);
- }
- if (!view->bExpand) {
- /* look for next compitem with an expandable state*/
- for (i = startrow; i < view->rows; i++) {
- if (compitem_getstate(view->pItems[i]) == STATE_DIFFER) {
- ViewLeave();
- return(i);
- }
- }
- /* none found */
- ViewLeave();
- return(-1);
- } else {
- /*
- * find the next line that matches, then go on to the
- * next line that does not match
- *
- */
- for (i= startrow; i < view->rows; i++) {
- if (section_getstate(view->pLines[i].section)
- == STATE_SAME) {
- break;
- }
- }
- for ( ; i < view->rows; i++) {
- if (section_getstate(view->pLines[i].section)
- != STATE_SAME) {
- ViewLeave();
- return(i);
- }
- }
- ViewLeave();
- return(-1);
- }
- } else {
- /* same search backwards */
- if (startrow <= 0) {
- ViewLeave();
- return(-1);
- }
- if (view->bExpand) {
- /* search backwards for first row that is not
- * changed (has state SAME). then carry on for
- * the next changed row.
- */
- for (i = startrow; i >= 0; i--) {
- if (section_getstate(view->pLines[i].section)
- == STATE_SAME) {
- break;
- }
- }
- for ( ; i >= 0; i--) {
- if (section_getstate(view->pLines[i].section)
- != STATE_SAME) {
- ViewLeave();
- return(i);
- }
- }
- ViewLeave();
- return(-1);
- } else {
- for (i = startrow; i >= 0; i--) {
- if(compitem_getstate(view->pItems[i]) == STATE_DIFFER) {
- ViewLeave();
- return(i);
- }
- }
- ViewLeave();
- return(-1);
- }
- }
- }
- /***************************************************************************
- * Function: view_findrow
- *
- * Purpose:
- *
- * Find the new row number for the line numbered 'number'
- * or the nearest line if possible. If bRight is true, number is
- * a right file number; otherwise it is a left file number.
- *
- * We must be in expand mode
- */
- int
- view_findrow(VIEW view, int number, BOOL bRight)
- {
- int i;
- if (!view->bExpand) {
- return(0);
- }
- for (i = 0; i < view->rows; i++) {
- if (bRight) {
- if (view->pLines[i].nr_right == number) {
- /* found the exact number */
- return(i);
- } else if (view->pLines[i].nr_right > number) {
- /* passed our line -stop here */
- return(i);
- }
- } else {
- if (view->pLines[i].nr_left == number) {
- /* found the exact number */
- return(i);
- } else if (view->pLines[i].nr_left > number) {
- /* passed our line -stop here */
- return(i);
- }
- }
- }
- return(-1);
- }
- /***************************************************************************
- * Function: view_freemappings
- *
- * Purpose:
- *
- * Free memory associated with the expand mode or outline mode mappings
- * called whenever we rebuild the mapping, and on deletion
- */
- void
- view_freemappings(VIEW view)
- {
- if (view->pLines) {
- gmem_free(hHeap, (LPSTR) view->pLines,
- view->rows * sizeof(VIEWLINE));
- view->pLines = NULL;
- } else if (view->pItems) {
- /* previous outline mapping array is still there - free it
- * before we build a new one
- */
- gmem_free(hHeap, (LPSTR) view->pItems,
- view->rows * sizeof(COMPLIST));
- view->pItems = NULL;
- }
- }
- /***************************************************************************
- * Function: view_outline_opt
- *
- * Purpose:
- *
- * Build a view outline to map one row to a COMPITEM handle by traversing
- * the list of COMPITEMs obtained from our complist.
- * Optionally tell the table class to redraw (if bRedraw), and if so,
- * scroll the new table to select the row that represents the
- * file we were expanding, if possible
- */
- void
- view_outline_opt(VIEW view, BOOL bRedraw)
- {
- int prev_row = -1; /* the row nr of the previously-expanded row*/
- int i; /* nr of includable items */
- LIST li;
- COMPITEM ci;
- int state;
- TableSelection select;
- /*
- * check that view_setcomplist has already been called. if not,
- * nothing to do
- */
- if (view->cl == NULL) {
- return;
- }
- ViewEnter();
- /* clear the mode flag and free up memory associated with expand mode */
- view->bExpand = FALSE;
- view_freemappings(view);
- /* traverse the list of compitems counting up the number of
- * includable items
- */
- li = complist_getitems(view->cl);
- ci = (COMPITEM) List_First(li);
- for (i = 0; ci != NULL; ci = (COMPITEM) List_Next(ci)) {
- state = compitem_getstate(ci);
- if (((outline_include & INCLUDE_SAME) && (state == STATE_SAME)) ||
- ((outline_include & INCLUDE_DIFFER) && (state == STATE_DIFFER)) ||
- ((outline_include & INCLUDE_LEFTONLY) && (state == STATE_FILELEFTONLY)) ||
- ((outline_include & INCLUDE_RIGHTONLY) && (state == STATE_FILERIGHTONLY))) {
- i++;
- }
- }
- /* allocate an array big enough for all of these */
- view->pItems = (COMPITEM FAR *) gmem_get(hHeap, i * sizeof(COMPITEM));
- view->rows = i;
- /* keep track of the column widths */
- view->maxtag = 0;
- view->maxrest = 0;
- /* loop through again filling the array, and at the same time looking
- * out for the handle of the previously expanded item
- */
- ci = (COMPITEM) List_First(li);
- for (i = 0; ci != NULL; ci = (COMPITEM) List_Next(ci)) {
- state = compitem_getstate(ci);
- if (((outline_include & INCLUDE_SAME) && (state == STATE_SAME)) ||
- ((outline_include & INCLUDE_DIFFER) && (state == STATE_DIFFER)) ||
- ((outline_include & INCLUDE_LEFTONLY) && (state == STATE_FILELEFTONLY)) ||
- ((outline_include & INCLUDE_RIGHTONLY) && (state == STATE_FILERIGHTONLY))) {
- view->pItems[i] = ci;
- if (ci == view->ciSelect) {
- prev_row = i;
- }
- /* check the column widths in characters */
- view->maxtag = max(view->maxtag,
- lstrlen(compitem_gettext_tag(ci)));
- view->maxrest = max(view->maxrest,
- lstrlen(compitem_gettext_result(ci)));
- i++;
- }
- }
- ViewLeave();
- /* inform table of new layout of table - force refresh */
- if (bRedraw) {
- SendMessage(view->hwnd, TM_NEWLAYOUT, 0, (DWORD) view);
- /* scroll to and highlight the row that represents the file
- * we were previously expanding
- */
- if (prev_row != -1) {
- select.startrow = prev_row;
- select.startcell = 0;
- select.nrows = 1;
- select.ncells = 1;
- SendMessage(view->hwnd, TM_SELECT, 0,
- (DWORD) (LPSTR) &select);
- }
- }
- }
- /***************************************************************************
- * Function: view_expand_item
- *
- * Purpose:
- *
- * Expand a view - given the handle to the compitem to expand.
- *
- * Called from view_expand, and also to re-do an expanded view
- * after options change in view_changediffoptions and _changeviewoptions
- *
- * We get the composite section list from the compitem,
- * and pick out all the sections that are includable (according
- * to the global option expand_mode: we include all sections, or
- * just those in one side left or right). Once we know the count of rows,
- * allocate the mapping array: in each element of the array we keep
- * a handle to the section for that row (to get the state and hence the
- * tag text), and a handle to the line within that section (for the line text).
- *
- * We no longer insist on only expanding text files that differ - if the
- * compitem can give us a composite section list, we will map it.
- *
- * We need to be able to give a line number for a line, in either of
- * the original files according to which option is in force. Each section
- * can give us its base line number (number of first line in section) in
- * each of the two files or 0 if not present, and we track these here.
- *
- * MUST BE INSIDE CSView BEFORE CALLING HERE.
- */
- BOOL
- view_expand_item(VIEW view, COMPITEM ci)
- {
- LIST li;
- SECTION sh;
- LINE line1, line2;
- int i, base_left, base_right, state;
- /* remember the compitem we are expanding */
- view->ciSelect = ci;
- /* get the composite section list */
- li = compitem_getcomposite(view->ciSelect);
- if (li == NULL) {
- ViewLeave();
- return FALSE;
- }
- /* switch modes and free the current mapping
- *
- * NOTE: must do this AFTER the compitem_getcomposite,
- * since that can fail: if it fails it could put up a
- * message box, and that could cause a queued paint message
- * to be processed, which would cause us to use these mappings
- * and gpfault if they had been cleared first.
- */
- view->bExpand = TRUE;
- view_freemappings(view);
- /* loop through totalling the lines in sections
- * that we should include
- */
- view->rows = 0;
- for (sh = (SECTION) List_First(li); sh != NULL;
- sh = (SECTION) List_Next(sh)) {
- state = section_getstate(sh);
- if (expand_mode == IDM_RONLY) {
- if ((state == STATE_LEFTONLY) ||
- (state == STATE_MOVEDLEFT)) {
- continue;
- }
- } else if (expand_mode == IDM_LONLY) {
- if ((state == STATE_RIGHTONLY) ||
- (state == STATE_MOVEDRIGHT)) {
- continue;
- }
- }
- /* include all lines in this section */
- view->rows += section_getlinecount(sh);
- }
- /* allocate the memory for the mapping array */
- view->pLines = (PVIEWLINE) gmem_get(hHeap, view->rows * sizeof(VIEWLINE));
- /* loop through the sections again filling in the mapping array */
- i = 0;
- view->maxtag = 5;
- view->maxrest = 0;
- for (sh = (SECTION) List_First(li); sh != NULL;
- sh = (SECTION) List_Next(sh)) {
- state = section_getstate(sh);
- if (expand_mode == IDM_RONLY) {
- if ((state == STATE_LEFTONLY) ||
- (state == STATE_MOVEDLEFT)) {
- continue;
- }
- } else if (expand_mode == IDM_LONLY) {
- if ((state == STATE_RIGHTONLY) ||
- (state == STATE_MOVEDRIGHT)) {
- continue;
- }
- }
- /* find the base line number in each file */
- base_left = section_getleftbasenr(sh);
- base_right = section_getrightbasenr(sh);
- /* add each line in section to the view. section_getfirst()
- * returns us to a handle that is in a list. We can
- * call List_Next and will eventually get to the
- * line returned by section_getlast(). Sections always have
- * at least one line
- */
- line1 = section_getfirstline(sh);
- line2 = section_getlastline(sh);
- for (; line1 != NULL; line1 = (LINE) List_Next(line1)) {
- view->pLines[i].line = line1;
- view->pLines[i].section = sh;
- /* calculate the line number for this line by
- * incrementing the base nr for this section
- */
- view->pLines[i].nr_left = base_left;
- if (base_left != 0) {
- base_left++;
- }
- view->pLines[i].nr_right = base_right;
- if (base_right != 0) {
- base_right++;
- }
- /* increment index into view */
- i++;
- /* check the column widths */
- view->maxrest = max(view->maxrest,
- (line_gettabbedlength(line1, 8)));
- /* end of section ? */
- if (line1 == line2) {
- break;
- }
- }
- }
- /* We must NOT hold a critical section here as SendMessage may hang */
- ViewLeave();
- /*inform table window of revised mapping */
- SendMessage(view->hwnd, TM_NEWLAYOUT, 0, (DWORD) view);
- return(TRUE);
- }