1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_connectivity.hxx" 30 31 #include "MacabRecord.hxx" 32 #include "macabutilities.hxx" 33 #include <com/sun/star/util/DateTime.hpp> 34 35 #include <premac.h> 36 #include <Carbon/Carbon.h> 37 #include <AddressBook/ABAddressBookC.h> 38 #include <postmac.h> 39 #include <connectivity/dbconversion.hxx> 40 41 using namespace connectivity::macab; 42 using namespace com::sun::star::util; 43 using namespace ::dbtools; 44 45 // ------------------------------------------------------------------------- 46 MacabRecord::MacabRecord() 47 { 48 size = 0; 49 fields = NULL; 50 } 51 52 // ------------------------------------------------------------------------- 53 MacabRecord::MacabRecord(const sal_Int32 _size) 54 { 55 size = _size; 56 fields = new macabfield *[size]; 57 sal_Int32 i; 58 for(i = 0; i < size; i++) 59 fields[i] = NULL; 60 } 61 62 // ------------------------------------------------------------------------- 63 MacabRecord::~MacabRecord() 64 { 65 if(size > 0) 66 { 67 int i; 68 for(i = 0; i < size; i++) 69 { 70 delete fields[i]; 71 fields[i] = NULL; 72 } 73 } 74 delete [] fields; 75 fields = NULL; 76 } 77 78 // ------------------------------------------------------------------------- 79 void MacabRecord::insertAtColumn (CFTypeRef _value, ABPropertyType _type, const sal_Int32 _column) 80 { 81 if(_column < size) 82 { 83 if(fields[_column] == NULL) 84 fields[_column] = new macabfield; 85 86 fields[_column]->value = _value; 87 if (fields[_column]->value) 88 CFRetain(fields[_column]->value); 89 fields[_column]->type = _type; 90 } 91 } 92 93 // ------------------------------------------------------------------------- 94 sal_Bool MacabRecord::contains (const macabfield *_field) const 95 { 96 if(_field == NULL) 97 return sal_False; 98 else 99 return contains(_field->value); 100 } 101 102 // ------------------------------------------------------------------------- 103 sal_Bool MacabRecord::contains (const CFTypeRef _value) const 104 { 105 sal_Int32 i; 106 for(i = 0; i < size; i++) 107 { 108 if(fields[i] != NULL) 109 { 110 if(CFEqual(fields[i]->value, _value)) 111 { 112 return sal_True; 113 } 114 } 115 } 116 117 return sal_False; 118 } 119 120 // ------------------------------------------------------------------------- 121 sal_Int32 MacabRecord::getSize() const 122 { 123 return size; 124 } 125 126 // ------------------------------------------------------------------------- 127 macabfield *MacabRecord::copy(const sal_Int32 i) const 128 { 129 /* Note: copy(i) creates a new macabfield identical to that at 130 * location i, whereas get(i) returns a pointer to the macabfield 131 * at location i. 132 */ 133 if(i < size) 134 { 135 macabfield *_copy = new macabfield; 136 _copy->type = fields[i]->type; 137 _copy->value = fields[i]->value; 138 if (_copy->value) 139 CFRetain(_copy->value); 140 return _copy; 141 } 142 143 return NULL; 144 } 145 146 // ------------------------------------------------------------------------- 147 macabfield *MacabRecord::get(const sal_Int32 i) const 148 { 149 /* Note: copy(i) creates a new macabfield identical to that at 150 * location i, whereas get(i) returns a pointer to the macabfield 151 * at location i. 152 */ 153 if(i < size) 154 { 155 return fields[i]; 156 } 157 158 return NULL; 159 } 160 161 // ------------------------------------------------------------------------- 162 void MacabRecord::releaseFields() 163 { 164 /* This method is, at the moment, only used in MacabHeader.cxx, but 165 * the idea is simple: if you are not destroying this object but want 166 * to clear it of its macabfields, you should release each field's 167 * value. 168 */ 169 sal_Int32 i; 170 for(i = 0; i < size; i++) 171 CFRelease(fields[i]->value); 172 } 173 174 // ------------------------------------------------------------------------- 175 sal_Int32 MacabRecord::compareFields(const macabfield *_field1, const macabfield *_field2) 176 { 177 178 /* When comparing records, if either field is NULL (and the other is 179 * not), that field is considered "greater than" the other, so that it 180 * shows up later in the list when fields are ordered. 181 */ 182 if(_field1 == _field2) 183 return 0; 184 if(_field1 == NULL) 185 return 1; 186 if(_field2 == NULL) 187 return -1; 188 189 /* If they aren't the same type, for now, return the one with 190 * the smaller type ID... I don't know of a better way to compare 191 * two different data types. 192 */ 193 if(_field1->type != _field2->type) 194 return(_field1->type - _field2->type); 195 196 CFComparisonResult result; 197 198 /* Carbon has a unique compare function for each data type: */ 199 switch(_field1->type) 200 { 201 case kABStringProperty: 202 result = CFStringCompare( 203 (CFStringRef) _field1->value, 204 (CFStringRef) _field2->value, 205 kCFCompareLocalized); // Specifies that the comparison should take into account differences related to locale, such as the thousands separator character. 206 break; 207 208 case kABDateProperty: 209 result = CFDateCompare( 210 (CFDateRef) _field1->value, 211 (CFDateRef) _field2->value, 212 NULL); // NULL = unused variable 213 break; 214 215 case kABIntegerProperty: 216 case kABRealProperty: 217 result = CFNumberCompare( 218 (CFNumberRef) _field1->value, 219 (CFNumberRef) _field2->value, 220 NULL); // NULL = unused variable 221 break; 222 223 default: 224 result = kCFCompareEqualTo; // can't compare 225 } 226 227 return (sal_Int32) result; 228 } 229 230 // ------------------------------------------------------------------------- 231 /* Create a macabfield out of an OUString and type. Together with the 232 * method fieldToString() (below), it is possible to switch conveniently 233 * between an OUString and a macabfield (for use when creating and handling 234 * SQL statement). 235 */ 236 macabfield *MacabRecord::createMacabField(const ::rtl::OUString _newFieldString, const ABPropertyType _abType) 237 { 238 macabfield *newField = NULL; 239 switch(_abType) 240 { 241 case kABStringProperty: 242 newField = new macabfield; 243 newField->value = OUStringToCFString(_newFieldString); 244 newField->type = _abType; 245 break; 246 case kABDateProperty: 247 { 248 DateTime aDateTime = DBTypeConversion::toDateTime(_newFieldString); 249 250 // bad format... 251 if(aDateTime.Year == 0 && aDateTime.Month == 0 && aDateTime.Day == 0) 252 { 253 } 254 else 255 { 256 double nTime = DBTypeConversion::toDouble(aDateTime, DBTypeConversion::getStandardDate()); 257 nTime -= kCFAbsoluteTimeIntervalSince1970; 258 newField = new macabfield; 259 newField->value = CFDateCreate(NULL, (CFAbsoluteTime) nTime); 260 newField->type = _abType; 261 } 262 } 263 break; 264 case kABIntegerProperty: 265 try 266 { 267 sal_Int64 nVal = _newFieldString.toInt64(); 268 269 newField = new macabfield; 270 newField->value = CFNumberCreate(NULL,kCFNumberLongType, &nVal); 271 newField->type = _abType; 272 } 273 // bad format... 274 catch(...) 275 { 276 } 277 break; 278 case kABRealProperty: 279 try 280 { 281 double nVal = _newFieldString.toDouble(); 282 283 newField = new macabfield; 284 newField->value = CFNumberCreate(NULL,kCFNumberDoubleType, &nVal); 285 newField->type = _abType; 286 } 287 // bad format... 288 catch(...) 289 { 290 } 291 break; 292 default: 293 ; 294 } 295 return newField; 296 } 297 298 // ------------------------------------------------------------------------- 299 /* Create an OUString out of a macabfield. Together with the method 300 * createMacabField() (above), it is possible to switch conveniently 301 * between an OUString and a macabfield (for use when creating and handling 302 * SQL statement). 303 */ 304 ::rtl::OUString MacabRecord::fieldToString(const macabfield *_aField) 305 { 306 if(_aField == NULL) 307 return ::rtl::OUString(); 308 309 ::rtl::OUString fieldString; 310 311 switch(_aField->type) 312 { 313 case kABStringProperty: 314 fieldString = CFStringToOUString((CFStringRef) _aField->value); 315 break; 316 case kABDateProperty: 317 { 318 DateTime aTime = CFDateToDateTime((CFDateRef) _aField->value); 319 fieldString = DBTypeConversion::toDateTimeString(aTime); 320 } 321 break; 322 case kABIntegerProperty: 323 { 324 CFNumberType numberType = CFNumberGetType( (CFNumberRef) _aField->value ); 325 sal_Int64 nVal; 326 // Should we check for the wrong type here, e.g., a float? 327 sal_Bool m_bSuccess = !CFNumberGetValue((CFNumberRef) _aField->value, numberType, &nVal); 328 if(m_bSuccess != sal_False) 329 fieldString = ::rtl::OUString::valueOf(nVal); 330 } 331 break; 332 case kABRealProperty: 333 { 334 CFNumberType numberType = CFNumberGetType( (CFNumberRef) _aField->value ); 335 double nVal; 336 // Should we check for the wrong type here, e.g., an int? 337 sal_Bool m_bSuccess = !CFNumberGetValue((CFNumberRef) _aField->value, numberType, &nVal); 338 if(m_bSuccess != sal_False) 339 fieldString = ::rtl::OUString::valueOf(nVal); 340 } 341 break; 342 default: 343 ; 344 } 345 return fieldString; 346 347 } 348