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