mirror of
https://github.com/fadden/ciderpress.git
synced 2024-11-26 17:49:21 +00:00
51b5f00f5c
CiderPress and MDC now compile, and execute far enough to open their respective "about" boxes, but I doubt they'll do much more than that. * Switch from MBCS to UNICODE APIs Microsoft switched to UTF-16 (by way of UCS-2) a long time ago, and the support for MBCS seems to be getting phased out. So it's time to switch to wide strings. This is a bit awkward for CiderPress because it works with disk and file archives with 8-bit filenames, and I want NufxLib and DiskImgLib to continue to work on Linux (which has largely taken the UTF-8 approach to Unicode). The libraries will continue to work with 8-bit filenames, with CiderPress/MDC doing the conversion at the appropriate point. There were a couple of places where strings from a structure handed back by one of the libraries were used directly in the UI, or vice-versa, which is a problem because we have nowhere to store the result of the conversion. These currently have fixed place-holder "xyzzy" strings. All UI strings are now wide. Various format strings now use "%ls" and "%hs" to explicitly specify wide and narrow. This doesn't play well with gcc, so only the Windows-specific parts use those. * Various updates to vcxproj files The project-file conversion had some cruft that is now largely gone. The build now has a common output directory for the EXEs and libraries, avoiding the old post-build copy steps. * Added zlib 1.2.8 and nufxlib 2.2.2 source snapshots The old "prebuilts" directory is now gone. The libraries are now built as part of building the apps. I added a minimal set of files for zlib, and a full set for nufxlib. The Linux-specific nufxlib goodies are included for the benefit of the Linux utilities, which are currently broken (don't build). * Replace symbols used for include guards Symbols with a leading "__" are reserved.
1416 lines
43 KiB
C++
1416 lines
43 KiB
C++
/*
|
|
* CiderPress
|
|
* Copyright (C) 2007 by faddenSoft, LLC. All Rights Reserved.
|
|
* See the file LICENSE for distribution terms.
|
|
*/
|
|
/*
|
|
* Support for the "view files" dialog box.
|
|
*/
|
|
#include "stdafx.h"
|
|
#include "ViewFilesDialog.h"
|
|
#include "Main.h"
|
|
#include "Print.h"
|
|
#include "HelpTopics.h"
|
|
#include "../util/UtilLib.h"
|
|
|
|
|
|
/*
|
|
* ===========================================================================
|
|
* ViewFilesDialog
|
|
* ===========================================================================
|
|
*/
|
|
|
|
static const UINT gFindReplaceID = RegisterWindowMessage(FINDMSGSTRING);
|
|
|
|
BEGIN_MESSAGE_MAP(ViewFilesDialog, CDialog)
|
|
ON_WM_CREATE()
|
|
ON_WM_DESTROY()
|
|
ON_WM_SIZE()
|
|
ON_WM_GETMINMAXINFO()
|
|
ON_REGISTERED_MESSAGE(gFindReplaceID, OnFindDialogMessage)
|
|
ON_COMMAND(IDC_FVIEW_NEXT, OnFviewNext)
|
|
ON_COMMAND(IDC_FVIEW_PREV, OnFviewPrev)
|
|
ON_COMMAND(IDC_FVIEW_FONT, OnFviewFont)
|
|
ON_COMMAND(IDC_FVIEW_PRINT, OnFviewPrint)
|
|
ON_COMMAND(IDC_FVIEW_FIND, OnFviewFind)
|
|
ON_BN_CLICKED(IDC_FVIEW_DATA, OnFviewData)
|
|
ON_BN_CLICKED(IDC_FVIEW_RSRC, OnFviewRsrc)
|
|
ON_BN_CLICKED(IDC_FVIEW_CMMT, OnFviewCmmt)
|
|
ON_COMMAND(IDC_FVIEW_FMT_BEST, OnFviewFmtBest)
|
|
ON_COMMAND(IDC_FVIEW_FMT_HEX, OnFviewFmtHex)
|
|
ON_COMMAND(IDC_FVIEW_FMT_RAW, OnFviewFmtRaw)
|
|
ON_CBN_SELCHANGE(IDC_FVIEW_FORMATSEL, OnFormatSelChange)
|
|
ON_COMMAND(IDHELP, OnHelp)
|
|
END_MESSAGE_MAP()
|
|
|
|
/*
|
|
* Window creation. Stuff the desired text into the RichEdit box.
|
|
*/
|
|
BOOL
|
|
ViewFilesDialog::OnInitDialog(void)
|
|
{
|
|
WMSG0("Now in VFD OnInitDialog!\n");
|
|
|
|
ASSERT(fpSelSet != nil);
|
|
|
|
/* delete dummy control and insert our own with modded styles */
|
|
CRichEditCtrl* pEdit = (CRichEditCtrl*)GetDlgItem(IDC_FVIEW_EDITBOX);
|
|
ASSERT(pEdit != nil);
|
|
CRect rect;
|
|
pEdit->GetWindowRect(&rect);
|
|
pEdit->DestroyWindow();
|
|
ScreenToClient(&rect);
|
|
|
|
DWORD styles = ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY |
|
|
WS_BORDER | WS_VSCROLL | WS_VISIBLE | WS_TABSTOP |
|
|
ES_NOHIDESEL;
|
|
if (fNoWrapText)
|
|
styles |= ES_AUTOHSCROLL | WS_HSCROLL;
|
|
fEditCtrl.Create(styles, rect, this, IDC_FVIEW_EDITBOX);
|
|
fEditCtrl.SetFocus();
|
|
/*
|
|
* HEY: I think we can do this with pEdit->ShowScrollBar(SB_BOTH) !!
|
|
* Could also use GetWindowLong/SetWindowLong to change the window style;
|
|
* probably need a SetWindowPos to cause changes to flush.
|
|
*/
|
|
|
|
|
|
/*
|
|
* We want to adjust the size of the window to match the last size used.
|
|
* However, if we do this after creating the edit dialog but before it
|
|
* actually has data to display, then when we stuff data into it the
|
|
* scroll bar goodies are all out of whack.
|
|
*/
|
|
fFirstResize = true;
|
|
#if 0
|
|
const Preferences* pPreferences = GET_PREFERENCES();
|
|
long width = pPreferences->GetFileViewerWidth();
|
|
long height = pPreferences->GetFileViewerHeight();
|
|
CRect fullRect;
|
|
GetWindowRect(&fullRect);
|
|
WMSG2(" VFD pre-size %dx%d\n", fullRect.Width(), fullRect.Height());
|
|
fullRect.right = fullRect.left + width;
|
|
fullRect.bottom = fullRect.top + height;
|
|
MoveWindow(fullRect, FALSE);
|
|
#endif
|
|
|
|
// This invokes UpdateData, which calls DoDataExchange, which leads to
|
|
// the StreamIn call. So don't do this until everything else is ready.
|
|
CDialog::OnInitDialog();
|
|
|
|
WMSG0("VFD OnInitDialog done\n");
|
|
return FALSE; // don't let Windows set the focus
|
|
}
|
|
|
|
|
|
/*
|
|
* Window creation stuff. Set the icon and the "gripper".
|
|
*/
|
|
int
|
|
ViewFilesDialog::OnCreate(LPCREATESTRUCT lpcs)
|
|
{
|
|
WMSG0("VFD OnCreate\n");
|
|
|
|
HICON hIcon;
|
|
hIcon = ::AfxGetApp()->LoadIcon(IDI_FILE_VIEWER);
|
|
SetIcon(hIcon, TRUE);
|
|
|
|
GetClientRect(&fLastWinSize);
|
|
|
|
CRect initRect(fLastWinSize);
|
|
initRect.left = initRect.right - ::GetSystemMetrics(SM_CXVSCROLL);
|
|
initRect.top = initRect.bottom - ::GetSystemMetrics(SM_CYHSCROLL);
|
|
fGripper.Create(WS_CHILD | WS_VISIBLE |
|
|
SBS_SIZEBOX | SBS_SIZEBOXBOTTOMRIGHTALIGN | SBS_SIZEGRIP,
|
|
initRect, this, AFX_IDW_SIZE_BOX);
|
|
|
|
WMSG0("VFD OnCreate done\n");
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Window is going away. Save the current size.
|
|
*/
|
|
void
|
|
ViewFilesDialog::OnDestroy(void)
|
|
{
|
|
Preferences* pPreferences = GET_PREFERENCES_WR();
|
|
CRect rect;
|
|
GetWindowRect(&rect);
|
|
|
|
pPreferences->SetPrefLong(kPrFileViewerWidth, rect.Width());
|
|
pPreferences->SetPrefLong(kPrFileViewerHeight, rect.Height());
|
|
|
|
CDialog::OnDestroy();
|
|
}
|
|
|
|
/*
|
|
* Override OnOK/OnCancel so we don't bail out while we're in the middle of
|
|
* loading something. It would actually be kind of nice to be able to do
|
|
* so, so someday we should make the "cancel" button work, or perhaps allow
|
|
* prev/next to skip over the thing being loaded. "TO DO"
|
|
*/
|
|
void
|
|
ViewFilesDialog::OnOK(void)
|
|
{
|
|
if (fBusy)
|
|
MessageBeep(-1);
|
|
else {
|
|
CRect rect;
|
|
|
|
GetWindowRect(&rect);
|
|
WMSG2(" VFD size now %dx%d\n", rect.Width(), rect.Height());
|
|
|
|
CDialog::OnOK();
|
|
}
|
|
}
|
|
void
|
|
ViewFilesDialog::OnCancel(void)
|
|
{
|
|
if (fBusy)
|
|
MessageBeep(-1);
|
|
else
|
|
CDialog::OnCancel();
|
|
}
|
|
|
|
|
|
/*
|
|
* Restrict the minimum window size to something reasonable.
|
|
*/
|
|
void
|
|
ViewFilesDialog::OnGetMinMaxInfo(MINMAXINFO* pMMI)
|
|
{
|
|
pMMI->ptMinTrackSize.x = 664;
|
|
pMMI->ptMinTrackSize.y = 200;
|
|
}
|
|
|
|
/*
|
|
* When the window resizes, we have to tell the edit box to expand, and
|
|
* rearrange the controls inside it.
|
|
*/
|
|
void
|
|
ViewFilesDialog::OnSize(UINT nType, int cx, int cy)
|
|
{
|
|
CDialog::OnSize(nType, cx, cy);
|
|
|
|
//WMSG2("Dialog: old size %d,%d\n",
|
|
// fLastWinSize.Width(), fLastWinSize.Height());
|
|
WMSG2("Dialog: new size %d,%d\n", cx, cy);
|
|
|
|
if (fLastWinSize.Width() == cx && fLastWinSize.Height() == cy) {
|
|
WMSG0("VFD OnSize: no change\n");
|
|
return;
|
|
}
|
|
|
|
int deltaX, deltaY;
|
|
deltaX = cx - fLastWinSize.Width();
|
|
deltaY = cy - fLastWinSize.Height();
|
|
//WMSG2("Delta is %d,%d\n", deltaX, deltaY);
|
|
|
|
ShiftControls(deltaX, deltaY);
|
|
|
|
GetClientRect(&fLastWinSize);
|
|
}
|
|
|
|
/*
|
|
* Adjust the positions and sizes of the controls.
|
|
*
|
|
* This relies on MinMaxInfo to guarantee that nothing falls off an edge.
|
|
*/
|
|
void
|
|
ViewFilesDialog::ShiftControls(int deltaX, int deltaY)
|
|
{
|
|
HDWP hdwp;
|
|
|
|
/*
|
|
* Use deferred reposn so that they don't end up drawing on top of each
|
|
* other and getting all weird.
|
|
*
|
|
* IMPORTANT: the DeferWindowPos stuff changes the tab order of the
|
|
* items in the window. The controls must be added in the reverse
|
|
* order in which they appear in the window.
|
|
*/
|
|
hdwp = BeginDeferWindowPos(15);
|
|
hdwp = MoveControl(hdwp, this, AFX_IDW_SIZE_BOX, deltaX, deltaY);
|
|
hdwp = MoveControl(hdwp, this, IDHELP, deltaX, deltaY);
|
|
hdwp = MoveControl(hdwp, this, IDC_FVIEW_FONT, deltaX, deltaY);
|
|
hdwp = MoveControl(hdwp, this, IDC_FVIEW_PRINT, deltaX, deltaY);
|
|
hdwp = MoveControl(hdwp, this, IDC_FVIEW_FIND, deltaX, deltaY);
|
|
hdwp = MoveControl(hdwp, this, IDC_FVIEW_FMT_RAW, 0, deltaY);
|
|
hdwp = MoveControl(hdwp, this, IDC_FVIEW_FMT_HEX, 0, deltaY);
|
|
hdwp = MoveControl(hdwp, this, IDC_FVIEW_FMT_BEST, 0, deltaY);
|
|
hdwp = MoveControl(hdwp, this, IDC_FVIEW_PREV, 0, deltaY);
|
|
hdwp = MoveControl(hdwp, this, IDC_FVIEW_NEXT, 0, deltaY);
|
|
hdwp = MoveControl(hdwp, this, IDC_FVIEW_CMMT, 0, deltaY);
|
|
hdwp = MoveControl(hdwp, this, IDC_FVIEW_RSRC, 0, deltaY);
|
|
hdwp = MoveControl(hdwp, this, IDC_FVIEW_DATA, 0, deltaY);
|
|
hdwp = MoveStretchControl(hdwp, this, IDC_FVIEW_FORMATSEL, 0, deltaY, deltaX, 0);
|
|
hdwp = StretchControl(hdwp, this, IDC_FVIEW_EDITBOX, deltaX, deltaY);
|
|
hdwp = MoveControl(hdwp, this, IDOK, deltaX, deltaY);
|
|
if (!EndDeferWindowPos(hdwp)) {
|
|
WMSG0("EndDeferWindowPos failed\n");
|
|
}
|
|
|
|
/*
|
|
* Work around buggy CRichEdit controls. The inner edit area is only
|
|
* resized when the box is shrunk, not when it's expanded, and the
|
|
* results are inconsistent between Win98 and Win2K.
|
|
*
|
|
* Set the internal size equal to the size of the entire edit box.
|
|
* This should be large enough to make everything work right, but small
|
|
* enough to avoid funky scrolling behavior. (If you want to set this
|
|
* more precisely, don't forget that scroll bars are not part of the
|
|
* edit control client area, and their sizes must be factored in.)
|
|
*/
|
|
CRect rect;
|
|
CRichEditCtrl* pEdit = (CRichEditCtrl*) GetDlgItem(IDC_FVIEW_EDITBOX);
|
|
ASSERT(pEdit != nil);
|
|
//pEdit->GetClientRect(&rect);
|
|
pEdit->GetWindowRect(&rect);
|
|
//GetClientRect(&rect);
|
|
rect.left = 2;
|
|
rect.top = 2;
|
|
pEdit->SetRect(&rect);
|
|
}
|
|
|
|
|
|
/*
|
|
* Shuffle data in and out.
|
|
*/
|
|
void
|
|
ViewFilesDialog::DoDataExchange(CDataExchange* pDX)
|
|
{
|
|
CDialog::DoDataExchange(pDX);
|
|
|
|
if (pDX->m_bSaveAndValidate) {
|
|
WMSG0("COPY OUT\n");
|
|
} else {
|
|
WMSG0("COPY IN\n");
|
|
OnFviewNext();
|
|
}
|
|
}
|
|
|
|
static void
|
|
DumpBitmapInfo(HBITMAP hBitmap)
|
|
{
|
|
BITMAP info;
|
|
CBitmap* pBitmap = CBitmap::FromHandle(hBitmap);
|
|
int gotten;
|
|
|
|
gotten = pBitmap->GetObject(sizeof(info), &info);
|
|
|
|
WMSG2("DumpBitmapInfo: gotten=%d of %d\n", gotten, sizeof(info));
|
|
WMSG1(" bmType = %d\n", info.bmType);
|
|
WMSG2(" bmWidth=%d, bmHeight=%d\n", info.bmWidth, info.bmHeight);
|
|
WMSG1(" bmWidthBytes=%d\n", info.bmWidthBytes);
|
|
WMSG1(" bmPlanes=%d\n", info.bmPlanes);
|
|
WMSG1(" bmBitsPixel=%d\n", info.bmBitsPixel);
|
|
WMSG1(" bmPits = 0x%08lx\n", info.bmBits);
|
|
|
|
}
|
|
|
|
/*
|
|
* Display a buffer of text in the RichEdit control.
|
|
*
|
|
* The RichEdit dialog will hold its own copy of the data, so "pHolder" can
|
|
* be safely destroyed after this returns.
|
|
*
|
|
* "fileName" is for display only.
|
|
*/
|
|
void
|
|
ViewFilesDialog::DisplayText(const WCHAR* fileName)
|
|
{
|
|
CWaitCursor wait; // streaming of big files can take a little while
|
|
bool errFlg;
|
|
bool emptyFlg = false;
|
|
bool editHadFocus = false;
|
|
|
|
ASSERT(fpOutput != nil);
|
|
ASSERT(fileName != nil);
|
|
|
|
errFlg = fpOutput->GetOutputKind() == ReformatOutput::kOutputErrorMsg;
|
|
|
|
ASSERT(fpOutput->GetOutputKind() != ReformatOutput::kOutputUnknown);
|
|
|
|
CRichEditCtrl* pEdit = (CRichEditCtrl*) GetDlgItem(IDC_FVIEW_EDITBOX);
|
|
ASSERT(pEdit != nil);
|
|
|
|
/* retain the selection even if we lose focus [can't do this in OnInit] */
|
|
pEdit->SetOptions(ECOOP_OR, ECO_SAVESEL);
|
|
|
|
#if 0
|
|
/*
|
|
* Start by trashing anything that's there. Not strictly necessary,
|
|
* but it prevents the control from trying to maintain the old stuff
|
|
* in an undo buffer. (Not entirely sure if a stream-in operation is
|
|
* undoable, but it costs very little to be certain.)
|
|
*
|
|
* UPDATE: I turned this off because it was dinging the speaker (?!).
|
|
* Might be doing that because it's in read-only mode.
|
|
*/
|
|
pEdit->SetSel(0, -1);
|
|
pEdit->Clear();
|
|
pEdit->EmptyUndoBuffer();
|
|
#endif
|
|
|
|
/*
|
|
* There's a redraw flash that goes away if you change the input
|
|
* focus to something other than the edit ctrl. (Move between large
|
|
* files; it looks like you can see the text being selected and
|
|
* hightlighted. The control doesn't have an "always highlight" flag
|
|
* set, so if the focus is on a different control it doesn't light up.)
|
|
*
|
|
* Since we're currently forcing the focus to be on the edit ctrl later
|
|
* on, we just jam it to something else here. If nothing has the focus,
|
|
* as can happen if we click on "resource fork" and then Alt-N to a
|
|
* file without a resource fork, we force the focus to return to the
|
|
* edit window.
|
|
*
|
|
* NOTE: this would look a little better if we used the Prev/Next
|
|
* buttons to hold the temporary focus, but we need to know which key
|
|
* the user hit. We could also create a bogus control, move it into
|
|
* negative space where it will be invisible, and use that as a "focus
|
|
* holder".
|
|
*/
|
|
CWnd* pFocusWnd = GetFocus();
|
|
if (pFocusWnd == nil || pFocusWnd->m_hWnd == pEdit->m_hWnd) {
|
|
editHadFocus = true;
|
|
GetDlgItem(IDOK)->SetFocus();
|
|
}
|
|
|
|
/*
|
|
* The text color isn't getting reset when we reload the control. I
|
|
* can't find a "set default text color" call, so I'm reformatting
|
|
* part of the buffer.
|
|
*
|
|
* Here's the weird part: it doesn't seem to matter what color I
|
|
* set it to under Win2K. It reverts to black so long as I do anything
|
|
* here. Under Win98, it uses the new color.
|
|
*/
|
|
//if (0)
|
|
{
|
|
CHARFORMAT cf;
|
|
cf.cbSize = sizeof(CHARFORMAT);
|
|
cf.dwMask = CFM_COLOR;
|
|
cf.crTextColor = RGB(0, 0, 0);
|
|
pEdit->SetSel(0, 1); // must select at least one char
|
|
pEdit->SetSelectionCharFormat(cf);
|
|
}
|
|
|
|
/*
|
|
* Add the appropriate data. If the "bitmap" flag is set, use the
|
|
* MyDIBitmap pointer instead.
|
|
*/
|
|
if (fpOutput->GetOutputKind() == ReformatOutput::kOutputBitmap) {
|
|
CClientDC dcScreen(this);
|
|
HBITMAP hBitmap;
|
|
|
|
if (fpRichEditOle == nil) {
|
|
/* can't do this in OnInitDialog -- m_pWnd isn't initialized */
|
|
fpRichEditOle = pEdit->GetIRichEditOle();
|
|
ASSERT(fpRichEditOle != nil);
|
|
}
|
|
|
|
//FILE* fp = fopen("C:/test/output.bmp", "wb");
|
|
//if (fp != nil) {
|
|
// pDib->WriteToFile(fp);
|
|
// fclose(fp);
|
|
//}
|
|
|
|
hBitmap = fpOutput->GetDIB()->ConvertToDDB(dcScreen.m_hDC);
|
|
if (hBitmap == nil) {
|
|
WMSG0("ConvertToDDB failed!\n");
|
|
pEdit->SetWindowText(L"Internal error.");
|
|
errFlg = true;
|
|
} else {
|
|
//DumpBitmapInfo(hBitmap);
|
|
//DumpBitmapInfo(pDib->GetHandle());
|
|
|
|
WMSG0("Inserting bitmap\n");
|
|
pEdit->SetWindowText(L"");
|
|
CImageDataObject::InsertBitmap(fpRichEditOle, hBitmap);
|
|
|
|
/* RichEditCtrl has it now */
|
|
::DeleteObject(hBitmap);
|
|
}
|
|
} else {
|
|
/*
|
|
* Stream the data in, using the appropriate format. Since we don't
|
|
* have the "replace selection" flag set, this replaces everything
|
|
* that's currently in there.
|
|
*
|
|
* We can't use SetWindowText() unless we're willing to forgo viewing
|
|
* of binary files in "raw" form. There doesn't seem to be any other
|
|
* difference between the two approaches.
|
|
*/
|
|
const char* textBuf;
|
|
long textLen;
|
|
int streamFormat;
|
|
|
|
textBuf = fpOutput->GetTextBuf();
|
|
textLen = fpOutput->GetTextLen();
|
|
streamFormat = SF_TEXT;
|
|
if (fpOutput->GetOutputKind() == ReformatOutput::kOutputRTF)
|
|
streamFormat = SF_RTF;
|
|
if (fpOutput->GetTextLen() == 0) {
|
|
textBuf = "(file is empty)";
|
|
textLen = strlen(textBuf);
|
|
emptyFlg = true;
|
|
EnableFormatSelection(FALSE);
|
|
}
|
|
if (fpOutput->GetOutputKind() == ReformatOutput::kOutputErrorMsg)
|
|
EnableFormatSelection(FALSE);
|
|
|
|
/* make sure the control will hold everything we throw at it */
|
|
pEdit->LimitText(textLen+1);
|
|
WMSG2("Streaming %ld bytes (kind=%d)\n",
|
|
textLen, fpOutput->GetOutputKind());
|
|
|
|
/* clear this early to avoid loading onto yellow */
|
|
if (errFlg)
|
|
pEdit->SetBackgroundColor(FALSE, RGB(255, 255, 0));
|
|
else if (emptyFlg)
|
|
pEdit->SetBackgroundColor(FALSE, RGB(192, 192, 192));
|
|
else
|
|
pEdit->SetBackgroundColor(TRUE, 0);
|
|
|
|
RichEditXfer xfer(textBuf, textLen);
|
|
EDITSTREAM es;
|
|
es.dwCookie = (DWORD) &xfer;
|
|
es.dwError = 0;
|
|
es.pfnCallback = RichEditXfer::EditStreamCallback;
|
|
long count;
|
|
count = pEdit->StreamIn(streamFormat, es);
|
|
WMSG2("StreamIn returned count=%ld dwError=%d\n", count, es.dwError);
|
|
|
|
if (es.dwError != 0) {
|
|
/* a -16 error can happen if the type is RTF but contents are not */
|
|
char errorText[256];
|
|
|
|
sprintf(errorText,
|
|
"ERROR: failed while loading data (err=0x%08lx)\n"
|
|
"(File contents might be too big for Windows to display)\n",
|
|
es.dwError);
|
|
RichEditXfer errXfer(errorText, strlen(errorText));
|
|
es.dwCookie = (DWORD) &errXfer;
|
|
es.dwError = 0;
|
|
|
|
count = pEdit->StreamIn(SF_TEXT, es);
|
|
WMSG2("Error StreamIn returned count=%ld dwError=%d\n", count, es.dwError);
|
|
|
|
errFlg = true;
|
|
}
|
|
|
|
//pEdit->SetSel(0, 0);
|
|
}
|
|
|
|
/* move us back to the top */
|
|
pEdit->LineScroll(-pEdit->GetFirstVisibleLine());
|
|
|
|
/* just in case it's trying to hold on to something */
|
|
pEdit->EmptyUndoBuffer();
|
|
|
|
/* work around bug that creates unnecessary scroll bars */
|
|
pEdit->SetScrollRange(SB_VERT, 0, 0, TRUE);
|
|
pEdit->SetScrollRange(SB_HORZ, 0, 0, TRUE);
|
|
|
|
/* display the entire message in the user's selected font */
|
|
if (!fpOutput->GetMultipleFontsFlag()) {
|
|
// adjust the font, stripping default boldness from SF_TEXT
|
|
NewFontSelected(fpOutput->GetOutputKind() != ReformatOutput::kOutputRTF);
|
|
}
|
|
|
|
/* enable/disable the scroll bars */
|
|
//pEdit->EnableScrollBar(SB_BOTH, ESB_DISABLE_BOTH);
|
|
|
|
if (errFlg)
|
|
pEdit->SetBackgroundColor(FALSE, RGB(255, 255, 0));
|
|
else if (emptyFlg)
|
|
pEdit->SetBackgroundColor(FALSE, RGB(192, 192, 192));
|
|
else
|
|
pEdit->SetBackgroundColor(TRUE, 0);
|
|
|
|
/*
|
|
* Work around a Windows bug that prevents the scroll bars from
|
|
* being displayed immediately. This makes them appear, but the
|
|
* vertical scroll bar comes out funky on short files (fixed with
|
|
* the SetScrollRange call above).
|
|
*
|
|
* Best guess: when the edit box is resized, it chooses the scroll bar
|
|
* configuration based on the currently-loaded data. If you resize it
|
|
* and *then* add data, you're stuck with the previous scroll bar
|
|
* values. This doesn't quite make sense though...
|
|
*
|
|
* This works:
|
|
* - Set up dialog.
|
|
* - Load data.
|
|
* - Do minor twiddling.
|
|
* - Resize box significantly.
|
|
*
|
|
* This works:
|
|
* - (box already has data in it)
|
|
* - Load new data.
|
|
* - Do minor twiddling.
|
|
*
|
|
* This doesn't:
|
|
* - Set up dialog
|
|
* - Resize box significantly.
|
|
* - Load data.
|
|
* - Do minor twiddling.
|
|
*
|
|
* There might be some first-time setup issues in here. Hard to say.
|
|
* Anything related to RichEdit controls is extremely fragile, and must
|
|
* be tested with a variety of inputs, preference settings, and under
|
|
* at least Win98 and Win2K (which are *very* different).
|
|
*/
|
|
if (fFirstResize) {
|
|
/* adjust the size of the window to match the last size used */
|
|
const Preferences* pPreferences = GET_PREFERENCES();
|
|
long width = pPreferences->GetPrefLong(kPrFileViewerWidth);
|
|
long height = pPreferences->GetPrefLong(kPrFileViewerHeight);
|
|
CRect fullRect;
|
|
GetWindowRect(&fullRect);
|
|
//WMSG2(" VFD pre-size %dx%d\n", fullRect.Width(), fullRect.Height());
|
|
fullRect.right = fullRect.left + width;
|
|
fullRect.bottom = fullRect.top + height;
|
|
MoveWindow(fullRect, TRUE);
|
|
|
|
editHadFocus = true; // force focus on edit box
|
|
|
|
fFirstResize = false;
|
|
} else {
|
|
/* this should be enough */
|
|
ShiftControls(0, 0);
|
|
}
|
|
|
|
if (fpOutput->GetOutputKind() == ReformatOutput::kOutputBitmap) {
|
|
/* get the cursor off of the image */
|
|
pEdit->SetSel(-1, -1);
|
|
}
|
|
|
|
/*
|
|
* We want the focus to be on the text window so keyboard selection
|
|
* commands work. However, it's also nice to be able to arrow through
|
|
* the format selection box.
|
|
*/
|
|
if (editHadFocus)
|
|
pEdit->SetFocus();
|
|
|
|
fTitle = fileName;
|
|
//if (fpOutput->GetOutputKind() == ReformatOutput::kOutputText ||
|
|
// fpOutput->GetOutputKind() == ReformatOutput::kOutputRTF ||
|
|
// fpOutput->GetOutputKind() == ReformatOutput::kOutputCSV ||
|
|
// fpOutput->GetOutputKind() == ReformatOutput::kOutputBitmap ||
|
|
// fpOutput->GetOutputKind() == ReformatOutput::kOutputRaw)
|
|
//{
|
|
// not for error messages
|
|
fTitle += _T(" [");
|
|
fTitle += fpOutput->GetFormatDescr();
|
|
fTitle += _T("]");
|
|
//} else if (fpOutput->GetOutputKind() == ReformatOutput::kOutputRaw) {
|
|
// fTitle += _T(" [Raw]");
|
|
//}
|
|
|
|
CString winTitle = _T("File Viewer - ");
|
|
winTitle += fTitle;
|
|
SetWindowText(winTitle);
|
|
|
|
/*
|
|
* Enable or disable the next/prev buttons.
|
|
*/
|
|
CButton* pButton;
|
|
pButton = (CButton*) GetDlgItem(IDC_FVIEW_PREV);
|
|
pButton->EnableWindow(fpSelSet->IterHasPrev());
|
|
pButton = (CButton*) GetDlgItem(IDC_FVIEW_NEXT);
|
|
pButton->EnableWindow(fpSelSet->IterHasNext());
|
|
}
|
|
|
|
/*
|
|
* Handle the "next" button.
|
|
*
|
|
* (This is also called from DoDataExchange.)
|
|
*/
|
|
void
|
|
ViewFilesDialog::OnFviewNext(void)
|
|
{
|
|
ReformatHolder::ReformatPart part;
|
|
ReformatHolder::ReformatID id;
|
|
int result;
|
|
|
|
if (fBusy) {
|
|
WMSG0("BUSY!\n");
|
|
return;
|
|
}
|
|
|
|
fBusy = true;
|
|
|
|
if (!fpSelSet->IterHasNext()) {
|
|
ASSERT(false);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Get the pieces of the file.
|
|
*/
|
|
SelectionEntry* pSelEntry = fpSelSet->IterNext();
|
|
GenericEntry* pEntry = pSelEntry->GetEntry();
|
|
result = ReformatPrep(pEntry);
|
|
#if 0
|
|
{
|
|
// for debugging -- simulate failure
|
|
result = -1;
|
|
delete fpHolder;
|
|
fpHolder = nil;
|
|
delete fpOutput;
|
|
fpOutput = nil;
|
|
}
|
|
#endif
|
|
|
|
fBusy = false;
|
|
if (result != 0) {
|
|
ASSERT(fpHolder == nil);
|
|
ASSERT(fpOutput == nil);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Format a piece.
|
|
*/
|
|
ConfigurePartButtons(pSelEntry->GetEntry());
|
|
part = GetSelectedPart();
|
|
id = ConfigureFormatSel(part);
|
|
Reformat(pSelEntry->GetEntry(), part, id);
|
|
|
|
DisplayText(pSelEntry->GetEntry()->GetDisplayName());
|
|
}
|
|
|
|
/*
|
|
* Handle the "prev" button.
|
|
*/
|
|
void
|
|
ViewFilesDialog::OnFviewPrev(void)
|
|
{
|
|
ReformatHolder::ReformatPart part;
|
|
ReformatHolder::ReformatID id;
|
|
int result;
|
|
|
|
if (fBusy) {
|
|
WMSG0("BUSY!\n");
|
|
return;
|
|
}
|
|
|
|
fBusy = true;
|
|
|
|
if (!fpSelSet->IterHasPrev()) {
|
|
ASSERT(false);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Get the pieces of the file.
|
|
*/
|
|
SelectionEntry* pSelEntry = fpSelSet->IterPrev();
|
|
GenericEntry* pEntry = pSelEntry->GetEntry();
|
|
result = ReformatPrep(pEntry);
|
|
|
|
fBusy = false;
|
|
if (result != 0) {
|
|
ASSERT(fpHolder == nil);
|
|
ASSERT(fpOutput == nil);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Format a piece.
|
|
*/
|
|
ConfigurePartButtons(pEntry);
|
|
part = GetSelectedPart();
|
|
id = ConfigureFormatSel(part);
|
|
Reformat(pEntry, part, id);
|
|
|
|
DisplayText(pEntry->GetDisplayName());
|
|
}
|
|
|
|
/*
|
|
* Configure the radio buttons that determine which part to view, enabling
|
|
* only those that make sense.
|
|
*
|
|
* Try to keep the previously-set button set.
|
|
*
|
|
* If "pEntry" is nil, all buttons are disabled (useful for first-time
|
|
* initialization).
|
|
*/
|
|
void
|
|
ViewFilesDialog::ConfigurePartButtons(const GenericEntry* pEntry)
|
|
{
|
|
int id = 0;
|
|
|
|
CButton* pDataWnd = (CButton*) GetDlgItem(IDC_FVIEW_DATA);
|
|
CButton* pRsrcWnd = (CButton*) GetDlgItem(IDC_FVIEW_RSRC);
|
|
CButton* pCmmtWnd = (CButton*) GetDlgItem(IDC_FVIEW_CMMT);
|
|
ASSERT(pDataWnd != nil && pRsrcWnd != nil && pCmmtWnd != nil);
|
|
|
|
/* figure out what was checked before, ignoring if it's not available */
|
|
if (pDataWnd->GetCheck() == BST_CHECKED && pEntry->GetHasDataFork())
|
|
id = IDC_FVIEW_DATA;
|
|
else if (pRsrcWnd->GetCheck() == BST_CHECKED && pEntry->GetHasRsrcFork())
|
|
id = IDC_FVIEW_RSRC;
|
|
else if (pCmmtWnd->GetCheck() == BST_CHECKED && pEntry->GetHasComment())
|
|
id = IDC_FVIEW_CMMT;
|
|
|
|
/* couldn't keep previous check, find a new one */
|
|
if (id == 0) {
|
|
if (pEntry->GetHasDataFork())
|
|
id = IDC_FVIEW_DATA;
|
|
else if (pEntry->GetHasRsrcFork())
|
|
id = IDC_FVIEW_RSRC;
|
|
else if (pEntry->GetHasComment())
|
|
id = IDC_FVIEW_CMMT;
|
|
// else leave it set to 0
|
|
}
|
|
|
|
/* set up the dialog */
|
|
pDataWnd->SetCheck(BST_UNCHECKED);
|
|
pRsrcWnd->SetCheck(BST_UNCHECKED);
|
|
pCmmtWnd->SetCheck(BST_UNCHECKED);
|
|
|
|
if (pEntry == nil) {
|
|
pDataWnd->EnableWindow(FALSE);
|
|
pRsrcWnd->EnableWindow(FALSE);
|
|
pCmmtWnd->EnableWindow(FALSE);
|
|
} else {
|
|
pDataWnd->EnableWindow(pEntry->GetHasDataFork());
|
|
pRsrcWnd->EnableWindow(pEntry->GetHasRsrcFork());
|
|
pCmmtWnd->EnableWindow(pEntry->GetHasComment());
|
|
}
|
|
|
|
if (id == IDC_FVIEW_RSRC)
|
|
pRsrcWnd->SetCheck(BST_CHECKED);
|
|
else if (id == IDC_FVIEW_CMMT)
|
|
pCmmtWnd->SetCheck(BST_CHECKED);
|
|
else
|
|
pDataWnd->SetCheck(BST_CHECKED);
|
|
}
|
|
|
|
/*
|
|
* Figure out which part of the file is selected (data/rsrc/comment).
|
|
*
|
|
* If no part is selected, throws up its hands and returns kPartData.
|
|
*/
|
|
ReformatHolder::ReformatPart
|
|
ViewFilesDialog::GetSelectedPart(void)
|
|
{
|
|
CButton* pDataWnd = (CButton*) GetDlgItem(IDC_FVIEW_DATA);
|
|
CButton* pRsrcWnd = (CButton*) GetDlgItem(IDC_FVIEW_RSRC);
|
|
CButton* pCmmtWnd = (CButton*) GetDlgItem(IDC_FVIEW_CMMT);
|
|
ASSERT(pDataWnd != nil && pRsrcWnd != nil && pCmmtWnd != nil);
|
|
|
|
if (pDataWnd->GetCheck() == BST_CHECKED)
|
|
return ReformatHolder::kPartData;
|
|
else if (pRsrcWnd->GetCheck() == BST_CHECKED)
|
|
return ReformatHolder::kPartRsrc;
|
|
else if (pCmmtWnd->GetCheck() == BST_CHECKED)
|
|
return ReformatHolder::kPartCmmt;
|
|
else {
|
|
assert(false);
|
|
return ReformatHolder::kPartData;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Set up the fpHolder. Does not reformat the data, just loads the source
|
|
* material and runs the applicability tests.
|
|
*
|
|
* Returns 0 on success, -1 on failure.
|
|
*/
|
|
int
|
|
ViewFilesDialog::ReformatPrep(GenericEntry* pEntry)
|
|
{
|
|
CWaitCursor waitc; // can be slow reading data from floppy
|
|
MainWindow* pMainWindow = GET_MAIN_WINDOW();
|
|
int result;
|
|
|
|
delete fpHolder;
|
|
fpHolder = nil;
|
|
|
|
result = pMainWindow->GetFileParts(pEntry, &fpHolder);
|
|
if (result != 0) {
|
|
WMSG0("GetFileParts(prev) failed!\n");
|
|
ASSERT(fpHolder == nil);
|
|
return -1;
|
|
}
|
|
|
|
/* set up the ReformatHolder */
|
|
MainWindow::ConfigureReformatFromPreferences(fpHolder);
|
|
|
|
/* prep for applicability test */
|
|
fpHolder->SetSourceAttributes(
|
|
pEntry->GetFileType(),
|
|
pEntry->GetAuxType(),
|
|
MainWindow::ReformatterSourceFormat(pEntry->GetSourceFS()),
|
|
pEntry->GetFileNameExtensionA());
|
|
|
|
/* figure out which reformatters apply to this file */
|
|
WMSG0("Testing reformatters\n");
|
|
fpHolder->TestApplicability();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Reformat a file.
|
|
*
|
|
* Returns 0 if the file was reformatted, -1 if not
|
|
*/
|
|
int
|
|
ViewFilesDialog::Reformat(const GenericEntry* pEntry,
|
|
ReformatHolder::ReformatPart part, ReformatHolder::ReformatID id)
|
|
{
|
|
CWaitCursor waitc;
|
|
|
|
delete fpOutput;
|
|
fpOutput = nil;
|
|
|
|
/* run the best one */
|
|
fpOutput = fpHolder->Apply(part, id);
|
|
|
|
//bail:
|
|
if (fpOutput != nil) {
|
|
// success -- do some sanity checks
|
|
switch (fpOutput->GetOutputKind()) {
|
|
case ReformatOutput::kOutputText:
|
|
case ReformatOutput::kOutputRTF:
|
|
case ReformatOutput::kOutputCSV:
|
|
case ReformatOutput::kOutputErrorMsg:
|
|
ASSERT(fpOutput->GetTextBuf() != nil);
|
|
ASSERT(fpOutput->GetDIB() == nil);
|
|
break;
|
|
case ReformatOutput::kOutputBitmap:
|
|
ASSERT(fpOutput->GetDIB() != nil);
|
|
ASSERT(fpOutput->GetTextBuf() == nil);
|
|
break;
|
|
case ReformatOutput::kOutputRaw:
|
|
// text buf might be nil
|
|
ASSERT(fpOutput->GetDIB() == nil);
|
|
break;
|
|
}
|
|
return 0;
|
|
} else {
|
|
/* shouldn't get here; handle it if we do */
|
|
static const char* kFailMsg = "Internal error\r\n";
|
|
fpOutput = new ReformatOutput;
|
|
fpOutput->SetTextBuf((char*) kFailMsg, strlen(kFailMsg), false);
|
|
fpOutput->SetOutputKind(ReformatOutput::kOutputErrorMsg);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Set up the entries in the drop box based on the "applicable" array in
|
|
* fpHolder. The set of values is different for each part of the file.
|
|
*
|
|
* Returns the default reformatter ID. This is always entry #0.
|
|
*
|
|
* I tried making it "sticky", so that if the user chose to go into hex
|
|
* dump mode it would stay there. We returned either entry #0 in the
|
|
* combo box, or the previously-selected reformatter ID if it also
|
|
* applies to this file. This was a little whacked, e.g. Intbasic vs.
|
|
* S-C assembler got ugly, so I tried restricting it to "always" classes.
|
|
* But then, the first time you hit a binary file with no reformatter,
|
|
* you're stuck there. Eventually I decided to discard the idea.
|
|
*/
|
|
ReformatHolder::ReformatID
|
|
ViewFilesDialog::ConfigureFormatSel(ReformatHolder::ReformatPart part)
|
|
{
|
|
//ReformatHolder::ReformatID prevID = ReformatHolder::kReformatUnknown;
|
|
ReformatHolder::ReformatID returnID = ReformatHolder::kReformatRaw;
|
|
CComboBox* pCombo = (CComboBox*) GetDlgItem(IDC_FVIEW_FORMATSEL);
|
|
|
|
WMSG0("--- ConfigureFormatSel\n");
|
|
|
|
//int sel;
|
|
//sel = pCombo->GetCurSel();
|
|
//if (sel != CB_ERR)
|
|
// prevID = (ReformatHolder::ReformatID) pCombo->GetItemData(sel);
|
|
//WMSG1(" prevID = %d\n", prevID);
|
|
|
|
EnableFormatSelection(TRUE);
|
|
pCombo->ResetContent();
|
|
|
|
/*
|
|
* Fill out the combo box with the reformatter entries.
|
|
*
|
|
* There's probably a way to do this that doesn't involve abusing
|
|
* enums, but this'll do for now.
|
|
*/
|
|
int applyIdx, idIdx;
|
|
bool preferred = true;
|
|
int comboIdx;
|
|
for (applyIdx = ReformatHolder::kApplicMAX;
|
|
applyIdx > ReformatHolder::kApplicNot; /*no incr*/)
|
|
{
|
|
if (applyIdx == ReformatHolder::kApplicMAX)
|
|
goto skip;
|
|
if (applyIdx == ReformatHolder::kApplicUnknown)
|
|
goto skip;
|
|
|
|
int testApplies;
|
|
|
|
testApplies = applyIdx;
|
|
if (preferred)
|
|
testApplies |= ReformatHolder::kApplicPreferred;
|
|
|
|
for (idIdx = 0; idIdx < ReformatHolder::kReformatMAX; idIdx++) {
|
|
if (idIdx == ReformatHolder::kReformatUnknown)
|
|
continue;
|
|
|
|
ReformatHolder::ReformatApplies applies;
|
|
|
|
applies = fpHolder->GetApplic(part,
|
|
(ReformatHolder::ReformatID) idIdx);
|
|
if ((int) applies == testApplies) {
|
|
/* match! */
|
|
CString str;
|
|
//WMSG2("MATCH at %d (0x%02x)\n", idIdx, testApplies);
|
|
str.Format(L"%ls", ReformatHolder::GetReformatName(
|
|
(ReformatHolder::ReformatID) idIdx));
|
|
comboIdx = pCombo->AddString(str);
|
|
pCombo->SetItemData(comboIdx, idIdx);
|
|
|
|
/* define initial selection as best item */
|
|
if (comboIdx == 0)
|
|
pCombo->SetCurSel(comboIdx);
|
|
|
|
//if (idIdx == (int) prevID &&
|
|
// applyIdx == ReformatHolder::kApplicAlways)
|
|
//{
|
|
// WMSG0(" Found 'always' prevID, selecting\n");
|
|
// pCombo->SetCurSel(comboIdx);
|
|
//}
|
|
}
|
|
}
|
|
|
|
skip:
|
|
if (!preferred)
|
|
applyIdx--;
|
|
preferred = !preferred;
|
|
}
|
|
|
|
/* return whatever we now have selected */
|
|
int sel = pCombo->GetCurSel();
|
|
WMSG1(" At end, sel is %d\n", sel);
|
|
if (sel != CB_ERR)
|
|
returnID = (ReformatHolder::ReformatID) pCombo->GetItemData(sel);
|
|
|
|
return returnID;
|
|
}
|
|
|
|
/*
|
|
* The user has changed entries in the format selection drop box.
|
|
*
|
|
* Also called from the "quick change" buttons.
|
|
*/
|
|
void
|
|
ViewFilesDialog::OnFormatSelChange(void)
|
|
{
|
|
CComboBox* pCombo = (CComboBox*) GetDlgItem(IDC_FVIEW_FORMATSEL);
|
|
ASSERT(pCombo != nil);
|
|
WMSG1("+++ SELECTION IS NOW %d\n", pCombo->GetCurSel());
|
|
|
|
SelectionEntry* pSelEntry = fpSelSet->IterCurrent();
|
|
GenericEntry* pEntry = pSelEntry->GetEntry();
|
|
ReformatHolder::ReformatPart part;
|
|
ReformatHolder::ReformatID id;
|
|
|
|
part = GetSelectedPart();
|
|
id = (ReformatHolder::ReformatID) pCombo->GetItemData(pCombo->GetCurSel());
|
|
Reformat(pEntry, part, id);
|
|
|
|
DisplayText(pEntry->GetDisplayName());
|
|
}
|
|
|
|
/*
|
|
* Change the fork we're looking at.
|
|
*/
|
|
void
|
|
ViewFilesDialog::OnFviewData(void)
|
|
{
|
|
ForkSelectCommon(ReformatHolder::kPartData);
|
|
}
|
|
void
|
|
ViewFilesDialog::OnFviewRsrc(void)
|
|
{
|
|
ForkSelectCommon(ReformatHolder::kPartRsrc);
|
|
}
|
|
void
|
|
ViewFilesDialog::OnFviewCmmt(void)
|
|
{
|
|
ForkSelectCommon(ReformatHolder::kPartCmmt);
|
|
}
|
|
void
|
|
ViewFilesDialog::ForkSelectCommon(ReformatHolder::ReformatPart part)
|
|
{
|
|
GenericEntry* pEntry;
|
|
ReformatHolder::ReformatID id;
|
|
|
|
WMSG1("Switching to file part=%d\n", part);
|
|
ASSERT(fpHolder != nil);
|
|
ASSERT(fpSelSet != nil);
|
|
ASSERT(fpSelSet->IterCurrent() != nil);
|
|
pEntry = fpSelSet->IterCurrent()->GetEntry();
|
|
ASSERT(pEntry != nil);
|
|
|
|
id = ConfigureFormatSel(part);
|
|
|
|
Reformat(pEntry, part, id);
|
|
DisplayText(pEntry->GetDisplayName());
|
|
}
|
|
|
|
/*
|
|
* Switch to hex dump mode.
|
|
*/
|
|
void
|
|
ViewFilesDialog::OnFviewFmtBest(void)
|
|
{
|
|
CComboBox* pCombo = (CComboBox*) GetDlgItem(IDC_FVIEW_FORMATSEL);
|
|
pCombo->SetCurSel(0); // best is always at the top
|
|
OnFormatSelChange();
|
|
pCombo->SetFocus();
|
|
}
|
|
|
|
/*
|
|
* Switch to hex dump mode.
|
|
*/
|
|
void
|
|
ViewFilesDialog::OnFviewFmtHex(void)
|
|
{
|
|
CComboBox* pCombo = (CComboBox*) GetDlgItem(IDC_FVIEW_FORMATSEL);
|
|
int sel = FindByVal(pCombo, ReformatHolder::kReformatHexDump);
|
|
if (sel < 0)
|
|
sel = 0;
|
|
pCombo->SetCurSel(sel);
|
|
OnFormatSelChange();
|
|
pCombo->SetFocus();
|
|
}
|
|
|
|
/*
|
|
* Switch to raw mode.
|
|
*/
|
|
void
|
|
ViewFilesDialog::OnFviewFmtRaw(void)
|
|
{
|
|
CComboBox* pCombo = (CComboBox*) GetDlgItem(IDC_FVIEW_FORMATSEL);
|
|
int sel = FindByVal(pCombo, ReformatHolder::kReformatRaw);
|
|
if (sel < 0)
|
|
sel = 0;
|
|
pCombo->SetCurSel(sel);
|
|
OnFormatSelChange();
|
|
pCombo->SetFocus();
|
|
}
|
|
|
|
/*
|
|
* Enable or disable all of the format selection buttons.
|
|
*/
|
|
void
|
|
ViewFilesDialog::EnableFormatSelection(BOOL enable)
|
|
{
|
|
GetDlgItem(IDC_FVIEW_FORMATSEL)->EnableWindow(enable);
|
|
GetDlgItem(IDC_FVIEW_FMT_BEST)->EnableWindow(enable);
|
|
GetDlgItem(IDC_FVIEW_FMT_HEX)->EnableWindow(enable);
|
|
GetDlgItem(IDC_FVIEW_FMT_RAW)->EnableWindow(enable);
|
|
}
|
|
|
|
/*
|
|
* Return the combo box index for the entry whose "data" field matches "val".
|
|
*
|
|
* Returns -1 if the entry couldn't be found.
|
|
*/
|
|
int
|
|
ViewFilesDialog::FindByVal(CComboBox* pCombo, DWORD val)
|
|
{
|
|
int count = pCombo->GetCount();
|
|
int i;
|
|
|
|
for (i = 0; i < count; i++) {
|
|
if (pCombo->GetItemData(i) == val)
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Handle the "font" button. Choose a font, then apply the choice to
|
|
* all of the text in the box.
|
|
*/
|
|
void
|
|
ViewFilesDialog::OnFviewFont(void)
|
|
{
|
|
LOGFONT logFont;
|
|
CFont font;
|
|
|
|
/*
|
|
* Create a LOGFONT structure with the desired default characteristics,
|
|
* then use that to initialize the font dialog.
|
|
*/
|
|
CreateSimpleFont(&font, this, fTypeFace, fPointSize);
|
|
font.GetLogFont(&logFont);
|
|
|
|
CFontDialog fontDlg(&logFont);
|
|
fontDlg.m_cf.Flags &= ~(CF_EFFECTS);
|
|
|
|
if (fontDlg.DoModal() == IDOK) {
|
|
//fontDlg.GetCurrentFont(&logFont);
|
|
fTypeFace = fontDlg.GetFaceName();
|
|
fPointSize = fontDlg.GetSize() / 10;
|
|
WMSG2("Now using %d-point '%ls'\n", fPointSize, (LPCWSTR) fTypeFace);
|
|
|
|
NewFontSelected(false);
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* Font selection has changed, update the richedit box.
|
|
*/
|
|
void
|
|
ViewFilesDialog::NewFontSelected(bool resetBold)
|
|
{
|
|
CRichEditCtrl* pEdit = (CRichEditCtrl*) GetDlgItem(IDC_FVIEW_EDITBOX);
|
|
ASSERT(pEdit != nil);
|
|
|
|
CHARFORMAT cf;
|
|
cf.cbSize = sizeof(CHARFORMAT);
|
|
cf.dwMask = CFM_FACE | CFM_SIZE;
|
|
if (resetBold) {
|
|
cf.dwMask |= CFM_BOLD;
|
|
cf.dwEffects = 0;
|
|
}
|
|
::lstrcpy(cf.szFaceName, fTypeFace);
|
|
cf.yHeight = fPointSize * 20; // in twips
|
|
pEdit->SetSel(0, -1); // select all
|
|
pEdit->SetSelectionCharFormat(cf);
|
|
pEdit->SetSel(0, 0); // unselect
|
|
}
|
|
|
|
|
|
/*
|
|
* Print a ContentList.
|
|
*/
|
|
void
|
|
ViewFilesDialog::OnFviewPrint(void)
|
|
{
|
|
MainWindow* pMainWindow = GET_MAIN_WINDOW();
|
|
CPrintDialog dlg(FALSE); // use CPrintDialogEx for Win2K? CPageSetUpDialog?
|
|
PrintRichEdit pre;
|
|
CDC dc;
|
|
int numPages;
|
|
|
|
dlg.m_pd.nFromPage = dlg.m_pd.nMinPage = 1;
|
|
dlg.m_pd.nToPage = dlg.m_pd.nMaxPage = 1;
|
|
|
|
/*
|
|
* Getting the expected number of pages requires a print test-run.
|
|
* However, if we use GetDefaults to get the DC, the call to DoModal
|
|
* returns immediately with IDCANCEL. So, we do our pre-flighting
|
|
* in a separate DC with a separate print dialog object.
|
|
*/
|
|
{
|
|
CPrintDialog countDlg(FALSE);
|
|
CDC countDC;
|
|
|
|
dlg.m_pd.hDevMode = pMainWindow->fhDevMode;
|
|
dlg.m_pd.hDevNames = pMainWindow->fhDevNames;
|
|
|
|
if (countDlg.GetDefaults() == TRUE) {
|
|
CWaitCursor waitc;
|
|
|
|
if (countDC.Attach(countDlg.GetPrinterDC()) != TRUE) {
|
|
ASSERT(false);
|
|
}
|
|
pre.Setup(&countDC, this);
|
|
pre.PrintPreflight(&fEditCtrl, &numPages);
|
|
WMSG1("Default printer generated %d pages\n", numPages);
|
|
|
|
dlg.m_pd.nToPage = dlg.m_pd.nMaxPage = numPages;
|
|
}
|
|
|
|
pMainWindow->fhDevMode = dlg.m_pd.hDevMode;
|
|
pMainWindow->fhDevNames = dlg.m_pd.hDevNames;
|
|
}
|
|
|
|
long startChar, endChar;
|
|
fEditCtrl.GetSel(/*ref*/startChar, /*ref*/endChar);
|
|
|
|
if (endChar != startChar) {
|
|
WMSG2("GetSel returned start=%ld end=%ld\n", startChar, endChar);
|
|
dlg.m_pd.Flags &= ~(PD_NOSELECTION);
|
|
}
|
|
|
|
dlg.m_pd.hDevMode = pMainWindow->fhDevMode;
|
|
dlg.m_pd.hDevNames = pMainWindow->fhDevNames;
|
|
dlg.m_pd.Flags |= PD_USEDEVMODECOPIESANDCOLLATE;
|
|
dlg.m_pd.Flags &= ~(PD_NOPAGENUMS);
|
|
|
|
|
|
/*
|
|
* Show them the print dialog.
|
|
*/
|
|
if (dlg.DoModal() != IDOK)
|
|
return;
|
|
|
|
/*
|
|
* Grab the chosen printer and prep ourselves.
|
|
*/
|
|
if (dc.Attach(dlg.GetPrinterDC()) != TRUE) {
|
|
CString msg;
|
|
msg.LoadString(IDS_PRINTER_NOT_USABLE);
|
|
ShowFailureMsg(this, msg, IDS_FAILED);
|
|
return;
|
|
}
|
|
pre.Setup(&dc, this);
|
|
|
|
/*
|
|
* Do the printing.
|
|
*/
|
|
if (dlg.PrintRange())
|
|
pre.PrintPages(&fEditCtrl, fTitle, dlg.GetFromPage(), dlg.GetToPage());
|
|
else if (dlg.PrintSelection())
|
|
pre.PrintSelection(&fEditCtrl, fTitle, startChar, endChar);
|
|
else // dlg.PrintAll()
|
|
pre.PrintAll(&fEditCtrl, fTitle);
|
|
|
|
pMainWindow->fhDevMode = dlg.m_pd.hDevMode;
|
|
pMainWindow->fhDevNames = dlg.m_pd.hDevNames;
|
|
}
|
|
|
|
/*
|
|
* User hit the "Find..." button. Open the modeless Find dialog.
|
|
*/
|
|
void
|
|
ViewFilesDialog::OnFviewFind(void)
|
|
{
|
|
DWORD flags = 0;
|
|
|
|
if (fpFindDialog != nil)
|
|
return;
|
|
|
|
if (fFindDown)
|
|
flags |= FR_DOWN;
|
|
if (fFindMatchCase)
|
|
flags |= FR_MATCHCASE;
|
|
if (fFindMatchWholeWord)
|
|
flags |= FR_WHOLEWORD;
|
|
|
|
/*
|
|
* I can't get this to work with FindText(). There's a lot of questions
|
|
* about this on web sites. Probably safest to just disable it.
|
|
*/
|
|
flags |= FR_HIDEUPDOWN;
|
|
|
|
fpFindDialog = new CFindReplaceDialog;
|
|
|
|
fpFindDialog->Create(TRUE, // "find" only
|
|
fFindLastStr, // default string to search for
|
|
NULL, // default string to replace
|
|
flags, // flags
|
|
this); // parent
|
|
}
|
|
|
|
/*
|
|
* Handle activity in the modeless "find" dialog.
|
|
*/
|
|
LRESULT
|
|
ViewFilesDialog::OnFindDialogMessage(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
assert(fpFindDialog != nil);
|
|
|
|
fFindDown = (fpFindDialog->SearchDown() != 0);
|
|
fFindMatchCase = (fpFindDialog->MatchCase() != 0);
|
|
fFindMatchWholeWord = (fpFindDialog->MatchWholeWord() != 0);
|
|
|
|
if (fpFindDialog->IsTerminating()) {
|
|
WMSG0("VFD find dialog closing\n");
|
|
fpFindDialog = nil;
|
|
return 0;
|
|
}
|
|
|
|
if (fpFindDialog->FindNext()) {
|
|
fFindLastStr = fpFindDialog->GetFindString();
|
|
FindNext(fFindLastStr, fFindDown, fFindMatchCase, fFindMatchWholeWord);
|
|
} else {
|
|
WMSG0("Unexpected find dialog activity\n");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Find the next ocurrence of the specified string.
|
|
*/
|
|
void
|
|
ViewFilesDialog::FindNext(const WCHAR* str, bool down, bool matchCase,
|
|
bool wholeWord)
|
|
{
|
|
WMSG4("FindText '%ls' d=%d c=%d w=%d\n", str, down, matchCase, wholeWord);
|
|
|
|
FINDTEXTEX findTextEx = { 0 };
|
|
CHARRANGE selChrg;
|
|
DWORD flags = 0;
|
|
long start, result;
|
|
|
|
if (matchCase)
|
|
flags |= FR_MATCHCASE;
|
|
if (wholeWord)
|
|
flags |= FR_WHOLEWORD;
|
|
|
|
fEditCtrl.GetSel(selChrg);
|
|
WMSG2(" selection is %ld,%ld\n",
|
|
selChrg.cpMin, selChrg.cpMax);
|
|
if (selChrg.cpMin == selChrg.cpMax)
|
|
start = selChrg.cpMin; // start at caret
|
|
else
|
|
start = selChrg.cpMin +1; // start past selection
|
|
|
|
findTextEx.chrg.cpMin = start;
|
|
findTextEx.chrg.cpMax = -1;
|
|
findTextEx.lpstrText = str;
|
|
|
|
/* MSVC++6 claims FindText doesn't exist, even though it's in the header */
|
|
//result = fEditCtrl.FindText(flags, &findTextEx);
|
|
result = fEditCtrl.SendMessage(EM_FINDTEXTEX, (WPARAM) flags,
|
|
(LPARAM) &findTextEx);
|
|
|
|
if (result == -1) {
|
|
/* didn't find it, wrap around to start */
|
|
findTextEx.chrg.cpMin = 0;
|
|
findTextEx.chrg.cpMax = -1;
|
|
findTextEx.lpstrText = str;
|
|
result = fEditCtrl.SendMessage(EM_FINDTEXTEX, (WPARAM) flags,
|
|
(LPARAM) &findTextEx);
|
|
}
|
|
|
|
WMSG3(" result=%ld min=%ld max=%ld\n", result,
|
|
findTextEx.chrgText.cpMin, findTextEx.chrgText.cpMax);
|
|
if (result != -1) {
|
|
/* select the text we found */
|
|
fEditCtrl.SetSel(findTextEx.chrgText);
|
|
} else {
|
|
/* remove selection, leaving caret at start of sel */
|
|
selChrg.cpMax = selChrg.cpMin;
|
|
fEditCtrl.SetSel(selChrg);
|
|
|
|
MainWindow* pMain = (MainWindow*)::AfxGetMainWnd();
|
|
pMain->FailureBeep();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* User pressed the "Help" button.
|
|
*/
|
|
void
|
|
ViewFilesDialog::OnHelp(void)
|
|
{
|
|
WinHelp(HELP_TOPIC_FILE_VIEWER, HELP_CONTEXT);
|
|
}
|