home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / macfe / prefs / CMenuTable.cp < prev    next >
Encoding:
Text File  |  1998-04-08  |  14.8 KB  |  522 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #ifdef PowerPlant_PCH
  20. #include PowerPlant_PCH
  21. #endif
  22.  
  23. #include "CMenuTable.h"
  24. #include <Menus.h>
  25. #include <UDrawingUtils.h>
  26. #include <UTextTraits.h>
  27. #include <LTableMonoGeometry.h>
  28. #include <LTableSingleSelector.h>
  29. #include <LTableArrayStorage.h>
  30. #include <LDropFlag.h>
  31. //#include <QAP_Assist.h>
  32.  
  33. #include "CPrefsMediator.h"
  34.  
  35. #pragma options align= packed
  36.  
  37. struct CellData
  38. {
  39.     MessageT    message;
  40.     Str255        label;
  41. };
  42.  
  43. #pragma options align=reset
  44.  
  45. //----------------------------------------------------------------------------------------
  46. CMenuTable::CMenuTable(LStream *inStream)
  47. :         LTextHierTable(inStream)
  48. //,        CQAPartnerTableMixin(this)
  49. //----------------------------------------------------------------------------------------
  50. {
  51.     *inStream >> mLeafTextTraits;
  52.     *inStream >> mParentTextTraits;
  53.     *inStream >> mFirstIndent;
  54.     *inStream >> mLevelIndent;
  55.     *inStream >> mMenuID;
  56. }
  57.  
  58.  
  59. //----------------------------------------------------------------------------------------
  60. CMenuTable::~CMenuTable()
  61. //----------------------------------------------------------------------------------------
  62. {
  63. }
  64.  
  65.  
  66. //-----------------------------------
  67. void CMenuTable::AddTableLabels(
  68.     TableIndexT    ¤tRow,
  69.     ResIDT        menuID,
  70.     Boolean        firstLevel)
  71. // Recursive.  Adds table entries by using a hierarchical menu structure.
  72. //-----------------------------------
  73. {
  74.     MenuHandle hMenu = nil;
  75.     Int16**    theMcmdH = nil;
  76.     try
  77.     {
  78.         hMenu = ::GetMenu(menuID);
  79.         ThrowIfResFail_(hMenu);
  80.         short iItemCnt = ::CountMItems(hMenu);
  81.         theMcmdH = (Int16**)::GetResource('Mcmd', menuID);
  82.         ThrowIfResFail_(theMcmdH);
  83.         if (**theMcmdH != iItemCnt)
  84.         {
  85.             ReleaseResource((Handle)theMcmdH);
  86.             theMcmdH = nil;
  87.             throw((OSErr)resNotFound);
  88.         }
  89.         StHandleLocker hl((Handle)theMcmdH);
  90.         MessageT* messages = (MessageT *)(*theMcmdH + 1);
  91.         // There does not seem to be a way to add a row that is at a higher
  92.         // level than the one immediately preceding it. For this reason we
  93.         // must make two pass through the labels. The first pass creates all of
  94.         // the rows for a given level and the next pass adds the children.
  95.         int menuItem;
  96.         TableIndexT    currentRowSaved = currentRow;
  97.         for (menuItem = 1; menuItem <= iItemCnt; ++menuItem)
  98.         {
  99.             CellData theData;
  100.             ::GetMenuItemText(hMenu, menuItem, theData.label);
  101.             if (messages)
  102.                 theData.message = messages[menuItem - 1];
  103.             else
  104.                 theData.message = 0;
  105.             short cmdChar;
  106.             ::GetItemCmd(hMenu, menuItem, &cmdChar);
  107.             Boolean    hasSubMenus = (hMenuCmd == cmdChar);
  108.             if (!firstLevel && (1 == menuItem))
  109.             {
  110.                 InsertChildRows(    1, currentRow++, &theData,
  111.                                     sizeof(MessageT) + theData.label[0] + 1,
  112.                                     hasSubMenus, false);
  113.             }
  114.             else
  115.             {
  116.                 InsertSiblingRows(    1, currentRow++, &theData,
  117.                                     sizeof(MessageT) + theData.label[0] + 1,
  118.                                     hasSubMenus, false);
  119.             }
  120.         }
  121.         currentRow = currentRowSaved;
  122.         for (menuItem = 1; menuItem <= iItemCnt; ++menuItem)
  123.         {
  124.             short cmdChar;
  125.             ::GetItemCmd(hMenu, menuItem, &cmdChar);
  126.             Boolean    hasSubMenus = (hMenuCmd == cmdChar);
  127.             ++currentRow;
  128.             if (hasSubMenus)
  129.             {
  130.                 short    markChar;
  131.                 ::GetItemMark(hMenu, menuItem, &markChar);
  132.     //            AddTableLabels(currentRow, markChar & 0x0F, false);
  133.                 AddTableLabels(currentRow, markChar, false);
  134.             }
  135.         }
  136.     }
  137.     catch(...)
  138.     {
  139.         if (hMenu)
  140.             ReleaseResource((Handle)hMenu);
  141.         if (theMcmdH)
  142.             ReleaseResource((Handle)theMcmdH);
  143.         throw;
  144.     }
  145.     if (hMenu)
  146.         ReleaseResource((Handle)hMenu);
  147.     if (theMcmdH)
  148.         ReleaseResource((Handle)theMcmdH);
  149. }
  150.  
  151. //----------------------------------------------------------------------------------------
  152. void CMenuTable::FinishCreate()
  153. //----------------------------------------------------------------------------------------
  154. {
  155.     // geometry
  156.     SDimension16 tableSize;
  157.     GetFrameSize(tableSize);
  158.  
  159.     StTextState    ts;
  160.     UTextTraits::SetPortTextTraits(mParentTextTraits);
  161.     FontInfo    fi;
  162.  
  163.     ::GetFontInfo(&fi);
  164.     Uint16        height = fi.ascent + fi.descent + fi.leading + 1;
  165.     // the height should never be less than 12
  166.     height = height > 12? height: 12;
  167.  
  168.     LTableMonoGeometry        *theGeometry =
  169.         new LTableMonoGeometry(    this,
  170.                                 tableSize.width,
  171.                                 fi.ascent + fi.descent + fi.leading + 1);
  172.     SetTableGeometry(theGeometry);
  173.     // selector
  174.     LTableSingleSelector    *theSelector =
  175.         new LTableSingleSelector(this);
  176.     SetTableSelector(theSelector);
  177.     // storage
  178.     LTableArrayStorage        *theStorage =
  179.         new LTableArrayStorage(this, (unsigned long)0);
  180.     SetTableStorage(theStorage);
  181.  
  182.     // rows and cols
  183.     InsertCols(1, 0, "", 0, false);
  184.  
  185.     TableIndexT currentRow = 0;
  186.     AddTableLabels(currentRow, mMenuID);
  187.     UnselectAllCells();
  188. }
  189.  
  190. //----------------------------------------------------------------------------------------
  191. void CMenuTable::SelectionChanged()
  192. //----------------------------------------------------------------------------------------
  193. {
  194.     BroadcastMessage(msg_SelectionChanged, this);
  195. }
  196.  
  197. //----------------------------------------------------------------------------------------
  198. MessageT CMenuTable::GetSelectedMessage()
  199. //----------------------------------------------------------------------------------------
  200. {
  201.     MessageT result = 0;
  202.     STableCell        theCell = GetFirstSelectedCell();    // we have only one
  203.     CellData        theData;
  204.     unsigned long    theSize = sizeof(theData);
  205.     if (theCell.row && theCell.col)
  206.     {
  207.         TableIndexT    index;
  208.         CellToIndex(theCell, index);
  209.         index = GetWideOpenIndex(index);
  210.         STableCell    expandedCell;
  211.         IndexToCell(index, expandedCell);
  212.         GetCellData(expandedCell, &theData, theSize);
  213.         if (theSize > sizeof(theData.message))
  214.         {
  215.             result = theData.message;
  216.         }
  217.     }
  218.     return result;
  219. }
  220.  
  221. //----------------------------------------------------------------------------------------
  222. TableIndexT    CMenuTable::FindMessage( MessageT message )
  223. // Returns Wide Open index
  224. //----------------------------------------------------------------------------------------
  225. {
  226.     TableIndexT index = 0;
  227.     CellData cellData;
  228.     STableCell cell(0,0);
  229.     unsigned long    theSize = sizeof(cellData);
  230.     TableIndexT numberRows, numberCols;
  231.     GetWideOpenTableSize( numberRows, numberCols ) ;
  232.     
  233.     for ( TableIndexT i = 1; i<= numberRows; i++ )
  234.     {
  235.         
  236.         IndexToCell( i, cell );
  237.         GetCellData( cell , &cellData, theSize );
  238.         if ( cellData.message == message )
  239.         {
  240.             index = i;
  241.             break;
  242.         }
  243.     }
  244.     return index;
  245. }
  246.  
  247. //----------------------------------------------------------------------------------------
  248. void CMenuTable::DrawCell(
  249.     const STableCell    &inCell,
  250.     const Rect            &inLocalRect)
  251. //----------------------------------------------------------------------------------------
  252. {
  253.     TableIndexT    woRow = mCollapsableTree->GetWideOpenIndex(inCell.row);
  254.     
  255.     DrawDropFlag(inCell, woRow);
  256.     
  257.     STableCell    woCell(woRow, inCell.col);
  258.     CellData    cellData;
  259.     Uint32        dataSize = sizeof(cellData);
  260.  
  261.     GetCellData(woCell, &cellData, dataSize);
  262.     
  263.     ResIDT    textTraitsID = mLeafTextTraits;
  264.     if (mCollapsableTree->IsCollapsable(woRow)) {
  265.         textTraitsID = mParentTextTraits;
  266.     }
  267.     UTextTraits::SetPortTextTraits(textTraitsID);
  268.     
  269.     Uint32    nestingLevel = mCollapsableTree->GetNestingLevel(woRow);
  270.     FontInfo    fi;
  271.     ::GetFontInfo(&fi);
  272.     Int16        height = inLocalRect.top +
  273.                             (inLocalRect.bottom - inLocalRect.top) / 2 +
  274.                             fi.ascent - ((fi.ascent + fi.descent) / 2);
  275.  
  276.     MoveTo(inLocalRect.left + mFirstIndent + nestingLevel * mLevelIndent,
  277.             height);
  278.     DrawString(cellData.label);
  279. }
  280.  
  281. //----------------------------------------------------------------------------------------
  282. void CMenuTable::GetHiliteRgn(RgnHandle ioHiliteRgn)
  283. //    Pass back a Region containing the frames of all selected cells which
  284. //    are within the visible rectangle of the Table
  285. //
  286. //    Caller must allocate space for the region
  287. //----------------------------------------------------------------------------------------
  288. {
  289.     ::SetEmptyRgn(ioHiliteRgn);            // Assume no visible selection
  290.  
  291.     Rect    visRect;
  292.     GetRevealedRect(visRect);            // Check if Table is revealed
  293.     if (!::EmptyRect(&visRect)) {
  294.         PortToLocalPoint(topLeft(visRect));
  295.         PortToLocalPoint(botRight(visRect));
  296.         
  297.         STableCell    topLeftCell, botRightCell;
  298.         FetchIntersectingCells(visRect, topLeftCell, botRightCell);
  299.         
  300.         RgnHandle    cellRgn = ::NewRgn();
  301.         
  302.         STableCell    cell;                // Loop thru all cells
  303.         for (cell.row = topLeftCell.row; cell.row <= botRightCell.row; cell.row++) {
  304.             for (cell.col = topLeftCell.col; cell.col <= botRightCell.col; cell.col++) {
  305.                 if (CellIsSelected(cell)) {
  306.                     Rect    cellRect;
  307.                     GetLocalCellRect(cell, cellRect);
  308.                     cellRect.left += (mFirstIndent - 1);
  309.                     ::RectRgn(cellRgn, &cellRect);
  310.                     ::UnionRgn(ioHiliteRgn, cellRgn, ioHiliteRgn);
  311.                 }
  312.             }
  313.         }
  314.         
  315.         ::DisposeRgn(cellRgn);
  316.     }
  317. }
  318.  
  319. //----------------------------------------------------------------------------------------
  320. void CMenuTable::HiliteSelection(
  321.     Boolean    inActively,
  322.     Boolean inHilite)
  323. //    Draw or undraw hiliting for the current selection in either the
  324. //    active or inactive state
  325. //----------------------------------------------------------------------------------------
  326. {
  327.     STableCell    theCell;
  328.     
  329.     while (GetNextSelectedCell(theCell))
  330.     {
  331.         if (inActively) {
  332.             HiliteCellActively(theCell, inHilite);
  333.         } else {
  334.             HiliteCellInactively(theCell, inHilite);
  335.         }
  336.     }
  337. }
  338.  
  339. //----------------------------------------------------------------------------------------
  340. void CMenuTable::HiliteCellActively(const STableCell    &inCell, Boolean /* inHilite */)
  341. //----------------------------------------------------------------------------------------
  342. {
  343.     Rect    cellFrame;
  344.     if (GetLocalCellRect(inCell, cellFrame) && FocusExposed())
  345.     {
  346.         StColorPenState saveColorPen;   // Preserve color & pen state
  347.         StColorPenState::Normalize();
  348.  
  349.         UDrawingUtils::SetHiliteModeOn();
  350.         cellFrame.left += (mFirstIndent - 1);
  351.         ::InvertRect(&cellFrame);
  352.     }
  353. }
  354.  
  355. //----------------------------------------------------------------------------------------
  356. void CMenuTable::HiliteCellInactively(const STableCell &inCell, Boolean /* inHilite */)
  357. //----------------------------------------------------------------------------------------
  358. {
  359.     Rect    cellFrame;
  360.     if (GetLocalCellRect(inCell, cellFrame) && FocusExposed())
  361.     {
  362.         StColorPenState saveColorPen;   // Preserve color & pen state
  363.         StColorPenState::Normalize();
  364.  
  365.         cellFrame.left += (mFirstIndent - 1);
  366.         UDrawingUtils::SetHiliteModeOn();
  367.         ::PenMode(srcXor);
  368.         ::FrameRect(&cellFrame);
  369.     }
  370. }
  371.  
  372. //----------------------------------------------------------------------------------------
  373. void CMenuTable::ClickSelf(const SMouseDownEvent &inMouseDown)
  374. //----------------------------------------------------------------------------------------
  375. {
  376.     STableCell    hitCell;
  377.     SPoint32    imagePt;
  378.     
  379.     LocalToImagePoint(inMouseDown.whereLocal, imagePt);
  380.     
  381.     if (GetCellHitBy(imagePt, hitCell))
  382.     {
  383.         // Before calling CPrefsPaneManager::CanSwitch() we should check to see
  384.         // if the click is on a different cell. (No point in calling CanSwitch()
  385.         // if we aren't going to switch.)
  386.         Boolean    switchAllowed = true;
  387.         if (hitCell != GetFirstSelectedCell())
  388.         {
  389.             switchAllowed = CPrefsMediator::CanSwitch();
  390.         }
  391.         if (switchAllowed)
  392.         {
  393.                                             // Click is inside hitCell
  394.                                             // Check if click is inside DropFlag
  395.             TableIndexT    woRow = mCollapsableTree->GetWideOpenIndex(hitCell.row);
  396.             Rect    flagRect;
  397.             CalcCellFlagRect(hitCell, flagRect);
  398.             
  399.             if (mCollapsableTree->IsCollapsable(woRow) &&
  400.                 ::PtInRect(inMouseDown.whereLocal, &flagRect))
  401.             {
  402.                                             // Click is inside DropFlag
  403.                 FocusDraw();
  404.                 Boolean    expanded = mCollapsableTree->IsExpanded(woRow);
  405.                 if (LDropFlag::TrackClick(flagRect, inMouseDown.whereLocal, expanded))
  406.                 {
  407.                                             // Mouse released inside DropFlag
  408.                                             //   so toggle the Row
  409.                     if (inMouseDown.macEvent.modifiers & optionKey)
  410.                     {
  411.                                             // OptionKey down means to do
  412.                                             //   a deep collapse/expand                        
  413.                         if (expanded)
  414.                         {
  415.                             DeepCollapseRow(woRow);
  416.                         }
  417.                         else
  418.                         {
  419.                             DeepExpandRow(woRow);
  420.                         }
  421.                     
  422.                     }
  423.                     else
  424.                     {                // Shallow collapse/expand
  425.                         if (expanded)
  426.                         {
  427.                             CollapseRow(woRow);
  428.                         }
  429.                         else
  430.                         {
  431.                             ExpandRow(woRow);
  432.                         }
  433.                     }
  434.                 }
  435.             }
  436.             if (ClickSelect(hitCell, inMouseDown))
  437.             {
  438.                                             // Click outside of the DropFlag
  439.                 ClickCell(hitCell, inMouseDown);
  440.             }
  441.         }    // else don't allow the selection to change
  442.     }
  443.     else
  444.     {                            // Click is outside of any Cell
  445.         UnselectAllCells();
  446.     }
  447. }
  448.  
  449. #pragma mark -
  450. #if defined(QAP_BUILD)
  451.  
  452. //-----------------------------------
  453. void CMenuTable::QapGetListInfo(PQAPLISTINFO pInfo)
  454. //-----------------------------------
  455. {
  456.     TableIndexT    outRows, outCols, lcv;
  457.     
  458.     if (pInfo == nil)
  459.         return;
  460.     
  461.     GetWideOpenTableSize(outRows, outCols);
  462.     
  463.     for (lcv = 0; lcv < outRows; lcv++)
  464.     {
  465.         if (IsCollapsable(lcv) && !IsExpanded(lcv))
  466.         {
  467.             ExpandRow(lcv);
  468.         }
  469.     }
  470.  
  471.     // fetch vertical scrollbar Macintosh control
  472.     ControlHandle macVScroll = NULL;
  473.     LScroller *myScroller = dynamic_cast<LScroller *>(GetSuperView());
  474.     if (myScroller != NULL)
  475.     {
  476.         if (myScroller->GetVScrollbar() != NULL)
  477.             macVScroll = myScroller->GetVScrollbar()->GetMacControl();
  478.     }
  479.  
  480.     pInfo->itemCount    = (short)outRows;
  481.     pInfo->topIndex     = 0;
  482.     pInfo->itemHeight     = GetRowHeight(0);
  483.     pInfo->visibleCount = outRows;
  484.     pInfo->vScroll         = macVScroll;
  485.     pInfo->isMultiSel     = false;
  486.     pInfo->isExtendSel     = false;
  487.     pInfo->hasText         = true;
  488. }
  489.  
  490.  
  491. //-----------------------------------
  492. Ptr CMenuTable::QapAddCellToBuf(Ptr pBuf, Ptr pLimit, const STableCell& sTblCell)
  493. //-----------------------------------
  494. {
  495.     char         str[256];
  496.     short        len = 0;
  497.     CellData     theData;
  498.  
  499.     UInt32 dataSize = sizeof(theData);
  500.     GetCellData(sTblCell, (void *)&theData, dataSize);
  501.  
  502.     strncpy(str, (const char *)&theData.label[1], (short)theData.label[0]);
  503.     str[(short)theData.label[0]] = '\0';
  504.     len = strlen(str) + 1;
  505.  
  506.     if (pBuf + sizeof(short) + len >= pLimit)
  507.         return NULL;
  508.  
  509.     *(unsigned short *)pBuf = sTblCell.row - 1;
  510.     if (CellIsSelected(sTblCell))
  511.         *(unsigned short *)pBuf |= 0x8000;
  512.  
  513.     pBuf += sizeof(short);
  514.  
  515.     strcpy(pBuf, str);
  516.     pBuf += len;
  517.  
  518.     return pBuf;
  519. }
  520.  
  521. #endif //QAP_BUILD
  522.