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

  1. // Copyright © 1992 Peter Speck, speck@dat.ruc.dk. All rights reserved.
  2. // UGroupTreeView.cp
  3.  
  4. #include "UGroupTreeView.h"
  5. #include "UGroupViewCmds.h"
  6. #include "UGroupTreeCmds.h"
  7. #include "UGroupDocCmds.h"
  8. #include "UDiscListView.h"
  9. #include "UDynDynArray.h"
  10. #include "UGroupList.h"
  11. #include "UPrefsDatabase.h"
  12. #include "UNewsAppl.h"
  13. #include "UGroupTreeDoc.h"
  14. #include "UGroupTree.h"
  15. #include "Tools.h"
  16. #include "StreamTools.h"
  17. #include "UThread.h"
  18. #include "ViewTools.h"
  19.  
  20. #include <RsrcGlobals.h>
  21.  
  22. #include <Resources.h>
  23. #include <Packages.h>
  24.  
  25. #pragma segment MyGroupList
  26. // as netnews folders can't be empty, fExpandData has zero items for compacted folders
  27.  
  28. #define qDebugExpand qDebug & 0
  29. #define qDebugBalloons qDebug & 0
  30. #define qDebugGroupTreeView qDebug & 0
  31.  
  32. //************************************************************************************************
  33. const kIconSize = 16;
  34.  
  35. TreeSicn gNonExpandedDiamondSicn, gHalfExpandedDiamondSicn, gExpandedDiamondSicn;
  36. TreeSicn gDocumentSicn, gFolderSicn;
  37. Boolean gHasLoadedSicn = false;
  38.  
  39. void InitTreeSicn()
  40. {
  41.     InitializeSicnFastBits(gNonExpandedDiamondSicn[0]);
  42.     InitializeSicnFastBits(gNonExpandedDiamondSicn[1]);
  43.     InitializeSicnFastBits(gHalfExpandedDiamondSicn[0]);
  44.     InitializeSicnFastBits(gHalfExpandedDiamondSicn[1]);
  45.     InitializeSicnFastBits(gExpandedDiamondSicn[0]);
  46.     InitializeSicnFastBits(gExpandedDiamondSicn[1]);
  47.     InitializeSicnFastBits(gDocumentSicn[0]);
  48.     InitializeSicnFastBits(gDocumentSicn[1]);
  49.     InitializeSicnFastBits(gFolderSicn[0]);
  50.     InitializeSicnFastBits(gFolderSicn[1]);
  51.     GetNewSicnFastBits(gNonExpandedDiamondSicn[0], kNonExpandedDiamondSicn);
  52.     GetNewSicnFastBits(gNonExpandedDiamondSicn[1], kNonExpandedDiamondSicn + 1);
  53.     GetNewSicnFastBits(gHalfExpandedDiamondSicn[0], kHalfExpandedDiamondSicn);
  54.     GetNewSicnFastBits(gHalfExpandedDiamondSicn[1], kHalfExpandedDiamondSicn + 1);
  55.     GetNewSicnFastBits(gExpandedDiamondSicn[0], kExpandedDiamondSicn);
  56.     GetNewSicnFastBits(gExpandedDiamondSicn[1], kExpandedDiamondSicn + 1);
  57.     GetNewSicnFastBits(gDocumentSicn[0], kDocumentSicn);
  58.     GetNewSicnFastBits(gDocumentSicn[1], kDocumentSicn + 1);
  59.     GetNewSicnFastBits(gFolderSicn[0], kFolderSicn);
  60.     GetNewSicnFastBits(gFolderSicn[1], kFolderSicn + 1);
  61.     gHasLoadedSicn = true;
  62. }
  63. //-----------------------------------------------------------------------
  64. TGroupTreeView::TGroupTreeView()
  65. {
  66. }
  67.  
  68. pascal void TGroupTreeView::Initialize()
  69. {
  70.     inherited::Initialize();
  71.     fWindow = nil;
  72.     fGroupTreeDoc = nil;
  73.     fGroupTree = nil;
  74.     fScreenDepth = 1;
  75.     fPortBitsP = nil;
  76.     fExpandData = nil;
  77.     fWindowFolderIndex = kFirstIndex;
  78.     fLevelOffset = 1;
  79.     fLastTypeKeyTick = 0;
  80.     fKeyTypeChars = "";
  81. }
  82.  
  83. pascal void TGroupTreeView::Free()
  84. {
  85.     inherited::Free();
  86. }
  87.  
  88. pascal void TGroupTreeView::ReadFields(TStream *aStream)
  89. {
  90.     inherited::ReadFields(aStream);    
  91. }
  92.  
  93. pascal void TGroupTreeView::DoPostCreate(TDocument *itsDocument)
  94. {
  95.     inherited::DoPostCreate(itsDocument);
  96.     
  97.     if (!gHasLoadedSicn)
  98.         InitTreeSicn();
  99.     
  100.     fGroupTreeDoc = (TGroupTreeDoc*) itsDocument;
  101.     fGroupTree = fGroupTreeDoc->GetGroupTree();
  102.     TLongintList *lList = new TLongintList();
  103.     lList->ILongintList();
  104.     fExpandData = lList;
  105.     long size = fGroupTree->GetSize();
  106.     fExpandData->SetArraySize(size);
  107.     fExpandData->fSize = size;
  108.     BlockSet(fExpandData->ComputeAddress(1), size * sizeof(long), 0);
  109.     
  110.     fWindow = GetWindow();
  111.     
  112.     fPortBitsP = &(fWindow->GetGrafPort()->portBits);
  113.  
  114.     StandardGridViewTextStyle gvts;
  115.     gPrefs->GetTextStylePrefs('TSgt', gvts.fTextStyle);
  116.     CalcStandardGridViewFont(gvts);
  117.     fGridViewTextStyle = gvts;
  118.     fCellHeight = short(Max(kIconSize, fGridViewTextStyle.fRowHeight));
  119. }
  120.  
  121. pascal void TGroupTreeView::Close()
  122. {
  123.     VRect frame;
  124.     fWindow->GetFrame(frame);
  125.     fGroupTree->SetWindowFrame(fWindowFolderIndex, frame.ToRect());
  126.     fGroupTreeDoc->ForgetGroupTreeView(this);
  127.     inherited::Close();
  128. }
  129. //------------------------------------------------------------------
  130. pascal void TGroupTreeView::ShowReverted()
  131. {
  132.     SetWindowFolder(fWindowFolderIndex); // maybe need a UpdateList in future
  133. }
  134.  
  135. void TGroupTreeView::SetWindowFolder(ArrayIndex windowFolderIndex, TGroupTreeView *openFromView)
  136. {
  137.     fWindowFolderIndex = windowFolderIndex;
  138.     CStr255 title;
  139.     long level;
  140.     Boolean isFolder;
  141.     fGroupTree->GetDrawInfo(fWindowFolderIndex, level, title, isFolder);
  142. #if qDebug
  143.     if (!isFolder)
  144.         ProgramBreak("fWindowFolderIndex is not folder");
  145. #endif
  146.     fGroupTree->GetDotNameFromNodeIndex(fWindowFolderIndex, title);
  147.     fWindow->SetTitle(title);
  148.     CRect frame = fGroupTree->GetWindowFrame(fWindowFolderIndex);
  149.     fLevelOffset = -level;
  150.     if (fNumOfRows)
  151.         DelRowFirst(fNumOfRows);
  152.     if (frame != CRect(0, 0, 0, 0))
  153.     {
  154. #if qDebug
  155.         fprintf(stderr, "TGroupTreeView::SetWindowFolder, WindowFrame from TGroupTree: %s\n", (char*)frame);
  156. #endif
  157.         fWindow->SetFrame(frame, kRedraw);
  158.     }
  159.     else if (openFromView)
  160.     {
  161.         BytesMove(openFromView->fExpandData->ComputeAddress(1), fExpandData->ComputeAddress(1), fExpandData->GetSize() * sizeof(long));
  162.         VRect frame;
  163.         openFromView->GetWindow()->GetFrame(frame);
  164.         frame += VPoint(kStdStaggerAmount, kStdStaggerAmount);
  165.         fWindow->SetFrame(frame, kRedraw);
  166.     }
  167.     long noLines = fGroupTree->GetNoItems(fExpandData, fWindowFolderIndex);
  168.     InsRowLast(short(noLines), fCellHeight);
  169. #if qDebugGroupTreeView
  170.     fprintf(stderr, "TGroupTreeView::SetWindowFolder, windowFolderIndex = %hd, noLines = %ld, fLevelOffset = %ld\n", 
  171.             windowFolderIndex, noLines, fLevelOffset);
  172. #endif
  173. }
  174.  
  175. void TGroupTreeView::WriteWindowInfo(TStream *aStream)
  176. {
  177.     WriteDynamicArray(aStream, fExpandData);
  178.     aStream->WriteLong(fWindowFolderIndex);
  179.     VRect frame;
  180.     fWindow->GetFrame(frame);
  181.     aStream->WriteVRect(frame);
  182. }
  183.  
  184. void TGroupTreeView::ReadWindowInfo(TStream *aStream)
  185. {
  186.     ReadDynamicArray(aStream, fExpandData);
  187.     ArrayIndex windowFolderIndex = aStream->ReadLong();
  188.     SetWindowFolder(windowFolderIndex);
  189.     VRect frame;
  190.     aStream->ReadVRect(frame);
  191.     fWindow->SetFrame(frame, kRedraw);
  192. }
  193.  
  194.  
  195. void TGroupTreeView::ChangedFont()
  196. {
  197.     StandardGridViewTextStyle gvts = fGridViewTextStyle;
  198.     gPrefs->SetTextStylePrefs('TSgt', gvts.fTextStyle);
  199.     CalcStandardGridViewFont(gvts);
  200.     fGridViewTextStyle = gvts;
  201.     fCellHeight = short(Max(kIconSize, fGridViewTextStyle.fRowHeight));
  202.     if (fNumOfRows)
  203.         SetRowHeight(1, fNumOfRows, fCellHeight);
  204.     Focus();
  205.     ForceRedraw();
  206. }
  207.  
  208. void TGroupTreeView::UpdateDrawInfo()
  209. {
  210.     Focus();
  211.     TextStyle itsTextStyle = fGridViewTextStyle.fTextStyle;
  212.     SetPortTextStyle(itsTextStyle);
  213.     fScreenDepth = 1;
  214.     if (gConfiguration.hasColorQD)
  215.     {
  216.         VRect vr(VPoint(0, 0), fWindow->fSize);
  217.         vr += fWindow->fLocation;
  218.         GDHandle dev = GetMaxDevice(vr.ToRect());
  219.         if (dev)
  220.         {
  221.             PixMapHandle pixMap = (**dev).gdPMap;
  222.             fScreenDepth = (**pixMap).pixelSize;
  223.         }
  224.     }
  225. }
  226.  
  227. pascal void TGroupTreeView::DrawRangeOfCells(GridCell startCell,
  228.                                          GridCell stopCell,
  229.                                          const VRect & /* aRect */)
  230. {
  231.     UpdateDrawInfo();
  232.     GridCell cell(startCell);
  233.     while (cell.v <= stopCell.v)
  234.     {
  235.         DrawTheCell(cell);
  236.         cell.v++;
  237.     }
  238. }
  239.  
  240. pascal void TGroupTreeView::DrawCell(GridCell aCell, const VRect & /* aRect */)
  241. {
  242.     UpdateDrawInfo();
  243.     DrawTheCell(aCell);
  244. }
  245.  
  246. void TGroupTreeView::DrawSmallIcon(const SicnFastBits *sicn, CRect iconRect, Boolean drawSelected)
  247. {
  248.     CRect theRect(iconRect.left, iconRect.top, iconRect.left + kIconSize, iconRect.top + kIconSize);
  249.     if (fScreenDepth == 1)
  250.     {
  251.         // 1-bit bitmap
  252.         DrawSicnFastBits(fPortBitsP, sicn[drawSelected], CRect(0, 0, kIconSize, kIconSize), theRect);
  253.         return;
  254.     }
  255.     if (drawSelected)
  256.         PlotIconID(theRect, 0, ttSelected, sicn[0].fRsrcID);
  257.     else
  258.         PlotIconID(theRect, 0, ttNone, sicn[0].fRsrcID);
  259. }
  260.  
  261. void TGroupTreeView::DoTheGetCellInformation(GridCell aCell,
  262.                             ArrayIndex &nodeIndex, long &level, ArrayIndex &noVisibleSubLines,
  263.                             Boolean &isFolder,
  264.                             CRect &triangleRect, CRect &iconRect, CRect &textRect,
  265.                             CStr255 &text)
  266. {
  267.     VRect vr;
  268.     CellToVRect(aCell, vr);
  269.     CRect r;
  270.     ViewToQDRect(vr, r);    
  271.     nodeIndex = fGroupTree->FindSubGroupIndexFromLine(fExpandData, fWindowFolderIndex, aCell.v);
  272. #if qDebugGroupTreeView
  273.     fprintf(stderr, "line = %hd, wfi = %hd, nodeIndex = %hd\n", long(aCell.v), fWindowFolderIndex, nodeIndex);
  274. #endif
  275.     fGroupTree->GetDrawInfo(nodeIndex, level, text, isFolder);
  276.     level += fLevelOffset;
  277.     noVisibleSubLines = fExpandData->At(nodeIndex);
  278.     short left = r.left + kIconSize + 4 + short(level - 1) * kIconSize;
  279.     short iconTop = (r.top + r.bottom - kIconSize) / 2;
  280.     triangleRect = CRect(r.left, iconTop, r.left + kIconSize, iconTop + kIconSize);
  281.     iconRect = CRect(left, iconTop, left + kIconSize, iconTop + kIconSize);
  282.     left += kIconSize + 2 + fGridViewTextStyle.fHorzOffset / 4;
  283.     r.top += (fCellHeight - fGridViewTextStyle.fRowHeight) / 2;
  284.     textRect = CRect(left, r.top, left + StringWidth(text), r.top + fGridViewTextStyle.fRowHeight);
  285. }
  286.  
  287. void TGroupTreeView::GetCellInformation(GridCell aCell, 
  288.                             long &level, long &noVisibleSubLines,
  289.                             Boolean &isFolder,
  290.                             CRect &triangleRect, CRect &iconRect, CRect &textRect,
  291.                             CStr255 &text)
  292. {
  293.     Focus();
  294.     TextStyle itsTextStyle = fGridViewTextStyle.fTextStyle;
  295.     SetPortTextStyle(itsTextStyle);
  296.     ArrayIndex nodeIndex;
  297.     DoTheGetCellInformation(aCell, nodeIndex, level, noVisibleSubLines, isFolder, triangleRect, iconRect, textRect, text);
  298. }
  299.  
  300. void TGroupTreeView::DrawTheCell(GridCell aCell)
  301. {
  302.     CStr255 text;
  303.     ArrayIndex level, noVisibleSubLines, nodeIndex;
  304.     Boolean isFolder;
  305.     CRect triangleRect, iconRect, textRect;
  306.     
  307.     DoTheGetCellInformation(aCell, nodeIndex, level, noVisibleSubLines, isFolder, triangleRect, iconRect, textRect, text);
  308.  
  309.     if (isFolder)
  310.     {
  311.         if (noVisibleSubLines)
  312.             DrawSmallIcon(gExpandedDiamondSicn, triangleRect, false);
  313.         else
  314.             DrawSmallIcon(gNonExpandedDiamondSicn, triangleRect, false);
  315.         DrawSmallIcon(gFolderSicn, iconRect, false);
  316.     }
  317.     else
  318.         DrawSmallIcon(gDocumentSicn, iconRect, false);
  319.     MoveTo(textRect.left, textRect.top + fGridViewTextStyle.fVertOffset - 1);
  320.     DrawString(text);
  321. }
  322.  
  323. void TGroupTreeView::DrawTrackedTriangle(GridCell aCell, Boolean asExpanded, Boolean halfExpanded, Boolean highlight)
  324. {
  325.     UpdateDrawInfo();
  326.     CStr255 text;
  327.     ArrayIndex level, noVisibleSubLines, nodeIndex;
  328.     Boolean isFolder;
  329.     CRect triangleRect, iconRect, textRect;
  330.     
  331.     DoTheGetCellInformation(aCell, nodeIndex, level, noVisibleSubLines, isFolder, triangleRect, iconRect, textRect, text);
  332.     if (fScreenDepth > 1)
  333.         EraseRect(triangleRect);
  334.     if (isFolder)
  335.     {
  336.         if (halfExpanded)
  337.             DrawSmallIcon(gHalfExpandedDiamondSicn, triangleRect, highlight);
  338.         else if (asExpanded)
  339.             DrawSmallIcon(gExpandedDiamondSicn, triangleRect, highlight);
  340.         else
  341.             DrawSmallIcon(gNonExpandedDiamondSicn, triangleRect, highlight);
  342.     }
  343. }
  344.  
  345. void TGroupTreeView::HighlighTheCell(GridCell aCell, HLState fromHL, HLState toHL)
  346. {
  347.     CStr255 text;
  348.     ArrayIndex level, noVisibleSubLines, nodeIndex;
  349.     Boolean isFolder;
  350.     CRect triangleRect, iconRect, textRect;
  351.     
  352.     DoTheGetCellInformation(aCell, nodeIndex, level, noVisibleSubLines, isFolder, triangleRect, iconRect, textRect, text);
  353.  
  354.     if (isFolder)
  355.         DrawSmallIcon(gFolderSicn, iconRect, toHL == hlOn);
  356.     else
  357.         DrawSmallIcon(gDocumentSicn, iconRect, toHL == hlOn);
  358.     UseSelectionColor();
  359.     textRect.Inset(CPoint(-fGridViewTextStyle.fHorzOffset / 4, 1));
  360.     switch (fromHL + toHL)
  361.     {
  362.         case hlOffDim:
  363.             PenMode(patXor);
  364.             FrameRect(textRect);
  365.             break;
  366.  
  367.         case hlOnDim:
  368.             textRect.Inset(CPoint(1, 1));
  369.             InvertRect(textRect);
  370.             break;
  371.  
  372.         case hlOffOn:
  373.             InvertRect(textRect);
  374.             break;
  375.     }
  376. }
  377.  
  378. pascal void TGroupTreeView::HighlightCells(RgnHandle theCells,
  379.                                       HLState fromHL,
  380.                                       HLState toHL)
  381. {
  382.     if (fromHL == toHL)
  383.         return;
  384.     UpdateDrawInfo();
  385.     switch (fromHL + toHL)
  386.     {
  387.         case hlOffDim:
  388.         case hlOnDim:
  389.         case hlOffOn:
  390.             {
  391.                 CCellInRegionIterator iter(this, theCells);
  392.                 for (GridCell aCell = iter.FirstCell(); iter.More(); aCell = iter.NextCell())
  393.                     HighlighTheCell(aCell, fromHL, toHL);
  394.             }
  395.             break;
  396.     }
  397. }
  398.  
  399. pascal GridViewPart TGroupTreeView::IdentifyPoint(const VPoint& thePoint,
  400.                                              GridCell& aCell)
  401. {
  402.     GridViewPart part = inherited::IdentifyPoint(thePoint, aCell);
  403.     if (part == badChoice)
  404.         return part;
  405.     CStr255 text;
  406.     ArrayIndex level, noVisibleSubLines, nodeIndex;
  407.     Boolean isFolder;
  408.     CRect triangleRect, iconRect, textRect;
  409.     
  410.     DoTheGetCellInformation(aCell, nodeIndex, level, noVisibleSubLines, isFolder, triangleRect, iconRect, textRect, text);
  411.     CPoint pt = ViewToQDPt(thePoint);
  412.     if (triangleRect.Contains(pt) || iconRect.Contains(pt) || textRect.Contains(pt))
  413.         return part;
  414.     else
  415.         return badChoice;    
  416. }
  417.  
  418. pascal void TGroupTreeView::DoShowHelp(const VPoint& localPoint, RgnHandle helpRegion)
  419. {
  420. #if qDebugBalloons
  421. #define macroBalloonMsg(x) fprintf(stderr, x)
  422. #else
  423. #define macroBalloonMsg(x)
  424. #endif
  425.     Focus();
  426.     GridCell theCell = VPointToCell(localPoint);
  427.     if (theCell == GridCell(0, 0))
  428.     {
  429.         macroBalloonMsg("DoShowHelp: VPointToCell returned GridCell(0, 0)\n");
  430.         return;
  431.     }
  432.  
  433.     VRect vr;
  434.     CellToVRect(theCell, vr);
  435.     CRect qdCellRect;
  436.     ViewToQDRect(vr, qdCellRect);
  437.     RectRgn(helpRegion, qdCellRect);
  438.  
  439.     ArrayIndex nodeIndex = fGroupTree->FindSubGroupIndexFromLine(fExpandData, fWindowFolderIndex, theCell.v);
  440.     if (nodeIndex == kEmptyIndex)
  441.     {
  442.         macroBalloonMsg("DoShowHelp: didn't find any groups (node) with for that line\n");
  443.         return;
  444.     }
  445.  
  446.     CStr255 text;
  447.     ArrayIndex level, noVisibleSubLines;
  448.     Boolean isFolder;
  449.     CRect triangleRect, iconRect, textRect;
  450.     GetCellInformation(theCell, level, noVisibleSubLines, isFolder, triangleRect, iconRect, textRect, text);
  451.     if (localPoint.h < iconRect.left - 3)
  452.     {
  453.         qdCellRect.right = iconRect.left;
  454.         RectRgn(helpRegion, qdCellRect);
  455.         macroBalloonMsg("DoShowHelp: cursor to the left of iconRect\n");
  456.         return;
  457.     }
  458.     if (localPoint.h > textRect.right + 3)
  459.     {
  460.         qdCellRect.left = textRect.right + 3;
  461.         RectRgn(helpRegion, qdCellRect);
  462.         macroBalloonMsg("DoShowHelp: cursor to the right of textRect\n");
  463.         return;
  464.     }
  465.     qdCellRect.left = iconRect.left - 3;
  466.     qdCellRect.right = textRect.right + 3;
  467.     RectRgn(helpRegion, qdCellRect);
  468.  
  469.     CPoint tip(textRect.right, textRect.top + fGridViewTextStyle.fVertOffset);
  470.     LocalToGlobal(tip);
  471.  
  472.     CStr255 helpText;
  473.     fGroupTree->GetHelpText(nodeIndex, helpText);
  474.     if (!helpText.Length())
  475.     {
  476.         macroBalloonMsg("DoShowHelp: had no help for this group\n");
  477.         return;
  478.     }
  479.     HMMessageRecord msg;
  480.     msg.hmmHelpType = khmmString;
  481.     BytesMove(&helpText, msg.u.hmmString, helpText.Length() + 1);
  482.     OSErr err = HMShowBalloon(msg, tip, nil, nil, 0, hmDefaultOptions, kHMRegularWindow);
  483.     if (err != hmBalloonAborted)
  484.         FailOSErr(err);
  485. }
  486.  
  487.  
  488. //=========================================================================
  489. void TGroupTreeView::UpdateList()
  490. {
  491.     DelRowFirst(fNumOfRows); // slet alt
  492.     short noGroups = short(fGroupTree->GetNoItems(fExpandData, fWindowFolderIndex));
  493.     Focus();
  494.     InsRowLast(short(noGroups), fCellHeight);
  495.     ForceRedraw();
  496. }
  497.  
  498. ArrayIndex TGroupTreeView::GetWindowFolderIndex()
  499. {
  500.     return fWindowFolderIndex;
  501. }
  502.  
  503. TGroupTree *TGroupTreeView::GetGroupTree()
  504. {
  505.     return fGroupTree;
  506. }
  507.  
  508. void TGroupTreeView::OpenSelection(Boolean updateDatabase)
  509. {
  510.     FailSpaceIsLow();
  511.     CSelectedCellIterator iter(this);
  512.     CStr255 text;
  513.     ArrayIndex level, noVisibleSubLines, nodeIndex;
  514.     Boolean isFolder;
  515.     CRect triangleRect, iconRect, textRect;
  516.  
  517.     short numSelected = 0;
  518.     for (GridCell aCell = iter.FirstCell(); iter.More(); aCell = iter.NextCell())
  519.     {
  520.         DoTheGetCellInformation(aCell, nodeIndex, level, noVisibleSubLines, isFolder, triangleRect, iconRect, textRect, text);
  521.         if (!isFolder)
  522.             numSelected++;
  523.     }
  524.     if (numSelected > kOpenManyGroupsLimit)
  525.     {
  526.         CStr255 num;
  527.         NumToString(numSelected, num);
  528.         ParamText(gEmptyString, gEmptyString, gEmptyString, num);
  529.         if (MacAppAlert(phOpenManyGroups, nil) != ok)
  530.             Failure(0, 0);
  531.     }
  532.  
  533.     for (aCell = iter.FirstCell(); iter.More(); aCell = iter.NextCell())
  534.     {
  535.         
  536.         DoTheGetCellInformation(aCell, nodeIndex, level, noVisibleSubLines, isFolder, triangleRect, iconRect, textRect, text);
  537.  
  538.         if (!isFolder)
  539.         {
  540.             fGroupTree->GetDotNameFromNodeIndex(nodeIndex, text);
  541.             TOpenGroupCommand *aCommand = new TOpenGroupCommand();
  542.             aCommand->IOpenGroupCommand(text, updateDatabase, false, false);
  543.             gApplWideThreads->ExecuteCommand(aCommand, "TOpenGroupCommand (TGroupTreeView)");
  544.             continue;
  545.         }
  546.         fGroupTreeDoc->CreateGroupTreeWindow(nodeIndex, this);
  547.     }
  548. }
  549.  
  550. void TGroupTreeView::DoSuperKey(TToolboxEvent *event)
  551. {
  552.     short row;
  553.     if (IsAnyCellSelected())
  554.         row = FirstSelectedCell().v + 1;
  555.     else
  556.         row = 1;
  557.     if (row > fNumOfRows)
  558.     {
  559.         SetEmptySelection(true);
  560.         return;
  561.     }
  562.     SelectCell(GridCell(1, row), false, true, true);
  563.     ScrollSelectionIntoView(kRedraw);
  564.     OpenSelection(!event->IsOptionKeyPressed());
  565. }
  566.  
  567. void TGroupTreeView::ExpandCompactCell(GridCell aCell, Boolean doExpand, Boolean wayDown)
  568. {
  569.     long deltaLines;
  570.     long nodeIndex = fGroupTree->FindSubGroupIndexFromLine(fExpandData, fWindowFolderIndex, aCell.v);
  571.     fGroupTree->Expand(fExpandData, doExpand, wayDown, nodeIndex, deltaLines);
  572.     DrawTrackedTriangle(aCell, doExpand, false, false);
  573.     DirectDeltaRows(this, aCell.v + 1, short(deltaLines), fCellHeight);
  574. }
  575.  
  576. void TGroupTreeView::ExpandCompactSelection(Boolean doExpand, Boolean wayDown)
  577. {
  578.     if (!IsAnyCellSelected())
  579.         return;
  580.     if (doExpand)
  581.     {
  582.         GridCell aCell(FirstSelectedCell());
  583.         do
  584.         {
  585.             if (IsCellSelected(aCell))
  586.                 ExpandCompactCell(aCell, doExpand, wayDown);
  587.             aCell.v++;
  588.         } while (aCell.v <= LastSelectedCell().v);
  589.     }
  590.     else
  591.     {
  592.         GridCell aCell(LastSelectedCell());
  593.         do
  594.         {
  595.             if (IsCellSelected(aCell))
  596.                 ExpandCompactCell(aCell, doExpand, wayDown);
  597.             aCell.v--;
  598.         } while (aCell.v >= FirstSelectedCell().v);
  599.     }
  600. }
  601.  
  602. pascal void TGroupTreeView::DoMouseCommand(VPoint &theMouse,
  603.                                                         TToolboxEvent *event, CPoint /* hysteresis */)
  604. {
  605.     GridCell aCell;
  606.     if (IdentifyPoint(theMouse, aCell) == badChoice)
  607.     {
  608.         if (!event->IsShiftKeyPressed())
  609.             SetEmptySelection(kHighlight);
  610.         return;
  611.     }
  612.     CStr255 text;
  613.     ArrayIndex level, noVisibleSubLines, nodeIndex;
  614.     Boolean isFolder;
  615.     CRect triangleRect, iconRect, textRect;
  616.     
  617.     DoTheGetCellInformation(aCell, nodeIndex, level, noVisibleSubLines, isFolder, triangleRect, iconRect, textRect, text);
  618.  
  619.     if (theMouse.h < 20)
  620.     {
  621.         if (!isFolder)
  622.             return;
  623.         VRect vr;
  624.         CellToVRect(aCell, vr);
  625.         vr.Inset(VPoint(fColInset / 2, fRowInset / 2));
  626.         CRect r;
  627.         ViewToQDRect(vr, r);
  628.         TExpandGroupTracker *tracker = new TExpandGroupTracker();
  629.         tracker->IExpandGroupTracker(this, theMouse, aCell, noVisibleSubLines != 0, event->IsOptionKeyPressed(), r);
  630.         PostCommand(tracker);
  631.         return;
  632.     }
  633.     
  634.     if (event->fClickCount > 1) 
  635.     {
  636.         OpenSelection(!event->IsCommandKeyPressed());
  637.         return;
  638.     }
  639.  
  640.     Focus();
  641.     if (event->IsShiftKeyPressed())
  642.         SelectCell(aCell, true, true, !IsCellSelected(aCell));
  643.     else if (!IsCellSelected(aCell))
  644.         SelectCell(aCell, false, true, true);
  645.  
  646.     TSubscribeGroupTracker *tracker = new TSubscribeGroupTracker();
  647.     tracker->ISubscribeGroupTracker(this, theMouse, event->IsOptionKeyPressed());
  648.     PostCommand(tracker);
  649. }
  650.  
  651. pascal void TGroupTreeView::DoKeyEvent(TToolboxEvent *event)
  652. {
  653.     if (!this->IsEnabled())
  654.     {
  655.         inherited::DoKeyEvent(event);
  656.         return;
  657.     }
  658.     switch (event->fCharacter)
  659.     {
  660.         case chSpace:
  661.             DoSuperKey(event);
  662.             break;
  663.         
  664.         case chEnter:
  665.         case chReturn:
  666.             OpenSelection(true);
  667.             break;
  668.  
  669.         case chTab:
  670.             {
  671.                 TTreeTabKeyCommand *cmd = new TTreeTabKeyCommand();
  672.                 cmd->ITreeTabKeyCommand(this, fExpandData, fWindowFolderIndex, !event->IsShiftKeyPressed());
  673.                 PostCommand(cmd);
  674.             }
  675.             break;
  676.             
  677.         case chUp:
  678.             {
  679.                 GridCell aCell;
  680.                 if (IsAnyCellSelected())
  681.                 {
  682.                     aCell = FirstSelectedCell();
  683.                     aCell.v--;
  684.                 }
  685.                 else
  686.                     aCell = GridCell(1, fNumOfRows);
  687.                 if (aCell.v >= 1)
  688.                 {
  689.                     SelectCell(aCell, false, true, true);
  690.                     ScrollSelectionIntoView(kRedraw);
  691.                     Focus();
  692.                     Update();
  693.                 }
  694.             }
  695.             break;
  696.  
  697.         case chDown:
  698.             {
  699.                 GridCell aCell;
  700.                 if (IsAnyCellSelected())
  701.                 {
  702.                     aCell = LastSelectedCell();
  703.                     aCell.v++;
  704.                 }
  705.                 else
  706.                     aCell = GridCell(1, 1);
  707.                 if (aCell.v <= fNumOfRows)
  708.                 {
  709.                     SelectCell(aCell, false, true, true);
  710.                     ScrollSelectionIntoView(kRedraw);
  711.                     Focus();
  712.                     Update();
  713.                 }
  714.             }
  715.             break;
  716.  
  717.         default:
  718.             if (event->fCharacter >= 32)
  719.             {
  720.                 TTreeTypeName *cmd = new TTreeTypeName();
  721.                 cmd->ITreeTypeName(this, fExpandData, fWindowFolderIndex, event);
  722.                 PostCommand(cmd);
  723.             }
  724.             else
  725.                 inherited::DoKeyEvent(event);            
  726.     } // case
  727. }
  728.  
  729. pascal void TGroupTreeView::DoCommandKeyEvent(TToolboxEvent *event)
  730. {
  731.     if (!this->IsEnabled())
  732.     {
  733.         inherited::DoCommandKeyEvent(event);
  734.         return;
  735.     }
  736.     switch (event->fCharacter)
  737.     {
  738.         case chEnter:
  739.         case chReturn:
  740.             OpenSelection(false);
  741.             break;
  742.         
  743.         case chUp:
  744.             if (event->IsShiftKeyPressed())
  745.             {
  746.                 DoMenuCommand(cOpenListOfAllGroups);
  747.                 return;
  748.             }
  749.             if (fWindowFolderIndex != kFirstIndex)
  750.             {
  751.                 ArrayIndex index = fGroupTree->GetParentIndex(fWindowFolderIndex);
  752.                 fGroupTreeDoc->CreateGroupTreeWindow(index, this);
  753.             }
  754.             break;
  755.  
  756.         case chDown:
  757.             OpenSelection(true);
  758.             break;
  759.  
  760.         case chLeft:
  761.             ExpandCompactSelection(false, event->IsOptionKeyPressed());
  762.             break;
  763.  
  764.         case chRight:
  765.             ExpandCompactSelection(true, event->IsOptionKeyPressed());
  766.             break;
  767.  
  768.         default:
  769.             inherited::DoCommandKeyEvent(event);
  770.     } // case
  771. }
  772.  
  773.  
  774. pascal void TGroupTreeView::DoMenuCommand(CommandNumber aCommandNumber)
  775. {
  776.     switch (aCommandNumber)
  777.     {
  778.         default:
  779.             {
  780.                 StandardGridViewTextStyle gvts = fGridViewTextStyle;
  781.                 if (gNewsAppl->HandleFontMenu(aCommandNumber, gvts.fTextStyle))
  782.                 {
  783.                     fGridViewTextStyle = gvts;
  784.                     ChangedFont();
  785.                 }
  786.                 else
  787.                     inherited::DoMenuCommand(aCommandNumber);
  788.             }
  789.     }
  790. }
  791.  
  792. pascal void TGroupTreeView::DoSetupMenus()
  793. {
  794.     gNewsAppl->EnableFontMenu(fGridViewTextStyle.fTextStyle);
  795.     Enable(cSelectAll, true);
  796.     inherited::DoSetupMenus();
  797.     Enable(cSaveAs, false);
  798.     Enable(cSaveCopy, false);
  799.     Enable(cRevert, false);
  800. }
  801.