gecko-dev/cmd/macfe/prefs/CPrefsMediator.cp

757 строки
24 KiB
C++
Исходник Ответственный История

/* -*- 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 "CPrefsMediator.h"
#include "prefapi.h"
#include "macutil.h"
#include "ufilemgr.h"
#include "MPreference.h"
#include "CSizePopup.h"
#ifdef MOZ_MAIL_NEWS
#include "CMessageFolder.h"
#endif
#include "StSetBroadcasting.h"
#include "InternetConfig.h"
#include "CMouseDragger.h"
Boolean CPrefsMediator::sUseIC = false;
LView *CPrefsMediator::sPanel = nil;
LWindow *CPrefsMediator::sWindow = nil;
CPrefsDialog::Selection_T CPrefsMediator::sInitialSelection
= CPrefsDialog::eIgnore;
#pragma mark ---CControlExtension---
//======================================
class CControlExtension: LCaption
//======================================
{
public:
enum
{
class_ID = 'CtlX'
};
CControlExtension(LStream *inStream);
virtual ~CControlExtension() {}
virtual void ClickSelf(const SMouseDownEvent& inMouseDown);
virtual void FinishCreateSelf();
protected:
PaneIDT mControlID;
LControl *mControl;
}; // class CControlExtension
//----------------------------------------------------------------------------------------
CControlExtension::CControlExtension(LStream *inStream):
LCaption(inStream),
mControl(nil)
//----------------------------------------------------------------------------------------
{
*inStream >> mControlID;
} // CControlExtension::CControlExtension
//----------------------------------------------------------------------------------------
void CControlExtension::FinishCreateSelf()
//----------------------------------------------------------------------------------------
{
LPane *pane = this;
LView *superView, *topView = nil;
#pragma warn_possunwant off
while (superView = pane->GetSuperView())
#pragma warn_possunwant reset
{
topView = superView;
pane = superView;
}
XP_ASSERT(topView);
if (topView)
{
mControl = (LControl *)topView->FindPaneByID(mControlID);
}
XP_ASSERT(mControl);
} // CControlExtension::FinishCreateSelf
//----------------------------------------------------------------------------------------
void CControlExtension::ClickSelf(const SMouseDownEvent& /*inMouseDown*/)
//----------------------------------------------------------------------------------------
{
if (mControl)
mControl->SimulateHotSpotClick(1); // any value > 0 && < 128 should work
} // CControlExtension::ClickSelf
#if 0
#pragma mark ---class CControlExtensionAttachment---
//======================================
class CControlExtensionAttachment: LAttachment
//======================================
{
public:
CControlExtensionAttachment(LControl *targetControl);
virtual ~CControlExtensionAttachment() {}
protected:
LControl *mControl;
virtual void ExecuteSelf(MessageT inMessage, void *ioParam);
}; // class CControlExtensionAttachment
//----------------------------------------------------------------------------------------
CControlExtensionAttachment::CControlExtensionAttachment(LControl* targetControl)
//----------------------------------------------------------------------------------------
: LAttachment(msg_Click, true)
, mControl(targetControl)
{
}
//----------------------------------------------------------------------------------------
void CControlExtensionAttachment::ExecuteSelf(MessageT inMessage, void* ioParam)
//----------------------------------------------------------------------------------------
{
if (mControl)
mControl->SimulateHotSpotClick(1); // any value > 0 && < 128 should work
}
#endif // 0
#ifdef MOZ_MAIL_NEWS
#pragma mark ---CPopupFolderMenu---
//======================================
class CPopupFolderMenu : public LGAPopup, public CGAPopupFolderMixin
//======================================
{
public:
enum
{
class_ID = 'PupF'
};
CPopupFolderMenu(LStream *inStream);
virtual ~CPopupFolderMenu();
virtual void FinishCreateSelf();
virtual Boolean FolderFilter(const CMessageFolder &folder);
// private:
// It turns out that this causes a crash in some thread code. Apparently someone
// is counting on the MSG_Master not going away
// CMailNewsContext mMailNewsContext;
// OK, what the heck is this for? Well the CPopupFolderMenus that we
// create will call CMailFolderMixin::UpdateMailFolderMixinsNow() in
// FinishCreateSelf(). This call will call CMailNewsContext::GetMailMaster().
// CMailNewsContext::GetMailMaster() will create a MSG_Master if the static
// MSG_Master does not already exist. This means that the code would work
// without mMailNewsContext, but the static MSG_Master would continue to exist
// after we are finished. This is not good if the user is not using mail. So
// we create a CMailNewsContext because its contrustor will create the
// the static MSG_Master but it is ref counted and destroyed in
// CMailNewsContext::~CMailNewsContext.
}; // class CPopupFolderMenu
//----------------------------------------------------------------------------------------
CPopupFolderMenu::CPopupFolderMenu(LStream *inStream)
//----------------------------------------------------------------------------------------
: LGAPopup(inStream)
{
mDesiredFolderFlags = eWantPOP;
}
//----------------------------------------------------------------------------------------
CPopupFolderMenu::~CPopupFolderMenu()
//----------------------------------------------------------------------------------------
{
}
//----------------------------------------------------------------------------------------
void CPopupFolderMenu::FinishCreateSelf()
//----------------------------------------------------------------------------------------
{
LGAPopup::FinishCreateSelf();
CMailFolderMixin::UpdateMailFolderMixinsNow(this);
}
//----------------------------------------------------------------------------------------
Boolean CPopupFolderMenu::FolderFilter(const CMessageFolder& folder)
//----------------------------------------------------------------------------------------
{
Boolean result = CGAPopupFolderMixin::FolderFilter(folder);
// We want to exclude the Outbox.
if (result && (folder.GetFolderFlags() & MSG_FOLDER_FLAG_QUEUE))
{
result = false;
}
return result;
}
#endif // MOZ_MAIL_NEWS
#pragma mark ---CPrefsMediator---
//----------------------------------------------------------------------------------------
CPrefsMediator::CPrefsMediator(PaneIDT inMainPaneID)
//----------------------------------------------------------------------------------------
: mMainPane(nil)
, mNeedsPrefs(true)
, mMainPaneID(inMainPaneID)
, mLatentSub(nil)
{
MPreferenceBase::SetWriteOnDestroy(false);
}
//----------------------------------------------------------------------------------------
CPrefsMediator::~CPrefsMediator()
//----------------------------------------------------------------------------------------
{
}
//----------------------------------------------------------------------------------------
void CPrefsMediator::LoadPrefs()
//----------------------------------------------------------------------------------------
{
}
//----------------------------------------------------------------------------------------
void CPrefsMediator::WritePrefs()
//----------------------------------------------------------------------------------------
{
}
//----------------------------------------------------------------------------------------
void CPrefsMediator::StepAside()
//----------------------------------------------------------------------------------------
{
if (mMainPane)
{
mLatentSub = LCommander::GetTarget();
SwitchTarget(nil); // take current chain off duty, so that SetLatentSub() can work.
mMainPane->Hide();
}
}
//----------------------------------------------------------------------------------------
void CPrefsMediator::LoadPanes()
//----------------------------------------------------------------------------------------
{
if (!mMainPane)
LoadMainPane();
mMainPane->Hide(); // this is needed for IC support
// when panes are loaded, but not immediately displayed
if (mNeedsPrefs)
{
LoadPrefs();
mNeedsPrefs = false;
}
UpdateFromIC();
}
//----------------------------------------------------------------------------------------
void CPrefsMediator::StepForward(LCommander *defaultSub)
//----------------------------------------------------------------------------------------
{
TrySetCursor(watchCursor);
Boolean firstTime = (mMainPane == nil);
if (!firstTime && mLatentSub != sWindow)
sWindow->SetLatentSub(mLatentSub); // restore latent sub from previously hidden pane.
// In the first-time case, it's done in FinishCreate().
LoadPanes();
if (mMainPane)
{
mMainPane->Show();
mLatentSub = sWindow->GetLatentSub();
if (!mLatentSub)
mLatentSub = defaultSub;
SwitchTarget(mLatentSub);
}
// if (firstTime)
// SelectFirstEnabledEditField(); // On subsequent times, use the user's selection?
// Actually, don't do this. The edittext pref resources all stand up and say which
// one wants to be the target.
SetCursor(&qd.arrow);
}
//----------------------------------------------------------------------------------------
void CPrefsMediator::LoadMainPane()
//----------------------------------------------------------------------------------------
{
sWindow->UpdatePort();
// The previous contents have been "hidden" but they are still visible. If we
// did not call UpdatePort() then the new content would appear over the old,
// but that is OK because everything gets straightened out at the next update.
// The only problem is if a panel is slow to draw itself-- the
// Mail & News / Messages pane is a good example--then we can actually see both
// the old and the new contents at the same time. Bad thing.
PaneIDT paneID = GetMainPaneID();
mMainPane = UReanimator::CreateView(paneID, sPanel, sWindow);
UReanimator::LinkListenerToControls(this, mMainPane, paneID);
}
//----------------------------------------------------------------------------------------
void CPrefsMediator::Canceled()
//----------------------------------------------------------------------------------------
{
mNeedsPrefs = true;
MPreferenceBase::SetWriteOnDestroy(false);
}
//----------------------------------------------------------------------------------------
void CPrefsMediator::ListenToMessage(MessageT inMessage, void */*ioParam*/)
//----------------------------------------------------------------------------------------
{
switch (inMessage)
{
case eCommitPrefs:
MPreferenceBase::SetWriteOnDestroy(true);
WritePrefs();
break;
case eCancelPrefs:
Canceled();
break;
default:
break;
}
}
//----------------------------------------------------------------------------------------
MPreferenceBase* CPrefsMediator::GetPreferenceObject(PaneIDT inPaneID) const
//----------------------------------------------------------------------------------------
{
LPane* p = FindPaneByID(inPaneID);
MPreferenceBase* pb = dynamic_cast<MPreferenceBase*>(p);
SignalIf_(!pb);
return pb;
}
//----------------------------------------------------------------------------------------
Boolean CPrefsMediator::PaneHasLockedPref(PaneIDT inPaneID) const
//----------------------------------------------------------------------------------------
{
MPreferenceBase* pb = GetPreferenceObject(inPaneID);
if (pb)
return pb->IsLocked();
return true;
}
//----------------------------------------------------------------------------------------
void CPrefsMediator::ReadDefaultPref(PaneIDT inPaneID)
//----------------------------------------------------------------------------------------
{
MPreferenceBase* pb = GetPreferenceObject(inPaneID);
if (pb)
pb->ReadDefaultSelf();
}
//----------------------------------------------------------------------------------------
void CPrefsMediator::ChangePrefName(PaneIDT inPaneID, const char* inNewName)
//----------------------------------------------------------------------------------------
{
MPreferenceBase::ChangePrefName(mMainPane, inPaneID, inNewName);
}
//----------------------------------------------------------------------------------------
void CPrefsMediator::SetValidationFunction(
PaneIDT inPaneID,
CValidEditField::ValidationFunc inFunc) const
//----------------------------------------------------------------------------------------
{
CValidEditField* p =
(CValidEditField*)FindPaneByID(inPaneID);
p = dynamic_cast<CValidEditField*>(p);
Assert_(p); // only makes sense for CValidEditField.
if (p)
p->SetValidationFunction(inFunc);
}
// static
//----------------------------------------------------------------------------------------
Boolean CPrefsMediator::CanSwitch(LCommander *inNewTarget)
//----------------------------------------------------------------------------------------
{
CValidEditField *target = dynamic_cast<CValidEditField *>(LCommander::GetTarget());
if (target)
return target->AllowTargetSwitch(inNewTarget);
return true;
}
//----------------------------------------------------------------------------------------
// static
void CPrefsMediator::SelectFirstEnabledEditField()
//----------------------------------------------------------------------------------------
{
LEditField *currentTarget = dynamic_cast<LEditField *>(LCommander::GetTarget());
if (currentTarget)
{
if (!currentTarget->IsEnabled())
{
LTabGroup *tabGroup =
dynamic_cast<LTabGroup *>(currentTarget->GetSuperCommander());
if (tabGroup)
{
tabGroup->RotateTarget(false /*not backward*/);
LEditField *oldTarget = currentTarget;
currentTarget = dynamic_cast<LEditField *>(LCommander::GetTarget());
if (currentTarget)
{
if (currentTarget == oldTarget)
{
// This means that the tab group couldn't find any edit field
// that was not disabled. So we need to take this guy off duty.
currentTarget->SwitchTarget(nil);
}
}
// else what the heck does this mean?
}
if (currentTarget && currentTarget->IsEnabled())
{
currentTarget->SelectAll();
}
}
}
}
enum
{
eNNTPStandardPort = 119,
eNNTPSecurePort = 563
};
//----------------------------------------------------------------------------------------
void CPrefsMediator::SetEditFieldsWithICPref(ConstStr255Param prefName,
PaneIDT editFieldID,
Boolean stripPortNumber,
PaneIDT portFieldID,
Boolean portLocked,
long /*portNumber*/)
// If stripPortNumber is false then portFieldID and portLocked are ignored.
// If stripPortNumber is true then the first colon and any chars following it are stripped.
// If portFieldID is non-zero and portLocked is false, then the port value is set.
//----------------------------------------------------------------------------------------
{
if (!PaneHasLockedPref(editFieldID))
{
LEditField *editField = (LEditField *)FindPaneByID(editFieldID);
assert(editField);
if (UseIC())
{
Str255 s;
long portNumber = eNNTPStandardPort;
long *portNumberPtr = stripPortNumber ? &portNumber: nil;
CInternetConfigInterface::GetInternetConfigString(prefName, s, portNumberPtr);
editField->SetDescriptor(s);
editField->Disable();
if (stripPortNumber && portFieldID && !portLocked)
{
LEditField *portField = (LEditField *)FindPaneByID(portFieldID);
assert(portField);
portField->SetValue(portNumber);
portField->Disable();
}
}
else
{
editField->Enable();
if (stripPortNumber && portFieldID && !portLocked)
{
LEditField *portField = (LEditField *)FindPaneByID(portFieldID);
assert(portField);
portField->Enable();
}
}
}
}
//----------------------------------------------------------------------------------------
int CPrefsMediator::SetFontSizePopupWithIntPref(const char *prefName,
PaneIDT popupID,
Boolean &locked,
int defaultValue)
//----------------------------------------------------------------------------------------
{
int32 result = defaultValue;
int prefError = PREF_NOERROR;
CSizePopup *thePopup = (CSizePopup *)FindPaneByID(popupID);
XP_ASSERT(thePopup);
prefError = PREF_GetIntPref(prefName, &result);
locked = PREF_PrefIsLocked(prefName);
if (prefError == PREF_NOERROR)
{
thePopup->SetFontSize(result);
}
if (locked)
{
thePopup->Disable();
}
return result;
}
#ifdef MOZ_MAIL_NEWS
//----------------------------------------------------------------------------------------
void CPrefsMediator::SetFolderPopupWithPref( const char *prefName,
PaneIDT popupID,
Boolean& locked,
const char* /*defaultValue*/)
//----------------------------------------------------------------------------------------
{
CPopupFolderMenu *thePopup =
(CPopupFolderMenu *)FindPaneByID(popupID);
XP_ASSERT(thePopup);
// XP prefs: Read alias as binary type
AliasHandle aliasH = NULL;
int size;
void* alias;
if (PREF_CopyBinaryPref(prefName, &alias, &size ) == 0)
{
PtrToHand(alias, &(Handle)aliasH, size);
XP_FREE(alias);
}
FSSpec target;
Boolean wasChanged;
OSErr err = ResolveAlias(nil, aliasH, &target, &wasChanged);
DisposeHandle((Handle)aliasH);
if (!err)
{
locked = PREF_PrefIsLocked(prefName);
// alias to path name
char* pathName = CFileMgr::EncodedPathNameFromFSSpec(target, true);
if (pathName && *pathName)
{
thePopup->MSetSelectedFolderName(pathName);
}
XP_FREEIF(pathName);
if (locked)
{
thePopup->Disable();
}
}
return;
}
#endif // MOZ_MAIL_NEWS
//----------------------------------------------------------------------------------------
Boolean CPrefsMediator::SetEditFieldWithLocalFileURL(PaneIDT editFieldID, Boolean /*locked*/)
//----------------------------------------------------------------------------------------
{
StandardFileReply spec;
Boolean result = CFilePicker::DoCustomGetFile(
spec,
CFilePicker::TextFiles,
false);
if (result)
{
char *url = CFileMgr::GetURLFromFileSpec(spec.sfFile);
if (url)
{
LEditField *theField = (LEditField *)FindPaneByID(editFieldID);
XP_ASSERT(theField);
LStr255 pString(url);
theField->SetDescriptor(pString);
theField->SelectAll();
XP_FREE(url);
}
}
return result;
}
//----------------------------------------------------------------------------------------
void CPrefsMediator::SetIntPrefWithFontSizePopup( const char *prefName,
PaneIDT popupID,
Boolean locked)
//----------------------------------------------------------------------------------------
{
if (!locked)
{
CSizePopup *thePopup = (CSizePopup *)FindPaneByID(popupID);
XP_ASSERT(thePopup);
Int32 popupValue = thePopup->GetFontSize();
PREF_SetIntPref(prefName, popupValue);
}
}
#ifdef MOZ_MAIL_NEWS
//----------------------------------------------------------------------------------------
void CPrefsMediator::SetPrefWithFolderPopup( const char *prefName,
PaneIDT popupID,
Boolean locked)
//----------------------------------------------------------------------------------------
{
if (!locked)
{
CPopupFolderMenu *thePopup =
(CPopupFolderMenu *)FindPaneByID(popupID);
XP_ASSERT(thePopup);
const char* folderName = thePopup->MGetSelectedFolderName();
// drop out if no folder is selected (b2 patch; the popups should really have
// non-empty defaults but this may also happen if folder doesn't exist anymore?)
if (!folderName || !*folderName)
return;
PREF_SetPathPref(prefName, folderName, FALSE);
}
}
#endif // MOZ_MAIL_NEWS
//----------------------------------------------------------------------------------------
void CPrefsMediator::ActivateHelp( )
// Called when the user clicks on the "Help" button in the Prefs window. Apart from working
// out the help name from the PPob resource name, this is just a pass-through
// to the appropriate FE call with the current help topic for this pane.
//----------------------------------------------------------------------------------------
{
// The help string is the resource name of the 'PPob' resource for the help pane.
::SetResLoad(false);
Handle h = ::GetResource('PPob', mMainPaneID);
if (!h)
return;
::SetResLoad(true);
short idIgnored; ResType resTypeIgnored;
CStr255 resName;
::GetResInfo(h, &idIgnored, &resTypeIgnored, resName);
if (!*h)
::ReleaseResource(h); // if master pointer is not nil, it was not we who loaded it!
if (resName.Length() == 0)
return;
// The pref strings are long and redundant. This means that the significant part
// is not visible in Constructor. So I replaced the two common substrings "avigat" and
// "r:PREFERENCES_" with "<22>" and I'm putting them back in here. Example:
// resource name "n<>APPEARANCE" becomes help name "navigatr:PREFERENCES_APPEARANCE"
// resource name "c<>EDITOR_GENERAL" becomes help name "composer:PREFERENCES_EDITOR_GENERAL"
char fullhelpname[256];
Assert_(resName[2] == (unsigned char)'<EFBFBD>');
if (resName[2] != (unsigned char)'<EFBFBD>')
return; // No help available for this topic
switch (resName[1])
{
case 'n':
XP_STRCPY(fullhelpname, "navigat");
break;
case 'c':
XP_STRCPY(fullhelpname, "compose");
break;
case 'm':
XP_STRCPY(fullhelpname, "messeng");
break;
default:
Assert_(false);
return;
}
XP_STRCAT(fullhelpname, "r:PREFERENCES_");
XP_STRCAT(fullhelpname, 2 + (const char*)resName);
ShowHelp(fullhelpname);
} // ActivateHelp
//----------------------------------------------------------------------------------------
void CDragOrderTextList::MoveRow(TableIndexT inCurrRow, TableIndexT inNewRow)
//----------------------------------------------------------------------------------------
{
Assert_(IsValidRow(inCurrRow) && IsValidRow(inNewRow));
if (inCurrRow == inNewRow)
return;
{ // -- broadcasting scope
STableCell currCell(inCurrRow, 1);
StSetBroadcasting(this, false);
// Don't broadcast that the selection has changed, because it really hasn't
Uint32 ioDataSize;
GetCellData(currCell, nil, ioDataSize);
if (ioDataSize)
{
char *temp = (char *)XP_ALLOC(ioDataSize);
if (temp)
{
GetCellData(currCell, temp, ioDataSize);
RemoveRows(1, inCurrRow, false);
InsertRows(1, inNewRow - 1, temp, ioDataSize, true);
XP_FREE(temp);
}
}
} // -- broadcasting scope
BroadcastMessage(msg_ChangedOrder);
SelectCell(STableCell(inNewRow, 1));
Refresh();
}
//----------------------------------------------------------------------------------------
void CDragOrderTextList::ClickCell( const STableCell &inCell,
const SMouseDownEvent &inMouseDown)
//----------------------------------------------------------------------------------------
{
if ( LPane::GetClickCount() == 2 )
{
if (mDoubleClickMsg != msg_Nothing)
{
BroadcastMessage(mDoubleClickMsg, (void*) this);
}
}
else if (mRows > 1 && !mOrderLocked)
{
CTableRowDragger dragger(inCell.row);
SPoint32 startMouseImagePt;
LocalToImagePoint(inMouseDown.whereLocal, startMouseImagePt);
// Restrict dragging to a thin vertical column the height of the image
LImageRect dragPinRect;
{
Int32 left, top, right, bottom;
GetImageCellBounds(inCell, left, top, right, bottom);
dragPinRect.Set(startMouseImagePt.h, startMouseImagePt.v - top, startMouseImagePt.h,
mImageSize.height - (bottom - startMouseImagePt.v) + 1);
}
TrySetCursor(eHandClosedCursorID);
dragger.DoTrackMouse(this, &startMouseImagePt, &dragPinRect, 2, 2);
TableIndexT newRow = dragger.GetDraggedRow();
if (newRow)
{
MoveRow(inCell.row, newRow);
// CMoveFilterAction *action = new CMoveFilterAction(this, inCell.row, newRow);
// FailNIL_(action);
// PostAction(action);
}
}
} // CDragOrderTextList::ClickCell
//----------------------------------------------------------------------------------------
void CPrefsMediator::RegisterViewClasses()
//----------------------------------------------------------------------------------------
{
#ifdef MOZ_MAIL_NEWS
RegisterClass_(CPopupFolderMenu);
#endif
RegisterClass_( CControlExtension);
RegisterClass_(CDragOrderTextList);
}