/* -*- 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) 1996 Netscape Communications Corporation. All Rights * Reserved. */ // CThreadWindow.cp // This is the 3-pane mail window #include "CThreadWindow.h" #include "CMessageFolder.h" #include "CGrayBevelView.h" #include "CProgressListener.h" #include "CBrowserContext.h" #include "CThreadView.h" #include "CMessageView.h" #include "CMessageFolderView.h" #include "CMailFolderButtonPopup.h" #include "CSpinningN.h" #include "CApplicationEventAttachment.h" #include "CMailProgressWindow.h" #include "CProxyPane.h" #include "CProxyDragTask.h" #include "LTableViewHeader.h" #include "CTargetFramer.h" #include "resgui.h" #include "MailNewsgroupWindow_Defines.h" #include "msg_srch.h" //#include "secnav.h" #include "uapp.h" #include "macutil.h" #include "StSetBroadcasting.h" #include "earlmgr.h" #include "prefapi.h" #include #include #include "CMessageAttachmentView.h" #include "CThreadMessageController.h" #include "CFolderThreadController.h" #include "UDeferredTask.h" #include "UMailSelection.h" #define kTwistieID 'Twst' static const PaneIDT paneID_ThreadFileButton = 'Bfil'; static const PaneIDT paneID_ThreadReplyButton = 'Brep'; static const PaneIDT paneID_ThreadGetMailButton = 'Bget'; // mail static const PaneIDT paneID_ThreadGetNewsButton = 'Bmor'; // news static const PaneIDT paneID_ThreadComposeButton = 'Bcmp'; // mail static const PaneIDT paneID_ThreadPostNewButton = 'Bpst'; // news static const PaneIDT paneID_ThreadPrintButton = 'Bprn'; // mail static const PaneIDT paneID_ThreadBackButton = 'Bbck'; // news static const PaneIDT paneID_ThreadDeleteButton = 'Bdel'; // mail static const PaneIDT paneID_ThreadMarkButton = 'Bmrk'; // news const PaneIDT paneID_ThreadRelocateButton = 'MfPM'; //----------------------------------- CThreadWindow::CThreadWindow(LStream *inStream) //----------------------------------- : Inherited(inStream, WindowType_MailThread) , mStatusResID(res_ID) , mThreadView(nil) , mFolderContext(nil) , mFolderView(nil) , mFolderThreadController(nil) , mThreadMessageController(nil) { } // CThreadWindow::CThreadWindow //----------------------------------- CThreadWindow::~CThreadWindow() //----------------------------------- { if (mFolderContext) { mFolderContext->RemoveUser(this); mFolderContext = nil; } } // CThreadWindow::~CThreadWindow #define kButtonBarResID 10513 // Common included button bar for thread windows. // This has the RIdl for the buttons. //----------------------------------- void CThreadWindow::FinishCreateSelf() //----------------------------------- { CNetscapeWindow::FinishCreateSelf(); // SKIP CMailNewsWindow, and roll our own! // should be in resource, but there's a resource freeze. CExpandoDivider* threadMessageExpandoView = dynamic_cast(FindPaneByID('Expo')); // Initialize our stored view pointers. CMessageView* messageView = GetMessageView(); Assert_(messageView); GetThreadView(); Assert_(mThreadView); // Else you're deadybones! CMessageAttachmentView* attachmentView = dynamic_cast( FindPaneByID('MATv') ); mFolderView = dynamic_cast(FindPaneByID('Flst')); ThrowIfNil_(mFolderView); //----------- // The following code is analogous to // CMailNewsWindow::FinishCreateSelf() except it deals with mFolderContext // as well as mMailNewsContext //----------- // Let there be a thread context mMailNewsContext = CreateContext(); mMailNewsContext->AddUser(this); // Let there be a progress listener, placed in my firmament, // which shall listen to both contexts mProgressListener = new CProgressListener(this, mMailNewsContext); // Let there be a folder context mFolderContext = new CMailNewsContext(MWContextMail); StSharer theLock(mFolderContext); mFolderContext->AddUser(this); // The progress listener must also listen to the folder context mFolderContext->AddListener(mProgressListener); #if !ONECONTEXTPERWINDOW // Make a listener list for the message context typedef LListener* SListenerPointer; const UInt8 kNumberOfListeners = 2; LListener** messageContextListeners = new SListenerPointer[kNumberOfListeners + 1]; // The progress listener must also listen to the message context. messageContextListeners[0] = mProgressListener; #endif // The progress listener is "just a bit" lazy during network activity and // "not at all" at idle time to display the URLs pointed by the mouse cursor. mProgressListener->SetLaziness(CProgressListener::lazy_NotAtAll); // The spinning N must listen to all three contexts CSpinningN* theN = dynamic_cast(FindPaneByID(CSpinningN::class_ID)); if (theN) { mFolderContext->AddListener(theN); mMailNewsContext->AddListener(theN); #if !ONECONTEXTPERWINDOW messageContextListeners[1] = theN; #endif } #if !ONECONTEXTPERWINDOW // Terminate the listener list messageContextListeners[kNumberOfListeners] = 0; #endif mThreadMessageController = new CThreadMessageController( threadMessageExpandoView , mThreadView , messageView , attachmentView #if !ONECONTEXTPERWINDOW , messageContextListeners #endif ); mThreadMessageController->InitializeDimensions(); // ThreadMessageController is a CExpandoListener, so let it do some listening! LControl* twistie = dynamic_cast(FindPaneByID(kTwistieID)); if (twistie) twistie->AddListener((CExpandoListener*)mThreadMessageController); //----------- // The next part of this code code is analogous to // CMailNewsFolderWindow::FinishCreateSelf() except it deals with mFolderContext // instead of mMailNewsContext //----------- mFolderView->LoadFolderList(mFolderContext); UReanimator::LinkListenerToControls(mFolderView, this, kButtonBarResID); // Make the Folder/Thread Controller LDividedView* folderThreadExpandoView = dynamic_cast(FindPaneByID('ExCt')); mFolderThreadController = new CFolderThreadController( folderThreadExpandoView, mMailNewsContext, mFolderView, mThreadView); SetLatentSub(mFolderView); mMailNewsContext->AddListener(mThreadView); // listen for all connections complete. mFolderContext->AddListener(mFolderView); // listen for all connections complete. mThreadMessageController->FinishCreateSelf(); // The folder-thread controller is a tabgroup, tabbing between the folder, thread, // and message views. We have to add the message view explicitly to the folder- // thread controller here, because it doesn't know about the message view. And we have to // do that after the folder-thread controller adds the folder and thread subcommanders. mFolderThreadController->FinishCreateSelf(); messageView->SetSuperCommander(mFolderThreadController); CTargetFramer* framer = new CTargetFramer(); messageView->AddAttachment(framer); // make the message view listen to buttons UReanimator::LinkListenerToControls((CMessageView::Inherited *)messageView, this, kButtonBarResID); // If the folder-thread controller can't handle a command (because the wrong pane // is the target), let it pass it up to the thread-message controller, which has a // mechanism for delegating to the message view. mFolderThreadController->SetSuperCommander(mThreadMessageController); mThreadMessageController->SetSuperCommander(this); // The 2-pane and 3-pane thread view have the same pane controls, so: UReanimator::LinkListenerToControls(mThreadView, this, kButtonBarResID); USecurityIconHelpers::AddListenerToSmallButton( this /*LWindow**/, mThreadView /*LListener**/); LGAIconSuiteControl* offlineButton = dynamic_cast(FindPaneByID(kOfflineButtonPaneID)); if (offlineButton) offlineButton->AddListener(CFrontApp::GetApplication()); LControl* stopButton = dynamic_cast(FindPaneByID('Bstp')); if (stopButton) stopButton->AddListener((CHTMLView*)messageView); // Create the new window just like the frontmost one of the same type, if possible CWindowIterator iter(WindowType_MailThread); CMediatedWindow* window; CThreadWindow* templateWindow = nil; for (iter.Next(window); window; iter.Next(window)) { templateWindow = dynamic_cast(window); if (!templateWindow || templateWindow != this) break; } if (templateWindow && templateWindow != this) { // Use the template window CSaveWindowStatus::FinishCreateWindow(templateWindow); } else { //Get it from disk CSaveWindowStatus::FinishCreateWindow(); } ReadGlobalDragbarStatus(); AdjustStagger(WindowType_MailThread); // And behold, he saw that it was good. SetLatentSub(mThreadView); SwitchTarget(mThreadView); // only one of these will work. } // CThreadWindow::FinishCreateSelf //----------------------------------- void CThreadWindow::AboutToClose() //----------------------------------- { CSaveWindowStatus::AttemptCloseWindow(); // Do this first: uses table and calls the window's WriteWindowStatus() method WriteGlobalDragbarStatus(); mFolderView = nil; // This is special: mFolderContext->RemoveListener(mProgressListener); if (mFolderView) { if (mFolderContext) mFolderContext->RemoveListener(mFolderView); // don't listen for all connections complete. mFolderView = nil; } mThreadView = nil; // This is special: mMailNewsContext->RemoveListener(mProgressListener); if (mThreadView) { if (mMailNewsContext) mMailNewsContext->RemoveListener(mThreadView); // don't listen for all connections complete. mThreadView = nil; } if (mThreadMessageController) { mThreadMessageController->InstallMessagePane(false); mThreadMessageController->SetThreadView(nil); // delete mThreadMessageController; No, it's a subcommander and will be deleted when we are. mThreadMessageController = nil; } // InstallMessagePane(false) can call InterruptContext, which in turn can show the window // so we must call Hide() here. Hiding is necessary so that views in the window are not // the current target while we are deleting them here. if (IsVisible()) Hide(); // Delete the folder-thread controller now, thus deleting all the msglib panes. We have // to do that first before deleting the context, because the destructor of the pane // references the context. Caution: Commanders delete all their subcommanders // when they die. So detach it before we delete it, so that our destructor doesn't // perform a double-deletion. //SwitchTarget(this); mFolderThreadController->SetSuperCommander(nil); delete mFolderThreadController; mFolderThreadController = nil; CSpinningN* theN = dynamic_cast(FindPaneByID(CSpinningN::class_ID)); if (theN) mFolderContext->RemoveListener(theN); } // CThreadWindow::AboutToClose //---------------------------------------------------------------------------------------- CNSContext* CThreadWindow::CreateContext() const //---------------------------------------------------------------------------------------- { #if ONECONTEXTPERWINDOW CNSContext* result = new CBrowserContext(MWContextMailMsg); FailNIL_(result); return result; #else return Inherited::CreateContext(); #endif } //CMailNewsWindow::CreateContext //---------------------------------------------------------------------------------------- static void InterruptTableContext(CMailFlexTable* inTable) //---------------------------------------------------------------------------------------- { if (inTable) { CNSContext* context = inTable->GetContext(); if (context) XP_InterruptContext(*context); } } //---------------------------------------------------------------------------------------- static Boolean IsTableContextBusy(CMailFlexTable* inTable) //---------------------------------------------------------------------------------------- { if (inTable) { CNSContext* context = inTable->GetContext(); if (context) return XP_IsContextBusy(*context); } return false; } //---------------------------------------------------------------------------------------- void CThreadWindow::StopAllContexts() //---------------------------------------------------------------------------------------- { InterruptTableContext(GetFolderView()); InterruptTableContext(GetThreadView()); #if !ONECONTEXTPERWINDOW CMessageView* mv = GetMessageView(); if (mv) { CBrowserContext* context = mv->GetContext(); if (context) XP_InterruptContext(*context); } #endif } //---------------------------------------------------------------------------------------- Boolean CThreadWindow::IsAnyContextBusy() //---------------------------------------------------------------------------------------- { Boolean busy = IsTableContextBusy(GetFolderView()); if (!busy) busy = IsTableContextBusy(GetThreadView()); #if !ONECONTEXTPERWINDOW if (!busy) { CMessageView* mv = GetMessageView(); if (mv) { CBrowserContext* context = mv->GetContext(); if (context) return XP_IsContextBusy(*context); } } #endif return busy; } //----------------------------------- void CThreadWindow::UpdateFilePopupCurrentItem() //----------------------------------- { CThreadView *threadView = GetThreadView(); MSG_FolderInfo* folderInfo = nil; if (threadView != nil) folderInfo = threadView->GetOwningFolder(); CMailFolderPatternTextPopup *popup2 = dynamic_cast(FindPaneByID(paneID_ThreadRelocateButton)); if ( popup2 != nil && threadView->GetOwningFolder()) { StSetBroadcasting setBroadcasting(popup2, false); // Don't broadcast anything here popup2->MSetSelectedFolder(folderInfo); } CMailFolderSubmenu::SetSelectedFolder(folderInfo); } // CThreadWindow::UpdateFilePopupCurrentItem //----------------------------------- void CThreadWindow::ActivateSelf() //----------------------------------- { Inherited::ActivateSelf(); #if 0 // Don't do this for the 3-pane UI // make sure the message view isn't target CMailFlexTable* threadView = GetThreadView(); if (threadView) { SwitchTarget(threadView); } #endif UpdateFilePopupCurrentItem(); // Is this really necessary? } // CThreadWindow::ActivateSelf //----------------------------------- void CThreadWindow::AdaptToolbarToFolder() //----------------------------------- { CThreadView* threadView = GetThreadView(); if (threadView == nil) return; // show/hide buttons depending on the window type (News vs Mail) LControl * aControl; Boolean isNewsWindow = ((threadView->GetFolderFlags() & MSG_FOLDER_FLAG_NEWSGROUP) != 0); static const short kBtnCount = 3; PaneIDT mailBtn[kBtnCount] = { paneID_ThreadGetMailButton, paneID_ThreadComposeButton, paneID_ThreadDeleteButton // update kBtnCount if you add a btn }; PaneIDT newsBtn[kBtnCount] = { paneID_ThreadGetNewsButton, paneID_ThreadPostNewButton, paneID_ThreadMarkButton // update kBtnCount if you add a btn }; for (short btnIndex = 0; btnIndex < kBtnCount; btnIndex ++) { if (isNewsWindow) { aControl = dynamic_cast(FindPaneByID(mailBtn[btnIndex])); if (aControl != nil) aControl->Hide(); aControl = dynamic_cast(FindPaneByID(newsBtn[btnIndex])); if (aControl != nil) aControl->Show(); } else { aControl = dynamic_cast(FindPaneByID(newsBtn[btnIndex])); if (aControl != nil) aControl->Hide(); aControl = dynamic_cast(FindPaneByID(mailBtn[btnIndex])); if (aControl != nil) aControl->Show(); } } // other changes depending on the window type if (isNewsWindow) { aControl = dynamic_cast(FindPaneByID(paneID_ThreadReplyButton)); if (aControl != nil) aControl->SetValueMessage(cmd_PostReply); // quick-click default } else { aControl = dynamic_cast(FindPaneByID(paneID_ThreadReplyButton)); if (aControl != nil) aControl->SetValueMessage(cmd_ReplyToSender); // quick-click default } CMessageFolder owningFolder(threadView->GetOwningFolder()); ResIDT iconID = owningFolder.GetIconID(); LIconPane* proxyIcon = dynamic_cast(FindPaneByID('poxy')); if (proxyIcon) proxyIcon->SetIconID(iconID); CProxyPane* newProxy = dynamic_cast(FindPaneByID(CProxyPane::class_ID)); if (newProxy) { newProxy->SetIconIDs(iconID, iconID); } } // CThreadWindow::AdaptToolbarToFolder //----------------------------------- CMailFlexTable* CThreadWindow::GetActiveTable() // Get the currently active table in the window. The active table is the table in // the window that the user considers to be receiving input. //----------------------------------- { CMailFlexTable* result = GetFolderView(); if (result && result->IsOnDuty()) return result; return GetThreadView(); } // CThreadWindow::GetActiveTable //----------------------------------- CMailFlexTable* CThreadWindow::GetSearchTable() // Get the table which should be used to set the search base node. The base class // returns GetActiveTable() for this, but now life is more complicated... // The fix is to return the folder view, even if it is not currently the target. Otherwise, // if we try to return the thread view and it's not currently displaying a folder, bad things // can happen. //----------------------------------- { CMailFlexTable* result = GetFolderView(); if (result) return result; result = GetThreadView(); if (::MSG_GetCurFolder(result->GetMessagePane())) return result; return nil; } // CThreadWindow::GetActiveTable //----------------------------------- CMessageFolderView* CThreadWindow::GetFolderView() //----------------------------------- { return mFolderView; } // CThreadWindow::GetFolderView //----------------------------------- CThreadView* CThreadWindow::GetThreadView() //----------------------------------- { if (!mThreadView) mThreadView = dynamic_cast(FindPaneByID('Tabl')); return mThreadView; } // CThreadWindow::GetThreadView //----------------------------------- CMessageView* CThreadWindow::GetMessageView() //----------------------------------- { return dynamic_cast(FindPaneByID(CMessageView::class_ID)); } //----------------------------------- void CThreadWindow::ShowMessageKey(MessageKey inKey) //----------------------------------- { CThreadView* threadView = GetThreadView(); Assert_(threadView); threadView->SelectMessageWhenReady(inKey); } // CThreadWindow::ShowSearchMessage //----------------------------------- CThreadWindow* CThreadWindow::FindOrCreate( const MSG_FolderInfo* inFolderInfo, CommandT inCommand) //----------------------------------- { // First see if there's an open window open to this folder. ThrowIf_(Memory_MemoryIsLow()); CWindowIterator iter(WindowType_MailThread); CMediatedWindow* window; CThreadWindow* threadWindow = nil; for (iter.Next(window); window; iter.Next(window)) { threadWindow = dynamic_cast(window); ThrowIfNULL_(threadWindow); CThreadView* threadView = threadWindow->GetThreadView(); ThrowIfNULL_(threadView); if (threadView->GetOwningFolder() == inFolderInfo) { if (inCommand != cmd_Nothing) threadView->ObeyCommand(inCommand, nil); return threadWindow; } } // Window not found: let's create it return FindAndShow(inFolderInfo, true, inCommand, true); } // CThreadWindow::FindOrCreate //----------------------------------- CThreadWindow* CThreadWindow::FindAndShow( const MSG_FolderInfo* inFolderInfo, Boolean inMakeNew, CommandT inCommand, Boolean forceNewWindow) //----------------------------------- { // NOTE: all references to 'categories' have been removed from // this function in v1.63 on Tuesday 97/06/03. // First see if there's an open window open to this folder. // If there is, bring it to the front. ThrowIf_(Memory_MemoryIsLow()); CWindowIterator iter(WindowType_MailThread, false); // false, don't want hidden windows. CMediatedWindow* window; CThreadWindow* existingThreadWindow = nil; CThreadWindow* threadWindow = nil; for (iter.Next(window); window; iter.Next(window)) { existingThreadWindow = dynamic_cast(window); ThrowIfNULL_(existingThreadWindow); CThreadView* tempThreadView = existingThreadWindow->GetThreadView(); ThrowIfNULL_(tempThreadView); if (tempThreadView->GetOwningFolder() == inFolderInfo) { threadWindow = existingThreadWindow; // Found it! break; } } if (!threadWindow && !inMakeNew) return nil; // Re-use another Thread window, if possible... if (!threadWindow && !forceNewWindow) { XP_Bool prefReuseWindow; PREF_GetBoolPref("mailnews.reuse_thread_window", &prefReuseWindow); if ( CApplicationEventAttachment::CurrentEventHasModifiers(optionKey) ) prefReuseWindow = !prefReuseWindow; if (prefReuseWindow) { CWindowIterator iter(WindowType_MailThread); iter.Next(threadWindow); // use the frontmost open thread window } } // ...Otherwise create a new window CMessageFolder folder(inFolderInfo); if (!threadWindow) { try { ::SetCursor(*::GetCursor(watchCursor)); SetDefaultCommander(LCommander::GetTopCommander()); SetDefaultAttachable(nil); threadWindow = (CThreadWindow*) UReanimator::ReadObjects('PPob', res_ID); #if 0 // FIX ME: for CSaveWindowStatus, use one resID for inbox, and 2-pane resid // for all other thread panes. We will not use staggering for inbox. threadWindow->SetStatusResID(folder.IsInbox() ? res_ID : res_ID_Alt); #endif threadWindow->SetStatusResID(res_ID); threadWindow->FinishCreate(); } catch (...) { delete threadWindow; threadWindow = nil; throw; } } CThreadView* messageList = threadWindow->GetThreadView(); ThrowIfNULL_(messageList); // Load in the Mail messages or News postings if (messageList->GetOwningFolder() != inFolderInfo) { try { ::SetCursor(*::GetCursor(watchCursor)); if (threadWindow->mProgressListener) threadWindow->mProgressListener->SetLaziness( CProgressListener::lazy_VeryButForThisCommandOnly); messageList->EnableStopButton(true); CMessageFolderView* folderView = threadWindow->GetFolderView(); if (folderView) folderView->SelectFolder(inFolderInfo); else messageList->LoadMessageFolder( (CMailNewsContext*)threadWindow->GetWindowContext(), // thread view's own context folder); // loadNow = false. } catch(...) { // Note, threadView has timer that will delete window. throw; } } if (inCommand == cmd_GetNewMail) { // only do a get new mail here if were are executing the command on an existing window // (because the user must have really wanted it if the command was passed in) // or if we are online and the folder is pop (because IMAP gets new mail automatically // if the folder is loaded for the first time). if (threadWindow == existingThreadWindow || (!NET_IsOffline() && !(folder.GetFolderFlags() & MSG_FOLDER_FLAG_IMAPBOX))) { // A thread window has two panes that can handle this command. If the thread // pane is busy, why not give the folder pane something to do? Boolean handled = false; CNSContext* context = messageList->GetContext(); if (context && XP_IsContextBusy(*context)) { CMessageFolderView* fv = threadWindow->GetFolderView(); if (fv) { context = fv->GetContext(); if (context && !XP_IsContextBusy(*context)) { CDeferredTaskManager::Post(new CDeferredCommand(fv, inCommand, nil), fv); handled = true; } } } if (!handled) messageList->ObeyCommandWhenReady(inCommand); } } else if (inCommand != cmd_Nothing) messageList->ObeyCommandWhenReady(inCommand); threadWindow->Show(); threadWindow->Select(); // HACK TO SUPPORT OPENING OF MORE THAN ONE FOLDER. // Otherwise, the BE doesn't initialize itself completely and the second window // fails. EventRecord ignoredEvent = {0}; TheEarlManager.SpendTime(ignoredEvent); return threadWindow; } // CThreadWindow::FindAndShow //----------------------------------- CThreadWindow* CThreadWindow::OpenFromURL(const char* url) //----------------------------------- { CThreadWindow* threadWindow = nil; MSG_FolderInfo* folderInfo = MSG_GetFolderInfoFromURL( CMailNewsContext::GetMailMaster(), url, true); if (!folderInfo) return nil; if (!CThreadWindow::FindAndShow(folderInfo, CThreadWindow::kDontMakeNew)) threadWindow = CThreadWindow::FindAndShow(folderInfo, CThreadWindow::kMakeNew); return threadWindow; } //----------------------------------- cstring CThreadWindow::GetCurrentURL() const //----------------------------------- { if (mThreadMessageController) return mThreadMessageController->GetCurrentURL(); else return cstring(""); } //----------------------------------- void CThreadWindow::SetFolderName(const char* inFolderName, Boolean inIsNewsgroup) //----------------------------------- { UpdateFilePopupCurrentItem(); AdaptToolbarToFolder(); if (!inFolderName) return; #if PRAGMA_ALIGN_SUPPORTED #pragma options align=mac68k #else #error "There'll probably be a bug here." #endif struct WindowTemplate { Rect boundsRect; short procID; Boolean visible; Boolean filler1; Boolean goAwayFlag; Boolean filler2; long refCon; Str255 title; }; #if PRAGMA_ALIGN_SUPPORTED #pragma options align=reset #endif // Name of window in PPob is "Netscape ^0 Ò^1Ó WindowTemplate** wt = (WindowTemplate**)GetResource('WIND', CThreadWindow::res_ID); Assert_(wt); if (wt) { StHandleLocker((Handle)wt); CStr255 windowTitle((*wt)->title); ReleaseResource((Handle)wt); CStr255 typeString; // Get "folder" or "newsgroup" as appropriate GetIndString(typeString, 7099, 1 + inIsNewsgroup); ::StringParamText(windowTitle, (const char*)typeString, inFolderName); SetDescriptor(windowTitle); CProxyPane* proxy = dynamic_cast(FindPaneByID(CProxyPane::class_ID)); if (proxy) proxy->ListenToMessage(msg_NSCDocTitleChanged, (char*)windowTitle); } } // CThreadWindow::SetFolderName //----------------------------------- void CThreadWindow::CloseAll(const MSG_FolderInfo* inFolderInfo) //----------------------------------- { CThreadWindow* win; do { win = CThreadWindow::FindAndShow(inFolderInfo); if (win) win->AttemptClose(); } while (win); } // CThreadWindow::CloseAll //----------------------------------- CThreadWindow* CThreadWindow::ShowInbox(CommandT inCommand) //----------------------------------- { CThreadWindow* result = nil; if (!CMailProgressWindow::GettingMail()) { CMailNewsContext::ThrowIfNoLocalInbox(); // prefs have not been set up. MSG_FolderInfo* inboxFolderInfo = nil; int32 numberOfInboxes = MSG_GetFoldersWithFlag( CMailNewsContext::GetMailMaster(), MSG_FOLDER_FLAG_INBOX, &inboxFolderInfo, 1); if (!numberOfInboxes || inboxFolderInfo == nil) CMailNewsContext::AlertPrefAndThrow(PREF_PopHost); result = FindAndShow(inboxFolderInfo, true, inCommand); } return result; } // CThreadWindow::ShowInbox //----------------------------------- UInt16 CThreadWindow::GetValidStatusVersion() const //----------------------------------- { return 0x0132; // to be updated whenever the form of the saved window data changes } // CThreadWindow::GetValidStatusVersion() //----------------------------------- void CThreadWindow::ReadWindowStatus(LStream *inStatusData) //----------------------------------- { //LCommander::SwitchTarget(mFolderView); // make sure it's the active table Inherited::ReadWindowStatus(inStatusData); if (inStatusData) { if (mFolderView) mFolderView->ReadSavedTableStatus(inStatusData); if (mThreadView) mThreadView->ReadSavedTableStatus(inStatusData); mThreadMessageController->ReadStatus(inStatusData); mFolderThreadController->ReadStatus(inStatusData); // We are currently closed, whatever the value of mExpandState may say (after // all, we only just read in the value). So we set mExpandState back to // closed_state, and bang the twistie to set everything the right way. ExpandStateT state = mThreadMessageController->GetExpandState(); mThreadMessageController->NoteExpandState(closed_state); LControl* twistie = dynamic_cast(FindPaneByID(kTwistieID)); mThreadMessageController->SetStoreStatusEnabled(false); if (twistie) twistie->SetValue(state); mThreadMessageController->SetStoreStatusEnabled(true); } } // CThreadWindow::ReadWindowStatus //----------------------------------- void CThreadWindow::WriteWindowStatus(LStream *outStatusData) // Overridden to stagger in the default case. //----------------------------------- { // don't mess with targets when closing windows any more //LCommander::SwitchTarget(mFolderView); // make sure it's the active table Inherited::WriteWindowStatus(outStatusData); // write the drag bar status and window location if (outStatusData) { if (mFolderView) mFolderView->WriteSavedTableStatus(outStatusData); if (mThreadView) mThreadView->WriteSavedTableStatus(outStatusData); mThreadMessageController->WriteStatus(outStatusData); // write expando status mFolderThreadController->WriteStatus(outStatusData); // write divided view status } } // CThreadWindow::WriteWindowStatus //----------------------------------- ResIDT CThreadWindow::GetStatusResID() const //----------------------------------- { return mStatusResID; } // CThreadWindow::GetStatusResID() #if 0 //----------------------------------- Boolean CThreadWindow::ObeyMotionCommand(MSG_ViewIndex index, MSG_MotionType cmd) //----------------------------------- { if (GetExpandState() == closed_state) return false; Try_ { CMessageView* messageView = GetMessageView(); if (messageView && messageView->ObeyMotionCommand(cmd)) { CThreadView* threadView = GetThreadView(); STableCell cell(resultIndex + 1,1); threadView->UnselectAllCells(); threadView->SelectCell(cell); } else Throw_(noErr); } Catch_ (err) { SysBeep(1); } EndCatch_ return false; } // CThreadWindow::ObeyMotionCommand #endif // 0 //----------------------------------- Boolean CThreadWindow::ObeyCommand( CommandT inCommand, void *ioParam) //----------------------------------- { switch (inCommand) { case cmd_RelocateViewToFolder: // Command was not (could not be) handled by the ThreadView, // so we leave the window as it is and just update the Location popup. UpdateFilePopupCurrentItem(); return true; case cmd_SelectSelection: // This command comes from the context menu, as the default in the thread view. LControl* twistie = dynamic_cast(FindPaneByID(kTwistieID)); if (twistie) twistie->SetValue(true); // and nature will take its course... return true; } return Inherited::ObeyCommand(inCommand, ioParam); } // CThreadWindow::ObeyCommand //----------------------------------- void CThreadWindow::FindCommandStatus( CommandT inCommand, Boolean &outEnabled, Boolean &outUsesMark, Char16 &outMark, Str255 outName) //----------------------------------- { switch (inCommand) { case cmd_SelectSelection: outEnabled = true; return; } Inherited::FindCommandStatus(inCommand, outEnabled, outUsesMark, outMark, outName); } // CThreadWindow::FindCommandStatus //----------------------------------- Int16 CThreadWindow::DefaultCSIDForNewWindow() //----------------------------------- { Int16 csid = 0; CMessageView* messageView = GetMessageView(); if (messageView) csid = messageView->DefaultCSIDForNewWindow(); if( 0 == csid) { CThreadView* threadView = GetThreadView(); if(threadView) csid = threadView->DefaultCSIDForNewWindow(); } return csid; } // CThreadWindow::DefaultCSIDForNewWindow //----------------------------------- void CThreadWindow::SetDefaultCSID(Int16 default_csid) //----------------------------------- { CMessageView* messageView = GetMessageView(); if (messageView) messageView->SetDefaultCSID(default_csid, true); // force repagination } // CThreadWindow::SetDefaultCSID //----------------------------------- URL_Struct* CThreadWindow::CreateURLForProxyDrag(char* outTitle) //----------------------------------- { return mThreadView->CreateURLForProxyDrag(outTitle); } // CThreadWindow::CreateURLForProxyDrag //---------------------------------------------------------------------------------------- const char* CThreadWindow::GetLocationBarPrefName() const //---------------------------------------------------------------------------------------- { if (mFolderThreadController) { const char* result = mFolderThreadController->GetLocationBarPrefName(); if (result) return result; } return Inherited::GetLocationBarPrefName(); } //---------------------------------------------------------------------------------------- CExtraFlavorAdder* CThreadWindow::CreateExtraFlavorAdder() const //---------------------------------------------------------------------------------------- { class ThreadWindowFlavorAdder : public CExtraFlavorAdder { public: ThreadWindowFlavorAdder(MSG_Pane* inFolderPane, MSG_FolderInfo* inFolderInfo) : mFolderPane(inFolderPane) , mFolderInfo(inFolderInfo) { } virtual void AddExtraFlavorData(DragReference inDragRef, ItemReference inItemRef) { // Pass a selection, as if this is done from a folder view. mSelection.xpPane = mFolderPane; if (!mSelection.xpPane) return; // drat. This is a real drag. MSG_ViewIndex viewIndex = ::MSG_GetFolderIndexForInfo( mFolderPane, mFolderInfo, true /*expand*/); if (viewIndex == MSG_VIEWINDEXNONE) return; mSelection.SetSingleSelection(viewIndex); ::AddDragItemFlavor( inDragRef, inItemRef, kMailNewsSelectionDragFlavor, &mSelection, sizeof(mSelection), 0); } private: MSG_Pane* mFolderPane; MSG_FolderInfo* mFolderInfo; CMailSelection mSelection; }; CThreadView* threadView = const_cast(this)->GetThreadView(); MSG_FolderInfo* folderInfo = threadView->GetOwningFolder(); MSG_Pane* folderPane = ::MSG_FindPane(nil, MSG_FOLDERPANE); return new ThreadWindowFlavorAdder(folderPane, folderInfo); } // CMessageWindow::CreateExtraFlavorAdder