API  1.0.0
CPByteCountFormatter.j
Go to the documentation of this file.
1 /*
2  * CPByteCountFormatter.j
3  * Foundation
4  *
5  * Created by Aparajita Fishman.
6  * Copyright 2013, Cappuccino Foundation.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 
24 
25 // Allowed units
34 
35 // Note: The Cocoa documentation says File is binary, but in practice it's decimal
40 
41 var CPByteCountFormatterUnits = [ @"bytes", @"KB", @"MB", @"GB", @"TB", @"PB" ];
42 
43 
50 @implementation CPByteCountFormatter : CPFormatter
51 {
52  int _countStyle;
53  BOOL _allowsNonnumericFormatting;
54  BOOL _includesActualByteCount;
55  BOOL _includesCount;
56  BOOL _includesUnit;
57  BOOL _adaptive;
58  BOOL _zeroPadsFractionDigits;
59  int _allowedUnits;
60  CPNumberFormatter _numberFormatter;
61 }
62 
63 - (id)init
64 {
65  if (self = [super init])
66  {
67  _adaptive = YES;
68  _allowedUnits = CPByteCountFormatterUseDefault;
69  _allowsNonnumericFormatting = YES;
71  _includesActualByteCount = NO;
72  _includesCount = YES;
73  _includesUnit = YES;
74  _zeroPadsFractionDigits = NO;
75  _numberFormatter = [CPNumberFormatter new];
76  [_numberFormatter setNumberStyle:CPNumberFormatterDecimalStyle];
77  [_numberFormatter setMinimumFractionDigits:0];
78  }
79 
80  return self;
81 }
82 
85 + (CPString)stringFromByteCount:(int)byteCount countStyle:(int)countStyle
86 {
87  var formatter = [CPByteCountFormatter new];
88 
89  [formatter setCountStyle:countStyle];
90 
91  return [formatter stringFromByteCount:byteCount];
92 }
93 
94 - (CPString)stringFromByteCount:(int)byteCount
95 {
96  var divisor,
97  exponent = 0,
98  unitIndex = ((_allowedUnits === 0) || (_allowedUnits & CPByteCountFormatterUseBytes)) ? 0 : -1,
99  bytes = byteCount,
100  unitBytes = bytes,
101  unitCount = [CPByteCountFormatterUnits count];
102 
103  if (_countStyle === CPByteCountFormatterCountStyleFile ||
105  divisor = 1000;
106  else
107  divisor = 1024;
108 
109  while ((bytes >= divisor) && (exponent < unitCount))
110  {
111  bytes /= divisor;
112  ++exponent;
113 
114  // If there is a valid unit for this exponent,
115  // update the unit we will use and the byte count for that unit
116  if (_allowedUnits === 0 || (_allowedUnits & (1 << exponent)))
117  {
118  unitIndex = exponent;
119  unitBytes = bytes;
120  }
121  }
122 
123  /*
124  If no allowed unit was found before bytes < divisor,
125  keep dividing until we find an allowed unit. We can skip
126  bytes, if that is allowed unit, unitIndex will be >= 0.
127  */
128  if (unitIndex === -1)
129  for (var i = 1; i < unitCount; ++i)
130  {
131  unitBytes /= divisor;
132 
133  if ((_allowedUnits === 0) || (_allowedUnits & (1 << i)))
134  {
135  unitIndex = i;
136  break;
137  }
138  }
139 
140  var minDigits = 0,
141  maxDigits = CPDecimalNoScale;
142 
143  // Fractional units get as many digits as they need
144  if (unitBytes >= 1.0)
145  {
146  if (_adaptive)
147  {
148  // 0 fraction digits for bytes and K, 1 fraction digit for MB, 2 digits for GB and above
149  var digits;
150 
151  if (exponent <= 1)
152  digits = 0;
153  else if (exponent == 2)
154  digits = 1;
155  else
156  digits = 2;
157 
158  maxDigits = digits;
159 
160  if (_zeroPadsFractionDigits)
161  minDigits = digits;
162  }
163  else
164  {
165  if (_zeroPadsFractionDigits)
166  minDigits = 2;
167 
168  if (bytes >= 1)
169  maxDigits = 2;
170  }
171  }
172 
173  [_numberFormatter setMinimumFractionDigits:minDigits];
174  [_numberFormatter setMaximumFractionDigits:maxDigits];
175 
176  var parts = [];
177 
178  if (_includesCount)
179  {
180  if (_allowsNonnumericFormatting && bytes === 0)
181  [parts addObject:@"Zero"];
182  else
183  [parts addObject:[_numberFormatter stringFromNumber:unitBytes]];
184  }
185 
186  if (_includesUnit)
187  [parts addObject:CPByteCountFormatterUnits[unitIndex]];
188 
189  if ((unitIndex > 0) && _includesCount && _includesUnit && _includesActualByteCount)
190  {
191  [_numberFormatter setMaximumFractionDigits:0];
192  [parts addObject:[CPString stringWithFormat:@"(%s bytes)", [_numberFormatter stringFromNumber:byteCount]]];
193  }
194 
195  var result = [parts componentsJoinedByString:@" "];
196 
197  if (byteCount === 1)
198  return [result stringByReplacingOccurrencesOfString:@"bytes" withString:@"byte"];
199  else
200  return result;
201 }
202 
206 - (CPString)stringForObjectValue:(id)anObject
207 {
208  if ([anObject isKindOfClass:CPNumber])
209  return [self stringFromByteCount:anObject];
210  else
211  return nil;
212 }
213 
214 - (BOOL)getObjectValue:(idRef)anObject forString:(CPString)aString errorDescription:(CPStringRef)anError
215 {
216  // Not implemented
217  return NO;
218 }
219 
222 - (int)countStyle
223 {
224  return _countStyle;
225 }
226 
227 - (void)setCountStyle:(int)style
228 {
229  _countStyle = style;
230 }
231 
232 - (BOOL)allowsNonnumericFormatting
233 {
234  return _allowsNonnumericFormatting;
235 }
236 
237 - (void)setAllowsNonnumericFormatting:(BOOL)shouldAllowNonnumericFormatting
238 {
239  _allowsNonnumericFormatting = shouldAllowNonnumericFormatting;
240 }
241 
242 - (BOOL)includesActualByteCount
243 {
244  return _includesActualByteCount;
245 }
246 
247 - (void)setIncludesActualByteCount:(BOOL)shouldIncludeActualByteCount
248 {
249  _includesActualByteCount = shouldIncludeActualByteCount;
250 }
251 
252 - (BOOL)isAdaptive
253 {
254  return _adaptive;
255 }
256 
257 - (void)setAdaptive:(BOOL)shouldBeAdaptive
258 {
259  _adaptive = shouldBeAdaptive;
260 }
261 
262 - (int)allowedUnits
263 {
264  return _allowedUnits;
265 }
266 
267 - (void)setAllowedUnits:(int)allowed
268 {
269  // Note: CPByteCountFormatterUseDefault is equivalent to UseAll
270  _allowedUnits = allowed;
271 }
272 
273 - (BOOL)includesCount
274 {
275  return _includesCount;
276 }
277 
278 - (void)setIncludesCount:(BOOL)shouldIncludeCount
279 {
280  _includesCount = shouldIncludeCount;
281 }
282 
283 - (BOOL)includesUnit
284 {
285  return _includesUnit;
286 }
287 
288 - (void)setIncludesUnit:(BOOL)shouldIncludeUnit
289 {
290  _includesUnit = shouldIncludeUnit;
291 }
292 
293 - (BOOL)zeroPadsFractionDigits
294 {
295  return _zeroPadsFractionDigits;
296 }
297 
298 - (void)setZeroPadsFractionDigits:(BOOL)shouldZeroPad
299 {
300  _zeroPadsFractionDigits = shouldZeroPad;
301 }
302 
303 @end
304 
305 
306 var CPByteCountFormatterCountStyleKey = @"CPByteCountFormatterCountStyleKey",
307  CPByteCountFormatterAllowsNonnumericFormattingKey = @"CPByteCountFormatterAllowsNonnumericFormattingKey",
308  CPByteCountFormatterIncludesActualByteCountKey = @"CPByteCountFormatterIncludesActualByteCountKey",
309  CPByteCountFormatterIncludesCountKey = @"CPByteCountFormatterIncludesCountKey",
310  CPByteCountFormatterIncludesUnitKey = @"CPByteCountFormatterIncludesUnitKey",
311  CPByteCountFormatterAdaptiveKey = @"CPByteCountFormatterAdaptiveKey",
312  CPByteCountFormatterZeroPadsFractionDigitsKey = @"CPByteCountFormatterZeroPadsFractionDigitsKey",
313  CPByteCountFormatterAllowedUnitsKey = @"CPByteCountFormatterAllowedUnitsKey";
314 
316 
317 - (id)initWithCoder:(CPCoder)aCoder
318 {
319  self = [super initWithCoder:aCoder];
320 
321  if (self)
322  {
323  _countStyle = [aCoder decodeIntForKey:CPByteCountFormatterCountStyleKey];
324  _allowsNonnumericFormatting = [aCoder decodeBoolForKey:CPByteCountFormatterAllowsNonnumericFormattingKey];
325  _includesActualByteCount = [aCoder decodeBoolForKey:CPByteCountFormatterIncludesActualByteCountKey];
326  _includesCount = [aCoder decodeBoolForKey:CPByteCountFormatterIncludesCountKey];
327  _includesUnit = [aCoder decodeBoolForKey:CPByteCountFormatterIncludesUnitKey];
328  _adaptive = [aCoder decodeBoolForKey:CPByteCountFormatterAdaptiveKey];
329  _zeroPadsFractionDigits = [aCoder decodeBoolForKey:CPByteCountFormatterZeroPadsFractionDigitsKey];
330  _allowedUnits = [aCoder decodeIntForKey:CPByteCountFormatterAllowedUnitsKey];
331  }
332 
333  return self;
334 }
335 
336 - (void)encodeWithCoder:(CPCoder)aCoder
337 {
338  [super encodeWithCoder:aCoder];
339 
340  [aCoder encodeInt:_countStyle forKey:CPByteCountFormatterCountStyleKey];
341  [aCoder encodeBool:_allowsNonnumericFormatting forKey:CPByteCountFormatterAllowsNonnumericFormattingKey];
342  [aCoder encodeBool:_includesActualByteCount forKey:CPByteCountFormatterIncludesActualByteCountKey];
343  [aCoder encodeBool:_includesCount forKey:CPByteCountFormatterIncludesCountKey];
344  [aCoder encodeBool:_includesUnit forKey:CPByteCountFormatterIncludesUnitKey];
345  [aCoder encodeBool:_adaptive forKey:CPByteCountFormatterAdaptiveKey];
346  [aCoder encodeBool:_zeroPadsFractionDigits forKey:CPByteCountFormatterZeroPadsFractionDigitsKey];
347  [aCoder encodeInt:_allowedUnits forKey:CPByteCountFormatterAllowedUnitsKey];
348 }
349 
350 @end
CPByteCountFormatterUseGB
var CPByteCountFormatterIncludesActualByteCountKey
CPByteCountFormatterUseBytes
id init()
Definition: CALayer.j:126
CPByteCountFormatterCountStyleMemory
var CPByteCountFormatterAllowsNonnumericFormattingKey
CPByteCountFormatterCountStyleDecimal
CPByteCountFormatterCountStyleBinary
CPByteCountFormatterUseAll
CPByteCountFormatterUsePB
CPByteCountFormatterCountStyleFile
An immutable string (collection of characters).
Definition: CPString.h:2
CPDecimalNoScale
Definition: CPDecimal.j:61
id initWithCoder:(CPCoder aCoder)
Definition: CPFormatter.j:167
var CPByteCountFormatterIncludesCountKey
CPByteCountFormatterUseMB
CPByteCountFormatterUseKB
CPFormatter is an abstract class that declares an interface for objects that create, interpret, and validate the textual representation of cell contents. The Foundation framework provides two concrete subclasses of CPFormatter to generate these objects: CPNumberFormatter and CPDateFormatter.
Definition: CPFormatter.h:2
var CPByteCountFormatterAllowedUnitsKey
CPByteCountFormatterUseTB
var CPByteCountFormatterZeroPadsFractionDigitsKey
var CPByteCountFormatterCountStyleKey
var CPByteCountFormatterAdaptiveKey
Defines methods for use when archiving & restoring (enc/decoding).
Definition: CPCoder.h:2
id new()
Definition: CPObject.j:122
A bridged object to native Javascript numbers.
Definition: CPNumber.h:2
void encodeWithCoder:(CPCoder aCoder)
Definition: CPFormatter.j:172
var CPByteCountFormatterIncludesUnitKey
var CPByteCountFormatterUnits
CPString stringFromByteCount:(int byteCount)
CPByteCountFormatterUseDefault
id stringWithFormat:(CPString format, [,] ...)
Definition: CPString.j:166