1 /* 2 * File : DisplayFormatters.java 3 * Created : 07-Oct-2003 4 * By : gardnerpar 5 * 6 * Azureus - a Java Bittorrent client 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program 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 16 * GNU General Public License for more details ( see the LICENSE file ). 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 */ 22 23 package org.gudy.azureus2.core3.util; 24 25 /** 26 * @author gardnerpar 27 * 28 */ 29 30 import java.util.ArrayList; 31 import java.util.Arrays; 32 import java.util.Calendar; 33 import java.util.Date; 34 import java.util.HashMap; 35 import java.util.List; 36 import java.util.Locale; 37 import java.util.Map; 38 import java.math.BigDecimal; 39 import java.text.DecimalFormat; 40 import java.text.DecimalFormatSymbols; 41 import java.text.SimpleDateFormat; 42 import java.text.NumberFormat; 43 44 import org.gudy.azureus2.core3.download.*; 45 import org.gudy.azureus2.core3.config.*; 46 import org.gudy.azureus2.core3.torrent.TOTorrent; 47 import org.gudy.azureus2.core3.disk.*; 48 import org.gudy.azureus2.core3.internat.*; 49 50 51 52 public class 53 DisplayFormatters 54 { 55 final private static boolean ROUND_NO = true; 56 //final private static boolean ROUND_YES = false; 57 final private static boolean TRUNCZEROS_NO = false; 58 final private static boolean TRUNCZEROS_YES = true; 59 60 final public static int UNIT_B = 0; 61 final public static int UNIT_KB = 1; 62 final public static int UNIT_MB = 2; 63 final public static int UNIT_GB = 3; 64 final public static int UNIT_TB = 4; 65 66 final private static int UNITS_PRECISION[] = { 0, // B 67 1, //KB 68 2, //MB 69 2, //GB 70 3 //TB 71 }; 72 73 final private static NumberFormat[] cached_number_formats = new NumberFormat[20]; 74 75 private static NumberFormat percentage_format; 76 77 private static final String[] all_units = new String[5]; 78 79 private static String[] units; 80 private static String[] units_bits; 81 private static String[] units_rate; 82 private static int unitsStopAt = UNIT_TB; 83 84 private static String[] units_base10; 85 86 private static String per_sec; 87 88 private static boolean use_si_units; 89 private static boolean force_si_values; 90 private static boolean use_units_rate_bits; 91 private static boolean not_use_GB_TB; 92 93 private static int message_text_state = 0; 94 95 private static boolean separate_prot_data_stats; 96 private static boolean data_stats_only; 97 private static char decimalSeparator; 98 99 private static volatile Map<String,Formatter> format_map = new HashMap<String, Formatter>(); 100 101 static{ COConfigurationManager.addAndFireParameterListeners( new String[]{ R, R, R, R, R, }, new ParameterListener() { public void parameterChanged( String x ) { use_si_units = COConfigurationManager.getBooleanParameter(R); force_si_values = COConfigurationManager.getBooleanParameter(R); use_units_rate_bits = COConfigurationManager.getBooleanParameter(R); not_use_GB_TB = COConfigurationManager.getBooleanParameter(R); unitsStopAt = (not_use_GB_TB) ? UNIT_MB : UNIT_TB; setUnits(); updateFormatOverrides( COConfigurationManager.getStringParameter( R, R )); } })102 COConfigurationManager.addAndFireParameterListeners( 103 new String[]{ 104 "config.style.useSIUnits", 105 "config.style.forceSIValues", 106 "config.style.useUnitsRateBits", 107 "config.style.doNotUseGB", 108 "config.style.formatOverrides", 109 }, 110 new ParameterListener() 111 { 112 public void 113 parameterChanged( 114 String x ) 115 { 116 use_si_units = COConfigurationManager.getBooleanParameter("config.style.useSIUnits"); 117 force_si_values = COConfigurationManager.getBooleanParameter("config.style.forceSIValues"); 118 use_units_rate_bits = COConfigurationManager.getBooleanParameter("config.style.useUnitsRateBits"); 119 not_use_GB_TB = COConfigurationManager.getBooleanParameter("config.style.doNotUseGB"); 120 121 unitsStopAt = (not_use_GB_TB) ? UNIT_MB : UNIT_TB; 122 123 setUnits(); 124 125 updateFormatOverrides( COConfigurationManager.getStringParameter( "config.style.formatOverrides", "" )); 126 } 127 }); 128 COConfigurationManager.addListener( new COConfigurationListener() { public void configurationSaved() { setUnits(); loadMessages(); } })129 COConfigurationManager.addListener( 130 new COConfigurationListener() 131 { 132 public void 133 configurationSaved() 134 { 135 setUnits(); 136 loadMessages(); 137 138 } 139 140 }); 141 COConfigurationManager.addAndFireParameterListeners( new String[]{ R, R, }, new ParameterListener() { public void parameterChanged( String x ) { separate_prot_data_stats = COConfigurationManager.getBooleanParameter(R); data_stats_only = COConfigurationManager.getBooleanParameter(R); } })142 COConfigurationManager.addAndFireParameterListeners( 143 new String[]{ 144 "config.style.dataStatsOnly", 145 "config.style.separateProtDataStats", 146 }, 147 new ParameterListener() 148 { 149 public void 150 parameterChanged( 151 String x ) 152 { 153 separate_prot_data_stats = COConfigurationManager.getBooleanParameter("config.style.separateProtDataStats"); 154 data_stats_only = COConfigurationManager.getBooleanParameter("config.style.dataStatsOnly"); 155 } 156 }); 157 setUnits()158 setUnits(); 159 loadMessages()160 loadMessages(); 161 } 162 163 public static void setUnits()164 setUnits() 165 { 166 // (1) http://physics.nist.gov/cuu/Units/binary.html 167 // (2) http://www.isi.edu/isd/LOOM/documentation/unit-definitions.text 168 169 units = new String[unitsStopAt + 1]; 170 units_bits = new String[unitsStopAt + 1]; 171 units_rate = new String[unitsStopAt + 1]; 172 173 if ( use_si_units ){ 174 all_units[UNIT_TB] = getUnit("TiB"); 175 all_units[UNIT_GB] = getUnit("GiB"); 176 all_units[UNIT_MB] = getUnit("MiB"); 177 all_units[UNIT_KB] = getUnit("KiB"); 178 all_units[UNIT_B] = getUnit("B"); 179 180 // fall through intentional 181 182 switch (unitsStopAt) { 183 case UNIT_TB: 184 units[UNIT_TB] = all_units[UNIT_TB]; 185 units_bits[UNIT_TB] = getUnit("Tibit"); 186 units_rate[UNIT_TB] = (use_units_rate_bits) ? getUnit("Tibit") : getUnit("TiB"); 187 case UNIT_GB: 188 units[UNIT_GB]= all_units[UNIT_GB]; 189 units_bits[UNIT_GB]= getUnit("Gibit"); 190 units_rate[UNIT_GB] = (use_units_rate_bits) ? getUnit("Gibit") : getUnit("GiB"); 191 case UNIT_MB: 192 units[UNIT_MB] = all_units[UNIT_MB]; 193 units_bits[UNIT_MB] = getUnit("Mibit"); 194 units_rate[UNIT_MB] = (use_units_rate_bits) ? getUnit("Mibit") : getUnit("MiB"); 195 case UNIT_KB: 196 // can be upper or lower case k 197 units[UNIT_KB] = all_units[UNIT_KB]; 198 units_bits[UNIT_KB] = getUnit("Kibit"); 199 200 // can be upper or lower case k, upper more consistent 201 units_rate[UNIT_KB] = (use_units_rate_bits) ? getUnit("Kibit") : getUnit("KiB"); 202 case UNIT_B: 203 units[UNIT_B] =all_units[UNIT_B]; 204 units_bits[UNIT_B] = getUnit("bit"); 205 units_rate[UNIT_B] = (use_units_rate_bits) ? getUnit("bit") : getUnit("B"); 206 } 207 }else{ 208 all_units[UNIT_TB] = getUnit("TB"); 209 all_units[UNIT_GB] = getUnit("GB"); 210 all_units[UNIT_MB] = getUnit("MB"); 211 all_units[UNIT_KB] = getUnit("kB"); 212 all_units[UNIT_B] = getUnit("B"); 213 214 switch (unitsStopAt) { 215 case UNIT_TB: 216 units[UNIT_TB] = all_units[UNIT_TB]; 217 units_bits[UNIT_TB] = getUnit("Tbit"); 218 units_rate[UNIT_TB] = (use_units_rate_bits) ? getUnit("Tbit") : getUnit("TB"); 219 case UNIT_GB: 220 units[UNIT_GB]= all_units[UNIT_GB]; 221 units_bits[UNIT_GB]= getUnit("Gbit"); 222 units_rate[UNIT_GB] = (use_units_rate_bits) ? getUnit("Gbit") : getUnit("GB"); 223 case UNIT_MB: 224 units[UNIT_MB] = all_units[UNIT_MB]; 225 units_bits[UNIT_MB] = getUnit("Mbit"); 226 units_rate[UNIT_MB] = (use_units_rate_bits) ? getUnit("Mbit") : getUnit("MB"); 227 case UNIT_KB: 228 // yes, the k should be lower case 229 units[UNIT_KB] = all_units[UNIT_KB]; 230 units_bits[UNIT_KB] = getUnit("kbit"); 231 units_rate[UNIT_KB] = (use_units_rate_bits) ? getUnit("kbit") : getUnit("kB"); 232 case UNIT_B: 233 units[UNIT_B] = all_units[UNIT_B]; 234 units_bits[UNIT_B] = getUnit("bit"); 235 units_rate[UNIT_B] = (use_units_rate_bits) ? getUnit("bit") : getUnit("B"); 236 } 237 } 238 239 240 per_sec = getResourceString( "Formats.units.persec", "/s" ); 241 242 units_base10 = 243 new String[]{ 244 getUnit( use_units_rate_bits?"bit":"B"), 245 getUnit( use_units_rate_bits?"kbit":"KB"), 246 getUnit( use_units_rate_bits?"Mbit":"MB" ), 247 getUnit( use_units_rate_bits?"Gbit":"GB"), 248 getUnit( use_units_rate_bits?"Tbit":"TB" )}; 249 250 for (int i = 0; i <= unitsStopAt; i++) { 251 units[i] = units[i]; 252 units_rate[i] = units_rate[i] + per_sec; 253 } 254 255 Arrays.fill( cached_number_formats, null ); 256 257 percentage_format = NumberFormat.getPercentInstance(); 258 percentage_format.setMinimumFractionDigits(1); 259 percentage_format.setMaximumFractionDigits(1); 260 261 decimalSeparator = new DecimalFormatSymbols().getDecimalSeparator(); 262 } 263 264 private static String getUnit( String key )265 getUnit( 266 String key ) 267 { 268 String res = " " + getResourceString( "Formats.units." + key, key ); 269 270 return( res ); 271 } 272 273 private static String PeerManager_status_finished; 274 private static String PeerManager_status_finishedin; 275 private static String Formats_units_alot; 276 private static String discarded; 277 private static String ManagerItem_waiting; 278 private static String ManagerItem_initializing; 279 private static String ManagerItem_allocating; 280 private static String ManagerItem_checking; 281 private static String ManagerItem_finishing; 282 private static String ManagerItem_ready; 283 private static String ManagerItem_downloading; 284 private static String ManagerItem_swarmMerge; 285 private static String ManagerItem_seeding; 286 private static String ManagerItem_superseeding; 287 private static String ManagerItem_stopping; 288 private static String ManagerItem_stopped; 289 private static String ManagerItem_paused; 290 private static String ManagerItem_queued; 291 private static String ManagerItem_error; 292 private static String ManagerItem_forced; 293 private static String ManagerItem_moving; 294 295 private static String yes; 296 private static String no; 297 298 public static void loadMessages()299 loadMessages() 300 { 301 PeerManager_status_finished = getResourceString( "PeerManager.status.finished", "Finished" ); 302 PeerManager_status_finishedin = getResourceString( "PeerManager.status.finishedin", "Finished in" ); 303 Formats_units_alot = getResourceString( "Formats.units.alot", "A lot" ); 304 discarded = getResourceString( "discarded", "discarded" ); 305 ManagerItem_waiting = getResourceString( "ManagerItem.waiting", "waiting" ); 306 ManagerItem_initializing = getResourceString( "ManagerItem.initializing", "initializing" ); 307 ManagerItem_allocating = getResourceString( "ManagerItem.allocating", "allocating" ); 308 ManagerItem_checking = getResourceString( "ManagerItem.checking", "checking" ); 309 ManagerItem_finishing = getResourceString( "ManagerItem.finishing", "finishing" ); 310 ManagerItem_ready = getResourceString( "ManagerItem.ready", "ready" ); 311 ManagerItem_downloading = getResourceString( "ManagerItem.downloading", "downloading" ); 312 ManagerItem_swarmMerge = getResourceString( "TableColumn.header.mergeddata", "swarm merge" ); 313 ManagerItem_seeding = getResourceString( "ManagerItem.seeding", "seeding" ); 314 ManagerItem_superseeding = getResourceString( "ManagerItem.superseeding", "superseeding" ); 315 ManagerItem_stopping = getResourceString( "ManagerItem.stopping", "stopping" ); 316 ManagerItem_stopped = getResourceString( "ManagerItem.stopped", "stopped" ); 317 ManagerItem_paused = getResourceString( "ManagerItem.paused", "paused" ); 318 ManagerItem_queued = getResourceString( "ManagerItem.queued", "queued" ); 319 ManagerItem_error = getResourceString( "ManagerItem.error", "error" ); 320 ManagerItem_forced = getResourceString( "ManagerItem.forced", "forced" ); 321 ManagerItem_moving = getResourceString( "ManagerItem.moving", "moving" ); 322 yes = getResourceString( "GeneralView.yes", "Yes" ); 323 no = getResourceString( "GeneralView.no", "No" ); 324 } 325 326 private static String getResourceString( String key, String def )327 getResourceString( 328 String key, 329 String def ) 330 { 331 if ( message_text_state == 0 ){ 332 333 // this fooling around is to permit the use of this class in the absence of the (large) overhead 334 // of resource bundles 335 336 try{ 337 MessageText.class.getName(); 338 339 message_text_state = 1; 340 341 }catch( Throwable e ){ 342 343 message_text_state = 2; 344 } 345 } 346 347 if ( message_text_state == 1 ){ 348 349 return( MessageText.getString( key )); 350 351 }else{ 352 353 return( def ); 354 } 355 } 356 357 public static String getYesNo( boolean b )358 getYesNo( 359 boolean b ) 360 { 361 return( b?yes:no ); 362 } 363 364 public static String getRateUnit( int unit_size )365 getRateUnit( 366 int unit_size ) 367 { 368 return( units_rate[unit_size].substring(1, units_rate[unit_size].length()) ); 369 } 370 public static String getUnit( int unit_size )371 getUnit( 372 int unit_size ) 373 { 374 return( units[unit_size].substring(1, units[unit_size].length()) ); 375 } 376 377 public static String getRateUnitBase10(int unit_size)378 getRateUnitBase10(int unit_size) { 379 return units_base10[unit_size] + per_sec; 380 } 381 382 public static String getUnitBase10(int unit_size)383 getUnitBase10(int unit_size) { 384 return units_base10[unit_size]; 385 } 386 387 public static boolean isRateUsingBits()388 isRateUsingBits() 389 { 390 return( use_units_rate_bits ); 391 } 392 393 public static String formatByteCountToKiBEtc(int n)394 formatByteCountToKiBEtc(int n) 395 { 396 return( formatByteCountToKiBEtc((long)n)); 397 } 398 399 public static String formatByteCountToKiBEtc( long n )400 formatByteCountToKiBEtc( 401 long n ) 402 { 403 return( formatByteCountToKiBEtc( n, false, TRUNCZEROS_NO)); 404 } 405 406 public static formatByteCountToKiBEtc( long n, boolean bTruncateZeros )407 String formatByteCountToKiBEtc( 408 long n, boolean bTruncateZeros ) 409 { 410 return( formatByteCountToKiBEtc( n, false, bTruncateZeros )); 411 } 412 413 public static formatByteCountToKiBEtc( long n, boolean rate, boolean bTruncateZeros)414 String formatByteCountToKiBEtc( 415 long n, 416 boolean rate, 417 boolean bTruncateZeros) 418 { 419 return formatByteCountToKiBEtc(n, rate, bTruncateZeros, -1); 420 } 421 422 public static int getKinB()423 getKinB() 424 { 425 return( force_si_values?1024:(use_si_units?1024:1000)); 426 } 427 428 public static formatByteCountToKiBEtc( long n, boolean rate, boolean bTruncateZeros, int precision)429 String formatByteCountToKiBEtc( 430 long n, 431 boolean rate, 432 boolean bTruncateZeros, 433 int precision) 434 { 435 double dbl = (rate && use_units_rate_bits) ? n * 8 : n; 436 437 int unitIndex = UNIT_B; 438 439 long div = force_si_values?1024:(use_si_units?1024:1000); 440 441 while (dbl >= div && unitIndex < unitsStopAt){ 442 443 dbl /= div; 444 unitIndex++; 445 } 446 447 if (precision < 0) { 448 precision = UNITS_PRECISION[unitIndex]; 449 } 450 451 // round for rating, because when the user enters something like 7.3kbps 452 // they don't want it truncated and displayed as 7.2 453 // (7.3*1024 = 7475.2; 7475/1024.0 = 7.2998; trunc(7.2998, 1 prec.) == 7.2 454 // 455 // Truncate for rest, otherwise we get complaints like: 456 // "I have a 1.0GB torrent and it says I've downloaded 1.0GB.. why isn't 457 // it complete? waaah" 458 459 return formatDecimal(dbl, precision, bTruncateZeros, rate) 460 + (rate ? units_rate[unitIndex] : units[unitIndex]); 461 } 462 463 public static formatByteCountToKiBEtc( long n, boolean rate, boolean bTruncateZeros, int precision, int minUnit )464 String formatByteCountToKiBEtc( 465 long n, 466 boolean rate, 467 boolean bTruncateZeros, 468 int precision, 469 int minUnit ) 470 { 471 double dbl = (rate && use_units_rate_bits) ? n * 8 : n; 472 473 int unitIndex = UNIT_B; 474 475 long div = force_si_values?1024:(use_si_units?1024:1000); 476 477 while (dbl >= div && unitIndex < unitsStopAt){ 478 479 dbl /= div; 480 unitIndex++; 481 } 482 483 while( unitIndex < minUnit ){ 484 dbl /= div; 485 unitIndex++; 486 } 487 if (precision < 0) { 488 precision = UNITS_PRECISION[unitIndex]; 489 } 490 491 // round for rating, because when the user enters something like 7.3kbps 492 // they don't want it truncated and displayed as 7.2 493 // (7.3*1024 = 7475.2; 7475/1024.0 = 7.2998; trunc(7.2998, 1 prec.) == 7.2 494 // 495 // Truncate for rest, otherwise we get complaints like: 496 // "I have a 1.0GB torrent and it says I've downloaded 1.0GB.. why isn't 497 // it complete? waaah" 498 499 return formatDecimal(dbl, precision, bTruncateZeros, rate) 500 + (rate ? units_rate[unitIndex] : units[unitIndex]); 501 } 502 503 public static boolean isDataProtSeparate()504 isDataProtSeparate() 505 { 506 return( separate_prot_data_stats ); 507 } 508 509 public static String formatDataProtByteCountToKiBEtc( long data, long prot )510 formatDataProtByteCountToKiBEtc( 511 long data, 512 long prot ) 513 { 514 if ( separate_prot_data_stats ){ 515 if ( data == 0 && prot == 0 ){ 516 return( formatByteCountToKiBEtc(0)); 517 }else if ( data == 0 ){ 518 return( "(" + formatByteCountToKiBEtc( prot) + ")"); 519 }else if ( prot == 0 ){ 520 return( formatByteCountToKiBEtc( data )); 521 }else{ 522 return(formatByteCountToKiBEtc(data)+" ("+ formatByteCountToKiBEtc(prot)+")"); 523 } 524 }else if ( data_stats_only ){ 525 return( formatByteCountToKiBEtc( data )); 526 }else{ 527 return( formatByteCountToKiBEtc( prot + data )); 528 } 529 } 530 531 public static String formatDataProtByteCountToKiBEtcPerSec( long data, long prot )532 formatDataProtByteCountToKiBEtcPerSec( 533 long data, 534 long prot ) 535 { 536 if ( separate_prot_data_stats ){ 537 if ( data == 0 && prot == 0 ){ 538 return(formatByteCountToKiBEtcPerSec(0)); 539 }else if ( data == 0 ){ 540 return( "(" + formatByteCountToKiBEtcPerSec( prot) + ")"); 541 }else if ( prot == 0 ){ 542 return( formatByteCountToKiBEtcPerSec( data )); 543 }else{ 544 return(formatByteCountToKiBEtcPerSec(data)+" ("+ formatByteCountToKiBEtcPerSec(prot)+")"); 545 } 546 }else if ( data_stats_only ){ 547 return( formatByteCountToKiBEtcPerSec( data )); 548 }else{ 549 return( formatByteCountToKiBEtcPerSec( prot + data )); 550 } 551 } 552 553 public static String formatByteCountToKiBEtcPerSec( long n )554 formatByteCountToKiBEtcPerSec( 555 long n ) 556 { 557 return( formatByteCountToKiBEtc(n,true,TRUNCZEROS_NO)); 558 } 559 560 561 public static String formatByteCountToKiBEtcPerSec( long n, boolean bTruncateZeros)562 formatByteCountToKiBEtcPerSec( 563 long n, 564 boolean bTruncateZeros) 565 { 566 return( formatByteCountToKiBEtc(n,true, bTruncateZeros)); 567 } 568 569 // base 10 ones 570 571 public static String formatByteCountToBase10KBEtc( long n)572 formatByteCountToBase10KBEtc( 573 long n) 574 { 575 if ( use_units_rate_bits ){ 576 n *= 8; 577 } 578 579 if (n < 1000){ 580 581 return n + units_base10[UNIT_B]; 582 583 }else if (n < 1000 * 1000){ 584 585 return (n / 1000) + "." + 586 ((n % 1000) / 100) + 587 units_base10[UNIT_KB]; 588 589 }else if ( n < 1000L * 1000L * 1000L || not_use_GB_TB ){ 590 591 return (n / (1000L * 1000L)) + "." + 592 ((n % (1000L * 1000L)) / (1000L * 100L)) + 593 units_base10[UNIT_MB]; 594 595 }else if (n < 1000L * 1000L * 1000L * 1000L){ 596 597 return (n / (1000L * 1000L * 1000L)) + "." + 598 ((n % (1000L * 1000L * 1000L)) / (1000L * 1000L * 100L))+ 599 units_base10[UNIT_GB]; 600 601 }else if (n < 1000L * 1000L * 1000L * 1000L* 1000L){ 602 603 return (n / (1000L * 1000L * 1000L* 1000L)) + "." + 604 ((n % (1000L * 1000L * 1000L* 1000L)) / (1000L * 1000L * 1000L* 100L))+ 605 units_base10[UNIT_TB]; 606 }else{ 607 608 return Formats_units_alot; 609 } 610 } 611 612 public static String formatByteCountToBase10KBEtcPerSec( long n )613 formatByteCountToBase10KBEtcPerSec( 614 long n ) 615 { 616 return( formatByteCountToBase10KBEtc(n) + per_sec ); 617 } 618 619 620 /** 621 * Print the BITS/second in an international format. 622 * @param n - always formatted using SI (i.e. decimal) prefixes 623 * @return String in an internationalized format. 624 */ 625 public static String formatByteCountToBitsPerSec( long n)626 formatByteCountToBitsPerSec( 627 long n) 628 { 629 double dbl = n * 8; 630 631 int unitIndex = UNIT_B; 632 633 long div = 1000; 634 635 while (dbl >= div && unitIndex < unitsStopAt){ 636 637 dbl /= div; 638 unitIndex++; 639 } 640 641 int precision = UNITS_PRECISION[unitIndex]; 642 643 return( formatDecimal(dbl, precision, true, true) + units_bits[unitIndex] + per_sec ); 644 } 645 646 public static String formatETA(long eta)647 formatETA(long eta) 648 { 649 return( formatETA( eta, false )); 650 } 651 652 private static final SimpleDateFormat abs_df = new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss" ); 653 654 public static String formatETA(long eta,boolean abs )655 formatETA(long eta,boolean abs ) 656 { 657 if (eta == 0) return PeerManager_status_finished; 658 if (eta == -1) return ""; 659 if (eta > 0){ 660 if ( abs && !(eta == Constants.CRAPPY_INFINITY_AS_INT || eta >= Constants.CRAPPY_INFINITE_AS_LONG )){ 661 662 long now = SystemTime.getCurrentTime(); 663 long then = now + eta*1000; 664 665 if ( eta > 5*60 ){ 666 667 then = (then/(60*1000))*(60*1000); 668 } 669 670 String str1; 671 String str2; 672 673 synchronized( abs_df ){ 674 str1 = abs_df.format(new Date( now )); 675 str2 = abs_df.format(new Date( then )); 676 } 677 678 int len = Math.min(str1.length(), str2.length())-2; 679 680 int diff_at = len; 681 682 for ( int i=0; i<len; i++){ 683 684 char c1 = str1.charAt( i ); 685 686 if ( c1 != str2.charAt(i)){ 687 688 diff_at = i; 689 690 break; 691 } 692 } 693 694 String res; 695 696 if ( diff_at >= 11 ){ 697 698 res = str2.substring( 11 ); 699 700 }else if ( diff_at >= 5 ){ 701 702 res = str2.substring( 5 ); 703 704 }else{ 705 706 res = str2; 707 } 708 709 return( res ); 710 711 }else{ 712 return TimeFormatter.format(eta); 713 } 714 } 715 716 return PeerManager_status_finishedin + " " + TimeFormatter.format(eta * -1); 717 } 718 719 720 public static String formatDownloaded( DownloadManagerStats stats )721 formatDownloaded( 722 DownloadManagerStats stats ) 723 { 724 long total_discarded = stats.getDiscarded(); 725 long total_received = stats.getTotalGoodDataBytesReceived(); 726 727 if(total_discarded == 0){ 728 729 return formatByteCountToKiBEtc(total_received); 730 731 }else{ 732 733 return formatByteCountToKiBEtc(total_received) + " ( " + 734 DisplayFormatters.formatByteCountToKiBEtc(total_discarded) + " " + 735 discarded + " )"; 736 } 737 } 738 739 public static String formatHashFails( DownloadManager download_manager )740 formatHashFails( 741 DownloadManager download_manager ) 742 { 743 TOTorrent torrent = download_manager.getTorrent(); 744 745 if ( torrent != null ){ 746 747 long bad = download_manager.getStats().getHashFailBytes(); 748 749 // size can exceed int so ensure longs used in multiplication 750 751 long count = bad / (long)torrent.getPieceLength(); 752 753 String result = count + " ( " + formatByteCountToKiBEtc(bad) + " )"; 754 755 return result; 756 } 757 758 return ""; 759 } 760 761 public static String formatDownloadStatus( DownloadManager manager )762 formatDownloadStatus( 763 DownloadManager manager ) 764 { 765 if ( manager == null ){ 766 767 return( ManagerItem_error + ": Download is null" ); 768 } 769 770 int state = manager.getState(); 771 772 String tmp = ""; 773 774 switch (state) { 775 case DownloadManager.STATE_QUEUED: 776 tmp = ManagerItem_queued; 777 break; 778 779 case DownloadManager.STATE_DOWNLOADING: 780 tmp = ManagerItem_downloading; 781 if ( manager.isSwarmMerging() != null ){ 782 tmp += " + " + ManagerItem_swarmMerge; 783 } 784 break; 785 786 case DownloadManager.STATE_SEEDING:{ 787 788 DiskManager diskManager = manager.getDiskManager(); 789 790 if ( diskManager != null ){ 791 792 int mp = diskManager.getMoveProgress(); 793 794 if ( mp != -1 ){ 795 796 tmp = ManagerItem_moving + ": " + formatPercentFromThousands( mp ); 797 798 }else{ 799 int done = diskManager.getCompleteRecheckStatus(); 800 801 if ( done != -1 ){ 802 803 tmp = ManagerItem_seeding + " + " + ManagerItem_checking + ": " + formatPercentFromThousands(done); 804 } 805 } 806 } 807 808 if ( tmp == "" ){ 809 810 if (manager.getPeerManager() != null && manager.getPeerManager().isSuperSeedMode()) { 811 812 tmp = ManagerItem_superseeding; 813 814 }else{ 815 816 tmp = ManagerItem_seeding; 817 } 818 } 819 820 break; 821 } 822 case DownloadManager.STATE_STOPPED: 823 tmp = manager.isPaused() ? ManagerItem_paused : ManagerItem_stopped; 824 break; 825 826 case DownloadManager.STATE_ERROR: 827 tmp = ManagerItem_error + ": " + manager.getErrorDetails(); 828 break; 829 830 case DownloadManager.STATE_WAITING: 831 tmp = ManagerItem_waiting; 832 break; 833 834 case DownloadManager.STATE_INITIALIZING: 835 tmp = ManagerItem_initializing; 836 break; 837 838 case DownloadManager.STATE_INITIALIZED: 839 tmp = ManagerItem_initializing; 840 break; 841 842 case DownloadManager.STATE_ALLOCATING:{ 843 tmp = ManagerItem_allocating; 844 DiskManager diskManager = manager.getDiskManager(); 845 if (diskManager != null){ 846 tmp += ": " + formatPercentFromThousands( diskManager.getPercentDone()); 847 } 848 break; 849 } 850 case DownloadManager.STATE_CHECKING: 851 tmp = ManagerItem_checking + ": " 852 + formatPercentFromThousands(manager.getStats().getCompleted()); 853 break; 854 855 case DownloadManager.STATE_FINISHING: 856 tmp = ManagerItem_finishing; 857 break; 858 859 case DownloadManager.STATE_READY: 860 tmp = ManagerItem_ready; 861 break; 862 863 case DownloadManager.STATE_STOPPING: 864 tmp = ManagerItem_stopping; 865 break; 866 867 default: 868 tmp = String.valueOf(state); 869 } 870 871 if (manager.isForceStart() && 872 (state == DownloadManager.STATE_SEEDING || 873 state == DownloadManager.STATE_DOWNLOADING)) 874 tmp = ManagerItem_forced + " " + tmp; 875 return( tmp ); 876 } 877 878 public static String formatDownloadStatusDefaultLocale( DownloadManager manager )879 formatDownloadStatusDefaultLocale( 880 DownloadManager manager ) 881 { 882 int state = manager.getState(); 883 884 String tmp = ""; 885 886 DiskManager dm = manager.getDiskManager(); 887 888 switch (state) { 889 case DownloadManager.STATE_WAITING : 890 tmp = MessageText.getDefaultLocaleString("ManagerItem.waiting"); 891 break; 892 case DownloadManager.STATE_INITIALIZING : 893 tmp = MessageText.getDefaultLocaleString("ManagerItem.initializing"); 894 break; 895 case DownloadManager.STATE_INITIALIZED : 896 tmp = MessageText.getDefaultLocaleString("ManagerItem.initializing"); 897 break; 898 case DownloadManager.STATE_ALLOCATING : 899 tmp = MessageText.getDefaultLocaleString("ManagerItem.allocating"); 900 break; 901 case DownloadManager.STATE_CHECKING : 902 tmp = MessageText.getDefaultLocaleString("ManagerItem.checking"); 903 break; 904 case DownloadManager.STATE_FINISHING : 905 tmp = MessageText.getDefaultLocaleString("ManagerItem.finishing"); 906 break; 907 case DownloadManager.STATE_READY : 908 tmp = MessageText.getDefaultLocaleString("ManagerItem.ready"); 909 break; 910 case DownloadManager.STATE_DOWNLOADING : 911 tmp = MessageText.getDefaultLocaleString("ManagerItem.downloading"); 912 if ( manager.isSwarmMerging() != null ){ 913 tmp += " + " + MessageText.getDefaultLocaleString( "TableColumn.header.mergeddata" ); 914 } 915 break; 916 case DownloadManager.STATE_SEEDING : 917 if (dm != null && dm.getCompleteRecheckStatus() != -1 ) { 918 int done = dm.getCompleteRecheckStatus(); 919 920 if ( done == -1 ){ 921 done = 1000; 922 } 923 924 tmp = MessageText.getDefaultLocaleString("ManagerItem.seeding") + " + " + 925 MessageText.getDefaultLocaleString("ManagerItem.checking") + 926 ": " + formatPercentFromThousands( done ); 927 } 928 else if(manager.getPeerManager()!= null && manager.getPeerManager().isSuperSeedMode()){ 929 930 tmp = MessageText.getDefaultLocaleString("ManagerItem.superseeding"); 931 } 932 else { 933 tmp = MessageText.getDefaultLocaleString("ManagerItem.seeding"); 934 } 935 break; 936 case DownloadManager.STATE_STOPPING : 937 tmp = MessageText.getDefaultLocaleString("ManagerItem.stopping"); 938 break; 939 case DownloadManager.STATE_STOPPED : 940 tmp = MessageText.getDefaultLocaleString(manager.isPaused()?"ManagerItem.paused":"ManagerItem.stopped"); 941 break; 942 case DownloadManager.STATE_QUEUED : 943 tmp = MessageText.getDefaultLocaleString("ManagerItem.queued"); 944 break; 945 case DownloadManager.STATE_ERROR : 946 tmp = MessageText.getDefaultLocaleString("ManagerItem.error").concat(": ").concat(manager.getErrorDetails()); //$NON-NLS-1$ //$NON-NLS-2$ 947 break; 948 default : 949 tmp = String.valueOf(state); 950 } 951 952 return( tmp ); 953 } 954 955 public static String trimDigits( String str, int num_digits )956 trimDigits( 957 String str, 958 int num_digits ) 959 { 960 char[] chars = str.toCharArray(); 961 String res = ""; 962 int digits = 0; 963 964 for (int i=0;i<chars.length;i++){ 965 char c = chars[i]; 966 if ( Character.isDigit(c)){ 967 digits++; 968 if ( digits <= num_digits ){ 969 res += c; 970 } 971 }else if ( c == '.' && digits >= 3 ){ 972 973 }else{ 974 res += c; 975 } 976 } 977 978 return( res ); 979 } 980 formatPercentFromThousands(int thousands)981 public static String formatPercentFromThousands(int thousands) { 982 983 return percentage_format.format(thousands / 1000.0); 984 } 985 formatTimeStamp(long time)986 public static String formatTimeStamp(long time) { 987 StringBuffer sb = new StringBuffer(); 988 Calendar calendar = Calendar.getInstance(); 989 calendar.setTimeInMillis(time); 990 sb.append('['); 991 sb.append(formatIntToTwoDigits(calendar.get(Calendar.DAY_OF_MONTH))); 992 sb.append('.'); 993 sb.append(formatIntToTwoDigits(calendar.get(Calendar.MONTH)+1)); // 0 based 994 sb.append('.'); 995 sb.append(calendar.get(Calendar.YEAR)); 996 sb.append(' '); 997 sb.append(formatIntToTwoDigits(calendar.get(Calendar.HOUR_OF_DAY))); 998 sb.append(':'); 999 sb.append(formatIntToTwoDigits(calendar.get(Calendar.MINUTE))); 1000 sb.append(':'); 1001 sb.append(formatIntToTwoDigits(calendar.get(Calendar.SECOND))); 1002 sb.append(']'); 1003 return sb.toString(); 1004 } 1005 formatIntToTwoDigits(int n)1006 public static String formatIntToTwoDigits(int n) { 1007 return n < 10 ? "0".concat(String.valueOf(n)) : String.valueOf(n); 1008 } 1009 formatDate(long date, String format)1010 private static String formatDate(long date, String format) { 1011 if (date == 0) {return "";} 1012 SimpleDateFormat temp = new SimpleDateFormat(format); 1013 return temp.format(new Date(date)); 1014 } 1015 formatDate(long date)1016 public static String formatDate(long date) { 1017 return formatDate(date, "dd-MMM-yyyy HH:mm:ss"); 1018 } 1019 formatDateShort(long date)1020 public static String formatDateShort(long date) { 1021 return formatDate(date, "MMM dd, HH:mm"); 1022 } 1023 formatDateNum(long date)1024 public static String formatDateNum(long date) { 1025 return formatDate(date, "yyyy-MM-dd HH:mm:ss"); 1026 } 1027 1028 // 1029 // These methods will be exposed in the plugin API. 1030 // 1031 formatCustomDateOnly(long date)1032 public static String formatCustomDateOnly(long date) { 1033 if (date == 0) {return "";} 1034 return formatDate(date, "dd-MMM-yyyy"); 1035 } 1036 formatCustomTimeOnly(long date)1037 public static String formatCustomTimeOnly(long date) { 1038 return formatCustomTimeOnly(date, true); 1039 } 1040 formatCustomTimeOnly(long date, boolean with_secs)1041 public static String formatCustomTimeOnly(long date, boolean with_secs) { 1042 if (date == 0) {return "";} 1043 return formatDate(date, (with_secs) ? "HH:mm:ss" : "HH:mm"); 1044 } 1045 formatCustomDateTime(long date)1046 public static String formatCustomDateTime(long date) { 1047 if (date == 0) {return "";} 1048 return formatDate(date); 1049 } 1050 1051 // 1052 // End methods 1053 // 1054 1055 public static String formatTime( long time )1056 formatTime( 1057 long time ) 1058 { 1059 return( TimeFormatter.formatColon( time / 1000 )); 1060 } 1061 1062 /** 1063 * Format a real number to the precision specified. Does not round the number 1064 * or truncate trailing zeros. 1065 * 1066 * @param value real number to format 1067 * @param precision # of digits after the decimal place 1068 * @return formatted string 1069 */ 1070 public static String formatDecimal( double value, int precision)1071 formatDecimal( 1072 double value, 1073 int precision) 1074 { 1075 return formatDecimal(value, precision, TRUNCZEROS_NO, ROUND_NO); 1076 } 1077 1078 1079 /** 1080 * Format a real number 1081 * 1082 * @param value real number to format 1083 * @param precision max # of digits after the decimal place 1084 * @param bTruncateZeros remove any trailing zeros after decimal place 1085 * @param bRound Whether the number will be rounded to the precision, or 1086 * truncated off. 1087 * @return formatted string 1088 */ 1089 public static String formatDecimal( double value, int precision, boolean bTruncateZeros, boolean bRound)1090 formatDecimal( 1091 double value, 1092 int precision, 1093 boolean bTruncateZeros, 1094 boolean bRound) 1095 { 1096 if (Double.isNaN(value) || Double.isInfinite(value)) { 1097 return Constants.INFINITY_STRING; 1098 } 1099 1100 double tValue; 1101 if (bRound) { 1102 tValue = value; 1103 } else { 1104 // NumberFormat rounds, so truncate at precision 1105 if (precision == 0) { 1106 tValue = (long) value; 1107 } else { 1108 double shift = Math.pow(10, precision); 1109 tValue = ((long) (value * shift)) / shift; 1110 } 1111 } 1112 1113 int cache_index = (precision << 2) + ((bTruncateZeros ? 1 : 0) << 1) 1114 + (bRound ? 1 : 0); 1115 1116 NumberFormat nf = null; 1117 1118 if (cache_index < cached_number_formats.length) { 1119 nf = cached_number_formats[cache_index]; 1120 } 1121 1122 if (nf == null) { 1123 nf = NumberFormat.getNumberInstance(); 1124 nf.setGroupingUsed(false); // no commas 1125 if (!bTruncateZeros) { 1126 nf.setMinimumFractionDigits(precision); 1127 } 1128 if (bRound) { 1129 nf.setMaximumFractionDigits(precision); 1130 } 1131 1132 if (cache_index < cached_number_formats.length) { 1133 cached_number_formats[cache_index] = nf; 1134 } 1135 } 1136 1137 return nf.format(tValue); 1138 } 1139 1140 /** 1141 * Attempts vaguely smart string truncation by searching for largest token and truncating that 1142 * @param str 1143 * @param width 1144 * @return 1145 */ 1146 1147 public static String truncateString( String str, int width )1148 truncateString( 1149 String str, 1150 int width ) 1151 { 1152 int excess = str.length() - width; 1153 1154 if ( excess <= 0 ){ 1155 1156 return( str ); 1157 } 1158 1159 excess += 3; // for ... 1160 1161 int token_start = -1; 1162 int max_len = 0; 1163 int max_start = 0; 1164 1165 for (int i=0;i<str.length();i++){ 1166 1167 char c = str.charAt(i); 1168 1169 if ( Character.isLetterOrDigit( c ) || c == '-' || c == '~' ){ 1170 1171 if ( token_start == -1 ){ 1172 1173 token_start = i; 1174 1175 }else{ 1176 1177 int len = i - token_start; 1178 1179 if ( len > max_len ){ 1180 1181 max_len = len; 1182 max_start = token_start; 1183 } 1184 } 1185 }else{ 1186 1187 token_start = -1; 1188 } 1189 } 1190 1191 if ( max_len >= excess ){ 1192 1193 int trim_point = max_start + max_len; 1194 1195 return( str.substring( 0, trim_point - excess ) + "..." + str.substring( trim_point )); 1196 }else{ 1197 1198 return( str.substring( 0, width-3 ) + "..." ); 1199 } 1200 } 1201 1202 getDecimalSeparator()1203 public static char getDecimalSeparator() { 1204 return decimalSeparator; 1205 } 1206 1207 private static void updateFormatOverrides( String formats )1208 updateFormatOverrides( 1209 String formats ) 1210 { 1211 Map<String,Formatter> map = new HashMap<String, Formatter>(); 1212 1213 String[] lines = formats.split( "\n" ); 1214 1215 List<String> errors = new ArrayList<String>(); 1216 1217 for ( String line: lines ){ 1218 1219 String error = null; 1220 1221 line = line.trim(); 1222 1223 if ( line.length() == 0 ){ 1224 1225 continue; 1226 } 1227 1228 String[] key_value = line.split( ":", 2 ); 1229 1230 if ( key_value.length != 2 ){ 1231 1232 error = "is missing ':'"; 1233 1234 }else{ 1235 1236 String key = key_value[0].trim(); 1237 String value = key_value[1].trim(); 1238 1239 Formatter formatter = new Formatter(); 1240 1241 error = formatter.parse( value ); 1242 1243 if ( error == null ){ 1244 1245 map.put( key, formatter ); 1246 } 1247 } 1248 1249 if ( error != null ){ 1250 1251 errors.add( "'" + line + "' " + error ); 1252 } 1253 } 1254 1255 String status_msg; 1256 1257 if ( errors.size() > 0 ){ 1258 1259 status_msg = "Format parsing failed: " + errors; 1260 1261 }else{ 1262 1263 status_msg = ""; 1264 } 1265 1266 COConfigurationManager.setParameter( "config.style.formatOverrides.status", status_msg ); 1267 1268 format_map = map; 1269 } 1270 1271 public static String formatCustomRate( String key, long value )1272 formatCustomRate( 1273 String key, 1274 long value ) 1275 { 1276 Formatter formatter = format_map.get( key ); 1277 1278 if ( formatter != null ){ 1279 1280 return( formatter.format( value, true )); 1281 } 1282 1283 return( null ); 1284 } 1285 1286 public static String formatCustomSize( String key, long value )1287 formatCustomSize( 1288 String key, 1289 long value ) 1290 { 1291 Formatter formatter = format_map.get( key ); 1292 1293 if ( formatter != null ){ 1294 1295 return( formatter.format( value, false )); 1296 } 1297 1298 return( null ); 1299 } 1300 1301 private static class 1302 Formatter 1303 { 1304 private final static int FORMAT_UNIT_B = 0x0001; 1305 private final static int FORMAT_UNIT_K = 0x0002; 1306 private final static int FORMAT_UNIT_M = 0x0004; 1307 private final static int FORMAT_UNIT_G = 0x0008; 1308 private final static int FORMAT_UNIT_T = 0x0010; 1309 1310 private final static int FORMAT_UNIT_NONE = 0x0000; 1311 private final static int FORMAT_UNIT_ALL = 0xffff; 1312 1313 private final static int[] tens = { 1, 10, 100, 1000, 10000, 100000, 1000000 }; 1314 1315 private int unit_formats = FORMAT_UNIT_ALL; 1316 private boolean hide_units = false; 1317 private boolean short_units = false; 1318 private Boolean rate_units = null; 1319 1320 private NumberFormat number_format = null; 1321 private long number_format_fact = 1; 1322 1323 private int rounding = BigDecimal.ROUND_HALF_EVEN; // decimal format default 1324 1325 private String parse( String str )1326 parse( 1327 String str ) 1328 { 1329 try{ 1330 String[] args = str.split( "," ); 1331 1332 for ( String arg: args ){ 1333 1334 arg = arg.trim(); 1335 1336 if ( arg.length() == 0 ){ 1337 1338 continue; 1339 } 1340 1341 String[] sub_args = arg.split( ";" ); 1342 1343 if ( sub_args.length == 0 ){ 1344 1345 return( "invalid argument '" + arg + "'" ); 1346 } 1347 1348 String main_arg = null; 1349 1350 for ( String sub_arg: sub_args ){ 1351 1352 sub_arg = sub_arg.trim(); 1353 1354 String[] bits = sub_arg.split( "=" ); 1355 1356 if ( bits.length != 2 ){ 1357 1358 return( "invalid argument '" + arg + "'" ); 1359 } 1360 1361 String arg_name = bits[0].trim().toLowerCase( Locale.US ); 1362 String arg_value = bits[1].trim(); 1363 1364 if ( main_arg == null ){ 1365 1366 main_arg = arg_name; 1367 1368 if ( main_arg.equals( "units" )){ 1369 1370 int mask = arg_value.contains( "-" )?FORMAT_UNIT_ALL:FORMAT_UNIT_NONE; 1371 1372 String[] units = arg_value.toLowerCase( Locale.US ).split( "&" ); 1373 1374 for ( String unit: units ){ 1375 1376 boolean remove; 1377 1378 if ( unit.startsWith( "-" )){ 1379 1380 unit = unit.substring(1); 1381 1382 remove = true; 1383 1384 }else{ 1385 1386 remove = false; 1387 } 1388 1389 char c = unit.charAt(0); 1390 1391 int m; 1392 1393 if ( c == 'b' ){ 1394 1395 m = FORMAT_UNIT_B; 1396 1397 }else if ( c == 'k' ){ 1398 1399 m = FORMAT_UNIT_K; 1400 1401 }else if ( c == 'm' ){ 1402 1403 m = FORMAT_UNIT_M; 1404 1405 }else if ( c == 'g' ){ 1406 1407 m = FORMAT_UNIT_G; 1408 1409 }else if ( c == 't' ){ 1410 1411 m = FORMAT_UNIT_T; 1412 1413 }else{ 1414 1415 return( "Invalid unit: " + unit ); 1416 } 1417 1418 if ( remove ){ 1419 1420 mask = mask & ~m; 1421 1422 }else{ 1423 1424 mask = mask | m; 1425 } 1426 } 1427 1428 unit_formats = mask; 1429 1430 }else if ( main_arg.equals( "format" )){ 1431 1432 number_format = NumberFormat.getInstance(); 1433 1434 if ( number_format instanceof DecimalFormat ){ 1435 1436 ((DecimalFormat)number_format).applyPattern( arg_value ); 1437 1438 }else{ 1439 1440 Debug.out( "Number pattern isn't a DecimalFormat: " + number_format ); 1441 } 1442 1443 int max_fd = number_format.getMaximumFractionDigits(); 1444 1445 if ( max_fd < tens.length ){ 1446 1447 number_format_fact = tens[max_fd]; 1448 1449 }else{ 1450 1451 number_format_fact = 1; 1452 1453 for (int i=0;i<max_fd;i++){ 1454 1455 number_format_fact *= 10; 1456 } 1457 } 1458 }else{ 1459 1460 Debug.out( "TODO: " + main_arg ); 1461 } 1462 }else{ 1463 1464 if ( main_arg.equals( "units" )){ 1465 1466 if ( arg_name.equals( "hide" )){ 1467 1468 hide_units = arg_value.toLowerCase( Locale.US ).startsWith( "y" ); 1469 1470 }else if ( arg_name.equals( "short" )){ 1471 1472 short_units = arg_value.toLowerCase( Locale.US ).startsWith( "y" ); 1473 1474 }else if ( arg_name.equals( "rate" )){ 1475 1476 rate_units = arg_value.toLowerCase( Locale.US ).startsWith( "y" ); 1477 1478 }else{ 1479 1480 Debug.out( "TODO: " + arg_name ); 1481 } 1482 }else if ( main_arg.equals( "format" )){ 1483 1484 if ( arg_name.equals( "round" )){ 1485 1486 String r = arg_value.toLowerCase( Locale.US ); 1487 1488 if ( r.equals( "up" )){ 1489 1490 rounding = BigDecimal.ROUND_UP; 1491 1492 }else if ( r.equals( "down" )){ 1493 1494 rounding = BigDecimal.ROUND_DOWN; 1495 1496 }else if ( r.equals( "halfup" )){ 1497 1498 rounding = BigDecimal.ROUND_HALF_UP; 1499 1500 }else if ( r.equals( "halfdown" )){ 1501 1502 rounding = BigDecimal.ROUND_HALF_DOWN; 1503 1504 }else{ 1505 1506 return( "Invald round mode: " + r ); 1507 } 1508 } 1509 }else{ 1510 1511 Debug.out( "TODO: " + arg_name ); 1512 } 1513 } 1514 } 1515 } 1516 1517 return( null ); 1518 1519 }catch( Throwable e ){ 1520 1521 return( Debug.getNestedExceptionMessage( e )); 1522 } 1523 } 1524 1525 private String format( long _value, boolean is_rate )1526 format( 1527 long _value, 1528 boolean is_rate ) 1529 { 1530 try{ 1531 double value = _value; 1532 1533 String unit_str = ""; 1534 1535 if ( unit_formats == FORMAT_UNIT_K ){ 1536 1537 value = value/1024; 1538 1539 unit_str = all_units[ UNIT_KB ]; 1540 1541 }else if ( unit_formats == FORMAT_UNIT_M ){ 1542 1543 value = value/(1024*1024); 1544 1545 unit_str = all_units[ UNIT_MB ]; 1546 1547 }else if ( unit_formats == FORMAT_UNIT_G ){ 1548 1549 value = value/(1024*1024*1024L); 1550 1551 unit_str = all_units[ UNIT_GB ]; 1552 1553 }else if ( unit_formats == FORMAT_UNIT_T ){ 1554 1555 value = value/(1024*1024*1024*1024L); 1556 1557 unit_str = all_units[ UNIT_TB ]; 1558 } 1559 1560 String result; 1561 1562 if ( number_format != null ){ 1563 1564 if ( rounding != BigDecimal.ROUND_HALF_EVEN ){ 1565 1566 // meh, DecimalFormat doesn't support rounding modes so we have to pre-calculate and hope 1567 1568 double l_value = (long)value; 1569 1570 double fraction = value - l_value; 1571 1572 fraction *= number_format_fact; 1573 1574 double l_fraction = (long)fraction; 1575 1576 double rem = fraction - l_fraction; 1577 1578 if ( rounding == BigDecimal.ROUND_DOWN ){ 1579 1580 }else if ( rounding == BigDecimal.ROUND_UP ){ 1581 1582 if ( rem > 0 ){ 1583 1584 l_fraction++; 1585 } 1586 }else if ( rounding == BigDecimal.ROUND_HALF_UP ){ 1587 1588 if ( rem >= 0.5 ){ 1589 1590 l_fraction++; 1591 } 1592 }else if ( rounding == BigDecimal.ROUND_HALF_DOWN ){ 1593 1594 if ( rem > 0.5 ){ 1595 1596 l_fraction++; 1597 } 1598 } 1599 1600 l_fraction /= number_format_fact; 1601 1602 //System.out.println( value + " -> " + l_value + "/" + l_fraction + "/" + rem ); 1603 1604 value = l_value + l_fraction; 1605 } 1606 1607 synchronized( number_format ){ 1608 1609 result = number_format.format( value ); 1610 } 1611 1612 }else{ 1613 1614 result = String.valueOf( value ); 1615 } 1616 1617 if ( hide_units ){ 1618 1619 return( result ); 1620 } 1621 1622 if ( unit_str.length() > 0 ){ 1623 1624 if ( short_units ){ 1625 1626 result += " " + unit_str.charAt(1); 1627 1628 }else{ 1629 1630 result += unit_str; 1631 } 1632 } 1633 1634 if ( is_rate && ( rate_units == null || rate_units )){ 1635 1636 result += per_sec; 1637 } 1638 1639 return( result ); 1640 1641 }catch( Throwable e ){ 1642 1643 Debug.out( e ); 1644 1645 return( String.valueOf( _value )); 1646 } 1647 } 1648 } 1649 1650 1651 1652 // Used to test fractions and displayformatter. 1653 // Keep until everything works okay. 1654 public static void main(String[] args)1655 main(String[] args) 1656 { 1657 // set decimal display to "," 1658 //Locale.setDefault(Locale.GERMAN); 1659 1660 double d = 0.000003991630774821635; 1661 NumberFormat nf = NumberFormat.getNumberInstance(); 1662 nf.setMaximumFractionDigits(6); 1663 nf.setMinimumFractionDigits(6); 1664 String s = nf.format(d); 1665 1666 System.out.println("Actual: " + d); // Displays 3.991630774821635E-6 1667 System.out.println("NF/6: " + s); // Displays 0.000004 1668 // should display 0.000003 1669 System.out.println("DF: " + DisplayFormatters.formatDecimal(d , 6)); 1670 // should display 0 1671 System.out.println("DF 0: " + DisplayFormatters.formatDecimal(d , 0)); 1672 // should display 0.000000 1673 System.out.println("0.000000:" + DisplayFormatters.formatDecimal(0 , 6)); 1674 // should display 0.001 1675 System.out.println("0.001:" + DisplayFormatters.formatDecimal(0.001, 6, TRUNCZEROS_YES, ROUND_NO)); 1676 // should display 0 1677 System.out.println("0:" + DisplayFormatters.formatDecimal(0 , 0)); 1678 // should display 123456 1679 System.out.println("123456:" + DisplayFormatters.formatDecimal(123456, 0)); 1680 // should display 123456 1681 System.out.println("123456:" + DisplayFormatters.formatDecimal(123456.999, 0)); 1682 System.out.println(DisplayFormatters.formatDecimal(0.0/0, 3)); 1683 } 1684 }