2001-10-19 19:41:13 +00:00
|
|
|
|
#include "DataBrowser.h"
|
|
|
|
|
#include "ResourceObject.h"
|
|
|
|
|
#include "InspectorWindow.h"
|
|
|
|
|
#include "Errors.h"
|
|
|
|
|
#include "Utility.h" // for TypeToCFString() et cetera
|
|
|
|
|
|
|
|
|
|
extern globals g;
|
|
|
|
|
|
|
|
|
|
#if TARGET_API_MAC_CARBON // CarbonLib 1.1+ or Public Beta only
|
|
|
|
|
|
|
|
|
|
/*** INITALISE DATA BROWSER ***/
|
|
|
|
|
OSStatus FileWindow::InitDataBrowser( void )
|
|
|
|
|
{
|
|
|
|
|
OSStatus error = noErr;
|
|
|
|
|
|
|
|
|
|
// get the db control - compatable with both CarbonLib and nib based versions
|
|
|
|
|
ControlID id = { kDataBrowserSignature, 0 };
|
|
|
|
|
GetControlByID( window, &id, &dataBrowser );
|
|
|
|
|
|
|
|
|
|
// set control ref to FileWindow
|
|
|
|
|
SetControlReference( dataBrowser, (long) this );
|
|
|
|
|
|
|
|
|
|
// turn off frame and focus
|
|
|
|
|
Boolean frame = false;
|
|
|
|
|
SetControlData( dataBrowser, kControlNoPart, kControlDataBrowserIncludesFrameAndFocusTag, sizeof(Boolean), &frame );
|
|
|
|
|
|
|
|
|
|
#if !USE_NIBS
|
|
|
|
|
// add empty columns
|
|
|
|
|
AddDataBrowserColumn( dataBrowser, kDBNameColumn, 0 ); // save column order into prefs file: Get/SetDataBrowserUserState()
|
|
|
|
|
AddDataBrowserColumn( dataBrowser, kDBTypeColumn, 1 );
|
|
|
|
|
AddDataBrowserColumn( dataBrowser, kDBIDColumn, 2 );
|
|
|
|
|
AddDataBrowserColumn( dataBrowser, kDBSizeColumn, 3 );
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// add callbacks
|
|
|
|
|
DataBrowserCallbacks theCallbacks;
|
|
|
|
|
theCallbacks.version = kDataBrowserLatestCallbacks;
|
|
|
|
|
InitDataBrowserCallbacks( &theCallbacks );
|
|
|
|
|
theCallbacks.u.v1.itemDataCallback = NewDataBrowserItemDataUPP( DataBrowserItemData );
|
|
|
|
|
theCallbacks.u.v1.itemCompareCallback = NewDataBrowserItemCompareUPP( SortDataBrowser );
|
|
|
|
|
theCallbacks.u.v1.itemNotificationCallback = NewDataBrowserItemNotificationUPP( DataBrowserMessage );
|
|
|
|
|
theCallbacks.u.v1.addDragItemCallback = NewDataBrowserAddDragItemUPP( DataBrowserAddDragItem );
|
|
|
|
|
theCallbacks.u.v1.acceptDragCallback = NewDataBrowserAcceptDragUPP( DataBrowserAcceptDrag );
|
|
|
|
|
theCallbacks.u.v1.receiveDragCallback = NewDataBrowserReceiveDragUPP( DataBrowserReceiveDrag );
|
|
|
|
|
theCallbacks.u.v1.postProcessDragCallback = NewDataBrowserPostProcessDragUPP( DataBrowserPostProcessDrag );
|
|
|
|
|
SetDataBrowserCallbacks( dataBrowser, &theCallbacks );
|
|
|
|
|
|
|
|
|
|
// setup rest of browser, inc. adding all resources
|
|
|
|
|
DataBrowserItemID item;
|
|
|
|
|
for( UInt32 n = 1; n <= numResources; n++ )
|
|
|
|
|
{
|
|
|
|
|
item = n;
|
|
|
|
|
error = AddDataBrowserItems( dataBrowser, kDataBrowserNoItem, 1, &item, kDataBrowserItemNoProperty );
|
|
|
|
|
if( error ) DebugError( "\pError occoured adding resource to data browser." );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// add data fork if present
|
|
|
|
|
if( resourceMap->RepresentsDataFork() ) // requires data fork to be first in chain
|
|
|
|
|
{
|
|
|
|
|
item = kDataBrowserDataForkItem; // curently 0xFFFFFFFF
|
|
|
|
|
error = AddDataBrowserItems( dataBrowser, kDataBrowserNoItem, 1, &item, kDataBrowserItemNoProperty );
|
|
|
|
|
if( error ) DebugError( "\pError occoured adding data fork to data browser." );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SetDataBrowserSortProperty( dataBrowser, kDBTypeColumn );
|
|
|
|
|
SetDataBrowserTableViewRowHeight( dataBrowser, 16 +2 );
|
|
|
|
|
SetDataBrowserListViewDisclosureColumn( dataBrowser, kDBNameColumn, true );
|
|
|
|
|
|
|
|
|
|
// set up drag tracking
|
|
|
|
|
SetControlDragTrackingEnabled( dataBrowser, true );
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** ADD DATA BROWSER COLUMN ***/
|
|
|
|
|
void AddDataBrowserColumn( ControlRef browser, DataBrowserPropertyID column, UInt16 position )
|
|
|
|
|
{
|
|
|
|
|
DataBrowserListViewColumnDesc columnDesc;
|
|
|
|
|
switch( column )
|
|
|
|
|
{
|
|
|
|
|
case kDataBrowserNameColumn:
|
|
|
|
|
columnDesc.propertyDesc.propertyID = kDataBrowserNameColumn;
|
|
|
|
|
columnDesc.propertyDesc.propertyType = kDataBrowserIconAndTextType;
|
|
|
|
|
columnDesc.propertyDesc.propertyFlags = kDataBrowserListViewDefaultColumnFlags | kDataBrowserListViewSelectionColumn;
|
|
|
|
|
|
|
|
|
|
columnDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
|
|
|
|
|
columnDesc.headerBtnDesc.minimumWidth = 150;
|
|
|
|
|
columnDesc.headerBtnDesc.maximumWidth = 250;
|
|
|
|
|
columnDesc.headerBtnDesc.titleOffset = 0;
|
|
|
|
|
columnDesc.headerBtnDesc.titleString = CFSTR("Resource Name"); // these should be resources for ease of localisation
|
|
|
|
|
columnDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
|
|
|
|
|
columnDesc.headerBtnDesc.btnFontStyle.font = kControlFontViewSystemFont;
|
|
|
|
|
columnDesc.headerBtnDesc.btnFontStyle.just = teFlushDefault;
|
|
|
|
|
columnDesc.headerBtnDesc.btnFontStyle.style = normal;
|
|
|
|
|
|
|
|
|
|
columnDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case kDataBrowserTypeColumn:
|
|
|
|
|
columnDesc.propertyDesc.propertyID = kDataBrowserTypeColumn;
|
|
|
|
|
columnDesc.propertyDesc.propertyType = kDataBrowserTextType;
|
|
|
|
|
columnDesc.propertyDesc.propertyFlags = kDataBrowserListViewDefaultColumnFlags;
|
|
|
|
|
|
|
|
|
|
columnDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
|
|
|
|
|
columnDesc.headerBtnDesc.minimumWidth = (g.systemVersion < kMacOSX)? 56:72;
|
|
|
|
|
columnDesc.headerBtnDesc.maximumWidth = columnDesc.headerBtnDesc.minimumWidth;
|
|
|
|
|
columnDesc.headerBtnDesc.titleOffset = 0;
|
|
|
|
|
columnDesc.headerBtnDesc.titleString = CFSTR("Type"); // these should be resources for ease of localisation
|
|
|
|
|
columnDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
|
|
|
|
|
|
|
|
|
|
columnDesc.headerBtnDesc.btnFontStyle.font = kControlFontViewSystemFont;
|
|
|
|
|
columnDesc.headerBtnDesc.btnFontStyle.just = teFlushRight;
|
|
|
|
|
columnDesc.headerBtnDesc.btnFontStyle.style = normal;
|
|
|
|
|
columnDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case kDataBrowserIDColumn:
|
|
|
|
|
columnDesc.propertyDesc.propertyID = kDataBrowserIDColumn;
|
|
|
|
|
columnDesc.propertyDesc.propertyType = kDataBrowserTextType;
|
|
|
|
|
columnDesc.propertyDesc.propertyFlags = kDataBrowserListViewDefaultColumnFlags;
|
|
|
|
|
|
|
|
|
|
columnDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
|
|
|
|
|
columnDesc.headerBtnDesc.minimumWidth = (g.systemVersion < kMacOSX)? 56:72;
|
|
|
|
|
columnDesc.headerBtnDesc.maximumWidth = columnDesc.headerBtnDesc.minimumWidth;
|
|
|
|
|
columnDesc.headerBtnDesc.titleOffset = 0;
|
|
|
|
|
columnDesc.headerBtnDesc.titleString = CFSTR("ID"); // these should be resources for ease of localisation
|
|
|
|
|
columnDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
|
|
|
|
|
|
|
|
|
|
columnDesc.headerBtnDesc.btnFontStyle.font = kControlFontViewSystemFont;
|
|
|
|
|
columnDesc.headerBtnDesc.btnFontStyle.just = teFlushRight;
|
|
|
|
|
columnDesc.headerBtnDesc.btnFontStyle.style = normal;
|
|
|
|
|
columnDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case kDataBrowserSizeColumn:
|
|
|
|
|
columnDesc.propertyDesc.propertyID = kDataBrowserSizeColumn;
|
|
|
|
|
columnDesc.propertyDesc.propertyType = kDataBrowserTextType;
|
|
|
|
|
columnDesc.propertyDesc.propertyFlags = kDataBrowserListViewDefaultColumnFlags;
|
|
|
|
|
|
|
|
|
|
columnDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
|
|
|
|
|
columnDesc.headerBtnDesc.minimumWidth = (g.systemVersion < kMacOSX)? 56:72;
|
|
|
|
|
columnDesc.headerBtnDesc.maximumWidth = columnDesc.headerBtnDesc.minimumWidth;
|
|
|
|
|
columnDesc.headerBtnDesc.titleOffset = 0;
|
|
|
|
|
columnDesc.headerBtnDesc.titleString = CFSTR("Size"); // these should be resources for ease of localisation
|
|
|
|
|
columnDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing;
|
|
|
|
|
|
|
|
|
|
columnDesc.headerBtnDesc.btnFontStyle.font = kControlFontViewSystemFont;
|
|
|
|
|
columnDesc.headerBtnDesc.btnFontStyle.just = teFlushRight;
|
|
|
|
|
columnDesc.headerBtnDesc.btnFontStyle.style = normal;
|
|
|
|
|
columnDesc.headerBtnDesc.btnContentInfo.contentType = kControlContentTextOnly;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// create column and make respond to sorting
|
|
|
|
|
AddDataBrowserListViewColumn( browser, &columnDesc, position );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** HANDLE ITEM DATA I/O ***/
|
|
|
|
|
pascal OSStatus DataBrowserItemData( ControlRef browser, DataBrowserItemID itemID, DataBrowserPropertyID property, DataBrowserItemDataRef itemData, Boolean setValue )
|
|
|
|
|
{
|
|
|
|
|
#pragma unused( setValue )
|
|
|
|
|
OSStatus result = noErr;
|
|
|
|
|
if( setValue ) return result;
|
|
|
|
|
FileWindowPtr file = (FileWindowPtr) GetControlReference( browser );
|
|
|
|
|
ResourceObjectPtr resource = file->GetResource( itemID );
|
|
|
|
|
|
|
|
|
|
if( resource == null )
|
|
|
|
|
DebugError( "\pNull resource returned within DataBrowserItemData()" );
|
|
|
|
|
|
|
|
|
|
switch( property )
|
|
|
|
|
{
|
|
|
|
|
case kDataBrowserItemIsEditableProperty:
|
|
|
|
|
if( true ) // should item be editable? (i.e. is it a name, ID or type?)
|
|
|
|
|
SetDataBrowserItemDataBooleanValue( itemData, true );
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case kDataBrowserItemIsContainerProperty:
|
|
|
|
|
if( resource->Type() == kIconFamilyType )
|
|
|
|
|
SetDataBrowserItemDataBooleanValue( itemData, true );
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case kDBNameColumn:
|
|
|
|
|
{ // icon <20> no resource for the icon!
|
|
|
|
|
IconRef theIcon = null;
|
|
|
|
|
#if !USE_NIBS
|
|
|
|
|
if( itemID != kDataBrowserDataForkItem )
|
|
|
|
|
{
|
|
|
|
|
Str255 iconString;
|
|
|
|
|
TypeToPString( resource->Type(), iconString );
|
|
|
|
|
IconFamilyHandle iconFamily = (IconFamilyHandle) Get1NamedResource( kIconFamilyType, iconString );
|
|
|
|
|
if( iconFamily )
|
|
|
|
|
{
|
|
|
|
|
RegisterIconRefFromIconFamily( kResKnifeCreator, resource->Type(), iconFamily, &theIcon );
|
|
|
|
|
ReleaseResource( (Handle) iconFamily ); // when dragging a rect this call caused other columns not to be displayed !?!
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
if( theIcon == null )
|
|
|
|
|
GetIconRef( kOnSystemDisk, kResKnifeCreator, kResourceFileType, &theIcon );
|
|
|
|
|
SetDataBrowserItemDataIcon( itemData, theIcon );
|
|
|
|
|
ReleaseIconRef( theIcon );
|
|
|
|
|
|
|
|
|
|
// resource name
|
|
|
|
|
CFStringRef nameCFStr;
|
|
|
|
|
if( itemID == kDataBrowserDataForkItem )
|
|
|
|
|
{
|
|
|
|
|
#if USE_NIBS // OS 9 version is not bundled at the present time
|
|
|
|
|
nameCFStr = CFBundleCopyLocalizedString( CFBundleGetMainBundle(), CFSTR("Data Fork"), null, null ); // bug: doesn't actually get localized string!
|
|
|
|
|
#else
|
|
|
|
|
nameCFStr = CFSTR("Data Fork");
|
|
|
|
|
#endif
|
|
|
|
|
SetDataBrowserItemDataRGBColor( itemData, &g.textColour );
|
|
|
|
|
}
|
|
|
|
|
else if( *resource->Name() == 0x00 )
|
|
|
|
|
{
|
|
|
|
|
#if USE_NIBS // OS 9 version is not bundled at the present time
|
|
|
|
|
nameCFStr = CFBundleCopyLocalizedString( CFBundleGetMainBundle(), CFSTR("Untitled Resource"), null, null ); // bug: doesn't actually get localized string!
|
|
|
|
|
#else
|
|
|
|
|
nameCFStr = CFSTR("Untitled Resource");
|
|
|
|
|
#endif
|
|
|
|
|
SetDataBrowserItemDataRGBColor( itemData, &g.textColour );
|
|
|
|
|
}
|
|
|
|
|
else nameCFStr = CFStringCreateWithPascalString( CFAllocatorGetDefault(), resource->Name(), kCFStringEncodingMacRoman );
|
|
|
|
|
SetDataBrowserItemDataText( itemData, nameCFStr );
|
|
|
|
|
#if USE_NIBS // OS 9 uses CFSTR()
|
|
|
|
|
CFRelease( nameCFStr );
|
|
|
|
|
#endif
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
case kDBTypeColumn:
|
|
|
|
|
{ // resource type
|
|
|
|
|
if( itemID == kDataBrowserDataForkItem )
|
|
|
|
|
{
|
|
|
|
|
SetDataBrowserItemDataText( itemData, CFSTR("-") );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CFStringRef typeString;
|
|
|
|
|
TypeToCFString( resource->Type(), &typeString );
|
|
|
|
|
SetDataBrowserItemDataText( itemData, typeString );
|
|
|
|
|
CFRelease( typeString );
|
|
|
|
|
}
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
case kDBIDColumn:
|
|
|
|
|
{ // resource ID
|
|
|
|
|
if( itemID == kDataBrowserDataForkItem )
|
|
|
|
|
{
|
|
|
|
|
SetDataBrowserItemDataText( itemData, CFSTR("-") );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
SInt16 id = resource->ID();
|
|
|
|
|
Str255 idPString;
|
|
|
|
|
NumToString( id, (StringPtr) &idPString );
|
|
|
|
|
CFStringRef idString = CFStringCreateWithPascalString( CFAllocatorGetDefault(), idPString, kCFStringEncodingMacRoman );
|
|
|
|
|
SetDataBrowserItemDataText( itemData, idString );
|
|
|
|
|
CFRelease( idString );
|
|
|
|
|
}
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
case kDBSizeColumn:
|
|
|
|
|
{ SInt32 size = resource->Size();
|
|
|
|
|
UInt8 power = 0, remainder = 0;
|
|
|
|
|
Str255 sizePString, frac;
|
|
|
|
|
while( size >= 1024 && power <= 30 )
|
|
|
|
|
{
|
|
|
|
|
power += 10; // 10 == KB, 20 == MB, 30 == GB
|
|
|
|
|
remainder = (UInt8) ((size % 1024) / 102.4); // 102.4 gives one dp, 10.24 would give two dps, 1.024 would give three dps
|
|
|
|
|
size /= 1024;
|
|
|
|
|
}
|
|
|
|
|
NumToString( (long) size, (StringPtr) &sizePString );
|
|
|
|
|
NumToString( remainder, (StringPtr) &frac );
|
|
|
|
|
if( power ) // some division has occoured
|
|
|
|
|
{
|
|
|
|
|
if( sizePString[0] < 3 && remainder > 0 )
|
|
|
|
|
{
|
|
|
|
|
AppendPString( (unsigned char *) &sizePString, "\p." ); // bug: should be a comma on european systems
|
|
|
|
|
AppendPString( (unsigned char *) &sizePString, (unsigned char *) &frac );
|
|
|
|
|
}
|
|
|
|
|
if( power == 10 ) AppendPString( (unsigned char *) &sizePString, "\p KB" );
|
|
|
|
|
else if( power == 20 ) AppendPString( (unsigned char *) &sizePString, "\p MB" );
|
|
|
|
|
else if( power == 30 ) AppendPString( (unsigned char *) &sizePString, "\p GB" ); // everything bigger will be given in GB
|
|
|
|
|
}
|
|
|
|
|
CFStringRef sizeString = CFStringCreateWithPascalString( CFAllocatorGetDefault(), sizePString, kCFStringEncodingMacRoman );
|
|
|
|
|
SetDataBrowserItemDataText( itemData, sizeString );
|
|
|
|
|
CFRelease( sizeString );
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
result = errDataBrowserPropertyNotSupported;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** SORT DATA BROWSER ***/
|
|
|
|
|
pascal Boolean SortDataBrowser( ControlRef browser, DataBrowserItemID itemOne, DataBrowserItemID itemTwo, DataBrowserPropertyID sortProperty )
|
|
|
|
|
{
|
|
|
|
|
short result;
|
|
|
|
|
Str255 typeOne, typeTwo;
|
|
|
|
|
StringPtr nameOne, nameTwo;
|
|
|
|
|
FileWindowPtr file = (FileWindowPtr) GetControlReference( browser );
|
|
|
|
|
|
|
|
|
|
// send data fork to top regardless of property
|
|
|
|
|
if( itemOne == kDataBrowserDataForkItem ) return true;
|
|
|
|
|
if( itemTwo == kDataBrowserDataForkItem ) return false;
|
|
|
|
|
|
|
|
|
|
// validate data browser item IDs
|
|
|
|
|
if( itemOne <= kDataBrowserNoItem || itemOne > file->GetResourceCount() )
|
|
|
|
|
{
|
|
|
|
|
DebugError( "\psort item one was invalid" );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if( itemTwo <= kDataBrowserNoItem || itemTwo > file->GetResourceCount() )
|
|
|
|
|
{
|
|
|
|
|
DebugError( "\psort item two was invalid" );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// get resource corrisponding to item ID
|
|
|
|
|
ResourceObjectPtr resourceOne = file->GetResource( itemOne );
|
|
|
|
|
ResourceObjectPtr resourceTwo = file->GetResource( itemTwo );
|
|
|
|
|
if( resourceOne == null || resourceTwo == null )
|
|
|
|
|
DebugError( "\pNull resource returned within SortDataBrowser()" );
|
|
|
|
|
|
|
|
|
|
// sort resources according to property user has selected
|
|
|
|
|
switch( sortProperty )
|
|
|
|
|
{
|
|
|
|
|
case kDBNameColumn:
|
|
|
|
|
nameOne = resourceOne->Name();
|
|
|
|
|
nameTwo = resourceTwo->Name();
|
|
|
|
|
result = CompareString( nameOne, nameTwo, null );
|
|
|
|
|
return result < 0;
|
|
|
|
|
|
|
|
|
|
case kDBTypeColumn:
|
|
|
|
|
TypeToPString( resourceOne->Type(), typeOne );
|
|
|
|
|
TypeToPString( resourceTwo->Type(), typeTwo );
|
|
|
|
|
result = CompareString( typeOne, typeTwo, null );
|
|
|
|
|
return result < 0;
|
|
|
|
|
|
|
|
|
|
case kDBIDColumn:
|
|
|
|
|
return resourceOne->ID() < resourceTwo->ID();
|
|
|
|
|
|
|
|
|
|
case kDBSizeColumn:
|
|
|
|
|
return resourceOne->Size() < resourceTwo->Size();
|
|
|
|
|
|
|
|
|
|
case kDataBrowserItemNoProperty: // this is valid when first constructing the data browser
|
|
|
|
|
// DebugError( "\pkDataBrowserItemNoProperty passed to sort function" );
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
DebugError( "\pInvalid sort property given" );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** DATA BROWSER MESSAGE ***/
|
2002-02-02 11:31:28 +00:00
|
|
|
|
pascal void DataBrowserMessage( ControlRef browser, DataBrowserItemID itemID, DataBrowserItemNotification message/*, DataBrowserItemDataRef itemData*/ )
|
2001-10-19 19:41:13 +00:00
|
|
|
|
{
|
2002-02-02 11:31:28 +00:00
|
|
|
|
#pragma unused( itemID/*, itemData*/ )
|
2001-10-19 19:41:13 +00:00
|
|
|
|
FileWindowPtr file = (FileWindowPtr) GetControlReference( browser );
|
|
|
|
|
switch( message )
|
|
|
|
|
{
|
|
|
|
|
case kDataBrowserItemDoubleClicked:
|
|
|
|
|
{ KeyMap theKeys;
|
|
|
|
|
Boolean shiftKeyDown = false,
|
|
|
|
|
optionKeyDown = false,
|
|
|
|
|
controlKeyDown = false;
|
|
|
|
|
GetKeys( theKeys );
|
|
|
|
|
if( theKeys[1] & (shiftKey >> shiftKeyBit) ) shiftKeyDown = true;
|
|
|
|
|
if( theKeys[1] & (optionKey >> shiftKeyBit) ) optionKeyDown = true;
|
|
|
|
|
if( theKeys[1] & (controlKey >> shiftKeyBit) ) controlKeyDown = true;
|
|
|
|
|
if( optionKeyDown ) file->OpenResource( itemID, kMenuCommandOpenHex );
|
|
|
|
|
else if( controlKeyDown ) file->OpenResource( itemID, kMenuCommandOpenTemplate );
|
|
|
|
|
else file->OpenResource( itemID, kMenuCommandOpenDefault );
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
case kDataBrowserItemSelected:
|
|
|
|
|
case kDataBrowserItemDeselected:
|
|
|
|
|
case kDataBrowserSelectionSetChanged:
|
|
|
|
|
// file->SetHeaderText();
|
|
|
|
|
if( g.inspector )
|
|
|
|
|
g.inspector->Update();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case kDataBrowserEditStarted:
|
|
|
|
|
case kDataBrowserEditStopped:
|
|
|
|
|
case kDataBrowserItemAdded:
|
|
|
|
|
case kDataBrowserItemRemoved:
|
|
|
|
|
case kDataBrowserContainerOpened:
|
|
|
|
|
case kDataBrowserContainerClosing:
|
|
|
|
|
case kDataBrowserContainerClosed:
|
|
|
|
|
case kDataBrowserContainerSorting:
|
|
|
|
|
case kDataBrowserContainerSorted:
|
|
|
|
|
case kDataBrowserTargetChanged:
|
|
|
|
|
case kDataBrowserUserStateChanged:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** ADD DRAG ITEM ***/
|
|
|
|
|
pascal Boolean DataBrowserAddDragItem( ControlRef browser, DragRef drag, DataBrowserItemID item, DragItemRef *itemRef )
|
|
|
|
|
{
|
|
|
|
|
#pragma unused( item )
|
|
|
|
|
|
|
|
|
|
// if drag already has phfs flavour, don't add another
|
|
|
|
|
UInt16 numFlavours;
|
|
|
|
|
CountDragItemFlavors( drag, *itemRef, &numFlavours );
|
|
|
|
|
if( numFlavours > 0 ) return true;
|
|
|
|
|
|
|
|
|
|
// add 'create file' callback
|
|
|
|
|
if( itemRef ) *itemRef = ItemReference( item );
|
|
|
|
|
FlavorFlags flags = flavorNotSaved;
|
|
|
|
|
DragSendDataUPP sendData = NewDragSendDataUPP( SendPromisedFile );
|
|
|
|
|
SetDragSendProc( drag, sendData, browser );
|
|
|
|
|
|
|
|
|
|
// setup imaginary file
|
|
|
|
|
PromiseHFSFlavor promisedFile;
|
|
|
|
|
promisedFile.fileType = kResourceFileType;
|
|
|
|
|
promisedFile.fileCreator = kResKnifeCreator;
|
|
|
|
|
promisedFile.fdFlags = null; // finder flags
|
|
|
|
|
promisedFile.promisedFlavor = kResourceTransferType;
|
|
|
|
|
|
|
|
|
|
// add phfs and TEXT flavours
|
|
|
|
|
AddDragItemFlavor( drag, *itemRef, flavorTypePromiseHFS, &promisedFile, sizeof(PromiseHFSFlavor), flags );
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
/* OSErr error = noErr;
|
|
|
|
|
DragReference theDragRef;
|
|
|
|
|
ItemReference theItemRef = 1;
|
|
|
|
|
|
|
|
|
|
// create the drag reference
|
|
|
|
|
NewDrag( &theDragRef );
|
|
|
|
|
if( MemError() ) return;
|
|
|
|
|
SetDragSendProc( theDragRef, sendProc, this );
|
|
|
|
|
|
|
|
|
|
RgnHandle dragRgn = NewRgn(),
|
|
|
|
|
subtractRgn = NewRgn();
|
|
|
|
|
|
|
|
|
|
// get region of dragged items, using translucent dragging where possible
|
|
|
|
|
Point dragOffset;
|
|
|
|
|
GWorldPtr imageGWorld = nil;
|
|
|
|
|
|
|
|
|
|
resData = GetResourceData( ownerWindow );
|
|
|
|
|
while( resData )
|
|
|
|
|
{
|
|
|
|
|
if( r.selected )
|
|
|
|
|
UnionRgn( r.nameIconRgn, dragRgn, dragRgn ); // add new region to rest of drag region
|
|
|
|
|
resData = r.next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( g.translucentDrag )
|
|
|
|
|
{
|
|
|
|
|
short resCounter = 0;
|
|
|
|
|
SetPt( &dragOffset, 0, kFileHeaderHeight );
|
|
|
|
|
resData = GetResourceData( ownerWindow );
|
|
|
|
|
|
|
|
|
|
while( !r.selected )
|
|
|
|
|
{
|
|
|
|
|
resCounter++;
|
|
|
|
|
resData = r.next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
error = CreateDragImage( resData, &imageGWorld );
|
|
|
|
|
if( !error )
|
|
|
|
|
{
|
|
|
|
|
// init mask region
|
|
|
|
|
RgnHandle maskRgn = NewRgn();
|
|
|
|
|
CopyRgn( r.nameIconRgn, maskRgn );
|
|
|
|
|
OffsetRgn( maskRgn, 0, -kFileLineHeight * resCounter );
|
|
|
|
|
|
|
|
|
|
// init rects
|
|
|
|
|
Rect sourceRect, destRect;
|
|
|
|
|
SetRect( &sourceRect, 0, 0, g.nameColumnWidth, kFileLineHeight );
|
|
|
|
|
SetRect( &destRect, 0, 0, g.nameColumnWidth, kFileLineHeight );
|
|
|
|
|
OffsetRect( &destRect, 0, kFileHeaderHeight );
|
|
|
|
|
|
|
|
|
|
// init GWorld
|
|
|
|
|
PixMapHandle imagePixMap = GetGWorldPixMap( imageGWorld );
|
|
|
|
|
DragImageFlags imageFlags = kDragStandardTranslucency | kDragRegionAndImage;
|
|
|
|
|
error = SetDragImage( theDragRef, imagePixMap, maskRgn, dragOffset, imageFlags );
|
|
|
|
|
CopyBits( &GrafPtr( imageGWorld )->portBits, &GrafPtr( ownerWindow )->portBits, &sourceRect, &destRect, srcCopy, maskRgn );
|
|
|
|
|
if( error ) SysBeep(0);
|
|
|
|
|
DisposeGWorld( imageGWorld );
|
|
|
|
|
DisposeRgn( maskRgn );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// subtract middles from icons
|
|
|
|
|
MakeGlobal( ownerWindow, NewPoint(), &globalMouse );
|
|
|
|
|
CopyRgn( dragRgn, subtractRgn ); // duplicate region
|
|
|
|
|
InsetRgn( subtractRgn, 2, 2 ); // inset it by 2 pixels
|
|
|
|
|
DiffRgn( dragRgn, subtractRgn, dragRgn ); // subtract subRgn from addRgn, save in nameIconRgn
|
|
|
|
|
OffsetRgn( dragRgn, globalMouse.h, globalMouse.v ); // change drag region to global coords
|
|
|
|
|
|
|
|
|
|
// add flavour data to drag
|
|
|
|
|
error = AddDragItemFlavor( theDragRef, theItemRef, flavorTypePromiseHFS, &theFile, sizeof(PromiseHFSFlavor), theFlags );
|
|
|
|
|
error = AddDragItemFlavor( theDragRef, theItemRef, kResType, nil, 0, theFlags );
|
|
|
|
|
|
|
|
|
|
// track the drag, then clean up
|
|
|
|
|
error = TrackDrag( theDragRef, theEvent, dragRgn );
|
|
|
|
|
if( theDragRef ) DisposeDrag( theDragRef );
|
|
|
|
|
if( subtractRgn ) DisposeRgn( subtractRgn );
|
|
|
|
|
if( dragRgn ) DisposeRgn( dragRgn );
|
|
|
|
|
return error == noErr; */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** ACCEPT DRAG ***/
|
|
|
|
|
pascal Boolean DataBrowserAcceptDrag( ControlRef browser, DragRef drag, DataBrowserItemID item )
|
|
|
|
|
{
|
|
|
|
|
#pragma unused( browser, drag, item )
|
|
|
|
|
/* OSStatus error = noErr;
|
|
|
|
|
Size size = null;
|
|
|
|
|
DragItemRef dragItem = 1;
|
|
|
|
|
UInt16 index, totalItems;
|
|
|
|
|
|
|
|
|
|
CountDragItems( theDrag, &totalItems );
|
|
|
|
|
for( index = 1; index <= totalItems; index++ )
|
|
|
|
|
{
|
|
|
|
|
GetDragItemReferenceNumber( theDrag, index, &dragItem );
|
|
|
|
|
error = GetFlavourDataSize( theDrag, dragItem, kDragFlavourTypeResource, &size );
|
|
|
|
|
// if( error ) return false;
|
|
|
|
|
if( !error ) index = totalItems; // stop when valid item is reached
|
|
|
|
|
}
|
|
|
|
|
return size >= sizeof(ResTransferDesc);
|
|
|
|
|
*/ return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** RECEIVE DRAG ***/
|
|
|
|
|
pascal Boolean DataBrowserReceiveDrag( ControlRef browser, DragRef drag, DataBrowserItemID item )
|
|
|
|
|
{
|
|
|
|
|
#pragma unused( browser, drag, item )
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** POST<53>PROCESS DRAG ***/
|
|
|
|
|
pascal void DataBrowserPostProcessDrag( ControlRef browser, DragRef drag, OSStatus trackDragResult )
|
|
|
|
|
{
|
|
|
|
|
#pragma unused( browser, drag, trackDragResult )
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** SEND PROMISED FILE ***/
|
|
|
|
|
pascal OSErr SendPromisedFile( FlavorType type, void *dragSendRefCon, ItemReference item, DragReference drag )
|
|
|
|
|
{
|
|
|
|
|
OSErr error = noErr;
|
|
|
|
|
ControlRef browser = (ControlRef) dragSendRefCon;
|
|
|
|
|
FSSpec fileSpec;
|
|
|
|
|
Str255 fileName;
|
|
|
|
|
short vRefNum;
|
|
|
|
|
long dirID;
|
|
|
|
|
|
|
|
|
|
if( type != flavorTypePromiseHFS ) return badDragFlavorErr;
|
|
|
|
|
|
|
|
|
|
// create file
|
|
|
|
|
GetIndString( fileName, kFileNameStrings, kStringNewDragFileName );
|
|
|
|
|
FindFolder( kOnSystemDisk, /*kTemporaryFolderType*/kDesktopFolderType, kCreateFolder, &vRefNum, &dirID );
|
|
|
|
|
FSMakeFSSpec( vRefNum, dirID, fileName, &fileSpec );
|
|
|
|
|
FSpCreateResFile( &fileSpec, kResKnifeCreator, kResourceFileType, smSystemScript );
|
|
|
|
|
|
|
|
|
|
// save resources into file
|
|
|
|
|
DragData clientData; // waiting for jim to add a ControlRef to DataBrowserItemUPP; bug: jim no longer works at Apple
|
|
|
|
|
clientData.browser = browser;
|
|
|
|
|
clientData.fileSpec = &fileSpec;
|
|
|
|
|
DataBrowserItemUPP callback = NewDataBrowserItemUPP( AddResourceToDragFile );
|
|
|
|
|
/* control, container, recurse, state, callback, clientData */
|
|
|
|
|
ForEachDataBrowserItem( browser, kDataBrowserNoItem, true, kDataBrowserItemIsSelected, callback, &clientData );
|
|
|
|
|
|
|
|
|
|
// save resources in file
|
|
|
|
|
/* ResourceObjectPtr resource = GetResourceData( file->window );
|
|
|
|
|
short refNum = FSpOpenResFile( &fileSpec, fsRdWrPerm );
|
|
|
|
|
UseResFile( refNum );
|
|
|
|
|
while( resData )
|
|
|
|
|
{
|
|
|
|
|
if( resource->Selected() )
|
|
|
|
|
AddResource( resource->Data(), resource->Type(), resource->ID(), resource->Name() );
|
|
|
|
|
resData = resource->Next();
|
|
|
|
|
}
|
|
|
|
|
CloseResFile( refNum );
|
|
|
|
|
UseResFile( g.appResFile );
|
|
|
|
|
*/
|
|
|
|
|
error = SetDragItemFlavorData( drag, item, type, &fileSpec, sizeof(FSSpec), 0 );
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** ADD RESOURCE TO DRAG FILE ***/
|
|
|
|
|
pascal void AddResourceToDragFile( DataBrowserItemID item, DataBrowserItemState state, void *clientData )
|
|
|
|
|
{
|
|
|
|
|
#pragma unused( state )
|
|
|
|
|
// FSSpecPtr fileSpec = (FSSpecPtr) clientData;
|
|
|
|
|
WindowRef window = GetControlOwner( ((DragDataPtr) clientData)->browser );
|
|
|
|
|
FileWindowPtr file = (FileWindowPtr) GetWindowRefCon( window );
|
|
|
|
|
ResourceObjectPtr resource = file->GetResource( item );
|
|
|
|
|
|
|
|
|
|
// add resource to file
|
|
|
|
|
short oldFile = CurResFile();
|
|
|
|
|
short refNum = FSpOpenResFile( ((DragDataPtr) clientData)->fileSpec, fsRdWrPerm );
|
|
|
|
|
UseResFile( refNum );
|
|
|
|
|
AddResource( resource->Data(), resource->Type(), resource->ID(), resource->Name() );
|
|
|
|
|
if( ResError() == addResFailed )
|
|
|
|
|
{
|
|
|
|
|
DisplayError( "\pDrag Partially Failed", "\pCould not add a resource to file." );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
SetResAttrs( resource->Data(), resource->Attributes() );
|
|
|
|
|
ChangedResource( resource->Data() );
|
|
|
|
|
|
|
|
|
|
// clean up & move on
|
|
|
|
|
DetachResource( resource->Data() );
|
|
|
|
|
}
|
|
|
|
|
CloseResFile( refNum );
|
|
|
|
|
UseResFile( oldFile );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
|
|
/*********************/
|
|
|
|
|
/* FAKE DATA BROWSER */
|
|
|
|
|
/*********************/
|
|
|
|
|
|
|
|
|
|
/*** CLEAR SELECTION ***/
|
|
|
|
|
OSStatus FileWindow::ClearSelection( void )
|
|
|
|
|
{
|
|
|
|
|
ResourceObjectPtr resource = resourceMap;
|
|
|
|
|
while( resource )
|
|
|
|
|
{
|
|
|
|
|
resource->Select( false );
|
|
|
|
|
resource = resource->Next();
|
|
|
|
|
}
|
|
|
|
|
return noErr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|