зеркало из https://github.com/mozilla/gecko-dev.git
932 строки
28 KiB
C++
932 строки
28 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.
|
||
|
*/
|
||
|
|
||
|
|
||
|
|
||
|
// CSearchWindowBase.cp
|
||
|
|
||
|
#define DEBUGGER_ASSERTIONS
|
||
|
|
||
|
#include "CSearchWindowBase.h"
|
||
|
#include "SearchHelpers.h"
|
||
|
#include "CMailNewsContext.h"
|
||
|
#include "CSearchTableView.h"
|
||
|
#include "libi18n.h"
|
||
|
#include "LGAPushButton.h"
|
||
|
#include "CPatternProgressBar.h"
|
||
|
#include "MailNewsgroupWindow_Defines.h"
|
||
|
#include "resgui.h"
|
||
|
#include <UModalDialogs.h>
|
||
|
#include "prefapi.h"
|
||
|
#include "LGARadioButton.h"
|
||
|
#include "UStClasses.h"
|
||
|
#include "CThreadWindow.h"
|
||
|
#include "CMessageWindow.h"
|
||
|
#include "CProgressListener.h"
|
||
|
|
||
|
const UInt16 resIDT_SearchOptionsDialog = 8851;
|
||
|
const char* const searchSubfolderPrefName = "mailnews.searchSubFolders";
|
||
|
const char* const searchServerPrefName = "mailnews.searchServer";
|
||
|
|
||
|
//-----------------------------------
|
||
|
CSearchWindowBase::CSearchWindowBase(LStream *inStream, DataIDT inWindowType) :
|
||
|
CMailNewsWindow(inStream, inWindowType),
|
||
|
LListener(),
|
||
|
LPeriodical(),
|
||
|
mSearchManager(),
|
||
|
mResultsEnclosure(nil),
|
||
|
mResultsTable(nil),
|
||
|
mResultsVertWindExtension(0),
|
||
|
mResultsTableVisible(true),
|
||
|
mSearchFolders(),
|
||
|
mProgressBar(nil),
|
||
|
mSearchButton(nil),
|
||
|
mSearchOptionsButton(nil)
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
SetRefreshAllWhenResized(false);
|
||
|
}
|
||
|
|
||
|
CSearchWindowBase::~CSearchWindowBase()
|
||
|
// Stop any current search.
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
Boolean canRotate = false;
|
||
|
if ( IsVisible() )
|
||
|
USearchHelper::FindWindowTabGroup(&mSubCommanders)->SetRotateWatchValue(&canRotate);
|
||
|
} // CSearchWindowBase::~CSearchWindowBase
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
UInt16
|
||
|
CSearchWindowBase::GetValidStatusVersion() const
|
||
|
//
|
||
|
// -- 10/30/97 ---------------------------------------------------------
|
||
|
//
|
||
|
// This is the proper place for this method, because
|
||
|
// every time the two subclasses of this class stream out they stream out a member of
|
||
|
// this class ( CSearchManager). Therefore when the search manager parameters for stream out
|
||
|
// are changed both subclasses are affected.
|
||
|
//
|
||
|
// Copied the following comments from the CAddressSearchWindow implementation, now defunct.
|
||
|
//
|
||
|
// ---------------------------------------------------------------------------
|
||
|
// So here's the skinny on the directory (aka address) search window.
|
||
|
// You see, when we shipped version 4.01, there were three "levels" of criteria,
|
||
|
// and the version we shipped with was:
|
||
|
//
|
||
|
// static const UInt16 cAddressSearchSaveWindowStatusVersion = 0x0203;
|
||
|
//
|
||
|
// Then on 97/06/30, the number of levels has changed from 3 to 5 in MailNewsSearch.cnst,
|
||
|
// in the enclosures include view. That meant that builds from 7/1 - 7/30 were writing
|
||
|
// out saved window status records containing five levels of criteria.
|
||
|
// Unfortunately, the data is written out as:
|
||
|
//
|
||
|
// bounds/vertextension/levelsdata/tableheaderdata
|
||
|
//
|
||
|
// so that the extra data was written out in the middle. In version 4.01, the routine
|
||
|
// CSearchManager::ReadSavedSearchStatus was not skipping the extra fields, so a crash
|
||
|
// occurred when reading in the table header stuff. This happened when the search window
|
||
|
// was used in 4.01 after running it in 4.02 (7/30 build).
|
||
|
//
|
||
|
// This is bug #78713. There are two parts of the fix. (1) start with a version number
|
||
|
// of zero. Then, version 4.01 will ignore the resource as being "too old", and write
|
||
|
// out a resource with version 0x203. This will be handled OK by version 4.02.
|
||
|
//
|
||
|
// The other part of the fix is that CSearchManager::ReadSavedSearchStatus will now skip
|
||
|
// extra fields, so that this crash won't happen if somebody further increases the number
|
||
|
// of levels.
|
||
|
//
|
||
|
// FINAL NOTE (97/10/13) Because of this same problem, I changed CSaveWindowStatus so that
|
||
|
// it always writes out zero in the first field, which will be interpreted as a zero version
|
||
|
// by Communicator 4.0x, and ignored. So now it's OK to increment this as originally
|
||
|
// intended.
|
||
|
{
|
||
|
return eValidStreamVersion;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------
|
||
|
void CSearchWindowBase::AboutToClose()
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
// Not re-entrant! Don't call this twice.
|
||
|
CSearchWindowBase::MessageWindStop(true);
|
||
|
|
||
|
Inherited::AttemptCloseWindow(); // Do this first: uses table
|
||
|
|
||
|
// Bug fix: Do these things in the right order here
|
||
|
if (mMailNewsContext)
|
||
|
mMailNewsContext->RemoveUser(this);
|
||
|
mMailNewsContext = nil;
|
||
|
mSearchManager.AboutToClose();
|
||
|
|
||
|
if (mResultsTable)
|
||
|
{
|
||
|
if (mMailNewsContext)
|
||
|
mMailNewsContext->RemoveListener(mResultsTable); // bad time to listen for all connections complete.
|
||
|
delete mResultsTable;
|
||
|
mResultsTable = nil;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------
|
||
|
void CSearchWindowBase::FinishCreateSelf()
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
// Create context and and progress listener
|
||
|
|
||
|
mMailNewsContext = new CMailNewsContext(MWContextSearch);
|
||
|
FailNIL_(mMailNewsContext);
|
||
|
|
||
|
mMailNewsContext->AddUser(this);
|
||
|
mMailNewsContext->AddListener(this);
|
||
|
|
||
|
CMediatedWindow::FinishCreateSelf(); // Call CMediatedWindow for now since we need to
|
||
|
// create a different context than CMailNewsWindow
|
||
|
if (mProgressListener)
|
||
|
mMailNewsContext->AddListener(mProgressListener);
|
||
|
else
|
||
|
mProgressListener = new CProgressListener(this, mMailNewsContext);
|
||
|
|
||
|
// SetAttribute(windAttr_DelaySelect); put in resource
|
||
|
// should be in resource, but there's a resource freeze.
|
||
|
|
||
|
mMailNewsContext->SetWinCSID(INTL_DocToWinCharSetID(mMailNewsContext->GetDefaultCSID()));
|
||
|
|
||
|
USearchHelper::FindWindowTabGroup(&mSubCommanders)->SetRotateWatchValue(&mCanRotateTarget);
|
||
|
|
||
|
// Populate scope window
|
||
|
|
||
|
mResultsEnclosure = USearchHelper::FindViewSubview(this, paneID_ResultsEnclosure);
|
||
|
FailNILRes_(mResultsEnclosure);
|
||
|
mResultsTable = dynamic_cast<CSearchTableView *>(USearchHelper::FindViewSubview(this, paneID_ResultsTable));
|
||
|
FailNILRes_(mResultsTable);
|
||
|
mSearchButton = dynamic_cast<LGAPushButton *>(USearchHelper::FindViewControl(this, paneID_Search));
|
||
|
FailNILRes_(mSearchButton);
|
||
|
mProgressBar = dynamic_cast<CPatternProgressCaption *>(USearchHelper::FindViewSubpane(this, paneID_ProgressBar));
|
||
|
FailNILRes_(mProgressBar);
|
||
|
|
||
|
mResultsTable->AddListener(this);
|
||
|
mSearchButton->SetDefaultButton(true, false);
|
||
|
mResultsEnclosure->SetRefreshAllWhenResized(false);
|
||
|
|
||
|
Rect windowBounds;
|
||
|
this->CalcPortFrameRect(windowBounds);
|
||
|
mMinVResultsSize = windowBounds.bottom - windowBounds.top;
|
||
|
|
||
|
UReanimator::LinkListenerToControls(this, this, GetStatusResID());
|
||
|
|
||
|
ShowHideSearchResults(false);
|
||
|
|
||
|
// Initialize the search manager
|
||
|
mSearchManager.AddListener(this);
|
||
|
mSearchManager.InitSearchManager(
|
||
|
this, USearchHelper::FindWindowTabGroup(&mSubCommanders),
|
||
|
GetWindowScope(),
|
||
|
&mSearchFolders );
|
||
|
mResultsTable->SetSearchManager(&mSearchManager);
|
||
|
|
||
|
// Call inherited method
|
||
|
FinishCreateWindow();
|
||
|
}
|
||
|
|
||
|
//-----------------------------------
|
||
|
Boolean CSearchWindowBase::ObeyCommand(CommandT inCommand, void *ioParam)
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
if ( IsResultsTableVisible() )
|
||
|
{
|
||
|
switch ( inCommand )
|
||
|
{
|
||
|
case cmd_PreviousMessage:
|
||
|
case cmd_NextMessage:
|
||
|
case cmd_NextUnreadMessage:
|
||
|
return true;
|
||
|
|
||
|
case cmd_SortBySubject:
|
||
|
case cmd_SortBySender:
|
||
|
case cmd_SortByDate:
|
||
|
case cmd_SortByLocation:
|
||
|
case cmd_SortByPriority:
|
||
|
case cmd_SortByStatus:
|
||
|
{
|
||
|
LTableHeader *theHeader = mResultsTable->GetTableHeader();
|
||
|
PaneIDT dataType = DataTypeFromSortCommand(inCommand);
|
||
|
if ( theHeader != nil )
|
||
|
{
|
||
|
theHeader->SetSortedColumn(theHeader->ColumnFromID(dataType),
|
||
|
mResultsTable->IsSortedBackwards(), true);
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
|
||
|
case cmd_SortAscending:
|
||
|
case cmd_SortDescending:
|
||
|
LTableHeader *theHeader = mResultsTable->GetTableHeader();
|
||
|
if ( theHeader != nil )
|
||
|
{
|
||
|
theHeader->SetSortedColumn(theHeader->ColumnFromID(mResultsTable->GetSortedColumn()),
|
||
|
inCommand == cmd_SortDescending, true);
|
||
|
}
|
||
|
return true;
|
||
|
|
||
|
case msg_TabSelect:
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
switch ( inCommand ) {
|
||
|
|
||
|
default:
|
||
|
return Inherited::ObeyCommand(inCommand, ioParam);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------
|
||
|
void CSearchWindowBase::FindCommandStatus(CommandT inCommand, Boolean &outEnabled,
|
||
|
Boolean &outUsesMark, Char16 &outMark,
|
||
|
Str255 outName)
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
// Boolean isLineSelected = (GetSelectedRowCount() > 0);
|
||
|
|
||
|
if ( IsResultsTableVisible() )
|
||
|
{
|
||
|
switch ( inCommand )
|
||
|
{
|
||
|
case cmd_PreviousMessage:
|
||
|
case cmd_NextMessage:
|
||
|
case cmd_NextUnreadMessage:
|
||
|
outEnabled = true;
|
||
|
outUsesMark = false;
|
||
|
return;
|
||
|
|
||
|
case cmd_SortBySubject:
|
||
|
case cmd_SortBySender:
|
||
|
case cmd_SortByDate:
|
||
|
case cmd_SortByLocation:
|
||
|
case cmd_SortByPriority:
|
||
|
case cmd_SortByStatus:
|
||
|
{
|
||
|
PaneIDT dataType = DataTypeFromSortCommand(inCommand);
|
||
|
PaneIDT paneID = mResultsTable->GetSortedColumn();
|
||
|
outUsesMark = true;
|
||
|
outEnabled = true;
|
||
|
outMark = ((dataType == paneID) ? checkMark : noMark);
|
||
|
}
|
||
|
return;
|
||
|
|
||
|
case cmd_SortAscending:
|
||
|
case cmd_SortDescending:
|
||
|
outMark =
|
||
|
((inCommand == cmd_SortDescending) == mResultsTable->IsSortedBackwards()) ?
|
||
|
checkMark : 0;
|
||
|
outUsesMark = true;
|
||
|
outEnabled = true;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
switch ( inCommand ) {
|
||
|
|
||
|
default:
|
||
|
if (inCommand == cmd_OpenSelection) // enabled in base class
|
||
|
::GetIndString(outName, kMailNewsMenuStrings, kOpenMessageStrID);
|
||
|
|
||
|
Inherited::FindCommandStatus(inCommand, outEnabled, outUsesMark, outMark,
|
||
|
outName);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------
|
||
|
void CSearchWindowBase::ListenToMessage(MessageT inMessage, void *ioParam)
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
switch ( inMessage )
|
||
|
{
|
||
|
case paneID_Search:
|
||
|
if (mProgressBar) mProgressBar->SetDescriptor("\p");
|
||
|
MessageWindSearch();
|
||
|
break;
|
||
|
|
||
|
case paneID_SearchOptions:
|
||
|
SearchOptions();
|
||
|
break;
|
||
|
|
||
|
case paneID_Stop:
|
||
|
MessageWindStop(true);
|
||
|
UpdateTableStatusDisplay();
|
||
|
break;
|
||
|
|
||
|
case CStandardFlexTable::msg_SelectionChanged:
|
||
|
UpdateTableStatusDisplay();
|
||
|
break;
|
||
|
|
||
|
case CSearchManager::msg_SearchParametersCleared:
|
||
|
ShowHideSearchResults(false);
|
||
|
break;
|
||
|
|
||
|
case CSearchManager::msg_SearchParametersResized:
|
||
|
MessageSearchParamsResized(*((Int16 *) ioParam));
|
||
|
break;
|
||
|
|
||
|
// Status messages
|
||
|
|
||
|
case msg_NSCAllConnectionsComplete:
|
||
|
MessageWindStop(false);
|
||
|
UpdateTableStatusDisplay();
|
||
|
// no break here
|
||
|
|
||
|
default:
|
||
|
// No superclass method
|
||
|
break;
|
||
|
}
|
||
|
} // CSearchWindowBase::ListenToMessage
|
||
|
|
||
|
//-----------------------------------
|
||
|
void CSearchWindowBase::SearchOptions()
|
||
|
// This function allows the user to set the following prefs:
|
||
|
// - search in subfolders [yes / no]
|
||
|
// - search locally / on server
|
||
|
// After changing these prefs, it is necessary to reconstruct the attributes menu
|
||
|
// because a search on server usually doesn't offer as many criteria as a local search.
|
||
|
// So we call PopulateAttributesMenus() which will do a MSG_GetAttributesForSearchScopes().
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
StDialogHandler theOptionsDialogHandler( resIDT_SearchOptionsDialog, dynamic_cast<LCommander*>(this) );
|
||
|
|
||
|
// get the options dialog
|
||
|
LWindow* theOptionsDialog = theOptionsDialogHandler.GetDialog();
|
||
|
AssertFail_( theOptionsDialog != nil );
|
||
|
|
||
|
int prefResult;
|
||
|
XP_Bool searchSubFolderPref = false;
|
||
|
XP_Bool searchServerPref = false;
|
||
|
|
||
|
// set the default value for the subfolder search from the preferences
|
||
|
LGACheckbox* searchSubChkb
|
||
|
= dynamic_cast<LGACheckbox*>( theOptionsDialog->FindPaneByID( 'SUBF' ) );
|
||
|
AssertFail_( searchSubChkb != nil );
|
||
|
|
||
|
prefResult = PREF_GetBoolPref( searchSubfolderPrefName, &searchSubFolderPref );
|
||
|
if ( prefResult == PREF_ERROR ) searchSubFolderPref = true; // default from spec.
|
||
|
searchSubFolderPref ? searchSubChkb->SetValue( Button_On ) : searchSubChkb->SetValue( Button_Off );
|
||
|
|
||
|
// set the default value for the local/server search from the preferences
|
||
|
LGARadioButton* searchServerBtn
|
||
|
= dynamic_cast<LGARadioButton*>( theOptionsDialog->FindPaneByID( 'SRCS' ) );
|
||
|
LGARadioButton* searchLocalBtn
|
||
|
= dynamic_cast<LGARadioButton*>( theOptionsDialog->FindPaneByID( 'SRCL' ) );
|
||
|
AssertFail_( searchServerBtn != nil );
|
||
|
|
||
|
prefResult = PREF_GetBoolPref( searchServerPrefName, &searchServerPref );
|
||
|
if ( prefResult == PREF_ERROR ) searchServerPref = true; // default from spec.
|
||
|
if( searchServerPref )
|
||
|
{
|
||
|
searchServerBtn->SetValue( Button_On ); // Other radio will be turned off via LTabGroup
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
searchLocalBtn->SetValue( Button_On ); // ditto
|
||
|
}
|
||
|
|
||
|
MessageT theMessage;
|
||
|
|
||
|
while( true )
|
||
|
{
|
||
|
theMessage = theOptionsDialogHandler.DoDialog();
|
||
|
|
||
|
if( theMessage == msg_OK )
|
||
|
{
|
||
|
Boolean choice;
|
||
|
if( ( choice = searchSubChkb->IsSelected() ) != searchSubFolderPref )
|
||
|
PREF_SetBoolPref( searchSubfolderPrefName, choice );
|
||
|
if( ( choice = searchServerBtn->IsSelected() ) != searchServerPref )
|
||
|
PREF_SetBoolPref( searchServerPrefName, choice );
|
||
|
// See the comment in the function header
|
||
|
mSearchManager.PopulateAttributesMenus(GetWindowScope());
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
if( theMessage == msg_Cancel )
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------
|
||
|
Boolean CSearchWindowBase::HandleKeyPress(const EventRecord &inKeyEvent)
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
Int16 theKey = inKeyEvent.message & charCodeMask;
|
||
|
|
||
|
if ( ((theKey == char_Enter) || (theKey == char_Return)) && !mSearchManager.IsSearching() )
|
||
|
{
|
||
|
mSearchButton->SimulateHotSpotClick(kControlButtonPart);
|
||
|
return true;
|
||
|
}
|
||
|
else if ( (((theKey == char_Escape) && ((inKeyEvent.message & keyCodeMask) == vkey_Escape)) ||
|
||
|
UKeyFilters::IsCmdPeriod(inKeyEvent)) && mSearchManager.IsSearching() )
|
||
|
{
|
||
|
|
||
|
USearchHelper::FindViewControl(this, paneID_Stop)->SimulateHotSpotClick(kControlButtonPart);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return Inherited::HandleKeyPress(inKeyEvent);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------
|
||
|
void CSearchWindowBase::SpendTime(const EventRecord &/*inMacEvent*/)
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
USearchHelper::EnableDisablePane(mSearchButton, mSearchManager.CanSearch());
|
||
|
}
|
||
|
|
||
|
//-----------------------------------
|
||
|
void CSearchWindowBase::Activate()
|
||
|
// Start repeating.
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
StopIdling();
|
||
|
StartRepeating();
|
||
|
|
||
|
// CSearchTabGroup *theTabGroup = USearchHelper::FindWindowTabGroup(&mSubCommanders);
|
||
|
// Boolean couldRotate = theTabGroup->SetCanRotate(false); // Don't rotate when activating
|
||
|
|
||
|
Inherited::Activate();
|
||
|
|
||
|
// theTabGroup->SetCanRotate(couldRotate);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------
|
||
|
void CSearchWindowBase::DeactivateSelf()
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
StopRepeating();
|
||
|
StartIdling();
|
||
|
|
||
|
Inherited::DeactivateSelf();
|
||
|
}
|
||
|
|
||
|
//-----------------------------------
|
||
|
void CSearchWindowBase::DrawSelf()
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
Boolean doResultsTable = IsResultsTableVisible();
|
||
|
Rect frame;
|
||
|
|
||
|
if ( doResultsTable && mResultsTable->CalcPortFrameRect(frame) &&
|
||
|
::RectInRgn(&frame, mUpdateRgnH) )
|
||
|
{
|
||
|
{
|
||
|
StExcludeVisibleRgn excludeRgn(mResultsTable);
|
||
|
Inherited::DrawSelf();
|
||
|
}
|
||
|
|
||
|
StColorPenState::Normalize();
|
||
|
::EraseRect(&frame);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Inherited::DrawSelf();
|
||
|
}
|
||
|
|
||
|
USearchHelper::RemoveSizeBoxFromVisRgn(this);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------
|
||
|
void CSearchWindowBase::SetDescriptor(ConstStr255Param inDescriptor)
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
if ( !::EqualString(inDescriptor, *((WindowPeek) GetMacPort())->titleHandle, true, true) )
|
||
|
{
|
||
|
Inherited::SetDescriptor(inDescriptor);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------
|
||
|
void CSearchWindowBase::MessageSearchParamsResized(Int16 inResizeAmount)
|
||
|
// React to more message.
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
LPane *resultsView = USearchHelper::FindViewSubpane(this, paneID_ResultsEnclosure);
|
||
|
|
||
|
if ( inResizeAmount > 0 ) { // Make refresh look good!
|
||
|
resultsView->ResizeFrameBy(0, -inResizeAmount, true);
|
||
|
resultsView->MoveBy(0, inResizeAmount, true);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
resultsView->MoveBy(0, inResizeAmount, true);
|
||
|
resultsView->ResizeFrameBy(0, -inResizeAmount, true);
|
||
|
}
|
||
|
|
||
|
if ( !IsResultsTableVisible() )
|
||
|
{
|
||
|
Rect bounds;
|
||
|
CSaveWindowStatus::GetPaneGlobalBounds(this, &bounds);
|
||
|
bounds.bottom += inResizeAmount;
|
||
|
this->DoSetBounds(bounds); // Update window size
|
||
|
}
|
||
|
|
||
|
RecalcMinMaxStdSizes();
|
||
|
}
|
||
|
|
||
|
//-----------------------------------
|
||
|
void CSearchWindowBase::MessageWindSearch()
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
AssertFail_(mSearchManager.CanSearch());
|
||
|
|
||
|
MSG_SearchAttribute attrib;
|
||
|
Boolean sortBackwards;
|
||
|
mResultsTable->GetSortParams(&attrib, &sortBackwards);
|
||
|
|
||
|
mResultsTable->StartSearch(*mMailNewsContext, CMailNewsContext::GetMailMaster(),
|
||
|
attrib, sortBackwards);
|
||
|
|
||
|
mSearchButton->Hide();
|
||
|
USearchHelper::FindViewSubpane(this, paneID_Stop)->Show();
|
||
|
USearchHelper::FindViewSubpane(this, paneID_ScopeEnclosure)->Disable();
|
||
|
|
||
|
ShowHideSearchResults(true);
|
||
|
UpdatePort();
|
||
|
} // CSearchWindowBase::MessageWindSearch()
|
||
|
|
||
|
//-----------------------------------
|
||
|
void CSearchWindowBase::RecalcMinMaxStdSizes()
|
||
|
// Recalculate the window's min/max and std sizes based on the current window state.
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
if ( IsResultsTableVisible() )
|
||
|
{
|
||
|
mMinMaxSize.top = mMinVResultsSize;
|
||
|
mMinMaxSize.bottom = 16000;
|
||
|
mStandardSize.height = max_Int16;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Rect bounds;
|
||
|
CSaveWindowStatus::GetPaneGlobalBounds(this, &bounds);
|
||
|
mMinMaxSize.top = mMinMaxSize.bottom = mStandardSize.height = (bounds.bottom - bounds.top);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------
|
||
|
void CSearchWindowBase::ShowHideSearchResults(Boolean inDoShow)
|
||
|
// Show or hide the search results in this window by resizing the window vertically.
|
||
|
// If the results are being hidden, the last window vertical extension is stored in
|
||
|
// mResultsVertWindExtension, otherwise mResultsVertWindExtension is used for determining
|
||
|
// the amount to resize the window.
|
||
|
//
|
||
|
// If search results are hidden, all current results are deleted from the result table.
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
if ( IsResultsTableVisible() )
|
||
|
return;
|
||
|
|
||
|
Rect curBounds;
|
||
|
|
||
|
CSaveWindowStatus::GetPaneGlobalBounds(this, &curBounds);
|
||
|
|
||
|
Rect newBounds = curBounds;
|
||
|
|
||
|
if ( inDoShow )
|
||
|
{
|
||
|
if ( mResultsVertWindExtension < 0 ) mResultsVertWindExtension = -mResultsVertWindExtension; // Undo initialization
|
||
|
newBounds.bottom += mResultsVertWindExtension;
|
||
|
mResultsEnclosure->Show();
|
||
|
if ( (newBounds.bottom - newBounds.top) < mMinVResultsSize )
|
||
|
{
|
||
|
newBounds.bottom = newBounds.top + mMinVResultsSize;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Rect bounds2;
|
||
|
CSaveWindowStatus::GetPaneGlobalBounds(USearchHelper::FindViewSubpane(this, CSearchManager::paneID_ParamEncl),
|
||
|
&bounds2);
|
||
|
Int16 newBottom = (bounds2.left - newBounds.left) + bounds2.bottom;
|
||
|
if ( mResultsVertWindExtension >= 0 ) mResultsVertWindExtension = newBounds.bottom - newBottom;
|
||
|
newBounds.bottom = newBottom;
|
||
|
mResultsEnclosure->Hide();
|
||
|
}
|
||
|
|
||
|
mResultsTableVisible = inDoShow;
|
||
|
mMinMaxSize.bottom = max_Int16; // Set so that VerifyWindowBounds() can do its work correctly!
|
||
|
mMinMaxSize.top = 100; // Set so that VerifyWindowBounds() can do its work correctly!
|
||
|
|
||
|
CSaveWindowStatus::VerifyWindowBounds(this, &newBounds);
|
||
|
if ( !::EqualRect(&newBounds, &curBounds) )
|
||
|
{
|
||
|
this->DoSetBounds(newBounds);
|
||
|
}
|
||
|
|
||
|
RecalcMinMaxStdSizes();
|
||
|
}
|
||
|
|
||
|
//-----------------------------------
|
||
|
void CSearchWindowBase::UpdateResultsVertWindExtension()
|
||
|
// Update the vertical window extension variable.
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
if ( IsResultsTableVisible() && (mResultsVertWindExtension >= 0) )
|
||
|
{
|
||
|
Rect windBounds, enclBounds;
|
||
|
CSaveWindowStatus::GetPaneGlobalBounds(this, &windBounds);
|
||
|
CSaveWindowStatus::GetPaneGlobalBounds(USearchHelper::FindViewSubpane(
|
||
|
this, CSearchManager::paneID_ParamEncl), &enclBounds);
|
||
|
Int16 enclBottom = (enclBounds.left - windBounds.left) + enclBounds.bottom;
|
||
|
mResultsVertWindExtension = windBounds.bottom - enclBottom;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------
|
||
|
void CSearchWindowBase::ReadWindowStatus(LStream *inStatusData)
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
if ( inStatusData != nil )
|
||
|
{
|
||
|
Rect bounds;
|
||
|
*inStatusData >> bounds;
|
||
|
|
||
|
CSaveWindowStatus::MoveWindowTo(this, topLeft(bounds));
|
||
|
|
||
|
Int16 resultsVertWindExtension;
|
||
|
|
||
|
*inStatusData >> resultsVertWindExtension;
|
||
|
if ( resultsVertWindExtension > 0 )
|
||
|
{
|
||
|
mResultsVertWindExtension = -resultsVertWindExtension; // See the ShowHideSearchResults(), set to negative
|
||
|
// to mean initialization
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CSaveWindowStatus::MoveWindowToAlertPosition(this);
|
||
|
}
|
||
|
|
||
|
mSearchManager.ReadSavedSearchStatus(inStatusData);
|
||
|
if( inStatusData )
|
||
|
mResultsTable->GetTableHeader()->ReadColumnState(inStatusData);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------
|
||
|
void CSearchWindowBase::WriteWindowStatus(LStream *outStatusData)
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
CSaveWindowStatus::WriteWindowStatus(outStatusData);
|
||
|
|
||
|
UpdateResultsVertWindExtension();
|
||
|
|
||
|
*outStatusData << ((Int16) ((mResultsVertWindExtension > 0) ? mResultsVertWindExtension :
|
||
|
(-mResultsVertWindExtension)));
|
||
|
|
||
|
mSearchManager.WriteSavedSearchStatus(outStatusData);
|
||
|
|
||
|
mResultsTable->GetTableHeader()->WriteColumnState(outStatusData);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------
|
||
|
void CSearchWindowBase::UpdateTableStatusDisplay()
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
if ( !IsResultsTableVisible() ) return;
|
||
|
|
||
|
AssertFail_(mResultsTable != nil);
|
||
|
|
||
|
TableIndexT numItems, numSelectedItems;
|
||
|
|
||
|
mResultsTable->GetTableSize(numItems, numSelectedItems);
|
||
|
numSelectedItems = mResultsTable->GetSelectedRowCount();
|
||
|
|
||
|
CStr255 messageString;
|
||
|
if ( numItems > 0 )
|
||
|
{
|
||
|
CStr31 numString, selectedString;
|
||
|
::NumToString(numItems, numString);
|
||
|
if ( numSelectedItems > 0 )
|
||
|
{
|
||
|
::NumToString(numSelectedItems, selectedString);
|
||
|
USearchHelper::AssignUString(
|
||
|
(numItems == 1) ?
|
||
|
USearchHelper::USearchHelper::uStr_OneMessageFoundSelected :
|
||
|
USearchHelper::uStr_MultipleMessagesSelected,
|
||
|
messageString);
|
||
|
}
|
||
|
else
|
||
|
USearchHelper::AssignUString((numItems == 1) ? USearchHelper::uStr_OneMessageFound : USearchHelper::uStr_MultipleMessagesFound,
|
||
|
messageString);
|
||
|
::StringParamText(messageString, numString, selectedString);
|
||
|
|
||
|
}
|
||
|
else
|
||
|
USearchHelper::AssignUString(USearchHelper::uStr_NoMessagesFound, messageString);
|
||
|
|
||
|
mProgressBar->SetDescriptor(messageString);
|
||
|
|
||
|
}
|
||
|
|
||
|
//-----------------------------------
|
||
|
Boolean CSearchWindowBase::GetDefaultSearchTable(
|
||
|
CMailNewsWindow*& outMailNewsWindow,
|
||
|
CMailFlexTable*& outMailFlexTable)
|
||
|
// Using the current PP window hierarchy, determine if the current top regular window is
|
||
|
// a window that we can use to associate with our search window. This method is
|
||
|
// called just before the search window is brought to the front of the regular window
|
||
|
// hierarchy. If the method returns false, no window was found that could be associated
|
||
|
// with our search window and the output parameters are set to nil. If the method returns
|
||
|
// true, a window was found that has an active flex table, and both objects are returned
|
||
|
// in the output parameters.
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
outMailNewsWindow = nil;
|
||
|
outMailFlexTable = nil;
|
||
|
|
||
|
// Get the current top regular window of the type we need
|
||
|
CMediatedWindow *theFoundWindow = nil;
|
||
|
CWindowIterator theIterator(WindowType_Any);
|
||
|
do
|
||
|
{
|
||
|
if (theIterator.Next(theFoundWindow))
|
||
|
{
|
||
|
DataIDT windowType = theFoundWindow->GetWindowType();
|
||
|
switch (windowType)
|
||
|
{
|
||
|
case WindowType_SearchMailNews:
|
||
|
continue; // Found ourselves.
|
||
|
|
||
|
case WindowType_MailNews:
|
||
|
outMailNewsWindow = dynamic_cast<CMailNewsFolderWindow *>(theFoundWindow);
|
||
|
break;
|
||
|
|
||
|
case WindowType_MailThread:
|
||
|
case WindowType_Newsgroup:
|
||
|
outMailNewsWindow = dynamic_cast<CThreadWindow *>(theFoundWindow);
|
||
|
break;
|
||
|
|
||
|
case WindowType_Message:
|
||
|
outMailNewsWindow = dynamic_cast<CMessageWindow *>(theFoundWindow);
|
||
|
break;
|
||
|
}
|
||
|
if (outMailNewsWindow)
|
||
|
break; // Found a MailNews window that can return a "search table"
|
||
|
}
|
||
|
else
|
||
|
theFoundWindow = nil;
|
||
|
}
|
||
|
while (theFoundWindow != nil);
|
||
|
|
||
|
if (outMailNewsWindow)
|
||
|
{
|
||
|
// Is there an active target table?
|
||
|
outMailFlexTable = outMailNewsWindow->GetSearchTable();
|
||
|
if (outMailFlexTable == nil)
|
||
|
outMailNewsWindow = nil;
|
||
|
|
||
|
}
|
||
|
return (outMailFlexTable != nil);
|
||
|
}
|
||
|
|
||
|
|
||
|
//-----------------------------------
|
||
|
void CSearchWindowBase::MessageWindStop(Boolean inUserAborted)
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
if ( mSearchManager.IsSearching() )
|
||
|
{
|
||
|
mSearchManager.StopSearch(inUserAborted ? ((MWContext *) *mMailNewsContext) : nil);
|
||
|
mSearchButton->Show();
|
||
|
USearchHelper::FindViewSubpane(this, paneID_Stop)->Hide();
|
||
|
USearchHelper::FindViewSubpane(this, paneID_ScopeEnclosure)->Enable();
|
||
|
|
||
|
// This call fixes a bug in the BE search row insertion
|
||
|
mResultsTable->ForceCurrentSort();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*======================================================================================
|
||
|
Return a display name for the specified folder name.
|
||
|
======================================================================================*/
|
||
|
|
||
|
CStr255& CSearchWindowBase::GetFolderDisplayName(const char *inFolderName, CStr255& outFolderName)
|
||
|
{
|
||
|
outFolderName = inFolderName;
|
||
|
char* temp = (char*)outFolderName;
|
||
|
NET_UnEscape(temp);
|
||
|
outFolderName = temp;
|
||
|
return outFolderName;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*======================================================================================
|
||
|
Get the display text for the specified attribute and table row index. Return
|
||
|
kNumAttributes if the inCellDataType is invalid.
|
||
|
======================================================================================*/
|
||
|
|
||
|
MSG_SearchAttribute CSearchWindowBase::AttributeFromDataType(PaneIDT inCellDataType)
|
||
|
{
|
||
|
MSG_SearchAttribute rtnVal;
|
||
|
|
||
|
switch ( inCellDataType )
|
||
|
{
|
||
|
// Message search columns
|
||
|
case kSubjectMessageColumn: rtnVal = attribSubject; break;
|
||
|
case kSenderMessageColumn: rtnVal = attribSender; break;
|
||
|
case kDateMessageColumn: rtnVal = attribDate; break;
|
||
|
case kStatusMessageLocation: rtnVal = attribLocation; break;
|
||
|
case kPriorityMessageColumn: rtnVal = attribPriority; break;
|
||
|
case kStatusMessageColumn: rtnVal = attribMsgStatus; break;
|
||
|
default: rtnVal = kNumAttributes; break;
|
||
|
}
|
||
|
|
||
|
return rtnVal;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*======================================================================================
|
||
|
Return a sort data type from the specified sort command. Return 0L if the
|
||
|
inSortCommand is invalid.
|
||
|
======================================================================================*/
|
||
|
|
||
|
PaneIDT CSearchWindowBase::DataTypeFromSortCommand(CommandT inSortCommand)
|
||
|
{
|
||
|
PaneIDT rtnVal;
|
||
|
|
||
|
switch ( inSortCommand )
|
||
|
{
|
||
|
case cmd_SortBySubject: rtnVal = kSubjectMessageColumn; break;
|
||
|
case cmd_SortBySender: rtnVal = kSenderMessageColumn; break;
|
||
|
case cmd_SortByDate: rtnVal = kDateMessageColumn; break;
|
||
|
case cmd_SortByLocation: rtnVal = kStatusMessageLocation; break;
|
||
|
case cmd_SortByPriority: rtnVal = kPriorityMessageColumn; break;
|
||
|
case cmd_SortByStatus: rtnVal = kStatusMessageColumn; break;
|
||
|
// Do we need these commands for column sorting in the LDAP search result pane?
|
||
|
default: rtnVal = cmd_Nothing; break;
|
||
|
}
|
||
|
|
||
|
return rtnVal;
|
||
|
}
|
||
|
|
||
|
|
||
|
//-----------------------------------
|
||
|
void CSearchWindowBase::AddOneScopeMenuItem(
|
||
|
Int16 inStringIndex,
|
||
|
Int16 inAttrib
|
||
|
)
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
CStr255 string;
|
||
|
USearchHelper::AssignUString(inStringIndex, string);
|
||
|
AddOneScopeMenuItem(string, inAttrib);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------
|
||
|
void CSearchWindowBase::AddOneScopeMenuItem(
|
||
|
const CStr255& inString,
|
||
|
Int16 inAttrib
|
||
|
)
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
Assert_(mNumBasicScopeMenuItems < MAX_SEARCH_MENU_ITEMS);
|
||
|
if (mNumBasicScopeMenuItems < MAX_SEARCH_MENU_ITEMS)
|
||
|
{
|
||
|
MSG_SearchMenuItem& curItem = mSearchMenuItems[mNumBasicScopeMenuItems];
|
||
|
LString::CopyPStr(inString, (UInt8*)curItem.name, sizeof(curItem.name));
|
||
|
curItem.attrib = inAttrib;
|
||
|
curItem.isEnabled = true;
|
||
|
++mNumBasicScopeMenuItems;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//-----------------------------------
|
||
|
void CSearchWindowBase::SetWinCSID(Int16 wincsid)
|
||
|
//-----------------------------------
|
||
|
{
|
||
|
if(mMailNewsContext)
|
||
|
mMailNewsContext->SetWinCSID(wincsid);
|
||
|
if(mResultsTable)
|
||
|
mResultsTable->SetWinCSID(wincsid);
|
||
|
mSearchManager.SetWinCSID(wincsid);
|
||
|
}
|
||
|
|