home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / macfe / rdfui / CHyperTreeFlexTable.cp next >
Encoding:
Text File  |  1998-04-08  |  42.9 KB  |  1,422 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. //
  20. // Mike Pinkerton, Netscape Communications
  21. //
  22. // Subclass of CStandardFlexTable to handle working with XP RDF Hyper Trees
  23. //
  24.  
  25. #include "CHyperTreeFlexTable.h"
  26.  
  27. // PowerPlant
  28. #include <LTableArrayStorage.h>
  29. #include <LDropFlag.h>
  30.  
  31. #include "CHyperTreeHeader.h"
  32. #include "URDFUtilities.h"
  33. #include "uapp.h"
  34. #include "CURLDragHelper.h"
  35. #include "CIconTextDragTask.h"
  36. #include "CNetscapeWindow.h"
  37. #include "resgui.h"
  38. #include "macutil.h"
  39. #include "ufilemgr.h"
  40. #include "CInlineEditField.h"
  41. #include "CContextMenuAttachment.h"
  42.  
  43. #include <vector.h>
  44. #include <algorithm>
  45.  
  46.  
  47. const ResIDT cFolderIconID = -3999;        // use the OS Finder folder icon
  48. const ResIDT cItemIconID = 15313;
  49. const ResIDT cFileIconID = 15408;
  50.  
  51.  
  52. #pragma mark -- class CHyperTreeFlexTable --
  53.  
  54.  
  55.  
  56. // ------------------------------------------------------------
  57. // Construction, Destruction
  58. // ------------------------------------------------------------
  59.  
  60. CHyperTreeFlexTable::CHyperTreeFlexTable(LStream* inStream)
  61.     :    CStandardFlexTable(inStream),
  62.         mHTView(NULL),
  63.         mHTNotificationData(NULL),
  64.         mViewBeforeDrag(NULL)
  65. {
  66.     mSendDataUPP = NewDragSendDataProc(LDropArea::HandleDragSendData);
  67.     ThrowIfNil_(mSendDataUPP);
  68.  
  69. }
  70.  
  71.  
  72. CHyperTreeFlexTable::~CHyperTreeFlexTable()
  73. {
  74. }
  75.  
  76.  
  77.  
  78.  
  79. // ------------------------------------------------------------
  80. // CStandardFlexTable overrides
  81. // ------------------------------------------------------------
  82. ResIDT CHyperTreeFlexTable::GetIconID(TableIndexT inRow) const
  83. {
  84.     HT_Resource node = HT_GetNthItem(GetHTView(), URDFUtilities::PPRowToHTRow(inRow) );
  85.     if (node) {
  86.         if ( HT_IsContainer(node) )
  87.             return cFolderIconID;
  88.         else {
  89.             char* url = HT_GetNodeURL(node);
  90.             if ( url && *url == 'f' )            // is it a file url?
  91.                 return cFileIconID;
  92.             else
  93.                 return cItemIconID;            
  94.         }
  95.     }
  96.     return cItemIconID;
  97. }
  98.  
  99.  
  100. //
  101. // SetUpTableHelpers
  102. //
  103. // Call the inherited version to do most of the work but replace the
  104. // selector with our own version to track the selection in the HT_API
  105. //
  106. void
  107. CHyperTreeFlexTable :: SetUpTableHelpers()
  108. {
  109.     CStandardFlexTable::SetUpTableHelpers();
  110.     
  111.     // replace selector....
  112.     SetTableSelector( new CHyperTreeSelector(this) );
  113.  
  114. } // SetupTableHelpers
  115.  
  116.  
  117. //
  118. // GetHiliteTextRect
  119. //
  120. // Find out what rectangle to draw selected in the currently selected row. This is
  121. // based on the item title.
  122. //
  123. Boolean
  124. CHyperTreeFlexTable::GetHiliteTextRect ( TableIndexT inRow, Rect& outRect) const
  125. {
  126.     STableCell cell(inRow, GetHiliteColumn());
  127.     if (!GetLocalCellRect(cell, outRect))
  128.         return false;
  129.     Rect iconRect;
  130.     GetIconRect(cell, outRect, iconRect);
  131.     outRect.left = iconRect.right;
  132.  
  133.     // Get cell data for first column
  134.     char buffer[1000];
  135.     GetHiliteText(inRow, buffer, 1000, &outRect);
  136.  
  137.     return true;
  138.     
  139. } // GetHiliteTextRect
  140.  
  141.  
  142. //
  143. // GetMainRowText
  144. //
  145. // Returns the text of the title of the item.
  146. //
  147. void 
  148. CHyperTreeFlexTable :: GetMainRowText( TableIndexT inRow, char* outText, UInt16 inMaxBufferLength) const
  149. {
  150.     if (!outText || inMaxBufferLength == 0)
  151.         return;
  152.  
  153.     void* data;
  154.     CHyperTreeHeader* header = dynamic_cast<CHyperTreeHeader*>(mTableHeader);
  155.     Assert_(header != NULL);
  156.     CHyperTreeHeader::ColumnInfo info = header->GetColumnInfo(FindTitleColumnID()-1);    // GCI() is 0-based
  157.     HT_Resource node = HT_GetNthItem(GetHTView(), URDFUtilities::PPRowToHTRow(inRow) );
  158.     if ( node && HT_GetNodeData(node, info.token, info.tokenType, &data) ) {
  159.         char* title = static_cast<char*>(data);
  160.         strcpy ( outText, title );
  161.     }
  162.     else
  163.         *outText = NULL;
  164.     
  165. } // GetMainRowText
  166.  
  167.  
  168. //
  169. // FindTitleColumnID
  170. //
  171. // Returns the index of the column that contains the item title and icon. This will search out the
  172. // correct column by looking at the column headers.
  173. //
  174. // NOTE: THERE IS CURRENTLY NO BACKEND SUPPORT FOR REORDERING COLUMNS, SO WE MAKE AN EXPLICIT
  175. // ASSUMPTION THAT THE FIRST COLUMN IS THE TITLE COLUMN. AT LEAST THIS SHOULD BE THE ONLY
  176. // ROUTINE THAT HAS TO CHANGE WHEN THAT ASSUMPTION CHANGES.
  177. //
  178. Uint32
  179. CHyperTreeFlexTable :: FindTitleColumnID ( ) const
  180. {
  181.     return 1;    // for now....
  182.  
  183. } // FindTitleColumnID
  184.  
  185.  
  186. //
  187. // CellInitiatesDrag
  188. //
  189. // Determines if a cell is allowed to start a drag. We disallow this for any cell except for the
  190. // cell with the title and icon.
  191. //
  192. Boolean
  193. CHyperTreeFlexTable :: CellInitiatesDrag ( const STableCell& inCell ) const
  194. {
  195.     return inCell.col == FindTitleColumnID() ? true : false;
  196.     
  197. } // CellInitiatesDrag
  198.  
  199.  
  200. //
  201. // CellSelects
  202. //
  203. // Determines if a cell is allowed to select the row. We disallow this for any cell except for the
  204. // cell with the title and icon.
  205. //
  206. Boolean
  207. CHyperTreeFlexTable :: CellSelects ( const STableCell& inCell ) const
  208. {
  209.     return inCell.col == FindTitleColumnID() ? true : false;
  210.     
  211. } // CellSelects
  212.  
  213.  
  214. //
  215. // DoHiliteRgn
  216. //
  217. // Override to not use the hilite color, since that would be confusing with in-place editing.
  218. // This is called when the user clicks on a row in the table to hilite that particular row.
  219. // The routine below is called when updating the window.
  220. //
  221. void 
  222. CHyperTreeFlexTable :: DoHiliteRgn ( RgnHandle inHiliteRgn ) const
  223. {    
  224.     ::InvertRgn ( inHiliteRgn );
  225.         
  226. } // DoHiliteRgn
  227.  
  228.  
  229. //
  230. // DoHiliteRect
  231. //
  232. // Override not to use hilite color, since it doesn't draw very well over the gray background.
  233. //
  234. void
  235. CHyperTreeFlexTable :: DoHiliteRect ( const Rect & inHiliteRect ) const
  236. {
  237.     ::InvertRect ( &inHiliteRect );
  238.  
  239. } // DoHiliteRect
  240.  
  241.  
  242. //
  243.  
  244. // HiliteSelection
  245. //
  246. // Overload the LTableView class' version of this routine to hilite the selected items
  247. // without setting the hilite bit before drawing. This is called when the window is updating
  248. // to redraw the selected items.
  249. //
  250. void
  251. CHyperTreeFlexTable :: HiliteSelection( Boolean    inActively, Boolean    /*inHilite*/)
  252. {
  253.     if (FocusExposed()) {
  254.         RgnHandle    hiliteRgn = ::NewRgn();
  255.         GetHiliteRgn(hiliteRgn);
  256.         StColorPenState saveColorPen;   // Preserve color & pen state
  257.         StColorPenState::Normalize();
  258.         
  259.         if (inActively) {
  260.             ::InvertRgn(hiliteRgn);
  261.             
  262.         } else {
  263.             ::PenMode(srcXor);
  264.             ::FrameRgn(hiliteRgn);
  265.         }
  266.  
  267.         ::DisposeRgn(hiliteRgn);
  268.     }
  269.     
  270. } // HiliteSelection
  271.  
  272.  
  273. //
  274. // SyncSelectionWithHT
  275. //
  276. // The selection has somehow changed by the backend's decree. Make sure that we are in
  277. // sync with that.
  278. //
  279. void
  280. CHyperTreeFlexTable :: SyncSelectionWithHT ( )
  281. {
  282.     CHyperTreeSelector* sel = dynamic_cast<CHyperTreeSelector*>(GetTableSelector());
  283.     Assert_( sel != NULL);
  284.     
  285.     sel->SyncSelectorWithHT();
  286.     
  287.     SelectionChanged();
  288.     ScrollSelectionIntoFrame();
  289.         
  290. } // SyncSelectionWithHT
  291.  
  292.  
  293. //
  294. // DrawCellContents
  295. //
  296. // Draw what goes inside each cell, naturally
  297. //
  298. void CHyperTreeFlexTable::DrawCellContents( const STableCell& inCell, const Rect& inLocalRect)
  299. {
  300.     PaneIDT    cellType = GetCellDataType(inCell);
  301.  
  302.     // Get info for column
  303.     CHyperTreeHeader* header = dynamic_cast<CHyperTreeHeader*>(mTableHeader);
  304.     Assert_(header != NULL);
  305.     CHyperTreeHeader::ColumnInfo info = header->GetColumnInfo(inCell.col - 1);
  306.  
  307.     //
  308.     // make the backdrop of the cell look like the Finder in OS8. Color/pen state is already
  309.     // restored for us by CStandardFlexTable::DrawCell() so we don't have to worry about reseting
  310.     // the bg color later.
  311.     //
  312.     {
  313.         static const RGBColor normalColumnColor = { 0xEEEE, 0xEEEE, 0xEEEE };
  314.         static const RGBColor sortedColumnColor = { 0xDDDD, 0xDDDD, 0xDDDD };
  315.         RGBColor backColor;
  316.         PaneIDT columnPane;
  317.         
  318.         Rect backRect = inLocalRect;
  319.         backRect.bottom--;                // leave a one pixel line on the bottom as separator
  320.         backRect.right++;                // cover up vertical dividing line on right side
  321.         backColor = inCell.col == header->GetSortedColumn(columnPane) ? sortedColumnColor : normalColumnColor;
  322.         ::RGBBackColor(&backColor);
  323.         ::EraseRect(&backRect);
  324.     }
  325.     
  326.     
  327.     // Get cell data
  328.     HT_Resource node = HT_GetNthItem(GetHTView(), URDFUtilities::PPRowToHTRow(inCell.row) );
  329.     if (node)
  330.     {
  331.         if ( HT_IsSeparator(node) ) {
  332.             StColorPenState savedPenState;
  333.             RGBColor black = { 0, 0, 0 };
  334.             Uint16 left = inLocalRect.left;
  335.             
  336.             if ( inCell.col == 1 ) {
  337.                 StTextState savedTextState;
  338.                 Rect iconRect, textRect = inLocalRect;
  339.                 
  340.                 // get level indent for text
  341.                 GetIconRect ( inCell, inLocalRect, iconRect );
  342.                 textRect.left = iconRect.left;
  343.                 left = iconRect.left;
  344.                 ::MoveTo ( left, iconRect.top );
  345.                 
  346.                 //ÑÑÑ REPLACE WITH GetIndString
  347.                 DrawTextString("<Separator>", &mTextFontInfo, 0, textRect);
  348.                 left += ::TextWidth("<Separator>", 0, 11) + 5;
  349.             }
  350.             
  351.             ::RGBForeColor ( &black );
  352.             ::MoveTo ( left,
  353.                         inLocalRect.top + ((inLocalRect.bottom - inLocalRect.top) / 2) );
  354.             ::PenSize ( 2, 2 );
  355.             ::PenPat ( &qd.gray );
  356.             ::Line ( inLocalRect.right - left, 0 );
  357.         }
  358.         else {
  359.             void* data;
  360.             char* str;
  361.             Rect localRect = inLocalRect;
  362.             if (HT_GetNodeData(node, info.token, info.tokenType, &data) && data)
  363.             {
  364.                 switch (info.tokenType) {
  365.                     case HT_COLUMN_STRING:
  366.                     case HT_COLUMN_DATE_STRING:
  367.                         str = static_cast<char*>(data);
  368.                         if (inCell.col == FindTitleColumnID())
  369.                         {
  370.                             localRect.left = DrawIcons(inCell, localRect);
  371.                             localRect.left += CStandardFlexTable::kDistanceFromIconToText;
  372.                         }
  373.                         break;
  374.  
  375.                     case HT_COLUMN_DATE_INT:
  376.                     case HT_COLUMN_INT:
  377.                         char intStr[32];
  378.                         sprintf(intStr, "%d", (int)data);
  379.                         str = intStr;
  380.                         break;
  381.                 }
  382.                 DrawTextString(str, &mTextFontInfo, 0, localRect);
  383.             }
  384.         }
  385.     }
  386. }
  387.  
  388.  
  389. Boolean    CHyperTreeFlexTable::CellHasDropFlag(const STableCell& inCell, Boolean& outIsExpanded) const
  390. {
  391.     // bail quickly if this cell isn't a title column
  392.     if ( FindTitleColumnID() != inCell.col )
  393.         return false;
  394.         
  395.     HT_Resource node = HT_GetNthItem(GetHTView(), URDFUtilities::PPRowToHTRow(inCell.row) );
  396.     if (node)
  397.     {
  398.         PRBool result = HT_IsContainer(node);
  399.         if (result)
  400.         {
  401.             PRBool openState;
  402.             HT_Error err = HT_GetOpenState(node, &openState);
  403.             if (err == HT_NoErr)
  404.                 outIsExpanded = openState;
  405.         }
  406.         else
  407.             outIsExpanded = false;
  408.         return result;
  409.     }
  410.     return false;
  411.     
  412. } // CellHasDropFlag
  413.  
  414.  
  415. UInt16 CHyperTreeFlexTable::GetNestedLevel(TableIndexT inRow) const
  416. {
  417.     HT_Resource node = HT_GetNthItem(GetHTView(), URDFUtilities::PPRowToHTRow(inRow) );
  418.     if (node)
  419.     {
  420.         // subtract one because root node as indentation of 1
  421.         return (HT_GetItemIndentation(node) - 1);
  422.     }
  423.     return CStandardFlexTable::GetNestedLevel(inRow);
  424. }
  425.  
  426.  
  427. //
  428. // SetCellExpansion
  429. //
  430. // User clicked on the disclosure triangle, tell HT to open/close the container. This call
  431. // may fail if the user has password protected the folder and they get the password wrong.
  432. // If that is the case, redraw the drop flag to its correct state.
  433. //
  434. void CHyperTreeFlexTable::SetCellExpansion(
  435.     const STableCell& inCell,
  436.     Boolean inExpand)
  437. {
  438.     HT_Resource node = HT_GetNthItem(GetHTView(), URDFUtilities::PPRowToHTRow(inCell.row) );
  439.     if (node)
  440.     {
  441.         if ( HT_SetOpenState(node, (PRBool)inExpand) != noErr )
  442.             RefreshCell(inCell);
  443.     }
  444. }
  445.  
  446.  
  447. // ------------------------------------------------------------
  448. // HT Operations
  449. // ------------------------------------------------------------
  450.  
  451.  
  452. //
  453. // OpenView
  454. //
  455. // opens up the given view in the navCenter (such as bookmarks). Make sure the selector for this
  456. // table knows about new view, sync the number of rows in the table with the
  457. // number of rows in the HT and setup the columns.
  458. //
  459. // This routine is called as a result of the HT notification mechanism (not directly from any
  460. // FE events like clicks). That means that the shelf may not be open yet.
  461. //
  462. void
  463. CHyperTreeFlexTable::OpenView( HT_View inHTView )
  464. {
  465.     // Hide the inline editor. This will send us a message that the name changed and attempt
  466.     // to redraw the entire window. We don't want this because is causes an ugly flash as it
  467.     // redraws the old view then draws the new view. Setting the visRgn to empty prevents
  468.     // the redraw of the old view.
  469.     if ( mNameEditor && mNameEditor->IsVisible() ) {
  470.         StVisRgn saved(GetMacPort());
  471.         mNameEditor->UpdateEdit(nil, nil, nil);
  472.     }
  473.  
  474.     mHTView = mViewBeforeDrag = inHTView;
  475.     CHyperTreeSelector* sel = dynamic_cast<CHyperTreeSelector*>(GetTableSelector());
  476.     Assert_( sel != NULL);
  477.     sel->TreeView ( inHTView );
  478.  
  479.     CHyperTreeHeader* header = dynamic_cast<CHyperTreeHeader*>(mTableHeader);
  480.     Assert_(header != NULL);
  481.     HT_Cursor columnCursor = HT_NewColumnCursor(inHTView);
  482.     header->SetUpColumns(columnCursor);
  483.     HT_DeleteColumnCursor(columnCursor);
  484.     SynchronizeColumnsWithHeader();    
  485.     if ( header->GetHeaderWidth() )        // don't do this if shelf collapsed, we'll do it again later
  486.         SetRightmostVisibleColumn(1);    //ÑÑÑ HACK UNTIL WE GET THE COLUMN STUFF FIGURED OUT....
  487.     
  488.     Uint32 count = HT_GetItemListCount(inHTView);
  489.     if (mRows != count)
  490.     {
  491.         if (count > mRows)
  492.             InsertRows(count - mRows, 0, NULL, 0, false);
  493.         else
  494.             RemoveRows(mRows - count, 0, true);
  495.     }
  496.         
  497.     SyncSelectionWithHT();
  498.     
  499.     // redraw the table. If the mouse is down, we're probably in the middle of a 
  500.     // drag and drop so we want to redraw NOW (not when we get an update event after
  501.     // the mouse has been released).
  502.     if ( ::StillDown() ) {
  503.         UnselectAllCells();
  504.         FocusDraw();
  505.         Rect localRect;
  506.         CalcLocalFrameRect(localRect);
  507.         localRect.left++;
  508.         ::EraseRect(&localRect);
  509.         GetSuperView()->Draw(nil);        // redraw NOW to get the # of visible rows correct
  510.     }
  511.     else
  512.         Refresh();
  513.         
  514. }
  515.  
  516. void CHyperTreeFlexTable::ExpandNode(HT_Resource inHTNode)
  517. {
  518.     Int32 index = HT_GetNodeIndex(GetHTView(), inHTNode);
  519.     
  520.     Uint32 count = HT_GetCountVisibleChildren(inHTNode);
  521.     if (count > 0)
  522.         InsertRows(count, index + 1, NULL, 0, true);
  523. }
  524.  
  525. void CHyperTreeFlexTable::CollapseNode(HT_Resource inHTNode)
  526. {
  527.     Int32 index = HT_GetNodeIndex(GetHTView(), inHTNode);
  528.     
  529.     Uint32 count = HT_GetCountVisibleChildren(inHTNode);
  530.     if (count > 0)
  531.         RemoveRows(count, index + 2, true);
  532. }
  533.  
  534. //-----------------------------------
  535. // Commands
  536. //-----------------------------------
  537.  
  538. //
  539. // FindCommandStatus
  540. //
  541. void
  542. CHyperTreeFlexTable :: FindCommandStatus ( CommandT inCommand, Boolean &outEnabled,
  543.                                         Boolean &outUsesMark, Char16 &outMark, Str255 outName)
  544. {
  545.     // safety check
  546.     if ( ! mHTView )
  547.         return;
  548.     
  549.     HT_Pane thePane = HT_GetPane(mHTView);
  550.     
  551.     outUsesMark = false;
  552.  
  553.     if ( inCommand >= cmd_NavCenterBase && inCommand <= cmd_NavCenterCap ) {
  554.         outEnabled = HT_IsMenuCmdEnabled(thePane, (HT_MenuCmd)(inCommand - cmd_NavCenterBase));
  555.         return;
  556.     }
  557.  
  558.     // process the regular menus...
  559.     switch ( inCommand ) {
  560.     
  561.         //
  562.         // handle commands that we have to share with other parts of the UI
  563.         //
  564.         case cmd_Cut:
  565.             outEnabled = HT_IsMenuCmdEnabled(thePane, HT_CMD_CUT );
  566.             break;
  567.         case cmd_Copy:
  568.             outEnabled = HT_IsMenuCmdEnabled(thePane, HT_CMD_COPY );
  569.             break;
  570.         case cmd_Paste:
  571.             outEnabled = HT_IsMenuCmdEnabled(thePane, HT_CMD_PASTE );
  572.             break;
  573.         case cmd_Clear:
  574.             outEnabled = HT_IsMenuCmdEnabled(thePane, HT_CMD_DELETE_FILE );
  575.             break;
  576.  
  577.         default:
  578.             LCommander::FindCommandStatus(inCommand, outEnabled, outUsesMark, outMark, outName);
  579.             break;
  580.     
  581.     } // case of command
  582.     
  583. } // FindCommandStatus
  584.  
  585.  
  586. //
  587. // DeleteSelection
  588. //
  589. // Delete the selection in the given view. This is called when the user hits backspace
  590. // in the current view, so we don't need to worry (as below) about the view switching
  591. // during a drag and drop.
  592. //
  593. void
  594. CHyperTreeFlexTable::DeleteSelection ( )
  595. {
  596.     HT_Pane pane = HT_GetPane(mHTView);
  597.     if ( HT_IsMenuCmdEnabled(pane, HT_CMD_CUT) )    //ÑÑÑ these should be HT_CMD_CLEAR
  598.         HT_DoMenuCmd ( pane, HT_CMD_CUT );
  599.     
  600. } // DeleteSelection
  601.  
  602.  
  603. //
  604. // DeleteSelectionByDragToTrash
  605. //
  606. // Called when the user drags some stuff in the pane into the trash can to delete
  607. // it. We don't rely on the current view or the PowerPlant selection because it
  608. // may have been wiped out by a temporary drag over another workspace pane on
  609. // the way to the trash.
  610. //
  611. void
  612. CHyperTreeFlexTable :: DeleteSelectionByDragToTrash ( LArray & inItems )
  613. {
  614.     //ÑÑÑ return if we're not allowed to delete these objects!!!
  615.     
  616.     CIconTextSuite* curr = NULL;
  617.     LArrayIterator it ( inItems );
  618.     while ( it.Next(&curr) ) {
  619.         HT_Resource node = curr->GetHTNodeData();
  620.         HT_Resource parent = HT_GetParent(node);
  621.         Assert_( node != NULL && parent != NULL );
  622.         HT_RemoveChild ( parent, node );
  623.     }
  624.     
  625. } // DeleteSelectionByDragToTrash
  626.  
  627.  
  628. //
  629. // OpenRow
  630. //
  631. // Called to tell us when the user has clicked on a row in such a way that it should
  632. // open. Whether this is by single click or double click is left up to parameters to
  633. // the CStandardFlexTable. Regardless, open the url at this row if it is one....
  634. //
  635. void
  636. CHyperTreeFlexTable :: OpenRow ( TableIndexT inRow )
  637. {
  638.     HT_Resource node = HT_GetNthItem(GetHTView(), URDFUtilities::PPRowToHTRow(inRow) );
  639.     if (node) {
  640.     
  641.         // we can ignore the click if it is a container.
  642.         if ( !HT_IsContainer(node) && !HT_IsSeparator(node) )
  643.             CFrontApp::DoGetURL( HT_GetNodeURL(node) );
  644.                     
  645.     } // if valid node
  646.  
  647. } // OpenRow
  648.  
  649.  
  650. //
  651. // RowCanAcceptDrop
  652. //
  653. // Check if the given row can accept any of the items dropped on it. We iterate over each item
  654. // being dropped and ask the backend if that item is ok. If any item can be dropped, the entire
  655. // lot can be dropped.
  656. //
  657. Boolean 
  658. CHyperTreeFlexTable::RowCanAcceptDrop ( DragReference inDragRef, TableIndexT inDropRow )
  659. {
  660.     if ( inDropRow > mRows )
  661.         return false;
  662.         
  663.     HT_Resource targetNode = HT_GetNthItem(GetHTView(), URDFUtilities::PPRowToHTRow(inDropRow) );
  664.     return NodeCanAcceptDrop ( inDragRef, targetNode );
  665.     
  666. } // CStandardFlexTable::RowCanAcceptDrop
  667.  
  668.  
  669. //
  670. // RowCanAcceptDropBetweenAbove
  671. //
  672. // Check if the item can be dropped above the current node. This means we need to ask the parent
  673. // of the node for this row if it can be dropped on.
  674. //
  675. Boolean 
  676. CHyperTreeFlexTable::RowCanAcceptDropBetweenAbove( DragReference inDragRef, TableIndexT inDropRow )
  677. {
  678.     if ( inDropRow > mRows ) 
  679.         return NodeCanAcceptDrop ( inDragRef, HT_TopNode(GetHTView()) );
  680.         
  681.     HT_Resource targetNode = HT_GetParent( HT_GetNthItem(GetHTView(), URDFUtilities::PPRowToHTRow(inDropRow)) );
  682.     return NodeCanAcceptDrop ( inDragRef, targetNode );
  683.     
  684. } // CStandardFlexTable::RowCanAcceptDropBetweenAbove
  685.  
  686.  
  687. //
  688. // RowIsContainer
  689. //
  690. // Is this row a folder or a leaf? HT will tell us!
  691. //
  692. Boolean        
  693. CHyperTreeFlexTable :: RowIsContainer ( const TableIndexT & inRow ) const
  694. {
  695.     if ( inRow > mRows )
  696.         return false;
  697.         
  698.     return HT_IsContainer ( HT_GetNthItem(GetHTView(), URDFUtilities::PPRowToHTRow(inRow)) );
  699.  
  700. } // RowIsContainer
  701.  
  702.  
  703. //
  704. // HiliteDropRow
  705. //
  706. // Override to handle drawing the "insertion bar" for every row to always indicate to the
  707. // user exactly where the drop will occur. The inherited version of this class only draws
  708. // the insertion bar when the mouse is between two cells, and I really don't like that.
  709. //
  710. void 
  711. CHyperTreeFlexTable :: HiliteDropRow ( TableIndexT inRow, Boolean inDrawBarAbove )
  712. {
  713.     if (inRow == LArray::index_Bad)
  714.         return;
  715.  
  716.     STableCell cell(inRow, GetHiliteColumn());
  717.     if ( mIsInternalDrop && CellIsSelected(cell) )
  718.         return;         // Don't show hiliting feedback for a drag when over the selection.
  719.  
  720.     Rect insertionBar, cellRect;        
  721.     GetLocalCellRect(cell, cellRect);
  722.     insertionBar = cellRect;
  723.  
  724.     // when the mouse is over a cell, there are several possibilities:
  725.     // - if the cell is a container, hilite the container and draw the insertion bar
  726.     //   below the last visible child of the container. The left edge should be indented
  727.     //   from the left edge of the container. 
  728.     // - if the cell is a normal row, draw the bar directly above the row at
  729.     //   the same horizontal indent as the row.
  730.     // - if the cell is a container but the mouse is between rows, treat it like
  731.     //   a normal row and draw the bar directly above at the same level and do not
  732.     //   hilite the container.
  733.     // - if the mouse is off the end, draw the bar directly below the last row
  734.     //   at the same indent as the 1st row (since they should be siblings).
  735.     // The only problem with the behavior occurs when you want to drop something
  736.     // directly at the end of an open container. Moving the mouse to where you think
  737.     // would do it ends up dropping the item after the parent container at the 
  738.     // same level as the parent, not as the last item in the container. As a result,
  739.     // the only way to add something to the end of a container is to drop it on the
  740.     // container itself. The drag feedback illustrates that this will happen when you
  741.     // drag on top of a container.
  742.  
  743.     const Uint32 kInsertionBarLength = 35;
  744.     Rect iconRect;
  745.     GetIconRect ( cell, insertionBar, iconRect );
  746.     mDropNode = HT_GetNthItem( GetHTView(), URDFUtilities::PPRowToHTRow(cell.row) );
  747.     if ( mDropNode && HT_IsContainer(mDropNode) && !inDrawBarAbove ) {
  748.         
  749.         // place the insertion bar below the last visible row at the appropriate
  750.         // indent level for its children
  751.         Uint32 children = HT_GetCountVisibleChildren(mDropNode);
  752.         Uint32 rowHeight = GetRowHeight(inRow);
  753.         insertionBar.bottom = insertionBar.top + rowHeight + 1;
  754.         insertionBar.bottom += (children * GetRowHeight(inRow));
  755.         insertionBar.left = iconRect.left + kIndentPerLevel;    // one indentation
  756.         insertionBar.right    = insertionBar.left + kInsertionBarLength;
  757.         insertionBar.top = insertionBar.bottom - 2;        
  758.         
  759.         // hilite the container
  760.         DrawIcons(cell, cellRect);
  761.         StRegion hiliteRgn;
  762.         GetRowHiliteRgn(inRow, hiliteRgn);
  763.         ::InvertRgn(hiliteRgn);
  764.     
  765.     } // if drop on container
  766.     else {
  767.         
  768.         // setup insertion bar rectangle. When we're dropping at the end of the list, use
  769.         // the indent of the 1st item in the list, as they will be siblings.
  770.         if ( inRow <= mRows ) {
  771.             insertionBar.left = iconRect.left - 5;
  772.             insertionBar.right    = insertionBar.left + kInsertionBarLength;
  773.             insertionBar.bottom = insertionBar.top + 1;
  774.             insertionBar.top -= 1;
  775.         }
  776.         else {
  777.             // compute the icon rect for the 1st row
  778.             Rect iconRect, cellRect;
  779.             STableCell firstCell(1, GetHiliteColumn());
  780.             GetLocalCellRect ( firstCell, cellRect );
  781.             GetIconRect ( firstCell, cellRect, iconRect );
  782.             
  783.             // use the last row to compute where the bar should go vertically
  784.             Rect lastRowRect;
  785.             GetLocalCellRect ( STableCell(mRows, GetHiliteColumn()), lastRowRect );
  786.             
  787.             insertionBar.left = iconRect.left;
  788.             insertionBar.right = insertionBar.left + kInsertionBarLength;
  789.             insertionBar.top = lastRowRect.bottom + 1;
  790.             insertionBar.bottom = insertionBar.top + 2;
  791.         }
  792.     
  793.     } // else drop on item or between rows
  794.     
  795.     DoHiliteRect ( insertionBar );
  796.     
  797. } // HiliteDropRow
  798.  
  799.  
  800. //
  801. // ItemIsAcceptable
  802. //
  803. // Determine if the current item can be dropped in this pane. Check to see if the 
  804. // pane as a whole accepts drops (history, for example, will not). The data, at this
  805. // point, is fairly moot and will be checked in RowCanAcceptDrop*() routines.
  806. //
  807. Boolean
  808. CHyperTreeFlexTable :: ItemIsAcceptable ( DragReference /*inDragRef*/, ItemReference /*inItemRef*/ )
  809. {
  810.     return HT_CanDropURLOn ( HT_TopNode(GetHTView()), "http://foo.com" );
  811.     
  812. } // ItemIsAcceptable
  813.  
  814.  
  815. //
  816. // DragSelection
  817. //
  818. // Overridden to use our own version of the drag task...
  819. //
  820. void 
  821. CHyperTreeFlexTable :: DragSelection(
  822.     const STableCell&         inCell, 
  823.     const SMouseDownEvent&    inMouseDown    )
  824. {
  825.     FocusDraw();
  826.     mViewBeforeDrag = GetHTView();
  827.     Assert_(mViewBeforeDrag != NULL);
  828.     
  829.     // add the members of the selection to a list we will pass to the drag task.
  830.     LArray selection;
  831.     STableCell cell(0, 1);
  832.     while (GetNextSelectedRow(cell.row)) {    
  833.         Rect bounds, iconBounds;
  834.         GetLocalCellRect(cell, bounds);
  835.         GetIconRect    ( cell, bounds, iconBounds );
  836.         bounds.left = iconBounds.left;
  837.         
  838.         HT_Resource node = HT_GetNthItem(mViewBeforeDrag, URDFUtilities::PPRowToHTRow(cell.row) );
  839.         cstring finalCaption = CURLDragHelper::MakeIconTextValid ( HT_GetNodeName(node) );
  840.         CIconTextSuite* suite = new CIconTextSuite( this, bounds, GetIconID(cell.row), finalCaption, node );
  841.         selection.InsertItemsAt ( 1, LArray::index_Last, &suite );
  842.     }
  843.     
  844.     
  845.     // create the drag task
  846.     Rect cellBoundsOfClick;
  847.     GetLocalCellRect(inCell, cellBoundsOfClick);
  848.     CIconTextDragTask theTask(inMouseDown.macEvent, selection, cellBoundsOfClick);
  849.     
  850.     // setup our special data transfer proc called upon drag completion
  851.     OSErr theErr = ::SetDragSendProc ( theTask.GetDragReference(), mSendDataUPP, (LDropArea*) this );
  852.     ThrowIfOSErr_(theErr);
  853.     
  854.     theTask.DoDrag();
  855.     
  856.     // There is a problem with the HT backend that if you tell it to say, delete
  857.     // both a node and its parent, things get really screwed up when it tries to
  858.     // double-delete the child. Iterate over each item, and for each node, if 
  859.     // we find any children in the list, remove them. LArrayIterator should be
  860.     // smart enough to handle deletions while iterating....
  861.     LArrayIterator it(selection);
  862.     CIconTextSuite* curr = NULL;
  863.     while ( it.Next(&curr) ) {
  864.         HT_Resource currentNode = curr->GetHTNodeData();
  865.         CIconTextSuite* possibleChildSuite = NULL;
  866.         LArrayIterator inner(selection);
  867.         Uint32 counter = 1;                                    // LArray counts from 1
  868.         while ( inner.Next(&possibleChildSuite) ) {
  869.             HT_Resource possibleChild = possibleChildSuite->GetHTNodeData();
  870.             if ( HT_GetParent(possibleChild) == currentNode )
  871.                 selection.RemoveItemsAt(1, counter);        // child found, delete it
  872.             else
  873.                 counter++;
  874.         }
  875.     }
  876.     
  877.     // remove the items if they went into the trash
  878.     if ( theTask.DropLocationIsFinderTrash() )
  879.         DeleteSelectionByDragToTrash(selection);
  880.  
  881.     UnselectAllCells();
  882.     
  883.     // cleanup after ourselves
  884.     LArrayIterator it2(selection);
  885.     curr = NULL;
  886.     while ( it.Next(&curr) )
  887.         delete curr;
  888.         
  889.     mViewBeforeDrag = GetHTView();
  890.         
  891. } // DragSelection
  892.  
  893.  
  894. //
  895. // DoDragSendData
  896. //
  897. // Called when this window is the originator of the drag, after the drop has succeeded. Since we
  898. // were the ones who created the drag task, we know that one of the flavors is emHTNodeDrag, which
  899. // contains as its data the HT_Resource representing this drag item. Use that resource to get
  900. // the url and title.
  901. //
  902. void
  903. CHyperTreeFlexTable :: DoDragSendData( FlavorType inFlavor, ItemReference inItemRef,
  904.                                             DragReference inDragRef)
  905. {
  906.     CNetscapeWindow* theWindow = dynamic_cast<CNetscapeWindow*>(LWindow::FetchWindowObject(GetMacPort()));
  907.     ThrowIfNil_(theWindow);
  908.     
  909.     HT_Resource node = NULL;
  910.     Size dataSize = sizeof(HT_Resource);
  911.     OSErr err = ::GetFlavorData(inDragRef, inItemRef, emHTNodeDrag, &node, &dataSize, 0);
  912.     if ( node && !err )
  913.         CURLDragHelper::DoDragSendData ( HT_GetNodeURL(node), HT_GetNodeName(node),
  914.                                             inFlavor, inItemRef, inDragRef );
  915.     else
  916.         DebugStr("\pFlavor data does not contain a valid HT_Resource structure");
  917.         
  918. } // DoDragSendData
  919.  
  920.  
  921. //
  922. // ReceiveDragItem
  923. //
  924. // Called for each item dropped on the table. FindAcceptableFlavor() will try to get us
  925. // the highest fidelity flavor to do the drop...
  926. //
  927. void
  928. CHyperTreeFlexTable :: ReceiveDragItem ( DragReference inDragRef, DragAttributes /*inDragAttrs*/,
  929.                                             ItemReference inItemRef, Rect & /*inItemBounds*/ )
  930. {
  931.     try {
  932.         FlavorType useFlavor = FindAcceptableFlavor ( inDragRef, inItemRef );
  933.         Size theDataSize = 0;
  934.         switch ( useFlavor ) {
  935.         
  936.             case emHTNodeDrag:
  937.             {
  938.                 HT_Resource draggedNode = NULL;
  939.                 HT_Resource node = NULL;
  940.                 theDataSize = sizeof(void*);
  941.                 ThrowIfOSErr_(::GetFlavorData( inDragRef, inItemRef, emHTNodeDrag, &node, &theDataSize, 0 ));
  942.                 HandleDropOfHTResource ( node );
  943.             }
  944.             break;
  945.                 
  946.             case emBookmarkDrag:
  947.             {
  948.                 OSErr err = ::GetFlavorDataSize(inDragRef, inItemRef, emBookmarkDrag, &theDataSize);
  949.                 if ( err && err != badDragFlavorErr )
  950.                     Throw_(err);
  951.                 else if ( theDataSize ) {
  952.                     vector<char> urlAndTitle ( theDataSize + 1 );
  953.                     try {
  954.                         ThrowIfOSErr_( ::GetFlavorData( inDragRef, inItemRef, emBookmarkDrag,
  955.                                                         urlAndTitle.begin(), &theDataSize, 0 ) );
  956.                         urlAndTitle[theDataSize] = NULL;
  957.                         HandleDropOfPageProxy ( urlAndTitle );
  958.                     }
  959.                     catch ( ... ) { 
  960.                         DebugStr ( "\pError getting flavor data for proxy drag" );
  961.                     }
  962.                 }
  963.             }
  964.             break;
  965.                 
  966.             case flavorTypeHFS:
  967.             {
  968.                 HFSFlavor theData;
  969.                 Boolean ignore1, ignore2;
  970.                 
  971.                 ::GetFlavorDataSize(inDragRef, inItemRef, flavorTypeHFS, &theDataSize);
  972.                 OSErr anError = ::GetFlavorData(inDragRef, inItemRef, flavorTypeHFS, &theData, &theDataSize, nil);
  973.                 if ( anError == badDragFlavorErr )
  974.                     anError = ::GetHFSFlavorFromPromise (inDragRef, inItemRef, &theData, true);
  975.             
  976.                 // if there's an error resolving the alias, the local file url will refer to the alias itself.
  977.                 ::ResolveAliasFile(&theData.fileSpec, true, &ignore1, &ignore2);
  978.                 char* localURL = CFileMgr::GetURLFromFileSpec(theData.fileSpec);
  979.                 Assert_(localURL != nil);
  980.                 HandleDropOfLocalFile ( localURL, CStr255(theData.fileSpec.name) );    
  981.             }
  982.             break;
  983.                 
  984.             case 'TEXT':
  985.                 DebugStr("\pchecking for TEXT flavor on drop into tree, unimplemented; g");
  986.                 break;
  987.         
  988.         } // case of best flavor
  989.     }
  990.     catch ( ... ) {
  991.         DebugStr ( "\pCan't find the flavor we want; g" );
  992.     }
  993.                     
  994. } // ReceiveDragItem
  995.  
  996.  
  997. //
  998. // HandleDropOfPageProxy
  999. //
  1000. // Called when the user drops the page proxy icon in the NavCenter. The page proxy flavor data
  1001. // consists of the url and title, separated by a return. Extract the components and create a
  1002. // new node.
  1003. //
  1004. void
  1005. CHyperTreeFlexTable :: HandleDropOfPageProxy ( vector<char> & inURLAndTitle )
  1006. {
  1007.     char* title = find(inURLAndTitle.begin(), inURLAndTitle.end(), '\r');
  1008.     if ( title != inURLAndTitle.end() ) {
  1009.         title[0] = NULL;
  1010.         title++;
  1011.         char* url = inURLAndTitle.begin();
  1012.     
  1013.         // Extract the node where the drop will occur. If the drop is on a container, put
  1014.         // it in the container, unless the mouse is actually between the rows which means the
  1015.         // user wants to put it at the same level as the container. Otherwise just put it
  1016.         // above (and at the same level) as the item it is dropped on.
  1017.         bool dropAtEnd = mDropNode == NULL;
  1018.         if ( dropAtEnd ) {
  1019.             mDropNode = HT_GetNthItem( GetHTView(), URDFUtilities::PPRowToHTRow(mRows) );
  1020.             if ( !mDropNode ) {
  1021.                 // the view is empty, do drop on and bail
  1022.                 HT_DropURLAndTitleOn ( HT_TopNode(GetHTView()), url, title );
  1023.                 return;
  1024.             }
  1025.         }
  1026.         if ( HT_IsContainer(mDropNode) && !mIsDropBetweenRows )
  1027.             HT_DropURLAndTitleOn ( mDropNode, url, title );
  1028.         else
  1029.             HT_DropURLAndTitleAtPos ( mDropNode, url, title, dropAtEnd ? PR_FALSE : PR_TRUE );
  1030.     }
  1031.  
  1032. } // HandleDropOfPageProxy
  1033.  
  1034.  
  1035. //
  1036. // HandleDropOfHTResource
  1037. //
  1038. // Called when the user drops something from one RDF-savvy location (navcenter, personal toolbar)
  1039. // to another. This may result in a move or a copy, so do the right thing for each.
  1040. //
  1041. void
  1042. CHyperTreeFlexTable :: HandleDropOfHTResource ( HT_Resource dropNode )
  1043. {
  1044.     // Extract the node where the drop will occur. If the drop is on a container, put
  1045.     // it in the container, unless the mouse is actually between the rows which means the
  1046.     // user wants to put it at the same level as the container. Otherwise just put it
  1047.     // above (and at the same level) as the item it is dropped on.
  1048.     bool dropAtEnd = mDropNode == NULL;
  1049.     if ( dropAtEnd ) {
  1050.         mDropNode = HT_GetNthItem( GetHTView(), URDFUtilities::PPRowToHTRow(mRows) );
  1051.         if ( !mDropNode ) {
  1052.             // the view is empty, do drop on and bail
  1053.             HT_DropHTROn ( HT_TopNode(GetHTView()), dropNode );
  1054.             return;
  1055.         }
  1056.     } // if we're dropping at end
  1057.     if ( HT_IsContainer(mDropNode) && !mIsDropBetweenRows )
  1058.         HT_DropHTROn ( mDropNode, dropNode );
  1059.     else
  1060.         HT_DropHTRAtPos ( mDropNode, dropNode, dropAtEnd ? PR_FALSE : PR_TRUE );
  1061.     
  1062. } // HandleDropOfHTResource
  1063.  
  1064.  
  1065. //
  1066. // HandleDropOfLocalFile
  1067. //
  1068. // Called when the user drops something from the Finder into the navCenter. Create a 
  1069. // bookmark with a file URL for that file. This assumes aliases have already been
  1070. // resolved
  1071. //
  1072. void
  1073. CHyperTreeFlexTable :: HandleDropOfLocalFile ( const char* inFileURL, const char* inFileName )
  1074. {
  1075.     // Extract the node where the drop will occur. If the drop is on a container, put
  1076.     // it in the container, unless the mouse is actually between the rows which means the
  1077.     // user wants to put it at the same level as the container. Otherwise just put it
  1078.     // above (and at the same level) as the item it is dropped on.
  1079.     bool dropAtEnd = mDropNode == NULL;
  1080.     if ( dropAtEnd ) {
  1081.         mDropNode = HT_GetNthItem( GetHTView(), URDFUtilities::PPRowToHTRow(mRows) );
  1082.         if ( !mDropNode ) {
  1083.             // the view is empty, do drop on and bail
  1084.             HT_DropURLAndTitleOn ( HT_TopNode(GetHTView()), 
  1085.                                     const_cast<char*>(inFileURL), const_cast<char*>(inFileName) );
  1086.             return;
  1087.         }
  1088.     }
  1089.     if ( HT_IsContainer(mDropNode) && !mIsDropBetweenRows )
  1090.         HT_DropURLAndTitleOn ( mDropNode, const_cast<char*>(inFileURL), const_cast<char*>(inFileName) );
  1091.     else
  1092.         HT_DropURLAndTitleAtPos ( mDropNode, const_cast<char*>(inFileURL), const_cast<char*>(inFileName), 
  1093.                                     dropAtEnd ? PR_FALSE : PR_TRUE );
  1094.     
  1095. } // HandleDropOfLocalFile
  1096.  
  1097.  
  1098. //
  1099. // FindAcceptableFlavor
  1100. // THROWS int
  1101. //
  1102. // Checks the item being dropped and returns the best flavor that we support. It checks in
  1103. // for the following:
  1104. //    - HT Node
  1105. //    - proxy icon
  1106. //    - file from desktop
  1107. //    - a TEXT url from some other app
  1108. //
  1109. FlavorType
  1110. CHyperTreeFlexTable :: FindAcceptableFlavor ( DragReference inDragRef, ItemReference inItemRef )
  1111. {
  1112.     FlavorFlags flags;
  1113.     FlavorType checkFor[] = { emHTNodeDrag, emBookmarkDrag, 'TEXT', flavorTypeHFS,
  1114.                                 flavorTypePromiseHFS, NULL };                // end this in a NULL
  1115.     for ( int i = 0; checkFor[i]; i++ )
  1116.         if ( ::GetFlavorFlags(inDragRef, inItemRef, checkFor[i], &flags) != badDragFlavorErr )
  1117.             return checkFor[i];
  1118.     
  1119.     // cant find anything we're looking for by this point
  1120.     throw(-1);
  1121.     return 0;
  1122.     
  1123. } // FindAcceptableFlavor
  1124.  
  1125.  
  1126. //
  1127. // NodeCanAcceptDrop
  1128. //
  1129. // Check each item in the drop to see if it can be dropped on the particular node given in |inTargetNode|.
  1130. //
  1131. Boolean
  1132. CHyperTreeFlexTable :: NodeCanAcceptDrop ( DragReference inDragRef, HT_Resource inTargetNode )
  1133. {
  1134.     Uint16 itemCount;
  1135.     ::CountDragItems(inDragRef, &itemCount);
  1136.     Boolean acceptableDrop = false;
  1137.     bool targetIsContainer = HT_IsContainer ( inTargetNode );
  1138.     
  1139.     for ( Uint16 item = 1; item <= itemCount; item++ ) {
  1140.         ItemReference itemRef;
  1141.         ::GetDragItemReferenceNumber(inDragRef, item, &itemRef);
  1142.  
  1143.         try {
  1144.             FlavorType useFlavor = FindAcceptableFlavor ( inDragRef, itemRef );
  1145.             switch ( useFlavor ) {
  1146.             
  1147.                 case emHTNodeDrag:
  1148.                 {
  1149.                     HT_Resource draggedNode = NULL;
  1150.                     Size theDataSize = sizeof(HT_Resource);
  1151.                     ThrowIfOSErr_(::GetFlavorData( inDragRef, itemRef, emHTNodeDrag, &draggedNode, &theDataSize, 0 ));
  1152.                     if ( targetIsContainer )
  1153.                         acceptableDrop |= HT_CanDropHTROn ( inTargetNode, draggedNode );        // FIX TO CHANGE CURSOR
  1154.                     else
  1155.                         acceptableDrop |= HT_CanDropHTRAtPos ( inTargetNode, draggedNode, PR_TRUE );                
  1156.                 }
  1157.                 break;
  1158.                     
  1159.                 case emBookmarkDrag:
  1160.                 {
  1161.                     // We don't care what kind of url it is, just that it is a url so pass a 
  1162.                     // bogus url to the backend.
  1163.                     if ( targetIsContainer )
  1164.                         acceptableDrop |= HT_CanDropURLOn ( inTargetNode, "http://foo.com" );    // FIX TO CHANGE CURSOR
  1165.                     else
  1166.                         acceptableDrop |= HT_CanDropURLAtPos ( inTargetNode, "http://foo.com", PR_TRUE );
  1167.                 }
  1168.                 break;
  1169.                     
  1170.                 case flavorTypeHFS:
  1171.                 case flavorTypePromiseHFS:
  1172.                     // We don't care what kind of url it is, just that it is a url so pass a 
  1173.                     // bogus url to the backend.
  1174.                     if ( targetIsContainer )
  1175.                         acceptableDrop |= HT_CanDropURLOn ( inTargetNode, "file://foo" );    // FIX TO CHANGE CURSOR....
  1176.                     else
  1177.                         acceptableDrop |= HT_CanDropURLAtPos ( inTargetNode, "file://foo", PR_TRUE );
  1178.                     break;
  1179.                     
  1180.                 case 'TEXT':
  1181.                     break;
  1182.                     
  1183.             }
  1184.         }
  1185.         catch ( ... ) {
  1186.             DebugStr("\pDrag with no recognized flavors; g");
  1187.         }
  1188.  
  1189.     } // for each file
  1190.  
  1191.     return acceptableDrop;
  1192.  
  1193. } // NodeCanAcceptDrop
  1194.  
  1195.  
  1196. //
  1197. // InlineEditorDone
  1198. //
  1199. // Called when the user hits return/enter or clicks outside of the inline editor. Tell RDF about the
  1200. // change and update the table.
  1201. //
  1202. void
  1203. CHyperTreeFlexTable :: InlineEditorDone ( ) 
  1204. {
  1205.     Str255 newName;
  1206.     mNameEditor->GetDescriptor(newName);
  1207.     cstring nameAsCString(newName);
  1208.  
  1209.     HT_Resource editedNode = HT_GetNthItem(GetHTView(), URDFUtilities::PPRowToHTRow(mRowBeingEdited) );    
  1210.     HT_SetNodeName ( editedNode, nameAsCString );
  1211.     
  1212. } // InlineEditorDone
  1213.  
  1214.  
  1215. //
  1216. // CanDoInlineEditing
  1217. //
  1218. // While we normally want to be able to do inline editing, we have to turn it off for panes
  1219. // that don't allow editing (like History). Assumes mRowBeingEdited is correctly set.
  1220. //
  1221. bool
  1222. CHyperTreeFlexTable :: CanDoInlineEditing ( ) 
  1223. {
  1224.     CHyperTreeHeader* header = dynamic_cast<CHyperTreeHeader*>(mTableHeader);
  1225.     Assert_(header);
  1226.     CHyperTreeHeader::ColumnInfo info = header->GetColumnInfo ( FindTitleColumnID() - 1 );
  1227.     
  1228.     HT_Resource item = HT_GetNthItem( GetHTView(), URDFUtilities::PPRowToHTRow(mRowBeingEdited) );
  1229.     return HT_IsNodeDataEditable ( item, info.token, info.tokenType );
  1230.     
  1231. } // CanDoInlineEditing
  1232.  
  1233.  
  1234. //
  1235. // ChangeSort
  1236. //
  1237. // called when the user clicks in one of the column headings to change the sort column or
  1238. // to change the sort order of the given column.
  1239. //
  1240. void 
  1241. CHyperTreeFlexTable :: ChangeSort ( const LTableHeader::SortChange* inSortChange )
  1242. {
  1243.     CHyperTreeHeader* header = dynamic_cast<CHyperTreeHeader*>(mTableHeader);
  1244.     Assert_(header);
  1245.     
  1246.     // CHyperTreeHeader::GetColumnInfo() is zero-based and PP is one-based.
  1247.     if ( inSortChange->sortColumn >= 1 ) {
  1248.         CHyperTreeHeader::ColumnInfo info = header->GetColumnInfo ( inSortChange->sortColumn - 1 );
  1249.         HT_SetSortColumn ( GetHTView(), info.token, info.tokenType, inSortChange->reverseSort ? PR_TRUE : PR_FALSE );
  1250.     }
  1251.     else
  1252.         HT_SetSortColumn ( GetHTView(), NULL, 0, PR_FALSE );    // return to natural order
  1253.         
  1254.     Refresh();
  1255.     
  1256. } // ChangeSort
  1257.  
  1258.  
  1259. //
  1260. // MouseLeave
  1261. //
  1262. // Called when the mouse leaves the tree view. Just update our "hot" cell to 0,0.
  1263. //
  1264. void 
  1265. CHyperTreeFlexTable :: MouseLeave ( ) 
  1266. {
  1267.     mTooltipCell = STableCell(0, 0);
  1268.         
  1269. } // MouseLeave
  1270.  
  1271.  
  1272. //
  1273. // MouseWithin
  1274. //
  1275. // Called while the mouse moves w/in the tree view. Find which cell the mouse is
  1276. // currently over and if it differs from the last cell it was in, hide the 
  1277. // tooltip and remember the new cell.
  1278. //
  1279. void 
  1280. CHyperTreeFlexTable :: MouseWithin ( Point inPortPt, const EventRecord& ) 
  1281. {
  1282.     SPoint32 imagePt;    
  1283.     PortToLocalPoint(inPortPt);
  1284.     LocalToImagePoint(inPortPt, imagePt);
  1285.     
  1286.     STableCell hitCell;
  1287.     if ( GetCellHitBy(imagePt, hitCell) )
  1288.         if ( mTooltipCell != hitCell ) {
  1289.             mTooltipCell = hitCell;
  1290.             ExecuteAttachments(msg_HideTooltip, this);    // hide tooltip
  1291.         }
  1292.  
  1293. } // MouseWithin
  1294.  
  1295.  
  1296. //
  1297. // FindTooltipForMouseLocation
  1298. //
  1299. // Return the appropriate title for the current mouse location.
  1300. void
  1301. CHyperTreeFlexTable :: FindTooltipForMouseLocation ( const EventRecord& inMacEvent,
  1302.                                                         StringPtr outTip )
  1303. {
  1304.     Point temp = inMacEvent.where;
  1305.     SPoint32 where;    
  1306.     GlobalToPortPoint(temp);
  1307.     PortToLocalPoint(temp);
  1308.     LocalToImagePoint(temp, where);
  1309.  
  1310.     STableCell hitCell;
  1311.     if ( GetCellHitBy(where, hitCell) && hitCell.col <= mCols ) {
  1312.     
  1313.         CHyperTreeHeader* header = dynamic_cast<CHyperTreeHeader*>(mTableHeader);
  1314.         Assert_(header != NULL);
  1315.         CHyperTreeHeader::ColumnInfo info = header->GetColumnInfo(hitCell.col - 1);
  1316.         
  1317.         HT_Resource node = HT_GetNthItem( GetHTView(), URDFUtilities::PPRowToHTRow(hitCell.row) );
  1318.         void* data;
  1319.         if ( HT_GetNodeData(node, info.token, info.tokenType, &data) && data ) {
  1320.             switch (info.tokenType) {
  1321.                 case HT_COLUMN_STRING:
  1322.                     const char* str = static_cast<char*>(data);
  1323.                     outTip[0] = strlen(str);
  1324.                      strcpy ( (char*) &outTip[1], str );
  1325.                      break;
  1326.                      
  1327.                  default:
  1328.                      outTip[0] = 0;        // don't display tooltip for other data types
  1329.              } // case of column data type
  1330.          } // if data is valid
  1331.     } // if valid cell
  1332.     else
  1333.         ::GetIndString ( outTip, 10506, 16);        // supply a helpful message...
  1334.  
  1335. } // FindTooltipForMouseLocation
  1336.  
  1337.  
  1338.  
  1339. //
  1340. // AdjustCursorSelf
  1341. //
  1342. // Handle changing cursor to contextual menu cursor if cmd key is down
  1343. //
  1344. void
  1345. CHyperTreeFlexTable::AdjustCursorSelf( Point /*inPoint*/, const EventRecord& inEvent )
  1346. {
  1347.     ExecuteAttachments(CContextMenuAttachment::msg_ContextMenuCursor, 
  1348.                                 static_cast<void*>(const_cast<EventRecord*>(&inEvent)));
  1349.  
  1350. }
  1351.  
  1352. #pragma mark -- class CHyperTreeSelector --
  1353.  
  1354. //
  1355. // DoSelect
  1356. //
  1357. // We need to make sure that the HTView's concept of the selection is in sync with what PP
  1358. // believes to be the current selection. Since all modifications to the selection are
  1359. // channeled through this method, we just override it to also tell HT about the selection
  1360. // change. This also picks up SelectCell() and UnselectCell() calls since the LTableRowSelector
  1361. // routes those calls here
  1362. //
  1363. void
  1364. CHyperTreeSelector :: DoSelect(    const TableIndexT     inRow, 
  1365.                                 Boolean             inSelect, 
  1366.                                 Boolean             inHilite,
  1367.                                 Boolean                inNotify    )
  1368. {
  1369.     HT_Resource node = HT_GetNthItem( mTreeView, URDFUtilities::PPRowToHTRow(inRow) );
  1370.     if (node) {
  1371.         // when we update the HT selection, we'll get an update event. We don't want
  1372.         // this because we know we're updating it.
  1373.         HT_NotificationMask oldMask;
  1374.         HT_Pane pane = HT_GetPane ( mTreeView );
  1375.         HT_GetNotificationMask ( pane, &oldMask );
  1376.         HT_SetNotificationMask ( pane, 0L );
  1377.         HT_SetSelectedState    ( node, inSelect ? PR_TRUE : PR_FALSE );    
  1378.         HT_SetNotificationMask ( pane, oldMask );
  1379.     }
  1380.     LTableRowSelector::DoSelect(inRow, inSelect, inHilite, inNotify);
  1381.  
  1382. } // DoSelect
  1383.  
  1384.  
  1385. //
  1386. // CellIsSelected
  1387. //
  1388. // Just let HT tell us about what is selected and what isn't.
  1389. //
  1390. Boolean
  1391. CHyperTreeSelector :: CellIsSelected ( const STableCell &inCell ) const
  1392. {
  1393.     HT_Resource node = HT_GetNthItem( mTreeView, URDFUtilities::PPRowToHTRow(inCell.row) );
  1394.     return HT_IsSelected(node);
  1395.  
  1396. } // CellIsSelected
  1397.  
  1398.  
  1399. //
  1400. // SyncSelectorWithHT
  1401. //
  1402. // Since HT is the one that retains the selection for the view, when a new view is
  1403. // displayed, we will be out of sync. This methods gets us back in sync.
  1404. //
  1405. void
  1406. CHyperTreeSelector :: SyncSelectorWithHT ( )
  1407. {
  1408.     // unselect all cells in this selector so we start with a clean slate
  1409.     mSelectedRowCount = 0;
  1410.     const char notSelected = 0;
  1411.     for ( int i = 1; i <= GetCount(); i++ )
  1412.         AssignItemsAt ( 1, i, ¬Selected );
  1413.     
  1414.     // walk through the HT selection and update our internal bookkeeping info
  1415.     HT_Resource curr = HT_GetNextSelection(mTreeView, HT_TopNode(mTreeView));
  1416.     while ( curr ) {
  1417.         LTableRowSelector::DoSelect ( URDFUtilities::HTRowToPPRow(HT_GetNodeIndex(mTreeView, curr)),
  1418.                                         true, true, false );
  1419.         curr = HT_GetNextSelection(mTreeView, curr);
  1420.     }
  1421.     
  1422. } // SyncSelectorWithHT