home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / macfe / gui / CPersonalToolbarTable.cp < prev    next >
Encoding:
Text File  |  1998-04-08  |  25.6 KB  |  898 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. // Implementation of the table that is the main component of the personal toolbar.
  21. //
  22.  
  23. #include <vector.h>
  24. #include <algorithm>
  25.  
  26. #include "CPersonalToolbarTable.h"
  27. #include "CPersonalToolbarManager.h"
  28. #include "uapp.h"
  29. #include "LTableMultiGeometry.h"
  30. #include "CURLDragHelper.h"
  31. #include "macutil.h"
  32. #include "CIconTextDragTask.h"
  33. #include "resgui.h"
  34. #include "URDFUtilities.h"
  35.  
  36. #include "miconutils.h"
  37. #include "UMemoryMgr.h"
  38.  
  39. static const RGBColor blue = { 0, 0, 0xFFFF };
  40. static const RGBColor black = { 0, 0, 0 };
  41. static const RGBColor bgColor = { 0xDDDD, 0xDDDD, 0xDDDD };
  42.  
  43. DragSendDataUPP CPersonalToolbarTable::sSendDataUPP;
  44.  
  45.  
  46. CPersonalToolbarTable :: CPersonalToolbarTable ( LStream* inStream )
  47.     : LSmallIconTable(inStream), LDragAndDrop ( GetMacPort(), this ),
  48.         mDropCol(LArray::index_Bad), mHiliteCol(LArray::index_Bad), mDropOn(false)
  49. {
  50.     // LSmallIconTable wants to use a LTableSingleGeometry, but since we want the toolbar
  51.     // to have variable column widths, replace it with a multiGeometry implementation
  52.     if ( mTableGeometry ) {
  53.         delete mTableGeometry;
  54.         mTableGeometry = new LTableMultiGeometry ( this, mFrameSize.width, 20 );
  55.     }
  56.     
  57. } // constructor
  58.  
  59.  
  60. CPersonalToolbarTable :: ~CPersonalToolbarTable ( )
  61. {
  62.     CFrontApp::GetPersonalToolbarManager()->RemoveListener(this);
  63.         
  64.     //ÑÑ dispose drag routine descriptor
  65.     
  66. } // destructor
  67.  
  68.  
  69. //
  70. // FinishCreateSelf
  71. //
  72. void
  73. CPersonalToolbarTable :: FinishCreateSelf ( )
  74. {
  75.     InsertRows ( 1, 1, NULL, 0, false );
  76.     CFrontApp::GetPersonalToolbarManager()->RegisterNewToolbar(this);
  77.  
  78.     if ( !sSendDataUPP) {
  79.         sSendDataUPP = NewDragSendDataProc(LDropArea::HandleDragSendData);
  80.         ThrowIfNil_(sSendDataUPP);
  81.     }
  82.  
  83. } // FinishCreateSelf
  84.  
  85.  
  86. //
  87. // FillInToolbar
  88. //
  89. // Add rows to the table based on the bookmark information in the manager object. This will try to give each
  90. // column as much space as possible on the fly. Don't make any assumptions about the incoming
  91. // text mode...be paranoid!
  92. //
  93. void 
  94. CPersonalToolbarTable :: FillInToolbar ( )
  95. {
  96.     const Uint32 kPadRight = 15;
  97.     const Uint32 kBMIconWidth = 28;
  98.     const Uint32 kButtonCount = CFrontApp::GetPersonalToolbarManager()->GetButtons().GetCount();
  99.     const Uint32 kMaxLength = CFrontApp::GetPersonalToolbarManager()->GetMaxToolbarButtonChars();
  100.     const Uint32 kMinLength = CFrontApp::GetPersonalToolbarManager()->GetMinToolbarButtonChars();
  101.  
  102.     StTextState saved;
  103.     UTextTraits::SetPortTextTraits(kTextTraitsID);
  104.     
  105.     //
  106.     // create an array that holds the # of characters currently in each column. Initialize this with
  107.     // the min column size (specified in prefs), or less if the title has less chars.
  108.     //
  109.     Uint16* widthArray = new Uint16[kButtonCount];
  110.     Uint16 totalWidth = 0;
  111.     CUserButtonInfo* curr;
  112.     Uint32 widthArrayIter = 0;
  113.     LArrayIterator it ( CFrontApp::GetPersonalToolbarManager()->GetButtons() );
  114.     while ( it.Next(&curr) ) {
  115.         
  116.         Uint16 numChars = min ( kMinLength, curr->GetName().length() );
  117.         widthArray[widthArrayIter] = numChars;
  118.         totalWidth += ::TextWidth(curr->GetName().c_str(), 0, numChars) + kBMIconWidth;        // extend the total...
  119.         widthArrayIter++;
  120.         
  121.     } // initialize each item
  122.     
  123.     InsertCols ( kButtonCount, 0, NULL, 0, false );
  124.     
  125.     // compute how much room we have left to divvy out after divvying out the minimum above. Leave
  126.     // a few pixels on the right empty...
  127.     int16 emptySpace = (mFrameSize.width - kPadRight) - totalWidth;
  128.     
  129.     //
  130.     // divvy out space to each column, one character at a time to each column
  131.     //
  132.     while ( emptySpace > 0 ) {
  133.  
  134.         bool updated = false;
  135.         Uint32 i = 0;
  136.         LArrayIterator it2 ( CFrontApp::GetPersonalToolbarManager()->GetButtons() );
  137.         while ( it2.Next(&curr) ) {
  138.             if ( emptySpace && widthArray[i] < curr->GetName().length() && widthArray[i] < kMaxLength ) {
  139.                 // subtract off the single character we're adding to the column
  140.                 char addedChar = curr->GetName()[widthArray[i]];
  141.                 emptySpace -= ::TextWidth(&addedChar, 0, 1);
  142.                 widthArray[i]++;
  143.                 updated = true;            // we found something to add, allow us to continue
  144.             }
  145.             i++;
  146.         } // for each column
  147.  
  148.         // prevent infinite looping if no column can be expanded and we still have extra room remaining
  149.         if ( !updated )
  150.             break;
  151.             
  152.     } // while space remains to divvy out
  153.     
  154.     //
  155.     // assign the widths to the columns and set the data in the columns.
  156.     //
  157.     STableCell where (1, 1);
  158.     widthArrayIter = 0;
  159.     LArrayIterator it3 ( CFrontApp::GetPersonalToolbarManager()->GetButtons() );
  160.     while ( it3.Next(&curr) ) {
  161.  
  162.         string bmText = curr->GetName();
  163.         Uint32 textLength = bmText.length();
  164.  
  165.         //
  166.         // fill in the cell with the name of the bookmark and set the column width to
  167.         // the width of the string. If the name is longer than the max, chop it.
  168.         //
  169.         SIconTableRec data;
  170.         Uint16 dispLength = widthArray[widthArrayIter];
  171.         ::BlockMove ( bmText.c_str(), &data.name[1], dispLength + 1 );
  172.         data.name[0] = dispLength <= kMaxLength ? dispLength : kMaxLength;    
  173.         data.iconID = curr->IsFolder() ? kFOLDER_ICON : kBOOKMARK_ICON;
  174.         SetCellData ( where, &data, sizeof(SIconTableRec) );
  175.         Uint32 pixelWidth = ::TextWidth(bmText.c_str(), 0, dispLength)+ kBMIconWidth;
  176.         mTableGeometry->SetColWidth (  pixelWidth, where.col, where.col );
  177.  
  178.         widthArrayIter++;
  179.         where.col++;        // next column, please....
  180.         
  181.     } // for each bookmark in the folder
  182.  
  183.     Refresh();
  184.     
  185.     delete[] widthArray;
  186.     
  187. } // FillInToolbar
  188.  
  189.  
  190. //
  191. // MouseLeave
  192. //
  193. // Called when the mouse leaves the personal toolbar. Redraw the previous selection to get rid
  194. // of the blue text color.
  195. //
  196. void 
  197. CPersonalToolbarTable :: MouseLeave ( ) 
  198. {
  199.     STableCell refresh(1, mHiliteCol);
  200.     mHiliteCol = LArray::index_Bad;
  201.     
  202.     StClipRgnState savedClip;
  203.     FocusDraw();
  204.     RedrawCellWithTextClipping ( refresh );
  205.     
  206. } // MouseLeave
  207.  
  208.  
  209. //
  210. // MouseWithin
  211. //
  212. // Called while the mouse moves w/in the personal toolbar. Find which cell the mouse is
  213. // currently over and remember it. If we've moved to a different cell, make sure to 
  214. // refresh the old one so it is drawn normally.
  215. //
  216. void 
  217. CPersonalToolbarTable :: MouseWithin ( Point inPortPt, const EventRecord& ) 
  218. {
  219.     // get the previous selection
  220.     STableCell old(1, mHiliteCol);
  221.     SPoint32 imagePt;    
  222.     PortToLocalPoint(inPortPt);
  223.     LocalToImagePoint(inPortPt, imagePt);
  224.     
  225.     STableCell hitCell;
  226.     if ( GetCellHitBy(imagePt, hitCell) )
  227.         if ( old != hitCell ) {
  228.             StClipRgnState savedClip;
  229.             
  230.             mHiliteCol = hitCell.col;
  231.  
  232.             FocusDraw();
  233.             if ( old.col )
  234.                 RedrawCellWithTextClipping(old);
  235.             if ( hitCell.col )
  236.                 RedrawCellWithTextClipping(hitCell);
  237.             
  238.             ExecuteAttachments(msg_HideTooltip, this);    // hide tooltip
  239.         }
  240.  
  241. } // MouseWithin
  242.  
  243.  
  244. //
  245. // Click
  246. //
  247. // Allow drags to occur when another window is in front of us.
  248. //
  249. void
  250. CPersonalToolbarTable :: Click ( SMouseDownEvent& inMouseDown )
  251. {
  252.     PortToLocalPoint(inMouseDown.whereLocal);
  253.     UpdateClickCount(inMouseDown);
  254.     
  255.     if (ExecuteAttachments(msg_Click, &inMouseDown))
  256.     {
  257.         ClickSelf(inMouseDown);
  258.     }
  259. }
  260.  
  261.  
  262. #if 0
  263. //
  264. // Click
  265. //
  266. // Overridden to handle clase of drag and drop when communicator is in the background. Code
  267. // copied from CWPro1 CD sample code (CDragAndDropTable.cp).
  268. //
  269. // FOR SOME REASON, THIS DOESN'T WORK....DUNNO WHY...
  270. void
  271. CPersonalToolbarTable :: Click ( SMouseDownEvent& inMouseDown )
  272. {
  273.     if ( inMouseDown.delaySelect && DragAndDropIsPresent() ) {
  274.  
  275.         // In order to support dragging from an inactive window,
  276.         // we must explicitly test for delaySelect and the
  277.         // presence of Drag and Drop.
  278.  
  279.         // Convert to a local point.
  280.         PortToLocalPoint( inMouseDown.whereLocal );
  281.         
  282.         // Execute click attachments.
  283.         if ( ExecuteAttachments( msg_Click, &inMouseDown ) ) {
  284.         
  285.             // Handle the actual click event.
  286.             ClickSelf( inMouseDown );
  287.  
  288.         }
  289.     
  290.     } else {
  291.  
  292.         // Call inherited for default behavior.    
  293.         LTableView::Click( inMouseDown );
  294.     
  295.     }
  296.  
  297. } // Click
  298. #endif
  299.  
  300.  
  301. //
  302. // ClickSelect
  303. //
  304. // Override to always say that we can be selected, because there is no concept of selection
  305. // in this toolbar.
  306. Boolean
  307. CPersonalToolbarTable :: ClickSelect( const STableCell &/*inCell*/, const SMouseDownEvent &/*inMouseDown*/)
  308. {
  309.     return true;
  310. }
  311.  
  312.  
  313. //
  314. // ClickCell
  315. //
  316. // Override the default behavior of selecting a cell to open the url associated with the bookmark
  317. // there.
  318. //
  319. void
  320. CPersonalToolbarTable :: ClickCell(const STableCell &inCell, const SMouseDownEvent &inMouseDown)
  321. {
  322.     if ( ::WaitMouseMoved(inMouseDown.macEvent.where) ) {
  323.     
  324.         if (LDropArea::DragAndDropIsPresent()) {
  325.         
  326.             mDraggedCell = inCell;        // save which cell is being dragged for later
  327.             
  328.             // create the drag task
  329.             Rect bounds;
  330.             GetLocalCellRect ( inCell, bounds );
  331.             CUserButtonInfo* data = GetButtonInfo ( inCell.col );
  332.             cstring finalCaption = CURLDragHelper::MakeIconTextValid ( data->GetName().c_str() );
  333.             HT_Resource node = HT_GetNthItem(CFrontApp::GetPersonalToolbarManager()->GetHTView(), 
  334.                                                 URDFUtilities::PPRowToHTRow(inCell.col));
  335.             CIconTextSuite suite ( this, bounds, kBOOKMARK_ICON, finalCaption, node );
  336.             CIconTextDragTask theTask(inMouseDown.macEvent, &suite, bounds);
  337.             
  338.             // setup our special data transfer proc called upon drag completion
  339.             OSErr theErr = ::SetDragSendProc ( theTask.GetDragReference(), sSendDataUPP, (LDropArea*) this );
  340.             ThrowIfOSErr_(theErr);
  341.             
  342.             theTask.DoDrag();
  343.             
  344.             // remove the url if it went into the trash
  345.             if ( theTask.DropLocationIsFinderTrash() )
  346.                 CFrontApp::GetPersonalToolbarManager()->RemoveButton ( inCell.col );
  347.             
  348.         } // if d&d allowed
  349.         
  350.     } // if drag
  351.     else {
  352.     
  353.         CUserButtonInfo* data = GetButtonInfo ( inCell.col );
  354.         
  355.         // code for context menu here, if appropriate....
  356.         
  357.         if ( data->IsFolder() ) {
  358.             SysBeep(1);
  359.         }
  360.         else {
  361.             CUserButtonInfo* clicked = GetButtonInfo ( inCell.col );
  362.             CFrontApp::DoGetURL( clicked->GetURL().c_str());
  363.         }
  364.         
  365.     } // else just a click
  366.     
  367. } // ClickCell
  368.  
  369.  
  370. //
  371. // RedrawCellWithHilite
  372. //
  373. // A helpful utility routine that wraps DrawCell() with calls to setup the drawing params
  374. // appropriately. When redrawing a cell during a drag and drop, call this routine instead
  375. // of calling DrawCell directly.
  376. //
  377. void
  378. CPersonalToolbarTable :: RedrawCellWithHilite ( const STableCell inCell, bool inHiliteOn )
  379. {
  380.     Rect localCellRect;
  381.     GetLocalCellRect ( inCell, localCellRect );
  382.     
  383.     // since mDropOn is used as the flag in DrawCell() for whether or not we want to 
  384.     // draw the hiliting on the cell, save its value and set it to what was passed in
  385.     // before calling DrawCell().
  386.     StValueChanger<Boolean> oldHilite(mDropOn, inHiliteOn);    //ÑÑÑ won't link with bool type =(
  387.     
  388.     // if the hiliting is being turned off, erase the cell so it draws normally again
  389.     if ( !inHiliteOn ) {
  390.         StColorState saved;
  391.         ::RGBBackColor(&bgColor);
  392.         ::EraseRect(&mTextHiliteRect);        // we can be sure this has been previously computed
  393.     }
  394.     
  395.     DrawCell ( inCell, localCellRect );
  396.     
  397. } // RedrawCellWithHilite
  398.  
  399.  
  400. //
  401. // DrawCell
  402. //
  403. // Override to draw differently when this is the selected cell. Otherwise, pass it back
  404. // to the inherited routine to draw normally. 
  405. //
  406. void 
  407. CPersonalToolbarTable :: DrawCell ( const STableCell &inCell, const Rect &inLocalRect )
  408. {
  409.     StTextState savedText;
  410.     StColorPenState savedColor;
  411.     ::RGBForeColor(&black);
  412.     
  413.     SIconTableRec iconAndName;
  414.     Uint32 dataSize = sizeof(SIconTableRec);
  415.     GetCellData(inCell, &iconAndName, dataSize);
  416.     
  417.     Rect iconRect;
  418.     iconRect.left = inLocalRect.left + 3;
  419.     iconRect.right = iconRect.left + 16;
  420.     iconRect.bottom = inLocalRect.bottom - 2;
  421.     iconRect.top = iconRect.bottom - 16;
  422.     IconTransformType transform = kTransformNone;
  423.     if ( mDropOn )                                        // handle drop on folder
  424.         transform = kTransformSelected;
  425.     ::PlotIconID(&iconRect, atNone, transform, iconAndName.iconID);
  426.     
  427.     UTextTraits::SetPortTextTraits(kTextTraitsID);
  428.     
  429.     if ( mDropOn ) {                                    // handle drop on folder
  430.         mTextHiliteRect = ComputeTextRect ( iconAndName, inLocalRect );
  431.         StColorState savedColorForTextDrawing;
  432.         ::RGBBackColor(&black);
  433.         ::EraseRect(&mTextHiliteRect);
  434.         ::TextMode(srcXor);
  435.     }
  436.     else if ( mHiliteCol == inCell.col ) {
  437.         TextFace(underline);
  438.         RGBForeColor( &blue );
  439.     }
  440.     ::MoveTo(inLocalRect.left + 22, inLocalRect.bottom - 4);
  441.     ::DrawString(iconAndName.name);
  442.     
  443. } // DrawCell
  444.  
  445.  
  446. //
  447. // ListenToMessage
  448. //
  449. // Handle broadcasts from the manager object, such as the personal toolbar folder being
  450. // changed or bookmarks being added/deleted/moved.
  451. //
  452. void
  453. CPersonalToolbarTable :: ListenToMessage ( MessageT inMessage, void* /*ioPtr*/ )
  454. {
  455.     switch ( inMessage ) {
  456.     
  457.         case CPersonalToolbarManager::k_PTToolbarChanged:
  458.             if ( mCols )
  459.                 RemoveCols ( mCols, 1, false );                 // out with the old...
  460.             FillInToolbar();
  461.             break;
  462.                 
  463.     } // case of which message
  464.     
  465. } // ListenToMessage
  466.  
  467.  
  468. //
  469. // DoDragSendData
  470. //
  471. // When the drag started, the ClickCell() routine cached which cell was the start of the drag in
  472. // |mDraggedCell|. Extract the URL and Title from this cell and pass it along to the helper
  473. // routine from CURLDragHelper
  474. // 
  475. void
  476. CPersonalToolbarTable :: DoDragSendData( FlavorType inFlavor, ItemReference inItemRef,
  477.                                             DragReference inDragRef)
  478. {
  479.     CUserButtonInfo* dragged = GetButtonInfo ( mDraggedCell.col );
  480.     CURLDragHelper::DoDragSendData ( dragged->GetURL().c_str(), 
  481.                                         const_cast<char*>(dragged->GetName().c_str()),
  482.                                         inFlavor, inItemRef, inDragRef );
  483.  
  484. } // DoDragSendData
  485.  
  486.  
  487. //
  488. // HiliteDropArea
  489. //
  490. // Show that this toolbar is a drop site for urls
  491. //
  492. void
  493. CPersonalToolbarTable :: HiliteDropArea ( DragReference inDragRef )
  494. {
  495.     Rect frame;
  496.     CalcLocalFrameRect ( frame );
  497.     
  498.     // show the drag hilite in drop area
  499.     RgnHandle rgn = ::NewRgn();
  500.     ThrowIfNil_(rgn);
  501.     ::RectRgn ( rgn, &frame );
  502.     ::ShowDragHilite ( inDragRef, rgn, true );
  503.     ::DisposeRgn ( rgn );    
  504.  
  505. } // HiliteDropArea
  506.  
  507.  
  508. //
  509. // InsideDropArea
  510. //
  511. // Called repeatedly while mouse is inside this during a drag. For each column, the cell
  512. // can be divided into several sections.
  513. // 
  514. void
  515. CPersonalToolbarTable :: InsideDropArea ( DragReference inDragRef )
  516. {
  517.     FocusDraw();
  518.     
  519.     Point mouseLoc;
  520.     SPoint32 imagePt;
  521.     ::GetDragMouse(inDragRef, &mouseLoc, NULL);
  522.     ::GlobalToLocal(&mouseLoc);
  523.     LocalToImagePoint(mouseLoc, imagePt);
  524.  
  525.     Rect localRect;
  526.     TableIndexT colMouseIsOver = mTableGeometry->GetColHitBy(imagePt);
  527.     GetLocalCellRect ( STableCell(1, colMouseIsOver), localRect );
  528.     TableIndexT newDropCol;
  529.     bool newDropOn = false;
  530.     CUserButtonInfo* info = GetButtonInfo(colMouseIsOver);
  531.     if ( info ) {
  532.         if ( info->IsFolder() ) {
  533.             Rect leftSide, rightSide;
  534.             ComputeFolderDropAreas ( localRect, leftSide, rightSide );
  535.             if ( ::PtInRect(mouseLoc, &leftSide) )
  536.                 newDropCol = colMouseIsOver;            // before this cell
  537.             else if ( ::PtInRect(mouseLoc, &rightSide) )
  538.                 newDropCol = colMouseIsOver + 1;        // after this cell
  539.             else {
  540.                 newDropCol = colMouseIsOver;
  541.                 newDropOn = true;                        // hilite folder, don't draw line
  542.             }
  543.         }
  544.         else {
  545.             // draw line between rows
  546.             Rect leftSide, rightSide;
  547.             ComputeItemDropAreas ( localRect, leftSide, rightSide );
  548.             if ( ::PtInRect(mouseLoc, &leftSide) )
  549.                 newDropCol = colMouseIsOver;            // before this cell
  550.             else
  551.                 newDropCol = colMouseIsOver + 1;        // after this cell
  552.         }
  553.     } // if drag over existing column
  554.     else {
  555.         // else drag over empty part of toolbar
  556.          newDropCol = mCols + 1;
  557.     }
  558.     
  559.     // if something has changed, redraw as necessary
  560.     if ( newDropCol != mDropCol || newDropOn != mDropOn ) {
  561.     
  562.         // unhilight old one (if necessary)
  563.         if ( mDropOn )
  564.             RedrawCellWithHilite( STableCell(1, mDropCol), false );
  565.         else
  566.             if ( mDropCol > 0 )
  567.                 DrawDividingLine ( mDropCol );
  568.         
  569.         mDropCol = newDropCol;
  570.         mDropOn = newDropOn;
  571.         
  572.         // hilight new one
  573.         if ( mDropOn )
  574.             RedrawCellWithHilite ( STableCell(1, mDropCol), true );
  575.         else
  576.             DrawDividingLine ( newDropCol );
  577.         
  578.     } // if mouse moved to another drop location
  579.     
  580. } // InsideDropArea
  581.  
  582.  
  583. //
  584. // LeaveDropArea
  585. //
  586. // Clean up the drop feedback stuff when the mouse leaves the area
  587. //
  588. void
  589. CPersonalToolbarTable :: LeaveDropArea( DragReference inDragRef )
  590. {
  591.     FocusDraw();
  592.     
  593.     // if we were hiliting a folder, redraw it without the hiliting. If we were drawing a 
  594.     // line, undraw it.
  595.     if ( mDropOn )
  596.         RedrawCellWithHilite ( STableCell(1,mDropCol), false );
  597.     else
  598.         DrawDividingLine( mDropCol );
  599.  
  600.     mDropCol = LArray::index_Bad;
  601.     mDropOn = false;
  602.     
  603.     // Call inherited.
  604.     LDragAndDrop::LeaveDropArea( inDragRef );
  605. }
  606.  
  607.  
  608. //
  609. // ComputeItemDropAreas
  610. //
  611. // When a drag goes over a cell that contains a single node, divide the node in half. The left
  612. // side will represent dropping before the node, the right side after.
  613. //
  614. void
  615. CPersonalToolbarTable :: ComputeItemDropAreas ( const Rect & inLocalCellRect, Rect & oLeftSide, 
  616.                                                 Rect & oRightSide )
  617. {
  618.     oRightSide = oLeftSide = inLocalCellRect;
  619.     uint16 midPt = (oLeftSide.right - oLeftSide.left) / 2;
  620.     oLeftSide.right = oLeftSide.left + midPt;
  621.     oRightSide.left = oLeftSide.left + midPt + 1;
  622.     
  623. } // ComputeItemDropAreas
  624.  
  625.  
  626. //
  627. // ComputeFolderDropAreas
  628. //
  629. // When a drag goes over a cell that contains a folder, divide the cell area into 3 parts. The middle
  630. // area, which corresponds to a drop on the folder takes up the majority of the cell space with the
  631. // left and right areas (corresponding to drop before and drop after, respectively) taking up the rest
  632. // at the ends.
  633. //
  634. void
  635. CPersonalToolbarTable :: ComputeFolderDropAreas ( const Rect & inLocalCellRect, Rect & oLeftSide, 
  636.                                                 Rect & oRightSide )
  637. {
  638.     // make sure the left/right area widths aren't too big for the cell
  639.     Uint16 endAreaWidth = 20;
  640.     if ( inLocalCellRect.right - inLocalCellRect.left < 50 )
  641.         endAreaWidth = 5;
  642.         
  643.     oRightSide = oLeftSide = inLocalCellRect;
  644.     oLeftSide.right = oLeftSide.left + endAreaWidth;
  645.     oRightSide.left = oRightSide.right - endAreaWidth;
  646.     
  647. } // ComputeFolderDropAreas
  648.  
  649.  
  650. //
  651. // DrawDividingLine
  652. //
  653. // Draws a vertical black line before the given column in the toolbar (or undraws if one
  654. // is already there). If the column given is after the right edge of the last column, it
  655. // draws after the last column (as the user expects).
  656. //
  657. void
  658. CPersonalToolbarTable :: DrawDividingLine( TableIndexT inCol )
  659. {
  660.     Uint32 numItems = CFrontApp::GetPersonalToolbarManager()->GetButtons().GetCount();
  661.     if ( !numItems )            // don't draw anything if toolbar empty
  662.         return;
  663.     
  664.     // Setup the target cell.
  665.     STableCell theCell;
  666.     theCell.row = 1;
  667.     theCell.col = inCol;
  668.  
  669.     // find the boundary of the cell we're supposed to be drawing the line before. If
  670.     // the incoming column is at the end (greater than the # of buttons) then hack up
  671.     // a boundary rect to draw after the last column.
  672.     Rect cellBounds;
  673.     if ( inCol > numItems ) {
  674.         // get the boundary of the last column
  675.         theCell.col = numItems;
  676.         GetLocalCellRect ( theCell, cellBounds );
  677.         
  678.         // make the left edge of our fake column the right edge of the last column
  679.         cellBounds.left = cellBounds.right;
  680.     }
  681.     else
  682.         GetLocalCellRect ( theCell, cellBounds );
  683.     
  684.     // Focus the pane and get the table and cell frames.
  685.     Rect theFrame;
  686.     if ( FocusDraw() && CalcLocalFrameRect( theFrame ) ) {
  687.  
  688.         // Save the draw state and clip the list view rect.
  689.         StColorPenState    theDrawState;
  690.         StClipRgnState    theClipState( theFrame );
  691.  
  692.         // Setup the color and pen state then draw the line
  693.         ::ForeColor( blackColor );
  694.         ::PenMode( patXor );
  695.         ::PenSize( 2, 2 );
  696.         ::MoveTo( cellBounds.left, cellBounds.top );
  697.         ::LineTo( cellBounds.left, cellBounds.bottom );
  698.     
  699.     }
  700.     
  701. } // DrawDividingLine
  702.  
  703.  
  704. //
  705. // FindBestFlavor
  706. //
  707. // Scan through the list of acceptable flavors and find the best one that is contained
  708. // in the given drag item. Returns true if it found one in the list and false if the
  709. // drag item doesn't contain any of the desired flavors.
  710. //
  711. bool
  712. CPersonalToolbarTable :: FindBestFlavor ( DragReference inDragRef, ItemReference inItemRef,
  713.                                             FlavorType & oFlavor ) 
  714. {
  715.     static FlavorType flavors[] = { emHTNodeDrag, emBookmarkDrag, NULL };    // must end in NULL
  716.     
  717.     oFlavor = '****';
  718.     short i = 0;
  719.     for ( FlavorType curr = flavors[0]; flavors[i]; i++, curr = flavors[i] ) {
  720.         FlavorFlags theFlags;
  721.         if ( ::GetFlavorFlags(inDragRef, inItemRef, curr, &theFlags) == noErr ) {
  722.             oFlavor = curr;
  723.             return true;
  724.         }
  725.     } // for each flavor in list
  726.  
  727.     return false;
  728.  
  729. } // FindBestFlavor
  730.  
  731.  
  732. //
  733. // ItemIsAcceptable
  734. //
  735. // If FindBestFlavor() finds an acceptable flavor, then this item can be accepted. If not, it
  736. // can't. We don't really care at this point what that flavor is.
  737. //
  738. Boolean
  739. CPersonalToolbarTable :: ItemIsAcceptable ( DragReference inDragRef, ItemReference inItemRef )
  740. {
  741.     FlavorType ignored;
  742.     return FindBestFlavor ( inDragRef, inItemRef, ignored );
  743.     
  744. } // ItemIsAcceptable
  745.  
  746.  
  747. //
  748. // ReceiveDragItem
  749. //
  750. // Called for each item dropped on the table. Create a new bookmark in the PT folder for
  751. // each item
  752. //
  753. void
  754. CPersonalToolbarTable :: ReceiveDragItem ( DragReference inDragRef, DragAttributes /*inDragAttrs*/,
  755.                                             ItemReference inItemRef, Rect & /*inItemBounds*/ )
  756. {
  757.     FlavorType flavorToUse;
  758.     FindBestFlavor ( inDragRef, inItemRef, flavorToUse );        // ok to ignore return result
  759.     
  760.     // Get the data.
  761.     Size theDataSize;
  762.     ThrowIfOSErr_( ::GetFlavorDataSize(inDragRef, inItemRef, flavorToUse, &theDataSize) );
  763.     
  764.     switch ( flavorToUse ) {
  765.         
  766.         case emHTNodeDrag:
  767.             HT_Resource node;
  768.             ThrowIfOSErr_( ::GetFlavorData( inDragRef, inItemRef, flavorToUse, &node, &theDataSize, 0 ) );
  769.  
  770.             if ( mDropOn ) {
  771.                 SysBeep(1);        //ÑÑÑ implement
  772.             }
  773.             else
  774.                 CFrontApp::GetPersonalToolbarManager()->AddButton ( node, mDropCol );    
  775.             break;
  776.             
  777.         case emBookmarkDrag:
  778.             vector<char> urlAndTitle ( theDataSize + 1 );
  779.             ThrowIfOSErr_( ::GetFlavorData( inDragRef, inItemRef, flavorToUse, urlAndTitle.begin(), &theDataSize, 0 ) );
  780.             urlAndTitle[theDataSize] = NULL;
  781.  
  782.             char* title = find(urlAndTitle.begin(), urlAndTitle.end(), '\r');
  783.             if ( title != urlAndTitle.end() ) {
  784.                 title[0] = NULL;
  785.                 title++;
  786.                 char* url = urlAndTitle.begin();
  787.                 
  788.                 if ( mDropOn ) {
  789.                     SysBeep(1);        //ÑÑÑ implement
  790.                 }
  791.                 else
  792.                     CFrontApp::GetPersonalToolbarManager()->AddButton ( url, title, mDropCol );
  793.             }
  794.             break;
  795.     
  796.     } // case of which flavor
  797.         
  798. } // ReceiveDragItem
  799.  
  800.  
  801. //
  802. // GetButtonInfo
  803. //
  804. // fetch cell data given a column #.
  805. //
  806. CUserButtonInfo* 
  807. CPersonalToolbarTable :: GetButtonInfo ( Uint32 inColumn ) 
  808. {
  809.     CUserButtonInfo* temp = nil;
  810.     CFrontApp::GetPersonalToolbarManager()->GetButtons().FetchItemAt (inColumn, &temp );
  811.  
  812.     return temp;
  813.  
  814. } // GetButtonInfo
  815.  
  816. void
  817. CPersonalToolbarTable :: FindTooltipForMouseLocation ( const EventRecord& inMacEvent,
  818.                                                         StringPtr outTip )
  819. {
  820.     Point temp = inMacEvent.where;
  821.     SPoint32 where;    
  822.     GlobalToPortPoint(temp);
  823.     PortToLocalPoint(temp);
  824.     LocalToImagePoint(temp, where);
  825.     
  826.     STableCell hitCell;
  827.     if ( GetCellHitBy(where, hitCell) && hitCell.col <= mCols ) {
  828.         CUserButtonInfo* bkmk = GetButtonInfo(hitCell.col);
  829.         outTip[0] = bkmk->GetName().length();
  830.         strcpy ( (char*) &outTip[1], bkmk->GetName().c_str() );
  831.     }
  832.     else
  833.         ::GetIndString ( outTip, 10506, 12);        // supply a helpful message...
  834.  
  835. } // FindTooltipForMouseLocation
  836.  
  837.  
  838. void
  839. CPersonalToolbarTable :: ResizeFrameBy ( Int16 inWidth, Int16 inHeight, Boolean inRefresh )
  840. {
  841.     LSmallIconTable::ResizeFrameBy(inWidth, inHeight, inRefresh);
  842.     
  843.     ListenToMessage ( CPersonalToolbarManager::k_PTToolbarChanged, nil );
  844.      
  845. } // ResizeFrameTo
  846.  
  847.  
  848. //
  849. // ComputeTextRect
  850. //
  851. // Compute the area of the text rectangle so we can clip to it on redraw
  852. //
  853. Rect
  854. CPersonalToolbarTable :: ComputeTextRect ( const SIconTableRec & inText, const Rect & inLocalRect )
  855. {
  856.     Rect textRect;
  857.     
  858.     uint16 width = ::TextWidth(inText.name, 1, *inText.name);
  859.     textRect.left = inLocalRect.left + 20;
  860.     textRect.right = textRect.left + width + 2;
  861.     textRect.bottom = inLocalRect.bottom - 1;
  862.     textRect.top = inLocalRect.top + 1;
  863.  
  864.     return textRect;
  865.     
  866. } // ComputeTextRect
  867.  
  868.  
  869. //
  870. // RedrawCellWithTextClipping
  871. //
  872. // A pretty way to redraw the cell because it won't flash. This sets the clip region to the 
  873. // text that needs to be redrawn so it looks fast to the user.
  874. //
  875. // NOTE: This blows away the current clip region so if you care, you must restore it afterwards. I
  876. // don't do it here because you may want to make a couple of these calls in a row and restoring the
  877. // clip rect in between would be a waste. It also blows away the background color.
  878. //
  879. void
  880. CPersonalToolbarTable :: RedrawCellWithTextClipping ( const STableCell & inCell )
  881. {
  882.     StTextState savedText;
  883.     SIconTableRec iconAndName;
  884.     Rect localRect;
  885.  
  886.     UTextTraits::SetPortTextTraits(kTextTraitsID);
  887.             
  888.     Uint32 dataSize = sizeof(SIconTableRec);
  889.     GetCellData(inCell, &iconAndName, dataSize);
  890.     GetLocalCellRect ( inCell, localRect );
  891.     Rect textRect = ComputeTextRect(iconAndName,localRect);
  892.     ::ClipRect(&textRect);
  893.     ::RGBBackColor(&bgColor);
  894.     ::EraseRect(&textRect);
  895.     DrawCell(inCell, localRect);
  896.  
  897. } // RedrawCellWithTextClipping
  898.