home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C++ / Applications / Nuntius 1.2 / src / Nuntius / UArticleListView.cp < prev    next >
Encoding:
Text File  |  1994-03-13  |  22.4 KB  |  914 lines  |  [TEXT/MPS ]

  1. // Copyright © 1992 Peter Speck, speck@dat.ruc.dk. All rights reserved.
  2. // UArticleListView.cp
  3.  
  4. #include "UArticleListView.h"
  5. #include "UArticleManageView.h"
  6. #include "UArticleView.h"
  7. #include "UArticleCache.h"
  8. #include "UArticle.h"
  9. #include "UDiscList.h"
  10. #include "UDiscListView.h"
  11. #include "UArticleCmds.h"
  12. #include "UBinariesCmds.h" 
  13. #include "UMailCmds.h"
  14. #include "UPrefsDatabase.h"
  15. #include "UGroupDoc.h"
  16. #include "UNewsAppl.h"
  17. #include "UPostArticleCmds.h"
  18. #include "UTextScroller.h"
  19. #include "UNavigatorView.h"
  20. #include "UThread.h"
  21. #include "Tools.h"
  22. #include "UFatalError.h"
  23. #include "NetAsciiTools.h"
  24.  
  25. #include <RsrcGlobals.h>
  26. #include <ErrorGlobals.h>
  27.  
  28. #include <ToolUtils.h>
  29. #include <Packages.h>
  30. #include <OSUtils.h>
  31.  
  32. #pragma segment MyArticle
  33.  
  34. #define qDebugUpdateListThread qDebug
  35. //============================ ARTICLE ITERATOR =========================
  36.  
  37. class CArticleViewIterator : public CSubViewIterator
  38. {
  39.     public:
  40.         CArticleViewIterator(TArticleListView *alv);
  41.         TArticleView *FirstArticleView();
  42.         TArticleView *NextArticleView();
  43.         TArticleView *CurrentArticleView();
  44.     protected:
  45.         virtual void Reset();
  46.         virtual void Advance();
  47.  
  48.     private:
  49.         TArticleView *fCurrentArticleView;
  50.         
  51.         void FindArticleView();
  52. };
  53.  
  54. CArticleViewIterator::CArticleViewIterator(TArticleListView *alv) :
  55.     CSubViewIterator(alv)
  56. {
  57.     fCurrentArticleView = nil;
  58. }
  59.  
  60. TArticleView *CArticleViewIterator::FirstArticleView()
  61. {
  62.     FirstSubView();
  63.     return CurrentArticleView();
  64. }
  65.  
  66. TArticleView *CArticleViewIterator::NextArticleView()
  67. {
  68.     NextSubView();
  69.     return CurrentArticleView();
  70. }
  71.  
  72. TArticleView *CArticleViewIterator::CurrentArticleView()
  73. {
  74.     return fCurrentArticleView;
  75. }
  76.  
  77. void CArticleViewIterator::Reset()
  78. {
  79.     CArrayIterator::Reset();
  80.     FindArticleView();
  81. }
  82.  
  83. void CArticleViewIterator::Advance()
  84. {
  85.     CArrayIterator::Advance();
  86.     FindArticleView();
  87. }
  88.  
  89. void CArticleViewIterator::FindArticleView()
  90. {
  91.     fCurrentArticleView = nil;
  92.     while (true)
  93.     {
  94.         TArticleManageView *amv = (TArticleManageView*)CurrentSubView();
  95.         if (!amv)
  96.             break;
  97.         TArticleView *av = amv->GetArticleView();
  98.         if (av)
  99.         {
  100.             fCurrentArticleView = av;
  101.             break;
  102.         }
  103.         CArrayIterator::Advance();
  104.         if (!More())
  105.             return;
  106.     }
  107. }
  108.  
  109. //--------------------------------------------------------------
  110. class CSelectedArticleViewIterator : public CArticleViewIterator
  111. {
  112.     public:
  113.         CSelectedArticleViewIterator(TArticleListView *alv);
  114.  
  115.     protected:
  116.         void Reset();
  117.         void Advance();
  118. };
  119.  
  120. CSelectedArticleViewIterator::CSelectedArticleViewIterator(TArticleListView *alv) :
  121.     CArticleViewIterator(alv)
  122. {
  123. }
  124.  
  125. void CSelectedArticleViewIterator::Reset()
  126. {
  127.     CArticleViewIterator::Reset();
  128.     TArticleView *av = CurrentArticleView();
  129.     if (av && !av->IsAnyCellSelected())
  130.         Advance();
  131. }
  132. void CSelectedArticleViewIterator::Advance()
  133. {
  134.     while (true)
  135.     {
  136.         CArticleViewIterator::Advance();
  137.         if (!More())
  138.             return;
  139.         TArticleView *av = CurrentArticleView();
  140.         if (av && av->IsAnyCellSelected())
  141.             return;
  142.     }
  143. }
  144. //============================ ARTICLE LIST VIEW ========================
  145. TArticleListView::TArticleListView()
  146. {
  147. }
  148.  
  149. pascal void TArticleListView::Initialize()
  150. {
  151.     inherited::Initialize();
  152.     fWindow = nil;
  153.     fDiscList = nil;
  154.     fDiscIndexList = nil;
  155.     fArticleIndex = 0;
  156.     fDoc = nil;
  157.     fArticleStatus = fOldArticleStatus = nil;
  158.     fPrefDiscArrow = nil;
  159.     fNextDiscArrow = nil;
  160.     fScroller = nil;
  161.     fUpdateThreadList = nil;
  162.     fDiscIndex = 0;
  163.     fIsClosing = false;
  164.     fUseROT13 = false;
  165. }
  166.  
  167. pascal void TArticleListView::ReadFields(TStream *aStream)
  168. {
  169.     inherited::ReadFields(aStream);
  170.     fUpdateThreadList = NewThreadList("ArticleListView update thread");
  171. }
  172.  
  173.  
  174. pascal void TArticleListView::DoPostCreate(TDocument *itsDocument)
  175. {
  176.     inherited::DoPostCreate(itsDocument);
  177.     fWindow = GetWindow();
  178.     fScroller = (TTextScroller*)(fWindow->FindSubView('SCL1'));
  179.     fDoc = (TGroupDoc*) itsDocument;
  180.     fDiscListView = fDoc->GetDiscListView();
  181.     fArticleStatus = fDoc->GetArticleStatus();
  182.     fOldArticleStatus = fDoc->GetOldArticleStatus();
  183.     
  184.     fDiscIndexList = nil;
  185.     fDiscList = fDoc->GetDiscList();
  186.     fPrefDiscArrow = (TNavigatorArrowView*) fWindow->FindSubView(kNavigatorLeftArrowView);
  187.     fNextDiscArrow = (TNavigatorArrowView*) fWindow->FindSubView(kNavigatorRightArrowView);
  188.  
  189.     fShowsHeaders = gPrefs->GetBooleanPrefs('Head');
  190.  
  191.     TextStyle ts;
  192.     gPrefs->GetTextStylePrefs('TSar', ts);
  193.     fTextStyle = ts;
  194. }
  195.  
  196. pascal void TArticleListView::Free()
  197. {
  198.     if (fUpdateThreadList && fUpdateThreadList->fSize)
  199.         PanicExitToShell("In TArticleListView: fUpdateThreadList was not empty");
  200.     FreeIfObject(fUpdateThreadList); fUpdateThreadList = nil;
  201.     fDiscList = nil; // not mine
  202.     FreeIfObject(fDiscIndexList); fDiscIndexList = nil;
  203.     fScroller = nil; // view
  204.     fWindow = nil; // not mine
  205.     fDoc = nil; // not mine
  206.     fArticleStatus = fOldArticleStatus = nil; // not mine
  207.     inherited::Free();
  208. }
  209.  
  210. pascal void TArticleListView::Close()
  211. {
  212.     FailInfo fi;
  213.     if (fi.Try())
  214.     {
  215.         fIsClosing = true;
  216.         KillUpdateListThread();
  217.         gPrefs->SetWindowPosPrefs('WArt', fWindow);
  218.         DeleteDisplayedArticles(true); // update fArticleStatus
  219.         inherited::Close();
  220.         fi.Success();
  221.     }
  222.     else // fail
  223.     {
  224.         fIsClosing = false;
  225.         fi.ReSignal();
  226.     }
  227. }
  228.  
  229. void TArticleListView::KillUpdateListThread()
  230. {
  231.     if (fUpdateThreadList->fSize)
  232.     {
  233. #if qDebugUpdateListThread
  234.         fprintf(stderr, "TArticleListView::KillUpdateListThread: Killing updateListThread at $%lx\n", long(fUpdateThreadList));
  235. #endif
  236.         fUpdateThreadList->KillAll();
  237.         if (fUpdateThreadList->fSize)
  238.             PanicExitToShell("In TArticleListView::KillUpdateListThread, fUpdateThreadList didn't became empty");
  239.     }
  240. }
  241.  
  242. VCoordinate TArticleListView::GetSeparatorHeight()
  243. {
  244.     return 8;
  245. }
  246.  
  247. void TArticleListView::CheckNewFrame(VRect &newFrame)
  248. {
  249. #if 0
  250.     VCoordinate width = GetPrintHandler()->fViewPerPage.h;
  251.     newFrame.right = newFrame.left + width;
  252. #else
  253.     inherited::CheckNewFrame(newFrame);
  254. #endif
  255. }
  256.  
  257. pascal void TArticleListView::DoCalcPageStrips(VPoint& pageStrips)
  258. {
  259.     inherited::DoCalcPageStrips(pageStrips);
  260.     pageStrips.v = 1;
  261. }
  262.  
  263. void TArticleListView::ChangedFont()
  264. {
  265.     TextStyle ts = fTextStyle;
  266.     CSubViewIterator iter(this);
  267.     for (TView *view = iter.FirstSubView(); iter.More(); view = iter.NextSubView())
  268.     {
  269.         TArticleManageView *amv = (TArticleManageView *)view;
  270.         amv->SetNewFont(ts);
  271.     }
  272. }
  273.  
  274. void TArticleListView::DeleteDisplayedArticles(Boolean isDoneReadingArticles)
  275. {
  276.     if (!fArticleIndex)
  277.         return; // has nothing
  278.     if (isDoneReadingArticles)
  279.     {
  280.         TLongintList *theIDList = nil;
  281.         VOLATILE(theIDList);
  282.         FailInfo fi;
  283.         if (fi.Try())
  284.         {    
  285.             theIDList = GetListOfAllArticles();
  286.             {
  287.                 CLongintIterator iter(theIDList);
  288.                 for (long id = iter.FirstLong(); iter.More(); id = iter.NextLong())
  289.                     fOldArticleStatus->SetMinStatus(id, fArticleStatus->GetStatus(id));
  290.             }
  291.             theIDList->Free(); theIDList = nil;
  292.             fi.Success();
  293.         }
  294.         else // fail
  295.         {
  296.             FreeIfObject(theIDList); theIDList = nil;
  297.             fi.ReSignal();
  298.         }
  299.         fDiscListView->UpdateDiscussion(fDiscIndex);
  300.     }
  301. }
  302.  
  303. //============================================== DRAWING ================================
  304. void TArticleListView::DrawViewSeparator(VCoordinate vOffset)
  305. {
  306.     short vOff = short(vOffset);
  307.     MoveTo(0, vOff + 3);
  308.     PenPat(&qd.gray);
  309.     PenSize(3, 3);
  310.     Line(1000, 0);
  311.     MoveTo(0, vOff + 4);
  312.     PenPat(&qd.black);
  313.     PenSize(1, 1);
  314.     Line(1000, 0);
  315.     PenNormal();
  316. }
  317.  
  318.  
  319. //======================== MANAGEMENT ==================================================
  320. void TArticleListView::SetArticleList(TLongintList *discIndexList)
  321. {
  322. #if qDebug
  323.     if (!IsObject(discIndexList))
  324.         ProgramBreak("discIndexList is not object");
  325. #endif
  326.     if (discIndexList->GetSize() == 0) {
  327. #if qDebug
  328.         ProgramBreak("No articles in discIndexList");
  329. #endif
  330.         return;
  331.     }
  332.     // throw old stuff away
  333.     FreeIfObject(fDiscIndexList); fDiscIndexList = nil;    
  334.     // use new stuff
  335.     fDiscIndexList = discIndexList;
  336.     UpdateList(1, ArticleShowType(gPrefs->GetShortPrefs('artS')));
  337. }
  338.  
  339. TLongintList *TArticleListView::GetListOfAllArticles()
  340. {
  341.     return fDiscList->GetArticleIDList(fDiscIndex);
  342. }
  343.  
  344. TLongintList *TArticleListView::GetListOfExpandedArticles()
  345. {
  346.     TLongintList *lList = new TLongintList();
  347.     lList->ILongintList();
  348.     CArticleViewIterator iter(this);
  349.     for (TArticleView *articleView = iter.FirstArticleView(); iter.More(); articleView = iter.NextArticleView())
  350.         lList->InsertLast(articleView->GetArticleID());
  351.     return lList;
  352. }
  353.  
  354. TLongintList *TArticleListView::GetListOfSelectedArticles()
  355. {
  356.     TLongintList *lList = new TLongintList();
  357.     lList->ILongintList();
  358.     CSelectedArticleViewIterator iter(this);
  359.     for (TArticleView *articleView = iter.FirstArticleView(); iter.More(); articleView = iter.NextArticleView())
  360.         lList->InsertLast(articleView->GetArticleID());
  361.     return lList;
  362. }
  363.  
  364. void TArticleListView::SetDiscussionDisplayed(long index)
  365. {
  366.     index = MinMax(1, index, fDiscIndexList->GetSize());
  367.     if (fArticleIndex != index) 
  368.         UpdateList(index, ArticleShowType(gPrefs->GetShortPrefs('artS')));
  369. }
  370.  
  371. void TArticleListView::UpdateList(ArrayIndex newArticleListIndex, ArticleShowType whatToShow)
  372. {
  373.     KillUpdateListThread();
  374.     if (newArticleListIndex != fArticleIndex)
  375.     {
  376.         DeleteDisplayedArticles(true);
  377.         {
  378.             // stuff from DeleteDisplayedArticles, moved to here as I got a serious crash
  379.             // when resizing view in Close()
  380.             while (fSubViews && fSubViews->GetSize() > 0)
  381.                 fSubViews->Last()->Free();
  382.             //    AdjustSubViewFrames();
  383.             SetFrame(VRect(0, 0, 0, 0), kRedraw);
  384.         }
  385.         fArticleIndex = newArticleListIndex;
  386.     }
  387.     TUpdateArticleViewCommand *cmd = new TUpdateArticleViewCommand();
  388.     cmd->IUpdateArticleViewCommand(this, whatToShow);
  389.     fUpdateThreadList->ExecuteCommand(cmd, "TUpdateArticleViewCommand (TArticleListView)");
  390. #if qDebugUpdateListThread
  391.     fprintf(stderr, "Created new UpdateListThread\n");
  392. #endif
  393. }
  394.  
  395. void TArticleListView::DoTheUpdateList(ArticleShowType whatToShow)
  396. {
  397.     TLongintList *theIDList = nil;
  398.     VOLATILE(theIDList);
  399.     FailInfo fi;
  400.     if (fi.Try())
  401.     {    
  402.         fDiscIndex = fDiscIndexList->At(fArticleIndex);
  403.         fPrefDiscArrow->SetEnable(fArticleIndex > 1);
  404.         fNextDiscArrow->SetEnable(fArticleIndex < fDiscIndexList->GetSize());
  405.  
  406.         theIDList = GetListOfAllArticles();
  407.         CStr255 title;
  408.         // find name for it
  409.         fDiscList->GetName(fDiscIndex, title);
  410.  
  411.         // display window
  412.         fWindow->SetTitle(title);
  413.         fWindow->Open();
  414.  
  415.         long maxIndex = theIDList->GetSize();
  416.         for (ArrayIndex index = 1; index <= maxIndex; index++)
  417.         {
  418.             long theID = theIDList->At(index);
  419.             Boolean showIt = ShouldExpandArticle(whatToShow, index, theID);
  420.             fAddSeparatorAtBottom = index < maxIndex;
  421.             if (fSubViews && fSubViews->GetSize() >= index)
  422.                 ExpandExistingArticleView(index, showIt);
  423.             else
  424.                 CreateNewArticleView(theID, showIt);
  425.             if (showIt)
  426.                 gCurThread->CheckYield();
  427.         }
  428.         theIDList->Free(); theIDList = nil;
  429.         fi.Success();
  430.     }
  431.     else // fail
  432.     {
  433.         FreeIfObject(theIDList); theIDList = nil;
  434.         fi.ReSignal();
  435.     }
  436. }
  437.  
  438. void TArticleListView::ExpandExistingArticleView(ArrayIndex index, Boolean showIt)
  439. {
  440.     FailInfo fi;
  441.     if (fi.Try())
  442.     {
  443.         TArticleManageView *amv = (TArticleManageView*) fSubViews->At(index);
  444.         amv->BuildDisplay(showIt);
  445.         fi.Success();
  446.     }
  447.     else // fail
  448.     {
  449.         if (fi.error < kFirstNntpError && fi.error > kLastNntpError) // negative!
  450.         {
  451.             // silent, just don't show the article
  452.             if (showIt)
  453.             {
  454.                 TArticleManageView *amv = (TArticleManageView*) fSubViews->At(index);
  455.                 amv->BuildDisplay(false);
  456.             }
  457.         }
  458.         else
  459.             fi.ReSignal(); // aborting, must resignal
  460.     }
  461. }
  462.  
  463. void TArticleListView::CreateNewArticleView(long theID, Boolean showIt)
  464. {
  465.     TArticle *article = nil;
  466.     VOLATILE(article);
  467.     VOLATILE(showIt);
  468.     FailInfo fi;
  469.     if (fi.Try())
  470.     {
  471.         if (showIt)
  472.         {
  473.             CStr255 groupDotName;
  474.             fDoc->GetGroupDotName(groupDotName);
  475.             article = gArticleCache->GetArticle(groupDotName, theID);
  476.         }
  477.         fi.Success();
  478.     }
  479.     else // fail
  480.     {
  481.         if (fi.error < kFirstNntpError && fi.error > kLastNntpError) // negative!
  482.         {
  483.             // silent, just don't show the article
  484.             showIt = false;
  485.         }
  486.         else
  487.             fi.ReSignal(); // aborting, must resignal
  488.     }
  489.     TArticleManageView *amv = new TArticleManageView();
  490.     amv->IArticleManageView(fDoc, this, fSize.v, theID, article, showIt);
  491. }
  492.  
  493. Boolean TArticleListView::ShouldExpandArticle(ArticleShowType whatToShow, ArrayIndex index, long theID)
  494. {
  495.     if (theID < fDoc->GetFirstArticleID() || theID > fDoc->GetLastArticleID())
  496.         return false;
  497.     Boolean showIt = true;
  498.     switch (whatToShow)
  499.     {
  500.         case kShowUnreadArticles:
  501.             return fOldArticleStatus->GetStatus(theID) <= kArticleSeen;
  502.  
  503.         case kShowNewArticles:
  504.             return fOldArticleStatus->GetStatus(theID) == kArticleNew;
  505.         
  506.         case kShowAllArticles:
  507.             return true;
  508.             
  509.         case kShowFirstArticleOnly:
  510.             return index == 1;
  511.             
  512.         case kShowNoArticles:
  513.             return false;
  514.  
  515. #if qDebug
  516.         default:
  517.             fprintf(stderr, "Invalid ArticleStatus: %ld\n", long(whatToShow));
  518.             ProgramBreak(gEmptyString);
  519.             return false;
  520. #endif
  521.     }
  522. }
  523. //--------------------------------------------------------
  524. Handle TArticleListView::GetSelectionAsQuotedTextForMail()
  525. {
  526.     short quoteID = kArticleQuoteLine;
  527.     CSelectedArticleViewIterator iter(this);
  528.     long numSelected = 0;
  529.     for (TArticleView *articleView = iter.FirstArticleView(); iter.More(); articleView = iter.NextArticleView())
  530.         numSelected++;
  531.     if (numSelected == 1)
  532.         quoteID = kArticleQuoteYouLine;
  533.     return GetSelectionAsQuoteText(true, true, quoteID);
  534. }
  535.  
  536. Handle TArticleListView::GetSelectionAsTextForClipboard(Boolean asQuote, Boolean addHeader)
  537. {
  538.     short quoteID = kArticleQuoteLine;
  539.     return GetSelectionAsQuoteText(asQuote, addHeader, quoteID);
  540. }
  541.  
  542.  
  543. Handle TArticleListView::GetSelectionAsQuoteText(Boolean asQuote, 
  544.                                             Boolean addHeader, short quoteID)
  545. {
  546.     Handle h = nil;
  547.     VOLATILE(h);
  548.     FailInfo fi;
  549.     if (fi.Try())
  550.     {
  551.         h = NewPermHandle(0);
  552.         // block for failure handling
  553.         {
  554.             CSelectedArticleViewIterator iter(this);
  555.             Boolean gotOne = false;
  556.             for (TArticleView *articleView = iter.FirstArticleView(); iter.More(); articleView = iter.NextArticleView())
  557.             {
  558.                 if (gotOne)
  559.                     AppendStringToHandle("\n", h);
  560.                 gotOne = true;
  561.                 articleView->AppendSelectionAsTextForClipboard(h, asQuote, addHeader, quoteID);
  562.             }
  563.         }
  564.         fi.Success();
  565.         return h;
  566.     }
  567.     else // fail
  568.     {
  569.         h = DisposeIfHandle(h);
  570.         fi.ReSignal();
  571.     }
  572. }
  573.  
  574.  
  575. void TArticleListView::CancelSelectedArticles()
  576. {
  577.     if (MacAppAlert(phCancelArticle, nil) != ok)
  578.         Failure(0, 0);
  579.     FailInfo fi;
  580.     if (fi.Try())
  581.     {
  582.         { // block for list iter failure handling
  583.             CStr255 myEmail, s, realname, email;
  584.             gPrefs->GetStringPrefs('@adr', myEmail);
  585.             CSelectedArticleViewIterator iter(this);
  586.             for (TArticleView *articleView = iter.FirstArticleView(); iter.More(); articleView = iter.NextArticleView())
  587.             {
  588.                 articleView->GetArticle()->GetHeader("From", s);
  589.                 GetAuthorName(s, realname, email);
  590.                 if (!EqualString(myEmail, email, false, false))
  591.                     FailOSErr(errCancelNotYourArticle);
  592.             }
  593.             for (articleView = iter.FirstArticleView(); iter.More(); articleView = iter.NextArticleView())
  594.             {
  595.                 articleView->GetArticle()->GetHeader("Message-ID", s);
  596.                 TCancelArticleCommand *cmd = new TCancelArticleCommand();
  597.                 cmd->ICancelArticleCommand(s);
  598.                 gApplWideThreads->ExecuteCommand(cmd, "TCancelArticleCommand (TArticleListView)");
  599.             }
  600.         }
  601.         fi.Success();
  602.     }
  603.     else // fail
  604.     {
  605.         FailNewMessage(fi.error, fi.message, messageCancelArticle);
  606.     }
  607. }
  608.  
  609. //================================================================
  610. pascal Boolean TArticleListView::HandleMouseDown(const VPoint& theMouse,
  611.                                 TToolboxEvent* event, CPoint hysteresis)
  612. {
  613.     if (fIsClosing)
  614.         return false;
  615.     if (!event->IsCommandKeyPressed() && !event->IsShiftKeyPressed() &&
  616.             !event->IsOptionKeyPressed() && !event->IsControlKeyPressed())
  617.     {
  618.         // deselect all other TArticleViews
  619.  
  620. // burde vist kun laves, hvis man laver mousedown i noget text som
  621. // kan vælges, og ikke fx i en triangle
  622.  
  623.         TArticleView *selectedArticleView = nil;
  624.         CArticleViewIterator iter(this);
  625.         for (TArticleView *articleView = iter.FirstArticleView(); iter.More(); articleView = iter.NextArticleView())
  626.         {
  627.             TView *view = articleView;
  628.             while (view->fSuperView != this)
  629.                 view = view->fSuperView;
  630.             VPoint subViewPt = theMouse;
  631.             view->SuperToLocal(subViewPt);
  632.             if (view->ContainsMouse(subViewPt))
  633.             {
  634.                 selectedArticleView = articleView;
  635.                 break;
  636.             }
  637.         }
  638.         for (articleView = iter.FirstArticleView(); iter.More(); articleView = iter.NextArticleView())
  639.         {
  640.             if (articleView != selectedArticleView)
  641.                 articleView->SetEmptySelection(kRedraw);
  642.         }
  643.     }
  644.     return inherited::HandleMouseDown(theMouse, event, hysteresis);
  645. }
  646.  
  647. pascal void TArticleListView::DoKeyEvent(TToolboxEvent *event)// override 
  648. {
  649.     if (!IsEnabled() || fIsClosing)
  650.     {
  651.         if (qDebug && fIsClosing)
  652.             fprintf(stderr, "Ignored: is closing\n");
  653.         inherited::DoKeyEvent(event);
  654.         return;
  655.     }
  656.     switch (event->fCharacter)
  657.     {
  658.         case chLeft:
  659.             DoMenuCommand(cPreviousDiscussion);
  660.             break;
  661.  
  662.         case chRight:
  663.             DoMenuCommand(cNextDiscussion);
  664.             break;
  665.  
  666.         case chUp:
  667.             if (event->IsOptionKeyPressed() && !event->IsCommandKeyPressed())
  668.                 DoMenuCommand(cPreviousArticle);
  669.             else
  670.                 inherited::DoKeyEvent(event);
  671.             break;
  672.         case chDown:
  673.             if (event->IsOptionKeyPressed() && !event->IsCommandKeyPressed())
  674.                 DoMenuCommand(cNextArticle);
  675.             else
  676.                 inherited::DoKeyEvent(event);
  677.             break;
  678.                 
  679.         case chSpace:
  680.             DoMenuCommand(cMultiSuperNextKey);
  681.             break;
  682.  
  683.         case chBackspace:
  684.             {
  685.                 CArticleViewIterator iter(this);
  686.                 for (TArticleView *articleView = iter.FirstArticleView(); iter.More(); articleView = iter.NextArticleView())
  687.                     articleView->SetEmptySelection(kRedraw);
  688.             }
  689.             break;
  690.  
  691.         default:
  692.             inherited::DoKeyEvent(event);
  693.             break;
  694.     }
  695. }
  696.  
  697. pascal void TArticleListView::DoMenuCommand(CommandNumber aCommandNumber)
  698. {
  699.     if (!IsEnabled() || fIsClosing)
  700.     {
  701.         if (qDebug && fIsClosing)
  702.             fprintf(stderr, "Ignored: is closing\n");
  703.         inherited::DoMenuCommand(aCommandNumber);
  704.         return;
  705.     }
  706. //    ArticleShowType ast;
  707.     switch (aCommandNumber)
  708.     {
  709.         case cPostFollowUpArticle: // most importent first!
  710.             {
  711.                 Handle h = GetSelectionAsTextForClipboard(!IsOptionKeyDown(), !IsShiftKeyDown());
  712.                 TCreateFollowupCommand *command = new TCreateFollowupCommand();
  713.                 command->ICreateFollowupCommand(fDoc, fDiscIndex, h);
  714.                 PostCommand(command);
  715.             }
  716.             break;
  717.         
  718.         case cShowHideHeadersCommand:
  719.             {
  720.                 fShowsHeaders = !fShowsHeaders;
  721.                 gPrefs->SetBooleanPrefs('Head', fShowsHeaders);
  722.                 CArticleViewIterator iter(this);
  723.                 for (TArticleView *articleView = iter.FirstArticleView(); iter.More(); articleView = iter.NextArticleView())
  724.                     articleView->UpdateDisplay();
  725.             }
  726.             break;
  727.         
  728.         case cUseROT13:
  729.             {
  730.                 fUseROT13 = !fUseROT13;
  731.                 CArticleViewIterator iter(this);
  732.                 for (TArticleView *articleView = iter.FirstArticleView(); iter.More(); articleView = iter.NextArticleView())
  733.                     articleView->SetUseROT13(fUseROT13);
  734.             }
  735.             break;
  736.         
  737.  
  738.         case cShowAllArticles:
  739.             UpdateList(fArticleIndex, kShowAllArticles);
  740.             break;
  741.  
  742.         case cShowOnlyFirstArticle:
  743.             UpdateList(fArticleIndex, kShowFirstArticleOnly);
  744.             break;
  745.  
  746.         case cShowOnlyUnreadArticles:
  747.             UpdateList(fArticleIndex, kShowUnreadArticles);
  748.             break;
  749.  
  750.         case cShowOnlyNewArticles:
  751.             UpdateList(fArticleIndex, kShowNewArticles);
  752.             break;
  753.  
  754.         case cShowNoneArticles:
  755.             UpdateList(fArticleIndex, kShowNoArticles);
  756.             break;
  757.  
  758.         case cSave:
  759.         case cSaveAs:
  760.         case cSaveCopy:
  761.             {
  762.                 TSaveArticlesCommand *aCommand = new TSaveArticlesCommand();
  763.                 aCommand->ISaveArticlesCommand(cSaveAs, fDoc, GetListOfExpandedArticles());
  764.                 gApplWideThreads->ExecuteCommand(aCommand, "TSaveArticlesCommand (TArticleListView)");
  765.                 break;
  766.             }
  767.  
  768.         case cExtractBinaries:
  769.             {
  770.                 TLongintList *lList;
  771.                 if (IsOptionKeyDown())
  772.                     lList = GetListOfSelectedArticles();
  773.                 else
  774.                     lList = GetListOfAllArticles();
  775.                 ExtractBinaries(cExtractBinaries, fDoc, lList);
  776.                 break;
  777.             }
  778.  
  779.         case cNextDiscussion:
  780.             {
  781.                 TShowDiscJunkCommand *aCommand = new TShowDiscJunkCommand();
  782.                 aCommand->IShowDiscJunkCommand(this, fArticleIndex + 1);
  783.                 PostCommand(aCommand);
  784.                 break;
  785.             }
  786.         case cPreviousDiscussion:
  787.             {
  788.                 TShowDiscJunkCommand *aCommand = new TShowDiscJunkCommand();
  789.                 aCommand->IShowDiscJunkCommand(this, fArticleIndex - 1);
  790.                 PostCommand(aCommand);
  791.                 break;
  792.             }
  793.             
  794.         case cMultiSuperNextKey:
  795.             {
  796.                 TScrollerScrollBar *sb = fScroller->fScrollBars[vSel];
  797.                 if (sb->fLongVal < sb->fLongMax)
  798.                 {
  799.                     fScroller->DoPageDown();
  800.                     break;
  801.                 }
  802.                 long maxIndex = fDiscIndexList->GetSize();
  803.                 if (fArticleIndex < maxIndex)
  804.                 {
  805.                     DoMenuCommand(cNextDiscussion);
  806.                     break;
  807.                 }
  808.                 else
  809.                 {
  810.                     TDiscListView *dlv = fDoc->GetDiscListView();
  811.                     if (dlv)
  812.                         dlv->SetEmptySelection(kHighlight);
  813.                     TCloseWindowCommand *cmd = new TCloseWindowCommand();
  814.                     cmd->ICloseWindowCommand(aCommandNumber, fWindow);
  815.                     PostCommand(cmd);
  816.                 }
  817.             }
  818.             break;
  819.  
  820.         case cCopy:
  821.             {
  822.                 TCopyArticleTextCommand *command = new TCopyArticleTextCommand();
  823.                 command->ICopyArticleTextCommand(this, !IsOptionKeyDown(), !IsShiftKeyDown());
  824.                 PostCommand(command);
  825.             }
  826.             break;
  827.  
  828.         case cSelectAll:
  829.             {
  830.                 CArticleViewIterator iter(this);
  831.                 for (TArticleView *articleView = iter.FirstArticleView(); iter.More(); articleView = iter.NextArticleView())
  832.                     articleView->DoMenuCommand(cSelectAll);
  833.             }
  834.             break;
  835.  
  836.         case cMailLetter:
  837.             {
  838.                 TMailToAuthorCommand *command = new TMailToAuthorCommand();
  839.                 command->IMailToAuthorCommand(fDoc, this, !IsOptionKeyDown(), !IsShiftKeyDown());
  840.                 PostCommand(command);
  841.             }
  842.             break;
  843.         
  844.         case cStoreNotes:
  845.             {
  846.                 TStoreNotesCommand *cmd = new TStoreNotesCommand();
  847.                 cmd->IStoreNotesCommand(this);
  848.                 PostCommand(cmd);
  849.             }
  850.             break;
  851.  
  852.         case cCancelArticle:
  853.             CancelSelectedArticles();
  854.             break;
  855.             
  856.         default:
  857.             {
  858.                 TextStyle ts = fTextStyle;
  859.                 if (gNewsAppl->HandleFontMenu(aCommandNumber, ts))
  860.                 {
  861.                     fTextStyle = ts;
  862.                     gPrefs->SetTextStylePrefs('TSar', ts);
  863.                     ChangedFont();
  864.                 }
  865.                 else
  866.                     inherited::DoMenuCommand(aCommandNumber);
  867.             }
  868.     }
  869. }
  870.  
  871. pascal void TArticleListView::DoSetupMenus()
  872. {
  873.     if (fIsClosing)
  874.     {
  875.         inherited::DoSetupMenus();
  876.         Enable(cRevert, false);
  877.         return;
  878.     }
  879.     Boolean lowSpace = MemSpaceIsLow();
  880.     Boolean anySelected = false;
  881.     CSelectedArticleViewIterator iter(this);
  882.     for (TArticleView *articleView = iter.FirstArticleView(); iter.More(); articleView = iter.NextArticleView())
  883.     {
  884.         anySelected = true;
  885.         break;
  886.     }
  887.     TextStyle ts = fTextStyle;
  888.     gNewsAppl->EnableFontMenu(ts);
  889.     Enable(cSave, true);
  890.     Enable(cSaveAs, true);
  891.     Enable(cSaveCopy, true);
  892.     Enable(cExtractBinaries, !lowSpace);
  893.     Enable(cSelectAll, true);
  894.     EnableCheck(cShowHideHeadersCommand, true, fShowsHeaders);
  895.     EnableCheck(cUseROT13, true, fUseROT13);
  896.     
  897.     Enable(cCopy, !lowSpace && anySelected);
  898.  
  899.     Enable(cPostFollowUpArticle, !lowSpace && anySelected);
  900.     Enable(cMailLetter, !lowSpace && anySelected);
  901.     Enable(cCancelArticle, !lowSpace && anySelected);
  902.  
  903.     Enable(cShowAllArticles, true);
  904.     Enable(cShowOnlyFirstArticle, true);
  905.     Enable(cShowOnlyUnreadArticles, true);
  906.     Enable(cShowOnlyNewArticles, true);
  907.     Enable(cShowNoneArticles, true);
  908.  
  909.     Enable(cStoreNotes, !lowSpace && anySelected);
  910.  
  911.     inherited::DoSetupMenus();
  912.     Enable(cRevert, false);
  913. }
  914.