home *** CD-ROM | disk | FTP | other *** search
Text File | 1998-04-08 | 69.7 KB | 1,987 lines |
- /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * The contents of this file are subject to the Netscape Public License
- * Version 1.0 (the "NPL"); you may not use this file except in
- * compliance with the NPL. You may obtain a copy of the NPL at
- * http://www.mozilla.org/NPL/
- *
- * Software distributed under the NPL is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
- * for the specific language governing rights and limitations under the
- * NPL.
- *
- * The Initial Developer of this code under the NPL is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1998 Netscape Communications Corporation. All Rights
- * Reserved.
- */
-
- /*
-
- Created 3/25/96 - Tim Craycroft
-
- */
-
-
- #pragma mark --- Includes
-
- #include "CStandardFlexTable.h"
-
- // Mac
- #include <Drag.h>
-
- // PowerPlant
- #include <LTableMultiSelector.h>
- #include <LTableArrayStorage.h>
- #include <URegions.h>
- #include <LDropFlag.h>
-
- // ANSI
- #include <string.h>
- #include <stdio.h>
-
- // Netscape Mac Libs
- #include "LFlexTableGeometry.h"
- #include "UGraphicGizmos.h"
- #include "LTableRowSelector.h"
- #include "CTableKeyAttachment.h"
- #include "CContextMenuAttachment.h"
- #include "CTargetFramer.h"
- #include "UMailFolderMenus.h"
-
- #include "macutil.h"
- #include "resgui.h"
- #include "secnav.h"
- #include "cstring.h"
-
- #include "CInlineEditField.h"
-
- #pragma mark --- CTableHeaderListener
-
- //----------------------------------------------------------------------------------------
- void CTableHeaderListener::ListenToMessage(MessageT inMessage, void *ioParam)
- //----------------------------------------------------------------------------------------
- {
- if (inMessage == LTableHeader::msg_SortedColumnChanged) {
- mTable->ChangeSort((const LTableHeader::SortChange*)ioParam);
- }
- } // CTableHeaderListener::ListenToMessage
-
-
- #pragma mark --- CTableHeaderListener
-
-
- //
- // ListenToMessage
- //
- // Respond to changes in the inline editor
- //
- void
- CInlineEditorListener::ListenToMessage ( MessageT inMessage, void * /*ioParam*/ )
- {
- switch ( inMessage ) {
-
- case CInlineEditField::msg_InlineEditFieldChanged:
- mTable->InlineEditorTextChanged();
- break;
-
- case CInlineEditField::msg_HidingInlineEditField:
- mTable->InlineEditorDone();
- mTable->mRowBeingEdited = LArray::index_Bad;
- break;
-
- } // case of which message
-
- } // ListenToMessage
-
- #pragma mark --- CClickTimer
-
- //========================================================================================
- class CClickTimer : public LPeriodical
- //========================================================================================
- {
- public:
- CClickTimer(
- CStandardFlexTable* inTable,
- const STableCell& inCell,
- const SMouseDownEvent& inMouseDown);
- virtual ~CClickTimer();
- void NoteDoubleClick();
- void NoteSingleClick();
- TableIndexT GetClickedRow() { return mCell.row; }
-
- protected:
- void ReverseTheHilite();
- virtual void SpendTime(const EventRecord& inMacEvent);
-
- // Data:
- protected:
- CStandardFlexTable* mTable;
- STableCell mCell;
- SMouseDownEvent mMouseDown; // Can't be a reference, orig. is on the stack & dies
- }; // class CClickTimer
-
- //----------------------------------------------------------------------------------------
- CClickTimer::CClickTimer(
- CStandardFlexTable* inTable,
- const STableCell& inCell,
- const SMouseDownEvent& inMouseDown)
- //----------------------------------------------------------------------------------------
- : mTable(inTable)
- , mCell(inCell)
- , mMouseDown(inMouseDown)
- {
- mTable->mClickTimer = this;
- ReverseTheHilite(); // fake a new selection (temporarily).
- StartRepeating();
- } // CClickTimer::CClickTimer()
-
- //----------------------------------------------------------------------------------------
- CClickTimer::~CClickTimer()
- //----------------------------------------------------------------------------------------
- {
- mTable->mClickTimer = nil;
- mTable->SetHiliteDisabled(false); // make sure it's normal
- } // CClickTimer::~CClickTimer()
-
- //----------------------------------------------------------------------------------------
- void CClickTimer::SpendTime(const EventRecord& inMacEvent)
- //----------------------------------------------------------------------------------------
- {
- if (inMacEvent.when >= mMouseDown.macEvent.when + LMGetDoubleTime())
- NoteSingleClick();
- } // CClickTimer::SpendTime()
-
- //----------------------------------------------------------------------------------------
- void CClickTimer::NoteDoubleClick()
- //----------------------------------------------------------------------------------------
- {
- ReverseTheHilite(); // Show the selection again
- delete this;
- } // CClickTimer::NoteDoubleClick()
-
- //----------------------------------------------------------------------------------------
- void CClickTimer::NoteSingleClick()
- //----------------------------------------------------------------------------------------
- {
- try
- {
- // ReverseTheHilite(); // Show the selection again
- // The hiliting is now correct. Turn off hiliting to avoid a double flash.
- mTable->SetHiliteDisabled(true);
- mTable->SetFancyDoubleClick(false);
- mTable->ClickSelect(mCell, mMouseDown);
- mTable->SetFancyDoubleClick(true);
- }
- catch (...)
- {
- delete this;
- throw;
- }
- delete this;
- } // CClickTimer::NoteSingleClick()
-
- const Boolean ignore = true;
-
- //----------------------------------------------------------------------------------------
- void CClickTimer::ReverseTheHilite()
- // This relies on the implementation of HiliteRow, which ignores the "inActively"
- // parameter.
- //----------------------------------------------------------------------------------------
- {
- STableCell cell = mTable->GetFirstSelectedCell();
- UInt32 total = mTable->GetSelectedRowCount();
- UInt32 count = 0;
- if (total > 0)
- for (; cell.row <= mTable->mRows && count < total; cell.row++)
- {
- if (mTable->CellIsSelected(cell))
- {
- mTable->HiliteRow(cell.row, ignore);
- count++;
- }
- }
- mTable->mDropRow = cell.row; // fake out the icon to draw selected
- mTable->HiliteRow(mCell.row, ignore);
- mTable->mDropRow = LArray::index_Bad;
- } // CClickTimer::ReverseTheHilite
-
- #pragma mark --- CStandardFlexTable
-
- //----------------------------------------------------------------------------------------
- CStandardFlexTable::CStandardFlexTable(LStream *inStream)
- //----------------------------------------------------------------------------------------
- : CSpecialTableView(inStream)
- , LDragAndDrop(GetMacPort(), this)
- , LCommander()
- , LBroadcaster()
- //, CQAPartnerTableMixin(this)
- , mTableHeaderListener(this)
- , mTableHeader(NULL)
- , mSelectionList(NULL)
- , mClickTimer(nil)
- , mFancyDoubleClick(false)
- , mHiliteDisabled(false)
- , mDropRow(LArray::index_Bad)
- , mIsInternalDrop(false)
- , mIsDropBetweenRows(false)
- , mNameEditor(NULL)
- , mRowBeingEdited(0)
- , mInlineListener(this)
- {
- *inStream >> mTableHeaderPaneID;
- *inStream >> mTextTraitsID;
- *inStream >> mClickCountToOpen;
-
- SetRefreshAllWhenResized(true);
- } // CStandardFlexTable::CStandardFlexTable
-
- //----------------------------------------------------------------------------------------
- CStandardFlexTable::~CStandardFlexTable()
- //----------------------------------------------------------------------------------------
- {
- delete mClickTimer;
- } // CStandardFlexTable::~CStandardFlexTable
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::FinishCreateSelf()
- //----------------------------------------------------------------------------------------
- {
- RGBColor ignore;
- UGraphicGizmos::CalcWindowTingeColors(GetMacPort(), mDropColor, ignore);
-
- LView *super = GetSuperView();
- Assert_(super != NULL);
- mTableHeader = (LTableViewHeader*)dynamic_cast<LTableViewHeader*>(super->FindPaneByID(mTableHeaderPaneID));
- Assert_(mTableHeader);
- // This class assumes the header is fully created first (Oh, yukky-poo).
- Boolean HEADER_MUST_BE_IN_RESOURCE_BEFORE_TABLE = mTableHeader->GetTableView() != NULL;
- Assert_(HEADER_MUST_BE_IN_RESOURCE_BEFORE_TABLE);
-
- mTableHeader->AddListener(&mTableHeaderListener);
- SetUpTableHelpers();
-
- // Add columns to match the header
-
- SynchronizeColumnsWithHeader();
-
- SetTextTraits(mTextTraitsID);
-
- SetRefreshAllWhenResized(true);
-
- // If an editor for in-place editing exists, find it. Don't worry if one can't be found.
- mNameEditor = dynamic_cast<CInlineEditField*>(FindPaneByID(paneID_InlineEdit));
- if ( mNameEditor ) {
- mNameEditor->AddListener ( &mInlineListener );
- mNameEditor->SetGrowableBorder(true);
- }
-
- } // CStandardFlexTable::FinishCreateSelf
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::SetTextTraits(ResIDT inmTextTraitsID)
- //----------------------------------------------------------------------------------------
- {
- // load the text traits and pre-measure them
- StTextState textState;
-
- SInt16 rowHeight;
-
- mTextTraitsID = inmTextTraitsID;
- UTextTraits::SetPortTextTraits(mTextTraitsID);
- ::GetFontInfo(&mTextFontInfo);
-
- rowHeight = mTextFontInfo.ascent + mTextFontInfo.descent + 1;
- if (rowHeight < kMinRowHeight) {
- rowHeight = kMinRowHeight;
- }
-
- mTableGeometry->SetRowHeight(rowHeight, 0, 0);
- }
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::ScrollRowIntoFrame(TableIndexT inRow)
- //----------------------------------------------------------------------------------------
- {
- // This avoids excessive erasure done in the base class.
- if (inRow == LArray::index_Bad)
- return;
- STableCell cellToShow(inRow, 1);
- SPoint32 startLocation;
- GetImageLocation(startLocation);
- ScrollCellIntoFrame(cellToShow);
- SPoint32 endLocation;
- GetImageLocation(endLocation);
- if (startLocation.h != endLocation.h || startLocation.v != endLocation.v)
- {
- // 97/08/06. jrm: not entirely sure about whether this will give us
- // a redraw bug, but ScrollCellIntoFrame seems to end up
- // calling UpdatePort(). So I've added DontRefresh() here,
- // and it seems to cut down on flashing.
- DontRefresh();
- }
- } // CStandardFlexTable::ScrollRowIntoFrame
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::SelectRow(TableIndexT inRow)
- //----------------------------------------------------------------------------------------
- {
- STableCell cellToSelect(inRow, 1);
- if (GetSelectedRowCount() == 0)
- ScrollRowIntoFrame(inRow);
- SelectCell(cellToSelect);
- } // CStandardFlexTable::SelectRow
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::ScrollSelectionIntoFrame()
- //----------------------------------------------------------------------------------------
- {
- if (mTableSelector)
- {
- STableCell cellToSelect = mTableSelector->GetFirstSelectedCell();
- if ( cellToSelect.row != LArray::index_Bad )
- ScrollRowIntoFrame(cellToSelect.row);
- else
- ScrollRowIntoFrame(1); // if no selection, scroll to topw
- }
- } // CStandardFlexTable::SelectRow
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::SynchronizeColumnsWithHeader()
- //----------------------------------------------------------------------------------------
- {
- Assert_(mTableHeader);
- Int32 deltaColumns = (Int32) mTableHeader->CountVisibleColumns() - (Int32) mCols;
- if ( deltaColumns != 0 ) {
- if ( deltaColumns > 0 ) {
- InsertCols(deltaColumns, mCols, NULL, 0, false);
- } else {
- RemoveCols(-deltaColumns, mCols + deltaColumns + 1, false);
- }
- }
- } // CStandardFlexTable::SynchronizeColumnsFromHeader
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::AddAttachmentFirst(LAttachment* inAttachment, Boolean inOwnsAttachment)
- // nb: AddAttachment adds at end. But this can be called if you want the new attachment
- // to be executed before the existing ones.
- //----------------------------------------------------------------------------------------
- {
- LAttachment* beforeItem = nil;
- if (mAttachments)
- mAttachments->FetchItemAt(LArray::index_First, beforeItem);
- LCommander::AddAttachment(inAttachment, beforeItem, inOwnsAttachment);
- }
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::SetUpTableHelpers()
- //----------------------------------------------------------------------------------------
- {
- SetTableGeometry( new LFlexTableGeometry(this, mTableHeader) );
- SetTableSelector( new LTableRowSelector(this));
- // NOTE: There is a dependency between LTableRowSelector and CThreadView
- // because CThreadView::DoSelectThread() needs to select several rows at once.
-
- // standard keyboard navigation.
- AddAttachment( new CTableKeyAttachment(this) );
- // We don't need table storage. It's safe to have a null one.
- // It is NOT safe, to call SetTableStorage(NULL), as its
- // implementation in LTableView does not check against NULL.
- // SetTableStorage(NULL);
- Assert_(mTableStorage == NULL);
- } // CStandardFlexTable::SetUpTableHelpers
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::RefreshCellRange(
- const STableCell &inTopLeft,
- const STableCell &inBotRight)
- // Fix a bug in LTableView. If neither cell intersects the frame, there are two
- // cases: union of two cells intersects in empty rect or entire rect. PP always
- // assumed the latter.
- //----------------------------------------------------------------------------------------
- {
- // I added this test to prevent updating the entire frame in the case
- // of an empty intersection (a very common case!).
- // Calculate the convex hull of the two cells
- Int32 cell1Left, cell1Top, dummy1, dummy2;
- mTableGeometry->GetImageCellBounds(inTopLeft, cell1Left, cell1Top,
- dummy1, dummy2);
- Int32 cell2Right, cell2Bottom;
- mTableGeometry->GetImageCellBounds(inBotRight, dummy1, dummy2,
- cell2Right, cell2Bottom);
- // Does this big rect intersect the frame? If not, nothing to do.
- if (!ImageRectIntersectsFrame(cell1Left, cell1Top, cell2Right, cell2Bottom))
- return;
- LTableView::RefreshCellRange(inTopLeft, inBotRight);
- } // CStandardFlexTable::RefreshCellRange
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::DrawSelf()
- //----------------------------------------------------------------------------------------
- {
- StTextState textState;
-
- UTextTraits::SetPortTextTraits(mTextTraitsID);
- ApplyForeAndBackColors();
- LTableView::DrawSelf();
- ExecuteAttachments(CTargetFramer::msg_DrawSelfDone, this);
- } // CStandardFlexTable::DrawSelf
-
- //----------------------------------------------------------------------------------------
- TableIndexT CStandardFlexTable::CountExtraRowsControlledByCell(const STableCell& /*inCell*/) const
- //----------------------------------------------------------------------------------------
- {
- return 0;
- } // CStandardFlexTable::CountExtraRowsControlledByCell
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::ApplyTextStyle(TableIndexT /* inrow */) const
- //----------------------------------------------------------------------------------------
- {
- } // CStandardFlexTable::ApplyTextStyle
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::GetMainRowText(
- TableIndexT /*inRow*/,
- char* outText,
- UInt16 inMaxBufferLength) const
- // Calculate the text and (if ioRect is not passed in as null) a rectangle that fits it.
- // Return result indicates if any of the text is visible in the cell
- //----------------------------------------------------------------------------------------
- {
- if (outText && inMaxBufferLength > 0)
- *outText = '\0';
- } // CStandardFlexTable::GetMainRowText
-
- //----------------------------------------------------------------------------------------
- Boolean CStandardFlexTable::GetHiliteText(
- TableIndexT inRow,
- char* outText,
- UInt16 inMaxTextLength,
- Rect* ioRect) const
- // Calculate the text and (if ioRect is not passed in as null) a rectangle that fits it.
- // Caller must initialize the rectangle
- // Return result indicates if any of the text is visible in the cell
- //----------------------------------------------------------------------------------------
- {
- GetMainRowText(inRow, outText, inMaxTextLength);
- if (!*outText)
- return false;
- if (!ioRect)
- return true;
- ioRect->left += kDistanceFromIconToText;
- ioRect->top += 2;
- ioRect->bottom -= 2;
- StColorState penState;
- UTextTraits::SetPortTextTraits(mTextTraitsID);
- ApplyTextStyle(inRow);
- ioRect->right = ioRect->left + ::TextWidth(outText, 0, ::strlen(outText));
- Rect cellRect;
- GetLocalCellRect(STableCell(inRow, GetHiliteColumn()), cellRect);
- if (ioRect->left < cellRect.right)
- {
- if (ioRect->right > cellRect.right)
- ioRect->right = cellRect.right;
- }
- else
- return false;
- return true;
- } // CStandardFlexTable::GetHiliteText
-
- //----------------------------------------------------------------------------------------
- Boolean CStandardFlexTable::GetHiliteTextRect(
- const TableIndexT inRow,
- Rect& outRect) const
- //----------------------------------------------------------------------------------------
- {
- // Default is to return a rect enclosing the entire row. Derived classes may wish
- // to use GetHiliteText instead.
- STableCell cell(inRow, 1);
- if (!GetLocalCellRect(cell, outRect))
- return false;
- cell.col = mCols;
- Rect cellRect;
- if (!GetLocalCellRect(cell, cellRect))
- return false;
- outRect.right = cellRect.right;
- return true;
- } // CStandardFlexTable::GetHiliteTextRect
-
- //----------------------------------------------------------------------------------------
- Boolean CStandardFlexTable::GetIconRect(
- const STableCell& inCell,
- const Rect& inLocalRect,
- Rect& outRect) const
- //----------------------------------------------------------------------------------------
- {
- GetDropFlagRect(inLocalRect, outRect);
- outRect.left = outRect.right + kIconMargin
- + kIndentPerLevel * GetNestedLevel(inCell.row);
- outRect.right = outRect.left + kIconWidth;
- return true;
- } // CStandardFlexTable::GetIconRect
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::HiliteRow(
- TableIndexT inRow,
- Boolean /*inHilite*/)
- //----------------------------------------------------------------------------------------
- {
- if (mHiliteDisabled)
- return;
- StRegion hiliteRgn;
- if (FocusExposed() && GetRowHiliteRgn(inRow, hiliteRgn))
- {
- StColorPenState saveColorPen; // Preserve color & pen state
- TableIndexT col = GetHiliteColumn();
- if (col)
- {
- Rect r;
- STableCell cell(inRow, col);
- GetLocalCellRect(cell, r);
- DrawIcons(cell, r);
- }
- if (!IsActive())
- {
- // Make a frame. Do it this way so we get the "Invert" color trickery
- // from the toolbox. The previous code (srcXOR/FrameRgn) did not work
- // well when the table was not the active view.
- StRegion tempRgn;
- ::CopyRgn(hiliteRgn, tempRgn);
- ::InsetRgn(tempRgn, 1, 1);
- ::DiffRgn(hiliteRgn, tempRgn, hiliteRgn);
- }
- ApplyForeAndBackColors();
- DoHiliteRgn(hiliteRgn); // can be overridden to do something different
- }
- } // CStandardFlexTable::HiliteRow
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable :: DoHiliteRgn( RgnHandle inHiliteRgn ) const
- // Hilite the given area using the system hilite color. Override this to do
- // something different (like not use the hilite color).
- //----------------------------------------------------------------------------------------
- {
- UDrawingUtils::SetHiliteModeOn(); // Don't use hilite color, except for inline editing.
- ::InvertRgn(inHiliteRgn);
- } // CStandardFlexTable :: DoHiliteRgn
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable :: DoHiliteRect( const Rect & inHiliteRect ) const
- // Hilite the given area using the system hilite color. Override this to do
- // something different (like not use the hilite color).
- //----------------------------------------------------------------------------------------
- {
- UDrawingUtils::SetHiliteModeOn(); // Don't use hilite color, except for inline editing.
- ::InvertRect(&inHiliteRect);
- } // CStandardFlexTable :: DoHiliteRect
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::Click(SMouseDownEvent &inMouseDown)
- // Click the table. Special processing for drag-n-drop stuff.
- //----------------------------------------------------------------------------------------
- {
- LPane *clickedPane = FindSubPaneHitBy(inMouseDown.wherePort.h,
- inMouseDown.wherePort.v);
- if ( clickedPane != nil )
- clickedPane->Click(inMouseDown);
- else
- {
- if ( !inMouseDown.delaySelect ) LCommander::SwitchTarget(this);
- StValueChanger<Boolean> change(inMouseDown.delaySelect, false);
- // For drag-n-drop functionality
- LPane::Click(inMouseDown); // will process click on this View
- }
- } // CStandardFlexTable::Click
-
- //----------------------------------------------------------------------------------------
- Boolean CStandardFlexTable::ClickDropFlag(
- const STableCell &inCell,
- const SMouseDownEvent &inMouseDown)
- // Handle drop-flag ("twistee icon") clicks. Return true if handled.
- //----------------------------------------------------------------------------------------
- {
- Boolean isCellExpanded;
- if (CellHasDropFlag(inCell, isCellExpanded))
- {
- Rect cellRect, flagRect;
- GetLocalCellRect(inCell, cellRect);
- GetDropFlagRect(cellRect, flagRect);
- if (::PtInRect(inMouseDown.whereLocal, &flagRect))
- {
- ApplyForeAndBackColors();
- if (FocusDraw() && LDropFlag::TrackClick(flagRect, inMouseDown.whereLocal, isCellExpanded))
- SetCellExpansion(inCell, !isCellExpanded);
- return true;
- }
- }
- return false;
- }
-
- //----------------------------------------------------------------------------------------
- Boolean CStandardFlexTable::ClickSelect(
- const STableCell &inCell,
- const SMouseDownEvent &inMouseDown)
- //----------------------------------------------------------------------------------------
- {
- Rect cellRect;
- GetLocalCellRect(inCell, cellRect);
-
- FocusDraw(); //to be on the safe side
-
- // compute the text and icon rectangles and if the click is in them
- Rect textRect, iconRect;
- GetHiliteTextRect ( inCell.row, textRect );
- GetIconRect ( inCell, cellRect, iconRect );
- bool clickIsInIcon = ::PtInRect(inMouseDown.whereLocal, &iconRect);
- bool clickIsInTitle = ::PtInRect(inMouseDown.whereLocal, &textRect);
-
- // If the click is outside of the icon/title, or if it is in the title (and in-place editing is on),
- // then temporarily turn off the fancy double-click stuff since we don't want it to happen.
- bool savedFancyDoubleClick = mFancyDoubleClick;
- if ( !clickIsInIcon && !clickIsInTitle )
- mFancyDoubleClick = false; // click was outside icon&title
- if ( clickIsInTitle && mNameEditor )
- mFancyDoubleClick = false; // click was in title and we're doing inplace editing
-
- // Fancy double-click behavior. There are two reasons for this new feature of 5.0:
- // Ñ Double-clicking a thread in a message thread view (for example) should
- // not select the new item, because then the selected message would load in
- // the message pane of the thread window as well as in the newly-opened message
- // window. The user would prefer to maintain the message displayed in the current
- // window, and open the double-clicked, different message in the separate window.
- // Ñ Selecting a new row can be expensive, because it causes the message/folder
- // to load. This loading usually unwanted after a double-click.
- if (mFancyDoubleClick
- && !CellIsSelected(inCell)
- && (inMouseDown.macEvent.modifiers & shiftKey) == 0
- && (inMouseDown.macEvent.modifiers & cmdKey) == 0
- )
- {
- if (GetClickCount() == 1)
- {
- // Single-click. First cancel any previous double-click in progress.
- if (mClickTimer)
- mClickTimer->NoteSingleClick();
- // Set a timer. If the timer times out, it will set the hilite
- // back and call ClickSelect again with fancy double-click set to false.
- mClickTimer = new CClickTimer(this, inCell, inMouseDown);
- }
- else
- {
- // Double-click. Get rid of the timer.
- if (mClickTimer)
- mClickTimer->NoteDoubleClick();
- OpenRow(inCell.row);
- }
- return false;
- }
-
- // 0, 1, >=2 rows selected are the values that change command-enabling configurations.
- int selectedRowCountForCommandStatus = GetSelectedRowCount();
- if (selectedRowCountForCommandStatus > 2)
- selectedRowCountForCommandStatus = 2;
- Boolean result = false;
-
- //
- // There are two cases here: user clicks in the hilite column and they don't click in the
- // hilite column. If they do, only select if the click is in the icon or the icon text. Any
- // other click w/in that column unselects or start a marquee selection. If they click outside
- // the hilite column, process as normal.
- //
- if ( (inCell.col != GetHiliteColumn()) || clickIsInIcon || clickIsInTitle ) {
- if (LTableView::ClickSelect(inCell, inMouseDown))
- {
- // Handle it ourselves if the popup attachment doesn't want it.
- CContextMenuAttachment::SExecuteParams params;
- params.inMouseDown = &inMouseDown;
- if (ExecuteAttachments(CContextMenuAttachment::msg_ContextMenu, (void*)¶ms))
- {
- // drag ? - don't become target
- if (CellInitiatesDrag(inCell) && ::WaitMouseMoved(inMouseDown.macEvent.where))
- DragSelection(inCell, inMouseDown);
- else
- {
- // become target
- if (!IsTarget())
- SwitchTarget(this);
-
- // check if the click is in the title of the icon. If so, and an editor is
- // present and we're not doing a shift-selection extension and it's not a
- // double click then invoke the inline editor. Otherwise process the click normally.
- // (whew!)
- //
- // The reason for not inline editing on a double-click is that it allows the
- // user to double-click anywhere on the item to open it, like in the Finder. Doing
- // a double-click to edit an item doesn't make sense and the user would get
- // confused. ÑÑÑDouble click check doesn't work right now.....will fix later....ÑÑÑ
- if ( clickIsInTitle && mNameEditor && !(inMouseDown.macEvent.modifiers & shiftKey)
- && GetClickCount() != 2 )
- DoInlineEditing ( inCell, textRect );
- else {
- // open selection if we've got the right click count
- if (GetClickCount() == mClickCountToOpen)
- OpenSelection();
- }
- }
- result = true;
- }
- }
- } // if click in icon or text
- else {
- // since the click is not in the icon and not in the text, the selection should be
- // cleared before we try to show any context menus. This is possibly faster than
- // calling UnselectAllCells() because it only iterates over the selection, not the whole table.
- static const Rect empty = { 0, 0, 0, 0 };
- UnselectCellsNotInSelectionOutline(empty);
-
- CContextMenuAttachment::SExecuteParams params;
- params.inMouseDown = &inMouseDown;
- if (ExecuteAttachments(CContextMenuAttachment::msg_ContextMenu, (void*)¶ms))
- HandleSelectionTracking(inMouseDown);
- }
-
- cmd_status:
- mFancyDoubleClick = savedFancyDoubleClick;
- int newSelectedRowCountForCommandStatus = GetSelectedRowCount();
- if (newSelectedRowCountForCommandStatus > 2)
- newSelectedRowCountForCommandStatus = 2;
- if (selectedRowCountForCommandStatus != newSelectedRowCountForCommandStatus)
- SetUpdateCommandStatus(true);
- return result;
- } // CStandardFlexTable::ClickSelect
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::ClickSelf(const SMouseDownEvent &inMouseDown)
- // Overridden so that certain cells (e.g. toggled icons) don't select on click and to
- // handle marquee selection.
- //----------------------------------------------------------------------------------------
- {
- STableCell hitCell;
- SPoint32 imagePt;
-
- LocalToImagePoint(inMouseDown.whereLocal, imagePt);
- if (GetCellHitBy(imagePt, hitCell))
- {
- // Handle drop-flag clicks first
- if (ClickDropFlag(hitCell, inMouseDown))
- return;
-
- // See if the cell selects. If so go ahead and process it (could be a drag or selection
- // outline). If the cell does not select, the cell may still really want the click (like
- // the "marked read message" column in mail/news. If it does, give it the click, otherwise
- // start doing a marquee selection.
- if ( CellSelects(hitCell) ) {
- if ( ClickSelect(hitCell, inMouseDown) )
- ClickCell(hitCell, inMouseDown);
- }
- else {
- if ( CellWantsClick(hitCell) )
- ClickCell(hitCell, inMouseDown);
- else
- HandleSelectionTracking(inMouseDown);
- }
- }
- else {
- // since the click is not in any cell, the selection should be cleared before we try to
- // show the context menus. This is possibly faster than calling UnselectAllCells() because
- // it only iterates over the selection, not the whole table.
- static const Rect empty = { 0, 0, 0, 0 };
- UnselectCellsNotInSelectionOutline(empty);
-
- CContextMenuAttachment::SExecuteParams params;
- params.inMouseDown = &inMouseDown;
- if ( ExecuteAttachments(CContextMenuAttachment::msg_ContextMenu, (void*)¶ms) )
- HandleSelectionTracking(inMouseDown);
- }
-
- } // CStandardFlexTable::ClickSelf
-
-
- //
- // DoInlineEditing
- //
- // Perform the necessary setup for inline editing of a row's main text and then show the edit field.
- // This version of the routine is public and does not require any external knowledge of table internals
- // besides the cell that we should edit. Most of the work is done by calling the routine below
- //
- void
- CStandardFlexTable::DoInlineEditing ( const STableCell &inCell )
- {
- Rect textRect;
- GetHiliteTextRect ( inCell.row, textRect );
- DoInlineEditing ( inCell, textRect );
-
- } // DoInlineEditing
-
-
- //
- // DoInlineEditing
- //
- // Perform the necessary setup for inline editing of a row's main text and then show the edit field
- //
- void
- CStandardFlexTable::DoInlineEditing ( const STableCell &inCell, Rect & inTextRect )
- {
- mRowBeingEdited = inCell.row;
- if ( !CanDoInlineEditing() ) { // bail if inline editing is temporarily turned off
- mRowBeingEdited = LArray::index_Bad;
- return;
- }
-
- #if 0
- // erase the text rectangle so that when the text field shrinks, you won't see the old name
- // behind it. This is kinda skanky, but we need to make sure we draw the background color
- // correctly.
- //ÑÑÑThis doesn't work.
- RGBColor backColor;
- ::GetCPixel ( inTextRect.right - 1, inTextRect.top - 1, &backColor );
- ::RGBBackColor(&backColor);
- ::EraseRect ( &inTextRect );
- #endif
-
- SPoint32 imagePoint;
- LocalToImagePoint(topLeft(inTextRect), imagePoint);
- imagePoint.h -= 1; imagePoint.v -= 1;
-
- LCommander::SwitchTarget(mNameEditor);
-
- // Don't broadcast that the selection has changed until we update the edit field
- SetNotifyOnSelectionChange(false);
- SelectCell(STableCell(mRowBeingEdited, GetHiliteColumn()));
- SetNotifyOnSelectionChange(true);
-
- char nameString[256];
- GetHiliteText(mRowBeingEdited, nameString, 255, &inTextRect);
-
- mNameEditor->UpdateEdit(LStr255(nameString), &imagePoint, nil);
-
- SelectionChanged();
-
- } // DoInlineEditing
-
-
- //----------------------------------------------------------------------------------------
- Boolean CStandardFlexTable::CellSelects(const STableCell& /*inCell*/) const
- // Determines if a cell is allowed to select the row.
- //----------------------------------------------------------------------------------------
- {
- return true;
- } // CStandardFlexTable::CellSelects
-
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::HandleSelectionTracking ( const SMouseDownEvent & inMouseDown )
- // Set up everything to start tracking a selection marquee
- //----------------------------------------------------------------------------------------
- {
- // bail if the table specifically doesn't want the tracking.
- if ( !TableDesiresSelectionTracking() )
- return;
-
- // Click is outside of any Cell. Unselect everything if the shift key is up.
- if ( !(inMouseDown.macEvent.modifiers & shiftKey) )
- UnselectAllCells();
-
- // track the mouse for doing drag selection
- FocusDraw();
- TrackSelection( inMouseDown );
-
- } // HandleSelectionTracking
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::TrackSelection( const SMouseDownEvent & inMouseDown )
- // Do the tracking of when the mouse is down and the user wants to do a multiple selection
- // by drawing a selection marquee.
- //----------------------------------------------------------------------------------------
- {
- Point originalLoc = inMouseDown.whereLocal;
-
- Rect selectionRect = { 0, 0, 0, 0 }, iconHotSpotRect = { 0, 0, 0, 0 };
- Rect cellHotSpotRect = { 0, 0, 0, 0 };
-
- Point lastMousePoint = { 0, 0 }, curMousePoint = { 0, 0 }, curOrigin = { 0, 0 };
-
- UInt32 currentRow = 0L, currentCol = 0L, maxRows = 0L, maxColumns = 0L;
-
- STableCell topLeftCell( 0, 0 );
- STableCell botRightCell( 0, 0 );
- STableCell currentCell( 0, 0 );
-
- StColorPenState oldPenState;
-
- // mTableView->GetTableSize( maxRows, maxColumns );
-
- SetNotifyOnSelectionChange(false);
- while ( ::StillDown() ) {
-
- ::GetMouse( &curMousePoint );
-
- if ( (curMousePoint.v != lastMousePoint.v) || (curMousePoint.h != lastMousePoint.h) ) {
-
- currentCell.row = 0;
- currentCell.col = 0;
-
- ::PenPat( &qd.gray );
- ::PenMode( patXor );
- ::PenSize( 2, 2 );
-
- if ( !::EmptyRect(&selectionRect) )
- ::FrameRect( &selectionRect );
-
- lastMousePoint = curMousePoint;
-
- ::Pt2Rect( curMousePoint, originalLoc, &selectionRect );
-
- // Don't let the selection rect be empty. Trust me.
- if ( (selectionRect.right - selectionRect.left) == 0 )
- ::InsetRect( &selectionRect, -1, 0 );
- if ( (selectionRect.bottom - selectionRect.top) == 0 )
- ::InsetRect( &selectionRect, 0, -1 );
-
- //
- // Restore the text traits, scroll the table if needed, unselect all the cells
- // that shouldn't be selected, select the ones that should be selected,
- // reset the text traits and *then* finally draw the gray rect.
- //
-
- oldPenState.Restore();
-
- if ( AutoScrollImage(curMousePoint) )
- FocusDraw();
-
- UnselectCellsNotInSelectionOutline(selectionRect);
-
- // find what cells are in w/in the rectangle and select them if the rectangle
- // encloses/touches the cell hot spot (usually the icon or icon text).
- FetchIntersectingCells( selectionRect, topLeftCell, botRightCell );
- for ( currentRow = topLeftCell.row; currentRow <= botRightCell.row; currentRow++ ) {
- for ( currentCol = topLeftCell.col; currentCol <= botRightCell.col; currentCol++ ) {
-
- currentCell.row = currentRow;
- currentCell.col = currentCol;
-
- if ( !CellIsSelected(currentCell) && HitCellHotSpot(currentCell, selectionRect) ) {
- SelectCell( currentCell );
- }
-
- } // for each column
- } // for each row
-
- oldPenState.Save();
-
- ::PenPat( &qd.gray );
- ::PenMode( patXor );
- ::PenSize( 2, 2 );
- ::FrameRect( &selectionRect );
-
- } // if mouse has moved
-
- } // while mouse still down
-
- SetNotifyOnSelectionChange(true);
- SelectionChanged();
-
- if ( !::EmptyRect(&selectionRect) )
- ::FrameRect( &selectionRect );
-
- } // TrackSelection
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::UnselectCellsNotInSelectionOutline( const Rect & inSelectionRect )
- // Iterate over existing selection looking for things that are no longer w/in
- // the rectangle and unselect them.
- //
- // IMPORTANT: This routine assumes a selection model that selects the entire row.
- // If another selection model is used (such as one that only selects individual
- // cells), this needs to be rewritten.
- //----------------------------------------------------------------------------------------
- {
- TableIndexT currentRow = LArray::index_Bad;
- while ( GetNextSelectedRow(currentRow) ) {
-
- STableCell currentCell;
- currentCell.row = currentRow;
- currentCell.col = GetHiliteColumn();
- if ( !HitCellHotSpot( currentCell, inSelectionRect) ) {
- UnselectCell( currentCell );
- currentRow = currentCell.row;
- }
-
- }
-
- } // UnselectCellsNotInSelectionOutline
-
-
- //----------------------------------------------------------------------------------------
- Boolean CStandardFlexTable::HitCellHotSpot( const STableCell &inCell, const Rect &inTotalSelectionRect )
- //----------------------------------------------------------------------------------------
- {
- Boolean result = false;
- TableIndexT hiliteCol = GetHiliteColumn();
-
- FocusDraw(); //to be on the safe side
-
- if ( hiliteCol ) {
- if ( hiliteCol == inCell.col ) {
- Rect cellRect;
- GetLocalCellRect(inCell, cellRect);
-
- Rect textRect, iconRect;
- GetHiliteTextRect ( inCell.row, textRect );
- GetIconRect ( inCell, cellRect, iconRect );
- if ( ::SectRect(&textRect, &inTotalSelectionRect, &textRect) ||
- ::SectRect(&iconRect, &inTotalSelectionRect, &iconRect) )
- result = true;
- }
- }
- else {
- Rect cellRect = { 0, 0, 0, 0 };
- GetLocalCellRect( inCell, cellRect );
- result = ::SectRect( &cellRect, &inTotalSelectionRect, &cellRect );
- }
-
- return result;
-
- } // HitCellHotSpot
-
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::BeTarget()
- //----------------------------------------------------------------------------------------
- {
- LCommander::BeTarget();
- Activate();
- ExecuteAttachments(CTargetFramer::msg_BecomingTarget, this);
- } // CStandardFlexTable::BeTarget
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::DontBeTarget()
- //----------------------------------------------------------------------------------------
- {
- if (mClickTimer)
- mClickTimer->NoteSingleClick();
- ExecuteAttachments(CTargetFramer::msg_ResigningTarget, this);
- Deactivate();
- LCommander::DontBeTarget();
- } // CStandardFlexTable::DontBeTarget
-
- //----------------------------------------------------------------------------------------
- PaneIDT CStandardFlexTable::GetCellDataType(const STableCell &inCell) const
- //----------------------------------------------------------------------------------------
- {
- return mTableHeader->GetColumnPaneID(inCell.col);
- } // CStandardFlexTable::GetCellDataType
-
- //----------------------------------------------------------------------------------------
- Boolean CStandardFlexTable::GetNextSelectedRow(TableIndexT& inOutAfterRow) const
- //----------------------------------------------------------------------------------------
- {
- TableIndexT nRows, nCols;
- GetTableSize(nRows, nCols);
- STableCell cell(inOutAfterRow, nCols);
- if (LTableView::GetNextSelectedCell(cell))
- {
- inOutAfterRow = cell.row;
- return true;
- }
- return false;
-
- } // CStandardFlexTable::GetNextSelectedRow
-
- //----------------------------------------------------------------------------------------
- Boolean CStandardFlexTable::GetLastSelectedRow(TableIndexT& inOutBeforeRow) const
- // Currently a little inefficient...
- //----------------------------------------------------------------------------------------
- {
- STableCell cell(inOutBeforeRow, 1);
- while (cell.row-- > LArray::index_Bad)
- {
- if (CellIsSelected(cell))
- {
- inOutBeforeRow = cell.row;
- return true;
- }
- }
- return false;
- } // CStandardFlexTable::GetLastSelectedRow
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::FindCommandStatus(
- CommandT inCommand,
- Boolean &outEnabled,
- Boolean &outUsesMark,
- Char16 &outMark,
- Str255 outName)
- //----------------------------------------------------------------------------------------
- {
- switch (inCommand)
- {
- case cmd_GetInfo:
- outEnabled = GetSelectedRowCount() == 1;
- break;
- // These commands require one or more lines to be selected.
- case cmd_OpenSelection:
- case cmd_OpenSelectionNewWindow:
- case cmd_Clear:
- case cmd_SecurityInfo:
- outEnabled = GetSelectedRowCount() > 0;
- break;
- // Selection not necessary
- case cmd_SelectAll:
- outEnabled = true;
- break;
- default:
- LCommander::FindCommandStatus(inCommand, outEnabled, outUsesMark, outMark, outName);
- break;
- }
- } // CStandardFlexTable::FindCommandStatus
-
- //----------------------------------------------------------------------------------------
- Boolean CStandardFlexTable::ObeyCommand(
- CommandT inCommand,
- void *ioParam)
- //----------------------------------------------------------------------------------------
- {
- Boolean result = false;
- switch(inCommand)
- {
- case cmd_OpenSelectionNewWindow:
- case cmd_OpenSelection:
- OpenSelection();
- return true;
- case cmd_GetInfo:
- GetInfo();
- return true;
- case cmd_SelectAll:
- SelectAllCells();
- return true;
- case cmd_Clear:
- DeleteSelection();
- return true;
- default:
- result = LCommander::ObeyCommand(inCommand, ioParam);
- break;
- }
- return result;
- } // CStandardFlexTable::ObeyCommand
-
-
- //----------------------------------------------------------------------------------------
- Boolean CStandardFlexTable::HandleKeyPress( const EventRecord& inKeyEvent)
- //----------------------------------------------------------------------------------------
- {
- // We are NOT masking off keyUp events. So let's beware of them!
- if (inKeyEvent.what == keyUp)
- return false;
- Char16 c = inKeyEvent.message & charCodeMask;
- switch (c)
- {
- case char_Return:
- case char_Enter:
- OpenSelection();
- return true;
- case char_Backspace:
- case char_FwdDelete:
- DeleteSelection();
- return true;
- case char_LeftArrow:
- case char_RightArrow:
- if (GetSelectedRowCount() == 1)
- {
- STableCell cell = mTableSelector->GetFirstSelectedCell();
- Boolean isCellExpanded;
- // selected cell will be in column 1, but dropflag may not be.
- for (; IsValidCell(cell); cell.col++)
- {
- if (CellHasDropFlag(cell, isCellExpanded))
- {
- SetCellExpansion(cell, c == char_RightArrow);
- break;
- }
- }
- }
- default:
- LCommander::HandleKeyPress(inKeyEvent);
- return true;
- } // switch
- return false;
- } // CStandardFlexTable::HandleKeyPress
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::OpenSelection()
- //----------------------------------------------------------------------------------------
- {
- TableIndexT selectedRow = 0;
- while (GetNextSelectedRow(selectedRow) && !CmdPeriod())
- OpenRow(selectedRow);
- }
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::GetInfo()
- //----------------------------------------------------------------------------------------
- {
- // Base class does nothing
- }
-
- //----------------------------------------------------------------------------------------
- Boolean CStandardFlexTable::RowCanAcceptDrop(
- DragReference /*inDragRef*/,
- TableIndexT /*inDropRow*/)
- //----------------------------------------------------------------------------------------
- {
- return false;
- } // CStandardFlexTable::RowCanAcceptDrop
-
- //----------------------------------------------------------------------------------------
- Boolean CStandardFlexTable::RowCanAcceptDropBetweenAbove(
- DragReference /*inDragRef*/,
- TableIndexT /*inDropRow*/)
- //----------------------------------------------------------------------------------------
- {
- return false;
- } // CStandardFlexTable::RowCanAcceptDropBetweenAbove
-
- //----------------------------------------------------------------------------------------
- TableIndexT CStandardFlexTable::GetHiliteColumn() const
- //----------------------------------------------------------------------------------------
- {
- return LArray::index_Bad; // default is to hilite the whole row.
- } // CStandardFlexTable::GetHiliteColumn
-
-
- //
- // ComputeItemDropAreas
- //
- // When a drag goes over a cell that contains a non-folder, divide the node in half. The top
- // half will represent dropping above the item, the bottom after.
- //
- void
- CStandardFlexTable :: ComputeItemDropAreas ( const Rect & inLocalCellRect, Rect & oTop,
- Rect & oBottom )
- {
- oBottom = oTop = inLocalCellRect;
- uint16 midPt = (oTop.bottom - oTop.top) / 2;
- oTop.bottom = oTop.top + midPt;
- oBottom.top = oTop.bottom + 1;
-
- } // ComputeItemDropAreas // ComputeItemDropAreas
-
-
- //
- // ComputeFolderDropAreas
- //
- // When a drag goes over a cell that contains a folder, divide the cell area into 3 parts. The middle
- // area, which corresponds to a drop on the folder takes up the majority of the cell space with the
- // top and bottom areas (corresponding to drop before and drop after, respectively) taking up the rest
- // at the ends.
- //
- void
- CStandardFlexTable :: ComputeFolderDropAreas ( const Rect & inLocalCellRect, Rect & oTop,
- Rect & oBottom )
- {
- const Uint8 capAreaHeight = 3;
-
- oBottom = oTop = inLocalCellRect;
- oTop.bottom = oTop.top + capAreaHeight;
- oBottom.top = oBottom.bottom - capAreaHeight;
-
- } // ComputeFolderDropAreas
-
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::InsideDropArea(DragReference inDragRef)
- // (override from LDragAndDrop)
- //----------------------------------------------------------------------------------------
- {
- Point mouseLoc;
- SPoint32 imagePt;
- Rect rowBounds; // only top/bottom are important
-
- FocusDraw();
-
- ::GetDragMouse(inDragRef, &mouseLoc, NULL);
- ::GlobalToLocal(&mouseLoc);
- // Auto scroll code -- jrm 97/05/03
- if (AutoScrollImage(mouseLoc))
- {
- Rect frame;
- CalcLocalFrameRect(frame);
- Int32 pt = ::PinRect(&frame, mouseLoc);
- mouseLoc = *(Point*)&pt;
- }
- LocalToImagePoint(mouseLoc, imagePt);
- TableIndexT rowMouseIsOver = mTableGeometry->GetRowHitBy(imagePt);
- GetLocalCellRect ( STableCell(rowMouseIsOver, GetHiliteColumn()), rowBounds );
-
- // Find the index of where we want to drop the item and if it is between two rows
- // of if it is on a row (can only happen if row is a container).
- bool newIsDropBetweenRows = false;
- TableIndexT newDropRow = LArray::index_Bad;
- if ( rowMouseIsOver >= 1 )
- {
- // is the current row in the existing table or off the end? If it's off the end, we
- // know we're dropping between rows.
- if ( rowMouseIsOver <= mRows ) {
- // divide row horizontally into several parts (3 if a container, 2 if not) and determine which
- // part of the row the mouse is over. This will determine if we should interpret this as
- // a drop before/after or a drop on.
- if ( RowIsContainer(rowMouseIsOver) ) {
- Rect topArea, bottomArea;
- ComputeFolderDropAreas ( rowBounds, topArea, bottomArea );
- if ( ::PtInRect(mouseLoc, &topArea) ) {
- newDropRow = rowMouseIsOver; // before current row
- newIsDropBetweenRows = true;
- }
- else if ( ::PtInRect(mouseLoc, &bottomArea) ) {
- newDropRow = rowMouseIsOver + 1; // after current row
- newIsDropBetweenRows = true;
- }
- else
- newDropRow = rowMouseIsOver; // hilite folder, don't draw line
- }
- else {
- Rect topArea, bottomArea;
- ComputeItemDropAreas ( rowBounds, topArea, bottomArea );
- if ( ::PtInRect(mouseLoc, &topArea) )
- newDropRow = rowMouseIsOver; // before current row
- else
- newDropRow = rowMouseIsOver + 1; // after current row
- newIsDropBetweenRows = true; // draw line between rows
- }
- }
- else {
- newDropRow = mRows + 1;
- newIsDropBetweenRows = true;
- newDropRow = rowMouseIsOver;
- }
-
- // we now know where the drop SHOULD go, now check if it CAN go there.
- newIsDropBetweenRows &= RowCanAcceptDropBetweenAbove(inDragRef, newDropRow);
- if (!newIsDropBetweenRows && !RowCanAcceptDrop(inDragRef, newDropRow))
- newDropRow = LArray::index_Bad;
- }
-
- // if things have changed from last time, unhilite the last drop feedback and redraw
- // the new drop feedback.
- if (newDropRow != mDropRow || newIsDropBetweenRows != mIsDropBetweenRows)
- {
- TableIndexT oldDropRow = mDropRow;
- mDropRow = LArray::index_Bad; // so that we'll unhilite
- HiliteDropRow(oldDropRow, mIsDropBetweenRows);
- mIsDropBetweenRows = newIsDropBetweenRows;
-
- if (newDropRow > LArray::index_Bad)
- {
- mDropRow = newDropRow; // so that we'll hilite
- HiliteDropRow(newDropRow, mIsDropBetweenRows);
- }
- else
- mDropRow = LArray::index_Bad;
- }
-
- } // CStandardFlexTable::InsideDropArea
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::HiliteDropRow(TableIndexT inRow, Boolean inDrawBarAbove)
- //----------------------------------------------------------------------------------------
- {
- if (inRow == LArray::index_Bad)
- return;
-
- STableCell cell(inRow, 1);
- if (mIsInternalDrop && CellIsSelected(cell))
- return; // Don't show hiliting feedback for a drag when over the selection.
-
- TableIndexT dropHiliteColumn = GetHiliteColumn();
- if ( dropHiliteColumn != LArray::index_Bad )
- cell.col = dropHiliteColumn;
- else
- cell.col = 1;
- Rect r;
- GetLocalCellRect(cell, r);
- if (inDrawBarAbove || dropHiliteColumn == LArray::index_Bad)
- {
- r.left = 0;
- r.right = mFrameSize.width;
- if (inDrawBarAbove)
- {
- #if 1
- // here's how you draw a bar above.
- r.bottom = r.top + 1;
- r.top -= 1;
- #else
- // here's how you underline below.
- r.top = r.bottom - 1;
- r.bottom += 1;
- #endif
- }
- DoHiliteRect(r);
- }
- else
- {
- DrawIcons(cell, r);
- StRegion hiliteRgn;
- GetRowHiliteRgn(inRow, hiliteRgn);
- ::InvertRgn(hiliteRgn);
- }
- } // CStandardFlexTable::HiliteDropRow
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::DrawCellContents(
- const STableCell& /*inCell*/,
- const Rect& /*inLocalRect*/)
- //----------------------------------------------------------------------------------------
- {
- }
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::DrawCell(
- const STableCell& inCell,
- const Rect& inLocalRect)
- //----------------------------------------------------------------------------------------
- {
- // Compute the update rgn's intersection with the cell
- // bounds and bail if they're disjoint.
- RgnHandle updateRgn = GetLocalUpdateRgn();
- if (!updateRgn)
- return;
- Rect updateRect = (**updateRgn).rgnBBox;
- ::DisposeRgn(updateRgn);
-
- Rect intersection;
- if (!::SectRect(&updateRect, &inLocalRect, &intersection))
- return;
-
- // Save clip, and clip to the cell/updateRgn intersection
- StClipRgnState savedClip;
- ::ClipRect(&intersection);
-
- StColorState penState;
- RGBColor white = { 0xFFFF, 0xFFFF, 0xFFFF };
- ::RGBBackColor(&white);
-
- // Inset the rectangle on the right for better separation
- // (long text looks bad when truncated).
- Rect localRect = inLocalRect;
- Rect insetRect = inLocalRect;
- insetRect.right--;
- // The rightmost column overlaps the scrollbar. We must not draw on the overlap.
- if (inCell.col == mTableHeader->CountVisibleColumns())
- localRect = insetRect;
- ::EraseRect(&inLocalRect);
-
- ApplyTextStyle(inCell.row);
- if ( mRowBeingEdited != inCell.row )
- DrawCellContents(inCell, insetRect);
- } // CStandardFlexTable::DrawCell
-
- //----------------------------------------------------------------------------------------
- Boolean CStandardFlexTable::GetRowDragRgn(TableIndexT inRow, RgnHandle ioHiliteRgn) const
- // The drag region is the hilite region plus the icon
- //----------------------------------------------------------------------------------------
- {
- ::SetEmptyRgn(ioHiliteRgn);
- Rect cellRect;
- TableIndexT col = GetHiliteColumn();
- if ( !col )
- col = 1;
- STableCell cell(inRow, col);
- if (!GetLocalCellRect(cell, cellRect))
- return false;
- ResIDT iconID = GetIconID(inRow);
- if (iconID)
- {
- GetIconRect(cell, cellRect, cellRect);
- ::IconIDToRgn(ioHiliteRgn, &cellRect, atNone, iconID);
- }
- StRegion cellRgn;
- GetRowHiliteRgn(inRow, cellRgn);
- ::UnionRgn(ioHiliteRgn, cellRgn, ioHiliteRgn);
- return true;
- } // CStandardFlexTable::GetRowHiliteRgn
-
- //----------------------------------------------------------------------------------------
- Boolean CStandardFlexTable::GetRowHiliteRgn(TableIndexT inRow, RgnHandle ioHiliteRgn) const
- //----------------------------------------------------------------------------------------
- {
- ::SetEmptyRgn(ioHiliteRgn);
- Rect cellRect;
- if (!GetHiliteTextRect(inRow, cellRect))
- return false;
- ::RectRgn(ioHiliteRgn, &cellRect);
- return true;
- } // CStandardFlexTable::GetRowHiliteRgn
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::GetHiliteRgn(RgnHandle ioHiliteRgn)
- //----------------------------------------------------------------------------------------
- {
- ::SetEmptyRgn(ioHiliteRgn);
- Rect visRect;
- GetRevealedRect(visRect); // Check if Table is revealed
- if (!::EmptyRect(&visRect))
- {
- PortToLocalPoint(topLeft(visRect));
- PortToLocalPoint(botRight(visRect));
-
- STableCell topLeftCell, botRightCell;
- FetchIntersectingCells(visRect, topLeftCell, botRightCell);
-
- StRegion cellRgn;
- STableCell cell(1, GetHiliteColumn()); // Loop thru all cells
- for (cell.row = topLeftCell.row; cell.row <= botRightCell.row; cell.row++)
- {
- if (CellIsSelected(cell))
- {
- if (GetRowHiliteRgn(cell.row, cellRgn))
- ::UnionRgn(ioHiliteRgn, cellRgn, ioHiliteRgn);
- }
- }
- }
- } // CStandardFlexTable::GetHiliteRgn
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::EnterDropArea(
- DragReference /*inDragRef*/,
- Boolean /*inDragHasLeftSender*/)
- // CStandardFlexTable overrides the LDropArea base method, because it assumes a drop-on-row
- // scenario
- //----------------------------------------------------------------------------------------
- {
- } // CStandardFlexTable::EnterDropArea
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::LeaveDropArea(DragReference /*inDragRef*/)
- // CStandardFlexTable overrides the LDropArea base method, because it assumes a drop-on-row
- // scenario
- //----------------------------------------------------------------------------------------
- {
- FocusDraw();
- if (mDropRow)
- {
- TableIndexT oldDropRow = mDropRow;
- mDropRow = LArray::index_Bad; // so that we'll unhilite
- HiliteDropRow(oldDropRow, mIsDropBetweenRows);
- }
-
- // HiliteSelection( IsActive(), true); // Finder does not do this.
- mIsDropBetweenRows = false;
- mIsInternalDrop = false;
- } // CStandardFlexTable::LeaveDropArea
-
- //----------------------------------------------------------------------------------------
- Boolean CStandardFlexTable::PointInDropArea(Point inGlobalPt)
- // Overridden to return true just above and below the view, to allow autoscroll
- // (override from LDragAndDrop)
- //----------------------------------------------------------------------------------------
- {
- #define kSlopPixels 20
- if (!IsEnabled())
- return false;
- Point portPoint = inGlobalPt;
- GlobalToPortPoint(portPoint);
- return ( (portPoint.h >= mFrameLocation.h) &&
- (portPoint.h < mFrameLocation.h + mFrameSize.width) &&
- (portPoint.v >= mFrameLocation.v - kSlopPixels) &&
- (portPoint.v < mFrameLocation.v + mFrameSize.height + kSlopPixels) );
- } // CStandardFlexTable::PointInDropArea
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::ScrollImageBy(
- Int32 inLeftDelta,
- Int32 inTopDelta,
- Boolean inRefresh)
- //----------------------------------------------------------------------------------------
- {
- Boolean mayAutoScrollLeavingTurds = inRefresh && IsTarget(); //&& mDropRow;
- // Turds will be left if we call scrollbits in ScrollImageBy
- if (mayAutoScrollLeavingTurds)
- {
- // Notify the CTargetFramer (if any) to erase the frame hilite
- ExecuteAttachments(CTargetFramer::msg_ResigningTarget, this);
- // invalidates the border, and stops the refresh from drawing a new one
- // If we are about to autoscroll and we are calling scrollbits, unhilite
- // the drop row as well
- TableIndexT dropRow = mDropRow;
- mDropRow = LArray::index_Bad; // So that we'll unhilite
- HiliteDropRow(dropRow, mIsDropBetweenRows);
- mDropRow = dropRow; // so that we'll hilite
- }
- Inherited::ScrollImageBy(inLeftDelta, inTopDelta, inRefresh);
- if (mayAutoScrollLeavingTurds && FocusDraw())
- {
- // Turn hiliting back on
- HiliteDropRow(mDropRow, mIsDropBetweenRows);
- // Notify the CTargetFramer to draw the border now.
- ExecuteAttachments(CTargetFramer::msg_BecomingTarget, this); // invert
- }
- } // CStandardFlexTable::ScrollImageBy
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::DragSelection(
- const STableCell& inCell,
- const SMouseDownEvent& inMouseDown )
- //----------------------------------------------------------------------------------------
- {
- #pragma unused(inCell)
-
- DragReference dragRef = 0;
-
- if (!FocusDraw()) return;
-
- try
- {
- StRegion dragRgn;
- OSErr err = ::NewDrag(&dragRef);
- ThrowIfOSErr_(err);
- AddSelectionToDrag(dragRef, dragRgn);
- if (inMouseDown.macEvent.modifiers & optionKey != 0)
- {
- CursHandle copyDragCursor = ::GetCursor(6608); // finder's copy-drag cursor
- if (copyDragCursor != nil)
- ::SetCursor(*copyDragCursor);
- }
- (void) ::TrackDrag(dragRef, &(inMouseDown.macEvent), dragRgn);
- }
- catch( ... )
- {
- }
-
- if (dragRef != 0)
- ::DisposeDrag(dragRef);
- } // CStandardFlexTable::DragSelection
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::AddSelectionToDrag(DragReference inDragRef, RgnHandle inDragRgn)
- //----------------------------------------------------------------------------------------
- {
- StRegion tempRgn;
-
- ::SetEmptyRgn(inDragRgn);
-
- STableCell cell(0, 1);
- while (GetNextSelectedRow(cell.row))
- {
- AddRowDataToDrag(cell.row, inDragRef);
- GetRowDragRgn(cell.row, tempRgn);
- ::UnionRgn(tempRgn, inDragRgn, inDragRgn);
- }
- ::CopyRgn(inDragRgn, tempRgn);
- ::InsetRgn(tempRgn, 1, 1);
- ::DiffRgn(inDragRgn, tempRgn, inDragRgn);
-
- // Convert the region to global coordinates
- Point p;
- p.h = p.v = 0;
- ::LocalToGlobal(&p);
- ::OffsetRgn(inDragRgn, p.h, p.v);
- } // CStandardFlexTable::AddSelectionToDrag
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::ChangeSort(const LTableHeader::SortChange* /*inSortChange*/)
- //----------------------------------------------------------------------------------------
- {
- } // CStandardFlexTable::ChangeSort
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::GetDropFlagRect(
- const Rect& inLocalCellRect,
- Rect& outFlagRect ) const
- //----------------------------------------------------------------------------------------
- {
- UInt32 vDiff = (inLocalCellRect.bottom - inLocalCellRect.top - 12) >> 1;
-
- outFlagRect.top = inLocalCellRect.top + vDiff;
- outFlagRect.bottom = outFlagRect.top + 12;
-
- outFlagRect.left = inLocalCellRect.left + 3;
- outFlagRect.right = outFlagRect.left + 16;
- } // CStandardFlexTable::GetDropFlagRect
-
- //----------------------------------------------------------------------------------------
- TableIndexT CStandardFlexTable::GetSelectedRowCount() const
- //----------------------------------------------------------------------------------------
- {
- return ((LTableRowSelector*)mTableSelector)->GetSelectedRowCount();
- // safe cast.
- } // CStandardFlexTable::GetSelectedRowCount
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::SetNotifyOnSelectionChange(Boolean inDoNotify)
- //----------------------------------------------------------------------------------------
- {
- if (inDoNotify)
- StartBroadcasting();
- else
- StopBroadcasting();
- } // CStandardFlexTable::SetNotifyOnSelectionChange
-
- //-----------------------------------
- Boolean CStandardFlexTable::GetNotifyOnSelectionChange()
- //-----------------------------------
- {
- return IsBroadcasting();
-
- } // CStandardFlexTable::GetNotifyOnSelectionChange
-
- //----------------------------------------------------------------------------------------
- const TableIndexT* CStandardFlexTable::GetUpdatedSelectionList(TableIndexT& outSelectionSize)
- // Returns a ONE-BASED list of TableIndexT, as it should.
- // The result is const because this is not a copy, it is
- // the actual list cached in this object. You probably want
- // to use CMailFlexTable::GetSelection() for message stuff.
- //----------------------------------------------------------------------------------------
- {
- outSelectionSize = GetSelectedRowCount();
- // if we've got a selection list, it's assumed up to date,
- // so return it. When the selection changes, we just get
- // rid of it (in SelectionChanged()) and set mSelectionList to NULL
- if (mSelectionList)
- return mSelectionList;
- // If there is a selection, allocate the list
- if (outSelectionSize > 0)
- {
- mSelectionList = new TableIndexT[outSelectionSize];
- if (!mSelectionList)
- outSelectionSize = 0;
- }
- if (mSelectionList)
- {
- TableIndexT selectedRow = 0;
- TableIndexT *item = mSelectionList;
- for (int i = 0; i < outSelectionSize; i++)
- {
- Boolean ok = GetNextSelectedRow(selectedRow);
- Assert_(ok);
- if (!ok) break;
- *item++ = selectedRow;
- }
- }
- return mSelectionList;
- } // CStandardFlexTable::GetUpdatedSelectionList
-
- //----------------------------------------------------------------------------------------
- Boolean CStandardFlexTable::IsColumnVisible(PaneIDT inID)
- //----------------------------------------------------------------------------------------
- {
- return mTableHeader->IsColumnVisible(inID);
- }
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::SelectionChanged()
- // invalidate any cached selection list
- //----------------------------------------------------------------------------------------
- {
- delete [] mSelectionList;
- mSelectionList = NULL;
- BroadcastMessage(msg_SelectionChanged, this);
- } // CStandardFlexTable::SelectionChanged
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::DrawTextString(
- const char* inText,
- const FontInfo* inFontInfo,
- SInt16 inMargin,
- const Rect& inBounds,
- SInt16 inJustification,
- Boolean inDoTruncate,
- TruncCode inTruncWhere)
- //----------------------------------------------------------------------------------------
- {
- Rect r = inBounds;
-
- r.left += inMargin;
- r.right -= inMargin;
-
- UGraphicGizmos::PlaceTextInRect(inText,
- strlen(inText),
- r,
- inJustification,
- teCenter,
- inFontInfo,
- inDoTruncate,
- inTruncWhere );
- } // CStandardFlexTable::DrawTextString
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::DrawIconFamily(
- ResIDT inIconID,
- SInt16 inIconWidth,
- SInt16 inIconHeight,
- IconTransformType inTransform,
- const Rect& inBounds)
- //----------------------------------------------------------------------------------------
- {
- OSErr err;
- Rect iconRect = inBounds;
-
- iconRect.right = iconRect.left + inIconWidth;
- iconRect.bottom = iconRect.top + inIconHeight;
-
- UGraphicGizmos::CenterRectOnRect(iconRect, inBounds);
- err = ::PlotIconID(&iconRect, atNone, inTransform, inIconID);
- } // CStandardFlexTable::DrawIconFamily
-
- //----------------------------------------------------------------------------------------
- SInt16 CStandardFlexTable::DrawIcons(
- const STableCell& inCell,
- const Rect& inLocalRect) const
- //----------------------------------------------------------------------------------------
- {
- Rect iconRect;
- GetDropFlagRect(inLocalRect, iconRect);
- // Draw the drop flag if the folder has subfolders
- // UI issue: the following test makes us differ from the Finder: there, all
- // folders have dropflags, whether they have subfolders or not. This diff may confuse
- // users... if so, just comment out the "if" line. - jrm
- Boolean expanded;
- if (CellHasDropFlag(inCell, expanded))
- {
- StColorState state; // LDropFlag::Draw has a bug (clobbers the color).
- LDropFlag::Draw(iconRect, expanded);
- }
-
- // Work out the correct transform type, and then call our virtual method so that
- // derived classes can draw the icons they want.
- IconTransformType transformType = kTransformNone;
- if (mClickTimer)
- {
- // A fancy double-click is in progress.
- // Only the fake selection should be hilited
- if (inCell.row == mClickTimer->GetClickedRow())
- transformType = kTransformSelected;
- }
- else
- {
- if (inCell.row == mDropRow)
- {
- // Drop-target always hilited
- transformType = kTransformSelected;
- }
- else if (IsActive() && CellIsSelected(inCell))
- {
- // Only the real selection is hilited (and only in the active pane)
- transformType = kTransformSelected;
- }
- }
- GetIconRect(inCell, inLocalRect, iconRect);
- DrawIconsSelf(inCell, transformType, iconRect);
- return iconRect.right;
- } // CStandardFlexTable::DrawIcons
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::DrawIconsSelf(
- const STableCell& inCell,
- IconTransformType inTransformType,
- const Rect& inIconRect) const
- //----------------------------------------------------------------------------------------
- {
- ResIDT iconID = GetIconID(inCell.row);
- if (iconID)
- DrawIconFamily(iconID, 16, 16, inTransformType, inIconRect);
- } // CStandardFlexTable::DrawIconsSelf
-
- //----------------------------------------------------------------------------------------
- Boolean CStandardFlexTable::IsSortedBackwards() const
- //----------------------------------------------------------------------------------------
- {
- return mTableHeader->IsSortedBackwards();
- }
-
- //----------------------------------------------------------------------------------------
- PaneIDT CStandardFlexTable::GetSortedColumn() const
- //----------------------------------------------------------------------------------------
- {
- PaneIDT result;
- mTableHeader->GetSortedColumn(result);
- return result;
- }
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::SetRightmostVisibleColumn(UInt16 inLastDesiredColumn)
- //----------------------------------------------------------------------------------------
- {
- mTableHeader->SetRightmostVisibleColumn(inLastDesiredColumn);
- } // CStandardFlexTable::SetRightmostVisibleColumn
-
- #pragma mark -
- #if defined(QAP_BUILD)
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::QapGetListInfo(PQAPLISTINFO pInfo)
- //----------------------------------------------------------------------------------------
- {
- if (pInfo == nil)
- return;
-
- // get table size
- TableIndexT outRows, outCols;
- GetTableSize(outRows, outCols);
-
- // get range of cells that are within the frame
- Rect frame;
- CalcLocalFrameRect(frame);
- STableCell topLeftCell, botRightCell;
- FetchIntersectingCells(frame, topLeftCell, botRightCell);
-
- // fetch vertical scrollbar Macintosh control
- ControlHandle macVScroll = NULL;
- LScroller *myScroller = dynamic_cast<LScroller *>(GetSuperView());
- if (myScroller != NULL)
- {
- if (myScroller->GetVScrollbar() != NULL)
- macVScroll = myScroller->GetVScrollbar()->GetMacControl();
- }
-
- pInfo->itemCount = (short)outRows;
- pInfo->topIndex = topLeftCell.row;
- pInfo->itemHeight = GetRowHeight(0);
- pInfo->visibleCount = botRightCell.row - topLeftCell.row + 1;
- pInfo->vScroll = macVScroll;
- pInfo->isMultiSel = true;
- pInfo->isExtendSel = true;
- pInfo->hasText = true;
- }
-
-
- //----------------------------------------------------------------------------------------
- Ptr CStandardFlexTable::QapAddCellToBuf(Ptr pBuf, Ptr pLimit, const STableCell& sTblCell)
- //----------------------------------------------------------------------------------------
- {
- char str[cMaxMailFolderNameLength + 1];
- short len = 0;
-
- GetQapRowText(sTblCell.row, str, sizeof(str));
- len = strlen(str) + 1;
-
- if (pBuf + sizeof(short) + len >= pLimit)
- return NULL;
-
- *(unsigned short *)pBuf = sTblCell.row - 1;
- if (CellIsSelected(sTblCell))
- *(unsigned short *)pBuf |= 0x8000;
-
- pBuf += sizeof(short);
-
- strcpy(pBuf, str);
- pBuf += len;
-
- return pBuf;
- }
-
- //----------------------------------------------------------------------------------------
- void CStandardFlexTable::GetQapRowText(
- TableIndexT /*inRow*/,
- char* outText,
- UInt16 inMaxBufferLength) const
- // Calculate the text and (if ioRect is not passed in as null) a rectangle that fits it.
- // Return result indicates if any of the text is visible in the cell
- //----------------------------------------------------------------------------------------
- {
- if (outText && inMaxBufferLength > 0)
- *outText = '\0';
- } // CStandardFlexTable::GetQapRowText
-
- #endif //QAP_BUILD
-