зеркало из https://github.com/mozilla/pjs.git
Adding support for new 'desktop' preferences
This commit is contained in:
Родитель
2c5b071138
Коммит
2724080b94
|
@ -1,892 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "pch.h"
|
||||
#include <assert.h>
|
||||
#include "prefpriv.h"
|
||||
#include "prefui.h"
|
||||
#include "framedlg.h"
|
||||
#include "ippageex.h"
|
||||
#include "prefuiid.h"
|
||||
#include "pagesite.h"
|
||||
#include "grayramp.h"
|
||||
#include "resource.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Helper routines
|
||||
|
||||
#ifndef _WIN32
|
||||
#define GET_WM_COMMAND_ID(wp, lp) ((int)(wp))
|
||||
#define GET_WM_COMMAND_HWND(wp, lp) ((HWND)LOWORD(lp))
|
||||
#define GET_WM_COMMAND_CMD(wp, lp) ((UINT)HIWORD(lp))
|
||||
#endif
|
||||
|
||||
static void
|
||||
ResizeChildBy(HWND hdlg, UINT nID, int dx, int dy)
|
||||
{
|
||||
RECT rect;
|
||||
HWND hwnd;
|
||||
|
||||
// Get the current rectangle
|
||||
hwnd = GetDlgItem(hdlg, nID);
|
||||
assert(hwnd != NULL);
|
||||
GetWindowRect(hwnd, &rect);
|
||||
|
||||
// Convert from screen coords to parent coordinates
|
||||
MapWindowPoints(NULL, hdlg, (LPPOINT)&rect, 2);
|
||||
|
||||
// Adjust the right and bottomn edges of the rectangle accordingly
|
||||
rect.right += dx;
|
||||
rect.bottom += dy;
|
||||
|
||||
// Set the new position
|
||||
MoveWindow(hwnd, rect.left, rect.top, rect.right - rect.left,
|
||||
rect.bottom - rect.top, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
MoveChildBy(HWND hdlg, UINT nID, int dx, int dy)
|
||||
{
|
||||
RECT rect;
|
||||
HWND hwnd;
|
||||
|
||||
// Get the current rectangle
|
||||
hwnd = GetDlgItem(hdlg, nID);
|
||||
assert(hwnd != NULL);
|
||||
GetWindowRect(hwnd, &rect);
|
||||
|
||||
// Convert from screen coords to parent coordinates
|
||||
MapWindowPoints(NULL, hdlg, (LPPOINT)&rect, 2);
|
||||
|
||||
// Offset by the delta
|
||||
OffsetRect(&rect, dx, dy);
|
||||
|
||||
// Set the new position
|
||||
MoveWindow(hwnd, rect.left, rect.top, rect.right - rect.left,
|
||||
rect.bottom - rect.top, FALSE);
|
||||
}
|
||||
|
||||
// Returns the window handle of the top-level parent/owner of the
|
||||
// specified window
|
||||
static HWND
|
||||
GetTopLevelWindow(HWND hwnd)
|
||||
{
|
||||
HWND hwndTop;
|
||||
|
||||
do {
|
||||
hwndTop = hwnd;
|
||||
hwnd = GetParent(hwnd);
|
||||
} while (hwnd != NULL);
|
||||
|
||||
return hwndTop;
|
||||
}
|
||||
|
||||
// Returns the window handle of the first-level child for the
|
||||
// specified window. As a precondition, this routine expects hchild
|
||||
// to be a child of hdlg
|
||||
static HWND
|
||||
GetFirstLevelChild(HWND hdlg, HWND hchild)
|
||||
{
|
||||
// Make sure hchild is a child of hdlg
|
||||
if (hchild == hdlg || !IsChild(hdlg, hchild))
|
||||
return NULL;
|
||||
|
||||
while (GetParent(hchild) != hdlg)
|
||||
hchild = GetParent(hchild);
|
||||
|
||||
return hchild;
|
||||
}
|
||||
|
||||
// Returns TRUE if the specified window is a dialog and FALSE otherwise
|
||||
static BOOL
|
||||
IsDialogWindow(HWND hwnd)
|
||||
{
|
||||
char szClassName[256];
|
||||
|
||||
// See if it's a dialog by checking its class name. The string
|
||||
// we're comparing against is the string name for WC_DIALOG
|
||||
if (GetClassName(hwnd, szClassName, sizeof(szClassName)) > 0) {
|
||||
if (lstrcmp(szClassName, "#32770") == 0) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Returns TRUE if the control is a push button and FALSE otherwise
|
||||
static BOOL inline
|
||||
IsPushButton(HWND hwnd)
|
||||
{
|
||||
return hwnd && (SendMessage(hwnd, WM_GETDLGCODE, 0, 0) &
|
||||
(DLGC_DEFPUSHBUTTON | DLGC_UNDEFPUSHBUTTON));
|
||||
}
|
||||
|
||||
// Finds the current default push button and removes the default
|
||||
// button style
|
||||
static void
|
||||
RemoveDefaultButton(HWND hwndDlg)
|
||||
{
|
||||
// We don't know which button is currently the default push button.
|
||||
// I suppose we could try and track it, but instead let's do like
|
||||
// everyone else does and scan through all the controls and remove
|
||||
// the default button style from any button that has it
|
||||
for (HWND hwnd = GetFirstChild(hwndDlg); hwnd; hwnd = GetNextSibling(hwnd)) {
|
||||
UINT nCode = (UINT)SendMessage(hwnd, WM_GETDLGCODE, 0, 0);
|
||||
|
||||
if (nCode & DLGC_DEFPUSHBUTTON)
|
||||
Button_SetStyle(hwnd, BS_PUSHBUTTON, TRUE);
|
||||
|
||||
else if (IsDialogWindow(hwnd))
|
||||
RemoveDefaultButton(hwnd);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the bounding rectangle of the message area in the coordinate
|
||||
// space of the dialog
|
||||
static void
|
||||
GetMessageAreaRect(HWND hwndDlg, RECT &r)
|
||||
{
|
||||
GetWindowRect(GetDlgItem(hwndDlg, IDC_MESSAGE), &r);
|
||||
MapWindowPoints(NULL, hwndDlg, (LPPOINT)&r, 2);
|
||||
}
|
||||
|
||||
// Callback function for the property frame dialog
|
||||
BOOL CALLBACK
|
||||
#ifndef _WIN32
|
||||
__export
|
||||
#endif
|
||||
DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
CPropertyFrameDialog *pDialog;
|
||||
PAINTSTRUCT paint;
|
||||
LPNMHDR lpnmh;
|
||||
|
||||
if (uMsg == WM_INITDIALOG) {
|
||||
// The lParam is the "this" pointer. Save it away
|
||||
SetWindowLong(hwndDlg, DWL_USER, (LONG)lParam);
|
||||
return ((CPropertyFrameDialog *)lParam)->InitDialog(hwndDlg);
|
||||
}
|
||||
|
||||
// Get the "this" pointer
|
||||
pDialog = (CPropertyFrameDialog*)GetWindowLong(hwndDlg, DWL_USER);
|
||||
|
||||
switch (uMsg) {
|
||||
case WM_COMMAND:
|
||||
return pDialog->OnCommand(GET_WM_COMMAND_ID(wParam, lParam),
|
||||
GET_WM_COMMAND_HWND(wParam, lParam),
|
||||
GET_WM_COMMAND_CMD(wParam, lParam));
|
||||
|
||||
case WM_PAINT:
|
||||
BeginPaint(hwndDlg, &paint);
|
||||
pDialog->OnPaint(paint.hdc);
|
||||
EndPaint(hwndDlg, &paint);
|
||||
return TRUE;
|
||||
|
||||
case WM_NOTIFY:
|
||||
lpnmh = (LPNMHDR)lParam;
|
||||
|
||||
if (lpnmh->idFrom == IDC_TREE && lpnmh->code == TVN_SELCHANGED)
|
||||
pDialog->TreeViewSelChanged((LPNM_TREEVIEW)lpnmh);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CPropertyFrameDialog implementation
|
||||
|
||||
// Constructor
|
||||
CPropertyFrameDialog::CPropertyFrameDialog(HWND hwndOwner,
|
||||
int x,
|
||||
int y,
|
||||
LPCSTR lpszCaption,
|
||||
NETHELPFUNC lpfnNetHelp)
|
||||
{
|
||||
m_hdlg = NULL;
|
||||
m_hwndOwner = hwndOwner;
|
||||
m_x = x;
|
||||
m_y = y;
|
||||
m_lpszCaption = lpszCaption;
|
||||
m_lpfnNetHelp = lpfnNetHelp;
|
||||
m_nInitialCategory = 0;
|
||||
m_pCurPage = NULL;
|
||||
m_hBoldFont = NULL;
|
||||
m_lpGradient = NULL;
|
||||
m_hBrush = NULL;
|
||||
}
|
||||
|
||||
CPropertyFrameDialog::~CPropertyFrameDialog()
|
||||
{
|
||||
if (m_hBoldFont)
|
||||
DeleteObject(m_hBoldFont);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (m_lpGradient)
|
||||
HeapFree(GetProcessHeap(), 0, m_lpGradient);
|
||||
#else
|
||||
assert(!m_lpGradient);
|
||||
#endif
|
||||
|
||||
if (m_hBrush)
|
||||
DeleteBrush(m_hBrush);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
CPropertyFrameDialog::CreatePages(ULONG nCategories,
|
||||
LPSPECIFYPROPERTYPAGEOBJECTS *lplpProviders,
|
||||
ULONG nInitialCategory)
|
||||
{
|
||||
CPropertyPageSite *pSite;
|
||||
HRESULT hres;
|
||||
|
||||
assert(nInitialCategory < nCategories);
|
||||
if (nInitialCategory >= nCategories)
|
||||
return ResultFromScode(E_INVALIDARG);
|
||||
|
||||
// Allocate a page site. Rather than create one page site per property
|
||||
// page, we create one that they all share
|
||||
pSite = new CPropertyPageSite(this);
|
||||
if (!pSite)
|
||||
return ResultFromScode(E_OUTOFMEMORY);
|
||||
|
||||
pSite->AddRef();
|
||||
hres = m_categories.Initialize(nCategories, lplpProviders, pSite);
|
||||
pSite->Release();
|
||||
|
||||
// Remember this for when we're displayed
|
||||
m_nInitialCategory = nInitialCategory;
|
||||
return hres;
|
||||
}
|
||||
|
||||
BOOL
|
||||
CPropertyFrameDialog::InitDialog(HWND hdlg)
|
||||
{
|
||||
HFONT hFont;
|
||||
LOGFONT font;
|
||||
HWND hwnd;
|
||||
|
||||
// Save away the window handle for the dialog
|
||||
m_hdlg = hdlg;
|
||||
|
||||
// Get the bold font we will be using. It's the same font as the
|
||||
// dialog box uses, except it's bold
|
||||
hFont = GetWindowFont(m_hdlg);
|
||||
GetObject(hFont, sizeof(font), &font);
|
||||
font.lfWeight = FW_BOLD;
|
||||
m_hBoldFont = CreateFontIndirect(&font);
|
||||
assert(m_hBoldFont);
|
||||
|
||||
// Add each page to the tree view
|
||||
FillTreeView();
|
||||
|
||||
// Size to fit the property frame dialog based on the size of the pages.
|
||||
// This routine also calculates the rectangle where the property page
|
||||
// will be displayed
|
||||
SizeToFit();
|
||||
|
||||
// See how many colors the device has
|
||||
HDC hdc = GetDC(hdlg);
|
||||
|
||||
if (GetDeviceCaps(hdc, BITSPIXEL) == 8) {
|
||||
// Use the "medium gray" SVGA color
|
||||
m_hBrush = CreateSolidBrush(PALETTERGB(160,160,164));
|
||||
|
||||
} else if (GetDeviceCaps(hdc, BITSPIXEL) > 8) {
|
||||
#ifdef _WIN32
|
||||
RECT rect;
|
||||
|
||||
// Create a gray scale ramp
|
||||
GetMessageAreaRect(m_hdlg, rect);
|
||||
m_lpGradient = MakeGrayScaleRamp(rect.right - rect.left, rect.bottom - rect.top);
|
||||
#else
|
||||
m_hBrush = CreateSolidBrush(RGB(160,160,160));
|
||||
#endif
|
||||
}
|
||||
|
||||
ReleaseDC(hdlg, hdc);
|
||||
|
||||
// Make sure the first category is open
|
||||
hwnd = GetDlgItem(m_hdlg, IDC_TREE);
|
||||
TreeView_Expand(hwnd, m_categories[0][0].m_hitem, TVE_EXPAND);
|
||||
|
||||
// Select the first item of the category that we should initially
|
||||
// display. Make sure the category is expanded as well
|
||||
TreeView_SelectItem(hwnd, m_categories[m_nInitialCategory][0].m_hitem);
|
||||
TreeView_Expand(hwnd, m_categories[m_nInitialCategory][0].m_hitem, TVE_EXPAND);
|
||||
|
||||
// Give the focus to the property page
|
||||
SetFocus(GetPropertyPageWindow());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Returns the dimensions of the widest and highest page
|
||||
SIZE
|
||||
CPropertyFrameDialog::GetMaxPageSize()
|
||||
{
|
||||
SIZE size = {0, 0};
|
||||
|
||||
for (ULONG i = 0; i < m_categories.m_nCategories; i++) {
|
||||
for (ULONG j = 0; j < m_categories[i].m_nPages; j++) {
|
||||
CPropertyPage &page = m_categories[i][j];
|
||||
|
||||
if (page.m_size.cx > size.cx)
|
||||
size.cx = page.m_size.cx;
|
||||
if (page.m_size.cy > size.cy)
|
||||
size.cy = page.m_size.cy;
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// Size to fit the property frame dialog based on the widest/highest
|
||||
// property page
|
||||
void
|
||||
CPropertyFrameDialog::SizeToFit()
|
||||
{
|
||||
SIZE curSize, maxSize, deltaSize;
|
||||
RECT clientRect, treeRect, msgRect, rect;
|
||||
|
||||
// Figure out the widest and highest page sizes
|
||||
maxSize = GetMaxPageSize();
|
||||
|
||||
// Compute how much room there currently is for the property page.
|
||||
//
|
||||
// We compute the vertical space as the distance between the bottom of
|
||||
// the tree view and the bottom of the message area, and we compute the
|
||||
// horizontal space as the distance between the right edge of the frame
|
||||
// dialog and the right edge of the text view
|
||||
GetClientRect(m_hdlg, &clientRect);
|
||||
GetWindowRect(GetDlgItem(m_hdlg, IDC_TREE), &treeRect);
|
||||
MapWindowPoints(NULL, m_hdlg, (LPPOINT)&treeRect, 2);
|
||||
GetMessageAreaRect(m_hdlg, msgRect);
|
||||
|
||||
curSize.cx = clientRect.right - treeRect.right;
|
||||
#ifndef _WIN32
|
||||
// Ctl3d draws part of its border outside of the window
|
||||
curSize.cx--;
|
||||
#endif
|
||||
curSize.cy = treeRect.bottom - msgRect.bottom;
|
||||
|
||||
// Determine how much we need to resize the window
|
||||
deltaSize.cx = maxSize.cx - curSize.cx;
|
||||
deltaSize.cy = maxSize.cy - curSize.cy;
|
||||
|
||||
// Resize the dialog
|
||||
GetWindowRect(m_hdlg, &rect);
|
||||
SetWindowPos(m_hdlg, NULL, 0, 0, rect.right - rect.left + deltaSize.cx,
|
||||
rect.bottom - rect.top + deltaSize.cy, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
|
||||
|
||||
// Resize the right edge of the message area
|
||||
ResizeChildBy(m_hdlg, IDC_MESSAGE, deltaSize.cx, 0);
|
||||
|
||||
// Resize the height of the tree view
|
||||
ResizeChildBy(m_hdlg, IDC_TREE, 0, deltaSize.cy);
|
||||
|
||||
// And reposition the buttons
|
||||
MoveChildBy(m_hdlg, IDOK, deltaSize.cx, deltaSize.cy);
|
||||
MoveChildBy(m_hdlg, IDCANCEL, deltaSize.cx, deltaSize.cy);
|
||||
MoveChildBy(m_hdlg, IDHELP, deltaSize.cx, deltaSize.cy);
|
||||
|
||||
// Update the property page rectangle
|
||||
m_pageRect.left = treeRect.right;
|
||||
#ifndef _WIN32
|
||||
// Ctl3d draws part of its border outside of the window
|
||||
m_pageRect.left++;
|
||||
#endif
|
||||
m_pageRect.top = msgRect.bottom;
|
||||
m_pageRect.right = m_pageRect.left + maxSize.cx;
|
||||
m_pageRect.bottom = m_pageRect.top + maxSize.cy;
|
||||
}
|
||||
|
||||
void
|
||||
CPropertyFrameDialog::FillTreeView()
|
||||
{
|
||||
HWND hwnd;
|
||||
|
||||
// Get the HWND for the tree view
|
||||
hwnd = GetDlgItem(m_hdlg, IDC_TREE);
|
||||
assert(hwnd != NULL);
|
||||
|
||||
for (ULONG i = 0; i < m_categories.m_nCategories; i++) {
|
||||
for (ULONG j = 0; j < m_categories[i].m_nPages; j++) {
|
||||
CPropertyPage &page = m_categories[i][j];
|
||||
TV_INSERTSTRUCT tvis;
|
||||
|
||||
// Add it to the outliner
|
||||
memset(&tvis.item, 0, sizeof(tvis.item));
|
||||
|
||||
if (j == 0) {
|
||||
// Insert this item at the root of the tree view
|
||||
tvis.hParent = NULL;
|
||||
tvis.item.cChildren = m_categories[i].m_nPages > 1 ? 1 : 0;
|
||||
} else {
|
||||
// Make this item a child of the category
|
||||
tvis.hParent = m_categories[i][0].m_hitem;
|
||||
}
|
||||
|
||||
tvis.hInsertAfter = TVI_LAST;
|
||||
tvis.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_CHILDREN;
|
||||
tvis.item.pszText = (LPSTR)page.m_lpszTitle;
|
||||
tvis.item.lParam = (LPARAM)&page;
|
||||
page.m_hitem = TreeView_InsertItem(hwnd, &tvis);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOL
|
||||
CPropertyFrameDialog::OnCommand(int id, HWND hwndCtl, UINT notifyCode)
|
||||
{
|
||||
ULONG i, j;
|
||||
|
||||
switch (id) {
|
||||
case IDOK:
|
||||
m_nModalResult = TRUE;
|
||||
m_bKeepGoing = FALSE;
|
||||
|
||||
// Ask each property page that's dirty to apply its changes
|
||||
for (i = 0; i < m_categories.m_nCategories; i++) {
|
||||
for (j = 0; j < m_categories[i].m_nPages; j++) {
|
||||
CPropertyPage &page = m_categories[i][j];
|
||||
|
||||
if (page.m_pPage->IsPageDirty() == S_OK) {
|
||||
// We must call the SetObjects method first. Note that we have
|
||||
// aleady done this for the current page so shouldn't do it again
|
||||
if (&page != m_pCurPage)
|
||||
page.m_pPage->SetObjects(1, (LPUNKNOWN *)&page.m_pCategory->m_pProvider);
|
||||
page.m_pPage->Apply();
|
||||
if (&page != m_pCurPage)
|
||||
page.m_pPage->SetObjects(0, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
case IDCANCEL:
|
||||
m_nModalResult = FALSE;
|
||||
m_bKeepGoing = FALSE;
|
||||
return TRUE;
|
||||
|
||||
case IDHELP:
|
||||
if (m_lpfnNetHelp) {
|
||||
if (m_pCurPage && m_pCurPage->m_lpszHelpTopic)
|
||||
m_lpfnNetHelp(m_pCurPage->m_lpszHelpTopic);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
CPropertyFrameDialog::OnPaint(HDC hdc)
|
||||
{
|
||||
RECT rect;
|
||||
|
||||
// Paint the gray background for the message area
|
||||
GetMessageAreaRect(m_hdlg, rect);
|
||||
|
||||
if (m_lpGradient)
|
||||
#ifdef _WIN32
|
||||
StretchDIBits(hdc, rect.left, rect.top, m_lpGradient->biWidth,
|
||||
rect.bottom - rect.top, 0, 0, m_lpGradient->biWidth, rect.bottom - rect.top,
|
||||
(LPSTR)m_lpGradient + m_lpGradient->biSize, (LPBITMAPINFO)m_lpGradient,
|
||||
DIB_RGB_COLORS, SRCCOPY);
|
||||
#else
|
||||
assert(FALSE);
|
||||
#endif
|
||||
else if (m_hBrush)
|
||||
FillRect(hdc, &rect, m_hBrush);
|
||||
else
|
||||
FillRect(hdc, &rect, (HBRUSH)GetStockObject(GRAY_BRUSH));
|
||||
|
||||
// Display the title and description
|
||||
if (m_pCurPage) {
|
||||
int nOldBkMode = SetBkMode(hdc, TRANSPARENT);
|
||||
HFONT hOldFont;
|
||||
|
||||
// Leave a margin of 7 pixels on the left and right
|
||||
rect.left += 7;
|
||||
rect.right -= 7;
|
||||
|
||||
// Use our bold font for the title
|
||||
hOldFont = SelectFont(hdc, m_hBoldFont);
|
||||
|
||||
if (m_pCurPage->m_lpszTitle) {
|
||||
DrawText(hdc, m_pCurPage->m_lpszTitle, -1, &rect,
|
||||
DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
|
||||
}
|
||||
|
||||
// Use the dialog font for the description
|
||||
SelectFont(hdc, GetWindowFont(m_hdlg));
|
||||
|
||||
if (m_pCurPage->m_lpszDescription) {
|
||||
DrawText(hdc, m_pCurPage->m_lpszDescription, -1, &rect,
|
||||
DT_RIGHT|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
|
||||
}
|
||||
|
||||
// Restore the HDC
|
||||
SetBkMode(hdc, nOldBkMode);
|
||||
SelectFont(hdc, hOldFont);
|
||||
}
|
||||
}
|
||||
|
||||
// Responds to the tree-view TVN_SELCHANGED notification message informing the
|
||||
// tree-view control's parent window that the selection has changed from one
|
||||
// item to another
|
||||
void
|
||||
CPropertyFrameDialog::TreeViewSelChanged(LPNM_TREEVIEW pnmtv)
|
||||
{
|
||||
CPropertyPage *pNewPage;
|
||||
|
||||
if (m_pCurPage)
|
||||
assert((CPropertyPage *)pnmtv->itemOld.lParam == m_pCurPage);
|
||||
|
||||
pNewPage = (CPropertyPage *)pnmtv->itemNew.lParam;
|
||||
assert(pNewPage);
|
||||
|
||||
if (pNewPage != m_pCurPage) {
|
||||
HRESULT hres;
|
||||
|
||||
// See if the current page wants to be queried about the page change
|
||||
if (m_pCurPage) {
|
||||
LPPROPERTYPAGEEX lpPageEx;
|
||||
|
||||
// See if it supports the IPropertyPageEx interface
|
||||
hres = m_pCurPage->m_pPage->QueryInterface(IID_IPropertyPageEx, (void **)&lpPageEx);
|
||||
if (SUCCEEDED(hres)) {
|
||||
BOOL bCanChange = lpPageEx->PageChanging(pNewPage->m_pPage) == S_OK;
|
||||
|
||||
lpPageEx->Release();
|
||||
if (!bCanChange)
|
||||
return; // current page is preventing the activation
|
||||
}
|
||||
}
|
||||
|
||||
// Activate the new page. First we need to provide it with the
|
||||
// preferences provider object
|
||||
assert(pNewPage->m_pCategory);
|
||||
hres = pNewPage->m_pPage->SetObjects(1, (LPUNKNOWN *)&pNewPage->m_pCategory->m_pProvider);
|
||||
assert(SUCCEEDED(hres));
|
||||
|
||||
// Now activate the page
|
||||
hres = pNewPage->m_pPage->Activate(m_hdlg, &m_pageRect, TRUE);
|
||||
assert(SUCCEEDED(hres));
|
||||
|
||||
if (SUCCEEDED(hres)) {
|
||||
// Deactivate the old page
|
||||
if (m_pCurPage) {
|
||||
// Ask the old page to release its pointer
|
||||
hres = m_pCurPage->m_pPage->SetObjects(0, NULL);
|
||||
assert(SUCCEEDED(hres));
|
||||
|
||||
// Deactivate the page
|
||||
hres = m_pCurPage->m_pPage->Deactivate();
|
||||
assert(SUCCEEDED(hres));
|
||||
}
|
||||
|
||||
// Remember the new page
|
||||
m_pCurPage = pNewPage;
|
||||
|
||||
// Update the message are
|
||||
HDC hdc = GetDC(m_hdlg);
|
||||
|
||||
OnPaint(hdc);
|
||||
ReleaseDC(m_hdlg, hdc);
|
||||
|
||||
} else {
|
||||
// We failed to activate the new page. Revoke the interface pointer
|
||||
// we passed it
|
||||
pNewPage->m_pPage->SetObjects(0, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Called by the property page site to give the property frame a chance
|
||||
// to translate accelerators
|
||||
HRESULT
|
||||
CPropertyFrameDialog::TranslateAccelerator(LPMSG lpMsg)
|
||||
{
|
||||
return IsDialogMessage(m_hdlg, lpMsg) ? ResultFromScode(S_OK) : ResultFromScode(S_FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
CPropertyFrameDialog::CheckDefPushButton(HWND hwndOldFocus, HWND hwndNewFocus)
|
||||
{
|
||||
// Do nothing if the same control
|
||||
if (hwndNewFocus == hwndOldFocus)
|
||||
return;
|
||||
|
||||
// Make sure the focus still belongs to us
|
||||
if (!IsChild(m_hdlg, hwndNewFocus))
|
||||
return;
|
||||
|
||||
// If either the old or new focus windows is a pushbutton then remove
|
||||
// the default button style from the current default button
|
||||
if (IsPushButton(hwndOldFocus) || IsPushButton(hwndNewFocus))
|
||||
RemoveDefaultButton(m_hdlg);
|
||||
|
||||
// If moving to a button make it be the default button
|
||||
if (IsPushButton(hwndNewFocus))
|
||||
Button_SetStyle(hwndNewFocus, BS_DEFPUSHBUTTON, TRUE);
|
||||
|
||||
else {
|
||||
// Make the original default button be the default button
|
||||
LRESULT lResult = (int)SendMessage(m_hdlg, DM_GETDEFID, 0, 0);
|
||||
int nID = HIWORD(lResult) == DC_HASDEFID ? LOWORD(lResult) : IDOK;
|
||||
HWND hwnd = GetDlgItem(m_hdlg, nID);
|
||||
|
||||
if (IsWindowEnabled(hwnd))
|
||||
Button_SetStyle(hwnd, BS_DEFPUSHBUTTON, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
HWND
|
||||
CPropertyFrameDialog::GetPropertyPageWindow()
|
||||
{
|
||||
for (HWND hwnd = GetFirstChild(m_hdlg); hwnd; hwnd = GetNextSibling(hwnd)) {
|
||||
if (IsDialogWindow(hwnd))
|
||||
return hwnd;
|
||||
}
|
||||
|
||||
assert(FALSE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
IsHelpKey(LPMSG lpMsg)
|
||||
{
|
||||
// return TRUE only for non-repeat F1 keydowns.
|
||||
return lpMsg->message == WM_KEYDOWN &&
|
||||
lpMsg->wParam == VK_F1 &&
|
||||
!(HIWORD(lpMsg->lParam) & KF_REPEAT) &&
|
||||
GetKeyState(VK_SHIFT) >= 0 &&
|
||||
GetKeyState(VK_CONTROL) >= 0 &&
|
||||
GetKeyState(VK_MENU) >= 0;
|
||||
}
|
||||
|
||||
// Returns TRUE if either the property page or the property frame dialog translated
|
||||
// the message and FALSE otherwise. If this routine returns TRUE then the message
|
||||
// must not be translated/dispatched
|
||||
BOOL
|
||||
CPropertyFrameDialog::PreTranslateMessage(LPMSG lpMsg)
|
||||
{
|
||||
// This routine does two things:
|
||||
// - manage the default push button
|
||||
// - where appropriate forward WM_SYSCHAR messages (keyboard mnemonics) to the
|
||||
// property page for translating
|
||||
//
|
||||
// Here's how it works. Both the property page and the property frame may be
|
||||
// involved in translating the message. Who gets first crack at it depends on
|
||||
// the message hwnd. There are two scearios:
|
||||
//
|
||||
// 1. the message hwnd is the property page or one of its children
|
||||
// 2. the message hwnd is not the property page or one of its children
|
||||
//
|
||||
// In scenario #1 the property page gets first crack at translating the message,
|
||||
// and if it didn't translate it then the property frame gets to translate it
|
||||
//
|
||||
// In scenario #2, if the message is a Tab/Shift-Tab and the property page is
|
||||
// the control that would receive focus, then it gets first crack at the message.
|
||||
// Otherwise, the property frame gets first crack at translating the message. If
|
||||
// the message is a WM_SYSCHAR and the property frame didn't translate it then the
|
||||
// message is forwarded to the property page for forwarding
|
||||
if (lpMsg->hwnd != m_hdlg && !IsChild(m_hdlg, lpMsg->hwnd))
|
||||
return FALSE;
|
||||
|
||||
// Translate accelerators. The only accelerator we handle is for bringing up the help
|
||||
// window
|
||||
if (IsHelpKey(lpMsg)) {
|
||||
FORWARD_WM_COMMAND(m_hdlg, IDHELP, 0, 0, SendMessage);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
HWND hwndFocus = GetFocus(); // remember this for later
|
||||
BOOL bHandled = FALSE;
|
||||
|
||||
// See whether the message is targeted for the property page
|
||||
HWND hwnd = GetFirstLevelChild(m_hdlg, lpMsg->hwnd);
|
||||
|
||||
if (hwnd && IsDialogWindow(hwnd)) {
|
||||
// Scenario #1. Let the property page have the first chance at
|
||||
// translating the accelerator
|
||||
//
|
||||
// Note that under certain circumstances the property page will
|
||||
// call the property page site and ask it to translate the message
|
||||
assert(m_pCurPage);
|
||||
bHandled = m_pCurPage->m_pPage->TranslateAccelerator(lpMsg) == S_OK;
|
||||
|
||||
if (!bHandled) {
|
||||
// Give the property frame a chance to translate the message
|
||||
bHandled = TranslateAccelerator(lpMsg) == S_OK;
|
||||
}
|
||||
|
||||
} else {
|
||||
// If the message is a WM_KEYDOWN of a Tab character and the property page
|
||||
// is going to become the focus window, then give it a chance to handle the
|
||||
// Tab. This gives it an opportunity to handle Shift-Tab by selecting the
|
||||
// last control in the tab order
|
||||
if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam == VK_TAB) {
|
||||
HWND hNewFocus = GetNextDlgTabItem(m_hdlg, hwndFocus, GetKeyState(VK_SHIFT) < 0);
|
||||
|
||||
if (IsDialogWindow(hNewFocus)) {
|
||||
// Give the property page a chance to translate the message
|
||||
assert(m_pCurPage);
|
||||
bHandled = m_pCurPage->m_pPage->TranslateAccelerator(lpMsg) == S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// Have the property frame translate the message
|
||||
if (!bHandled) {
|
||||
bHandled = TranslateAccelerator(lpMsg) == S_OK;
|
||||
|
||||
// If the message is a WM_SYSCHAR and the property frame didn't handle it,
|
||||
// we need to give the property page a chance.
|
||||
//
|
||||
// Unfortunately IsDialogMessage() returns TRUE for all WM_SYSCHAR messages
|
||||
// regardless of whether there was a matching mnemonic (it does this because
|
||||
// it calls DefWindowProc() so it can check for matching menu bar mnemonics and
|
||||
// it has no idea whether DefWindowProc() found a match)
|
||||
if (lpMsg->message == WM_SYSCHAR) {
|
||||
// See if the focus window has changed. If it has, then IsDialogMessage()
|
||||
// found a control that matched the mnemonic. Don't do this if it was for
|
||||
// the system menu though
|
||||
if (lpMsg->wParam != VK_SPACE && GetFocus() == hwndFocus) {
|
||||
// Didn't change the focus so there was not a matching mnemonic. Let
|
||||
// the property page translate it
|
||||
//
|
||||
// Temporarily change the hwnd to be the first child of the property page
|
||||
HWND hwndPage = GetPropertyPageWindow();
|
||||
|
||||
if (hwndPage) {
|
||||
HWND hwndSave = lpMsg->hwnd;
|
||||
|
||||
lpMsg->hwnd = GetFirstChild(hwndPage);
|
||||
bHandled = m_pCurPage->m_pPage->TranslateAccelerator(lpMsg) == S_OK;
|
||||
lpMsg->hwnd = hwndSave;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check the default push button
|
||||
if (hwndFocus)
|
||||
CheckDefPushButton(hwndFocus, GetFocus());
|
||||
|
||||
return bHandled;
|
||||
}
|
||||
|
||||
int
|
||||
CPropertyFrameDialog::RunModalLoop()
|
||||
{
|
||||
MSG msg;
|
||||
|
||||
if (m_hdlg == NULL)
|
||||
return -1;
|
||||
|
||||
assert(IsWindowVisible(m_hdlg));
|
||||
|
||||
for (;;) {
|
||||
// Check if we should send an idle message
|
||||
if (m_hwndOwner && !::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE)) {
|
||||
// Send WM_ENTERIDLE to the owner
|
||||
SendMessage(m_hwndOwner, WM_ENTERIDLE, MSGF_DIALOGBOX, (LPARAM)m_hdlg);
|
||||
}
|
||||
|
||||
// Pump the messages
|
||||
do {
|
||||
if (!GetMessage(&msg, NULL, NULL, NULL)) {
|
||||
// Repost the WM_QUIT message
|
||||
PostQuitMessage(msg.wParam);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// See if the message should be handled at all
|
||||
if (!CallMsgFilter(&msg, MSGF_DIALOGBOX)) {
|
||||
// Give the property page and the property frame dialog a chance to
|
||||
// translate the message
|
||||
if (!PreTranslateMessage(&msg)) {
|
||||
// No one wanted it so dispatch the message
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we should exit the modal loop
|
||||
if (!m_bKeepGoing)
|
||||
return m_nModalResult;
|
||||
|
||||
// If there's another message waiting then keep pumping; otherwise go back
|
||||
// to the top of the for loop and send another idle message before
|
||||
// calling GetMessage again
|
||||
} while (PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE));
|
||||
}
|
||||
|
||||
return m_nModalResult;
|
||||
}
|
||||
|
||||
int
|
||||
CPropertyFrameDialog::DoModal()
|
||||
{
|
||||
BOOL bEnableOwner = FALSE;
|
||||
int nResult;
|
||||
|
||||
// Make sure the parent window isn't a child window. You can't really have
|
||||
// a popup window owned by a child window
|
||||
if (m_hwndOwner && (GetWindowStyle(m_hwndOwner) & WS_CHILD))
|
||||
m_hwndOwner = GetTopLevelWindow(m_hwndOwner);
|
||||
|
||||
// Disable the parent window if necessary
|
||||
if (m_hwndOwner != NULL && IsWindowEnabled(m_hwndOwner)) {
|
||||
EnableWindow(m_hwndOwner, FALSE);
|
||||
bEnableOwner = TRUE;
|
||||
}
|
||||
|
||||
// Display the dialog
|
||||
CreateDialogParam(g_hInstance, MAKEINTRESOURCE(IDD_FRAME), m_hwndOwner,
|
||||
(DLGPROC)DialogProc, (LPARAM)this);
|
||||
|
||||
// Run a dispatch loop so we don't return until the dialog is closed
|
||||
m_bKeepGoing = TRUE;
|
||||
nResult = RunModalLoop();
|
||||
|
||||
// Hide our dialog before enabling the parent window
|
||||
SetWindowPos(m_hdlg, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|
|
||||
SWP_NOACTIVATE|SWP_NOZORDER);
|
||||
|
||||
if (bEnableOwner)
|
||||
EnableWindow(m_hwndOwner, TRUE);
|
||||
|
||||
// We don't want to be the active window
|
||||
if (m_hwndOwner && GetActiveWindow() == m_hdlg)
|
||||
SetActiveWindow(m_hwndOwner);
|
||||
|
||||
// Cleanup
|
||||
if (m_pCurPage)
|
||||
m_pCurPage->m_pPage->SetObjects(0, NULL);
|
||||
DestroyWindow(m_hdlg);
|
||||
|
||||
return nResult;
|
||||
}
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef __FRAMEDLG_H_
|
||||
#define __FRAMEDLG_H_
|
||||
|
||||
class CPPropertyPage;
|
||||
|
||||
class CPropertyFrameDialog {
|
||||
public:
|
||||
CPropertyFrameDialog(HWND hwndOwner,
|
||||
int x,
|
||||
int y,
|
||||
LPCSTR lpszCaption,
|
||||
NETHELPFUNC lpfnNetHelp);
|
||||
~CPropertyFrameDialog();
|
||||
|
||||
// Initialization
|
||||
HRESULT CreatePages(ULONG nCategories,
|
||||
LPSPECIFYPROPERTYPAGEOBJECTS *lplpProviders,
|
||||
ULONG nInitialCategory);
|
||||
|
||||
// Modal processing
|
||||
int DoModal();
|
||||
|
||||
// Event processing
|
||||
BOOL InitDialog(HWND hdlg);
|
||||
BOOL OnCommand(int id, HWND hwndCtl, UINT notifyCode);
|
||||
void OnPaint(HDC);
|
||||
void TreeViewSelChanged(LPNM_TREEVIEW);
|
||||
|
||||
// Called by the property page site to give the property frame
|
||||
// a chance to translate accelerators
|
||||
HRESULT TranslateAccelerator(LPMSG);
|
||||
|
||||
protected:
|
||||
int RunModalLoop();
|
||||
|
||||
private:
|
||||
HWND m_hdlg;
|
||||
HWND m_hwndOwner;
|
||||
int m_x, m_y;
|
||||
LPCSTR m_lpszCaption;
|
||||
ULONG m_nInitialCategory;
|
||||
CPropertyCategories m_categories;
|
||||
CPropertyPage *m_pCurPage;
|
||||
BOOL m_bKeepGoing;
|
||||
int m_nModalResult;
|
||||
RECT m_pageRect;
|
||||
HFONT m_hBoldFont;
|
||||
LPBITMAPINFOHEADER m_lpGradient;
|
||||
HBRUSH m_hBrush;
|
||||
NETHELPFUNC m_lpfnNetHelp;
|
||||
|
||||
// Helper routines
|
||||
void FillTreeView();
|
||||
void SizeToFit();
|
||||
SIZE GetMaxPageSize();
|
||||
HWND GetPropertyPageWindow();
|
||||
BOOL PreTranslateMessage(LPMSG);
|
||||
void CheckDefPushButton(HWND, HWND);
|
||||
};
|
||||
|
||||
#endif /* __FRAMEDLG_H_ */
|
||||
|
|
@ -1,388 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "pch.h"
|
||||
#include <assert.h>
|
||||
#include "prefui.h"
|
||||
#include "prefpriv.h"
|
||||
#include "framedlg.h"
|
||||
|
||||
HINSTANCE g_hInstance;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Global new/delete operators
|
||||
|
||||
void *
|
||||
operator new (size_t size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
|
||||
#else
|
||||
return (void *)(void NEAR *)LocalAlloc(LPTR, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
operator delete (void *lpMem)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
HeapFree(GetProcessHeap(), 0, lpMem);
|
||||
#else
|
||||
LocalFree((HLOCAL)OFFSETOF(lpMem));
|
||||
#endif
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Helper routines
|
||||
|
||||
#ifndef _WIN32
|
||||
static LPVOID
|
||||
CoTaskMemAlloc(ULONG cb)
|
||||
{
|
||||
LPMALLOC pMalloc;
|
||||
|
||||
if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pMalloc))) {
|
||||
LPVOID pv;
|
||||
|
||||
pv = pMalloc->Alloc(cb);
|
||||
pMalloc->Release();
|
||||
return pv;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
CoTaskMemFree(LPVOID pv)
|
||||
{
|
||||
if (pv) {
|
||||
LPMALLOC pMalloc;
|
||||
|
||||
if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pMalloc))) {
|
||||
pMalloc->Free(pv);
|
||||
pMalloc->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Converts an OLE string (UNICODE) to an ANSI string. The caller
|
||||
// must use CoTaskMemFree to free the memory
|
||||
static LPSTR
|
||||
AllocTaskAnsiString(LPOLESTR lpszString)
|
||||
{
|
||||
LPSTR lpszResult;
|
||||
UINT nBytes;
|
||||
|
||||
if (lpszString == NULL)
|
||||
return NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
nBytes = (wcslen(lpszString) + 1) * 2;
|
||||
#else
|
||||
nBytes = lstrlen(lpszString) + 1; // Win 16 doesn't use any UNICODE
|
||||
#endif
|
||||
lpszResult = (LPSTR)CoTaskMemAlloc(nBytes);
|
||||
|
||||
if (lpszResult) {
|
||||
#ifdef _WIN32
|
||||
WideCharToMultiByte(CP_ACP, 0, lpszString, -1, lpszResult, nBytes, NULL, NULL);
|
||||
#else
|
||||
lstrcpy(lpszResult, lpszString);
|
||||
#endif
|
||||
}
|
||||
|
||||
return lpszResult;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CPropertyCategories implementation
|
||||
|
||||
// Destructor. Release all the interface pointers and free the
|
||||
// counted arrays
|
||||
CPropertyCategories::~CPropertyCategories()
|
||||
{
|
||||
delete []m_pCategories;
|
||||
}
|
||||
|
||||
// Create the individual property pages for each of the
|
||||
// property categories
|
||||
HRESULT
|
||||
CPropertyCategories::Initialize(ULONG nCategories,
|
||||
LPSPECIFYPROPERTYPAGEOBJECTS *lplpProviders,
|
||||
LPPROPERTYPAGESITE pSite)
|
||||
{
|
||||
m_nCategories = nCategories;
|
||||
m_pCategories = new CPropertyCategory[nCategories];
|
||||
if (!m_pCategories)
|
||||
return ResultFromScode(E_OUTOFMEMORY);
|
||||
|
||||
for (ULONG i = 0; i < nCategories; i++) {
|
||||
HRESULT hres = m_pCategories[i].CreatePages(lplpProviders[i], pSite);
|
||||
|
||||
if (FAILED(hres))
|
||||
return hres;
|
||||
}
|
||||
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CPropertyCategory implementation
|
||||
|
||||
// Releases the reference to the interface for the property page provider,
|
||||
// and destroys each of the property pages objects
|
||||
CPropertyCategory::~CPropertyCategory()
|
||||
{
|
||||
delete []m_pPages;
|
||||
if (m_pProvider)
|
||||
m_pProvider->Release();
|
||||
}
|
||||
|
||||
// Gets the list of property page obejcts and initializes each of the pages
|
||||
HRESULT
|
||||
CPropertyCategory::CreatePages(LPSPECIFYPROPERTYPAGEOBJECTS pProvider,
|
||||
LPPROPERTYPAGESITE pSite)
|
||||
{
|
||||
CAPPAGE pages;
|
||||
HRESULT hres;
|
||||
|
||||
// Keep the pointer to the property page provider. This is passed
|
||||
// as the data object for each property page
|
||||
m_pProvider = pProvider;
|
||||
m_pProvider->AddRef();
|
||||
|
||||
// Get the list of property pages objects
|
||||
hres = pProvider->GetPageObjects(&pages);
|
||||
#ifdef _DEBUG
|
||||
if (FAILED(hres)) {
|
||||
OutputDebugString("Call to GetPageObjects() failed for property page provider\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (SUCCEEDED(hres)) {
|
||||
m_pPages = new CPropertyPage[pages.cElems];
|
||||
if (!m_pPages) {
|
||||
for (ULONG i = 0; i < pages.cElems; i++)
|
||||
pages.pElems[i]->Release();
|
||||
CoTaskMemFree(pages.pElems);
|
||||
return ResultFromScode(E_OUTOFMEMORY);
|
||||
}
|
||||
|
||||
// Initialize the array of property pages
|
||||
m_nPages = 0;
|
||||
for (ULONG i = 0; i < pages.cElems; i++) {
|
||||
LPPROPERTYPAGE pPage = pages.pElems[m_nPages];
|
||||
|
||||
// Set the back pointer
|
||||
m_pPages[m_nPages].m_pCategory = this;
|
||||
|
||||
// Initialize the property page
|
||||
hres = m_pPages[m_nPages].Initialize(pPage, pSite);
|
||||
|
||||
// We're all done with the page
|
||||
pPage->Release();
|
||||
m_nPages++;
|
||||
}
|
||||
|
||||
CoTaskMemFree(pages.pElems);
|
||||
}
|
||||
|
||||
return hres;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CPropertyPage implementation
|
||||
|
||||
// Releases the reference to the interface for the property page,
|
||||
// set its page site to NULL, and frees any memory
|
||||
CPropertyPage::~CPropertyPage()
|
||||
{
|
||||
if (m_pPage) {
|
||||
m_pPage->SetPageSite(NULL);
|
||||
m_pPage->Release();
|
||||
}
|
||||
|
||||
CoTaskMemFree((void *)m_lpszTitle);
|
||||
CoTaskMemFree((void *)m_lpszDescription);
|
||||
CoTaskMemFree((void *)m_lpszHelpTopic);
|
||||
}
|
||||
|
||||
// Initializes the property page by setting the page site
|
||||
// and getting the page info
|
||||
HRESULT
|
||||
CPropertyPage::Initialize(LPPROPERTYPAGE pPage, LPPROPERTYPAGESITE pSite)
|
||||
{
|
||||
HRESULT hres;
|
||||
|
||||
// Hold a reference to the property page
|
||||
m_pPage = pPage;
|
||||
m_pPage->AddRef();
|
||||
|
||||
// First thing we do is set the page site. This initializes
|
||||
// the property page
|
||||
hres = m_pPage->SetPageSite(pSite);
|
||||
#ifdef _DEBUG
|
||||
if (FAILED(hres))
|
||||
OutputDebugString("Call to SetPageSite() failed\n");
|
||||
#endif
|
||||
|
||||
// Get information about the property page
|
||||
PROPPAGEINFO pageInfo;
|
||||
|
||||
pageInfo.cb = sizeof(pageInfo);
|
||||
hres = m_pPage->GetPageInfo(&pageInfo);
|
||||
if (FAILED(hres)) {
|
||||
#ifdef _DEBUG
|
||||
OutputDebugString("Call to GetPageInfo() failed\n");
|
||||
#endif
|
||||
return hres;
|
||||
}
|
||||
|
||||
// The page must have a title
|
||||
if (!pageInfo.pszTitle) {
|
||||
#ifdef _DEBUG
|
||||
OutputDebugString("Property page has NULL 'pszTitle'\n");
|
||||
#endif
|
||||
hres = ResultFromScode(E_UNEXPECTED);
|
||||
}
|
||||
|
||||
// Save the size for later
|
||||
m_size = pageInfo.size;
|
||||
|
||||
// OLE strings are UNICODE and we need ANSI strings
|
||||
// XXX - use CString...
|
||||
m_lpszTitle = AllocTaskAnsiString(pageInfo.pszTitle);
|
||||
if (!m_lpszTitle) {
|
||||
hres = ResultFromScode(E_OUTOFMEMORY);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (pageInfo.pszDocString) {
|
||||
m_lpszDescription = AllocTaskAnsiString(pageInfo.pszDocString);
|
||||
if (!m_lpszDescription) {
|
||||
hres = ResultFromScode(E_OUTOFMEMORY);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (pageInfo.pszHelpFile) {
|
||||
// NetHelp help topic is a string so it's stored in pszHelpFile
|
||||
// instead of using dwHelpContext
|
||||
m_lpszHelpTopic = AllocTaskAnsiString(pageInfo.pszHelpFile);
|
||||
if (!m_lpszHelpTopic) {
|
||||
hres = ResultFromScode(E_OUTOFMEMORY);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
// Free the memory
|
||||
CoTaskMemFree(pageInfo.pszTitle);
|
||||
CoTaskMemFree(pageInfo.pszDocString);
|
||||
CoTaskMemFree(pageInfo.pszHelpFile);
|
||||
return hres;
|
||||
}
|
||||
|
||||
//
|
||||
// FUNCTION: NS_CreatePropertyFrame()
|
||||
//
|
||||
// PURPOSE: Called to create a property frame dialog. This function
|
||||
// doesn't return until the dialog is closed.
|
||||
//
|
||||
// PARAMETERS:
|
||||
// hwndOwner - parent window of property sheet dialog
|
||||
// x - horizontal position for dialog box, relative to hwndOwner
|
||||
// y - vertical position for dialog box, relative to hwndOwner
|
||||
// lpszCaption - dialog box caption
|
||||
// nCategories - number of property page providers in lplpProviders
|
||||
// lplpProviders - array of property page providers
|
||||
// nInitial - index of category to be initially displayed
|
||||
//
|
||||
STDAPI
|
||||
NS_CreatePropertyFrame(HWND hwndOwner,
|
||||
int x,
|
||||
int y,
|
||||
LPCSTR lpszCaption,
|
||||
ULONG nCategories,
|
||||
LPSPECIFYPROPERTYPAGEOBJECTS *lplpProviders,
|
||||
ULONG nInitial,
|
||||
NETHELPFUNC lpfnNetHelp)
|
||||
{
|
||||
HRESULT hres;
|
||||
|
||||
assert(nCategories > 0);
|
||||
if (nCategories == 0)
|
||||
return ResultFromScode(S_FALSE);
|
||||
|
||||
// Create the property frame dialog
|
||||
CPropertyFrameDialog dialog(hwndOwner, x, y, lpszCaption, lpfnNetHelp);
|
||||
|
||||
// Initialize the property frame dialog
|
||||
hres = dialog.CreatePages(nCategories, lplpProviders, nInitial);
|
||||
if (FAILED(hres)) {
|
||||
#ifdef _DEBUG
|
||||
OutputDebugString("CPropertyFrameDialog::CreatePages failed\n");
|
||||
#endif
|
||||
return hres;
|
||||
}
|
||||
|
||||
// Display the property frame as a modal dialog
|
||||
dialog.DoModal();
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Main entry point for the DLL. By defining the entry point ourselves
|
||||
// and not using the Visual C++ runtime library entry point we can avoid
|
||||
// linking in the runtime initialization code
|
||||
BOOL WINAPI
|
||||
DllEntryPoint(HINSTANCE hInstance, DWORD dwReason, LPVOID lpvReserved)
|
||||
{
|
||||
switch (dwReason) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
// The DLL is being loaded for the first time by a given process
|
||||
g_hInstance = hInstance;
|
||||
break;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
// The DLL is being unloaded by a given process
|
||||
break;
|
||||
|
||||
case DLL_THREAD_ATTACH:
|
||||
// A thread is being created in a process that has already loaded
|
||||
// this DLL
|
||||
break;
|
||||
|
||||
case DLL_THREAD_DETACH:
|
||||
// A thread is exiting cleanly in a process that has already
|
||||
// loaded this DLL
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#else
|
||||
extern "C" int CALLBACK
|
||||
LibMain(HINSTANCE hInstance, WORD wDataSeg, WORD cbHeapSize, LPSTR)
|
||||
{
|
||||
g_hInstance = hInstance;
|
||||
InitTreeViewControl();
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
Загрузка…
Ссылка в новой задаче