📄 view.c
字号:
/****************************** 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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -