forked from quicksilver/Plugins
-
Notifications
You must be signed in to change notification settings - Fork 1
/
CFDictArray.cp
executable file
·378 lines (318 loc) · 10.3 KB
/
CFDictArray.cp
1
//**************************************************************************************// Filename: CFDictArray.cp// Part of Contextual Menu Workshop by Abracode Inc.// http://free.abracode.com/cmworkshop/// Copyright © 2002-2003 Abracode, Inc. All rights reserved.//// Description: CFArray-based list of CFDictionaryRefs// Design goals:// - not to throw// - load and save to preferences file via CFPreferences// - the object does own the array and deletes it// - the dictionaries in array are assumed to be immutable// but if you want to change individual keys in a dictionary at given index// you need to call ReplaceDictionaryWithMutableCopyAt()////**************************************************************************************// Revision History:// Monday, August 19, 2002 - Original//**************************************************************************************#include "CFDictArray.h"#include "CFObjDel.h"//#include "AMacHandle.h"#include "CMUtils.h"#include "CFAliasArray.h"#include "ACFNumber.h"CFDictArray::CFDictArray(void){ mArray = ::CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks ); //mArray may return NULL, we do not throw, //but all functions in this class must be prepared for NULL and check for it}CFDictArray::CFDictArray(CFStringRef inKey, CFStringRef inPrefsIdentifier) : mArray(NULL){ LoadArrayFromPrefs(inKey, inPrefsIdentifier);}CFDictArray::CFDictArray(CFMutableArrayRef inArray, bool inDoRetain) : mArray(inArray){ if( (mArray != NULL) && (inDoRetain) ) ::CFRetain(inArray);}CFDictArray::CFDictArray(const CFDictArray& inArray){ mArray = ::CFArrayCreateMutableCopy ( kCFAllocatorDefault, 0, inArray.mArray );}CFDictArray::~CFDictArray(void){ if(mArray != NULL) { ::CFRelease(mArray); mArray = NULL; }}CFDictArray&CFDictArray::operator=(const CFDictArray& inArray){ if ( this != &inArray ) { ::CFRelease(mArray); mArray = ::CFArrayCreateMutableCopy ( kCFAllocatorDefault, 0, inArray.mArray ); } return *this;}CFIndexCFDictArray::GetCount() const{ if(mArray == NULL) return 0; return ::CFArrayGetCount(mArray);}voidCFDictArray::AddItem(CFDictionaryRef inItem){ if( (mArray == NULL) || (inItem == NULL) ) return; ::CFArrayAppendValue( mArray, (const void *)inItem );//the dict is retained}voidCFDictArray::InsertItemAt(CFDictionaryRef inItem, CFIndex inIndex){ if( (mArray == NULL) || (inItem == NULL) ) return; ::CFArrayInsertValueAtIndex(mArray, inIndex, (const void *)inItem);//the dict is retained}//zero-based indexvoidCFDictArray::RemoveItemAt(CFIndex inIndex){ if(mArray == NULL) return; ::CFArrayRemoveValueAtIndex( mArray, inIndex );}voidCFDictArray::RemoveAllItems(){ if(mArray == NULL) return; ::CFArrayRemoveAllValues(mArray);}CFIndexCFDictArray::MoveOneItem(CFIndex fromIndex, CFIndex toIndex){ if(mArray == NULL) return 0; CFIndex theCount = ::CFArrayGetCount(mArray); if( (fromIndex < 0) || (fromIndex > (theCount-1)) ) return 0;//request out of range if(toIndex < 0) toIndex = 0; else if (toIndex > theCount) toIndex = theCount; const void *ourItem = ::CFArrayGetValueAtIndex(mArray, fromIndex); ::CFArrayInsertValueAtIndex(mArray, toIndex, ourItem); if( ::CFArrayGetCount(mArray) == (theCount+1) ) {//insert succeeded CFIndex removalIndex = fromIndex; if(toIndex <= fromIndex)//inserted before old item, so old item is now shifted one position down removalIndex = fromIndex + 1; else toIndex--;//when old item is deleted in front, new index is decreased ::CFArrayRemoveValueAtIndex(mArray, removalIndex); if (toIndex == theCount) toIndex--;//should not happen if there is no error in logic, but let's make sure toIndex is valid return toIndex; } return fromIndex;}//on input, we get sorted list of indexes to move//on output we get the first index of moved blockCFIndexCFDictArray::MoveItems(CFArrayRef inIndexList, CFIndex toIndex){ if((mArray == NULL) || (inIndexList == NULL)) return 0; CFIndex arrayCount = ::CFArrayGetCount(mArray); CFMutableArrayRef tempList = ::CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks ); CFObjDel listDel(tempList);//first get all items to move and put them in temp array CFIndex moveCount = ::CFArrayGetCount(inIndexList); for(CFIndex i = 0; i < moveCount; i++) { CFTypeRef theItem = ::CFArrayGetValueAtIndex( inIndexList, i); if(::CFNumberGetTypeID() == ::CFGetTypeID(theItem)) { ACFNumber theIndex((CFNumberRef)theItem); CFIndex arrayIndex = (long)theIndex; if((arrayIndex >= 0) && (arrayIndex < arrayCount) ) {//valid index const void *ourItem = ::CFArrayGetValueAtIndex(mArray, arrayIndex); ::CFArrayAppendValue( tempList, ourItem ); } } } //now we have all items in our tem array //we may remove them from original array //we need to calculate the new insertion index while doing it for(CFIndex i = (moveCount-1); i >= 0 ; i--) { CFTypeRef theItem = ::CFArrayGetValueAtIndex( inIndexList, i); if(::CFNumberGetTypeID() == ::CFGetTypeID(theItem)) { ACFNumber theIndex((CFNumberRef)theItem); CFIndex arrayIndex = (long)theIndex; if((arrayIndex >= 0) && (arrayIndex < arrayCount) ) {//valid index ::CFArrayRemoveValueAtIndex(mArray, arrayIndex); if(arrayIndex < toIndex) {//removing item before new insertion point toIndex--; } } } } CFIndex storedItemsCount = ::CFArrayGetCount(tempList); for(CFIndex i = 0; i < storedItemsCount; i++) { const void *ourItem = ::CFArrayGetValueAtIndex(tempList, i); ::CFArrayInsertValueAtIndex(mArray, toIndex + i, ourItem); } return toIndex;}//index is zero-based//do not release the result dictionary - retain it if you plan to keep itCFDictionaryRefCFDictArray::FetchItemAt(CFIndex inIndex) const{ if(mArray == NULL) return NULL; CFIndex theCount = ::CFArrayGetCount(mArray); if( (inIndex >= 0) && (inIndex < theCount) ) { CFTypeRef theItem = ::CFArrayGetValueAtIndex( mArray, inIndex); if( (theItem != NULL) && (::CFGetTypeID(theItem) == ::CFDictionaryGetTypeID()) ) { return (CFDictionaryRef)theItem; } } return NULL;}voidCFDictArray::SetItemAt(CFDictionaryRef inItem, CFIndex inIndex){ if(mArray == NULL) return; CFIndex theCount = ::CFArrayGetCount(mArray); if( (inIndex >= 0) && (inIndex < theCount) ) { ::CFArraySetValueAtIndex( mArray, inIndex, (const void *)inItem); }}//returns newly created mutable dict as a convenienceCFMutableDictionaryRefCFDictArray::ReplaceDictionaryWithMutableCopyAt(CFIndex inIndex){ if(mArray == NULL) return NULL; CFIndex theCount = ::CFArrayGetCount(mArray); if( (inIndex >= 0) && (inIndex < theCount) ) { CFTypeRef theItem = ::CFArrayGetValueAtIndex( mArray, inIndex); if( (theItem != NULL) && (::CFGetTypeID(theItem) == ::CFDictionaryGetTypeID()) ) { CFDictionaryRef oldDict = (CFDictionaryRef)theItem; CFMutableDictionaryRef newDict = CFDictionaryCreateMutableCopy( kCFAllocatorDefault, 0, oldDict); ::CFArraySetValueAtIndex( mArray, inIndex, (const void *)newDict);//retained return newDict; } } return NULL;}//you may need to call CFPreferencesAppSynchronize before calling this functionvoidCFDictArray::LoadArrayFromPrefs(CFStringRef inKey, CFStringRef inPrefsIdentifier){ if(mArray != NULL) { ::CFRelease(mArray); mArray = NULL; } if( (inKey == NULL) || (inPrefsIdentifier == NULL) ) { mArray = ::CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks ); return; } CFPropertyListRef resultRef = ::CFPreferencesCopyAppValue( inKey, inPrefsIdentifier ); if(resultRef != NULL) { CFObjDel refDel(resultRef); if( ::CFGetTypeID(resultRef) == ::CFArrayGetTypeID() ) {//we need a mutable copy of this array mArray = ::CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, (CFArrayRef)resultRef); } } else {//unable to read or not created yet mArray = ::CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks ); }}//you may need to call CFPreferencesAppSynchronize after calling this functionvoidCFDictArray::SaveArrayToPrefs(CFStringRef inKey, CFStringRef inPrefsIdentifier) const{ if(mArray == NULL) return; ::CFPreferencesSetAppValue( inKey, (CFPropertyListRef)mArray, inPrefsIdentifier );}#pragma mark -//TODO: support other data types for dictionary CFStringRefCFDictArray::GetItemStringForKey(CFIndex inIndex, CFStringRef inKey){ CFDictionaryRef theDictItem = FetchItemAt(inIndex); if(theDictItem == NULL) return NULL; if(::CFGetTypeID(theDictItem) != ::CFDictionaryGetTypeID()) return NULL; CFTypeRef theResult = ::CFDictionaryGetValue( theDictItem, inKey ); if((theResult != NULL) && (::CFStringGetTypeID() == ::CFGetTypeID(theResult)) ) { return (CFStringRef)theResult; } return NULL;}voidCFDictArray::SetItemStringForKey(CFIndex inIndex, CFStringRef inKey, CFStringRef inString){ CFMutableDictionaryRef theDictItem = (CFMutableDictionaryRef)FetchItemAt(inIndex); if(theDictItem == NULL) return; if(inString == NULL) ::CFDictionaryRemoveValue(theDictItem, inKey); else ::CFDictionarySetValue(theDictItem, inKey, inString);}BooleanCFDictArray::GetItemBooleanForKey(CFIndex inIndex, CFStringRef inKey, Boolean defaultValue){ CFDictionaryRef theDictItem = FetchItemAt(inIndex); if(theDictItem == NULL) return defaultValue; if(::CFGetTypeID(theDictItem) != ::CFDictionaryGetTypeID()) return defaultValue; CFTypeRef theResult = ::CFDictionaryGetValue( theDictItem, inKey ); if((theResult != NULL) && (::CFBooleanGetTypeID() == ::CFGetTypeID(theResult)) ) { return ::CFBooleanGetValue( (CFBooleanRef)theResult ); } return defaultValue;}voidCFDictArray::SetItemBooleanForKey(CFIndex inIndex, CFStringRef inKey, Boolean inValue){ CFMutableDictionaryRef theDictItem = (CFMutableDictionaryRef)FetchItemAt(inIndex); if(theDictItem == NULL) return; ::CFDictionarySetValue(theDictItem, inKey, inValue ? kCFBooleanTrue : kCFBooleanFalse);}