StuffItem.cs (15062B)
1 using System; 2 using System.Collections.Generic; 3 using System.IO; 4 5 namespace LanTool.Classes 6 { 7 internal class StuffItemSorter : System.Collections.IComparer 8 { 9 public int Compare( object xx, object yy ) 10 { 11 StuffItem x = ( StuffItem )( ( System.Windows.Forms.TreeNode )xx ).Tag; 12 StuffItem y = ( StuffItem )( ( System.Windows.Forms.TreeNode )yy ).Tag; 13 string xa = ( x == null ) ? "0" : ( x.IsFile ? "2" + x.Path : "1" + x.Path ); 14 string ya = ( y == null ) ? "0" : ( y.IsFile ? "2" + y.Path : "1" + y.Path ); 15 return String.Compare( xa, ya ); 16 } 17 } 18 19 /// <summary> 20 /// Ein Ding des Begehrs, sei es auf der eigenen oder der fremden Platte 21 /// </summary> 22 internal class StuffItem 23 { 24 #region Parameter eines StuffItems 25 26 /// <summary> 27 /// Übergeordnetes StuffItem 28 /// </summary> 29 public StuffItem Parent = null; 30 31 private string _name = String.Empty; 32 /// <summary> 33 /// Name des StuffItems 34 /// z.B. Dateiname ohne Pfad oder Name des Verzeichnisses 35 /// </summary> 36 public string Name 37 { 38 get 39 { 40 // Field ist noch nicht gefüllt, dann Name aus dem Dateiname oder dem Verzeichnisname ermitteln 41 if ( String.IsNullOrEmpty( _name ) ) 42 { 43 if ( IsFile ) 44 { 45 _name = System.IO.Path.GetFileName( Path ); 46 } 47 else 48 { 49 _name = Path.Substring( Path.LastIndexOf( "\\" ) + 1 ); 50 } 51 } 52 53 return _name; 54 } 55 private set 56 { 57 _name = value; 58 } 59 60 } 61 62 /// <summary> 63 /// Kompletter Pfad zum StuffItems 64 /// </summary> 65 public string Path = String.Empty; 66 67 /// <summary> 68 /// Liste aller direkt untergeordneten StuffItems 69 /// </summary> 70 public List<StuffItem> ChildItems = new List<StuffItem>(); 71 72 /// <summary> 73 /// MD5-Hashwert des StuffItems 74 /// </summary> 75 public string Hash = ""; 76 77 /// <summary> 78 /// Dateigröße 79 /// </summary> 80 public long Size; 81 82 /// <summary> 83 /// Dateigröße in lesbarer Ausgabe 84 /// </summary> 85 public string ReadableSize 86 { 87 get 88 { 89 if ( this.Size > 1024 * 1024 ) 90 return ( ( ( double )( this.Size / 104857 ) ) / 10 ).ToString() + " MB"; 91 else 92 return ( ( ( double )( this.Size / 102 ) ) / 10 ).ToString() + " KB"; 93 } 94 } 95 96 /// <summary> 97 /// Dateigröße in Byte-Ausgabe 98 /// </summary> 99 public string LongSize 100 { 101 get 102 { 103 // Zahlenformat: mit 1000er-Punkten ohne Nachkommastellen 104 return String.Format( "{0:N0} Bytes", this.Size ); 105 } 106 } 107 108 private bool _checked = false; 109 /// <summary> 110 /// Dateien, die markiert sind aber nicht sichtbar, werden als nicht markiert gehandhabt 111 /// </summary> 112 public bool Checked 113 { 114 get 115 { 116 return _checked && IsVisible; 117 } 118 set 119 { 120 _checked = value; 121 } 122 } 123 124 private bool updateCheck = true; 125 126 private bool _isOnline = true; 127 /// <summary> 128 /// Online und Offline wird grundsätzlich für den ganzen Zweig darunter gesetzt 129 /// </summary> 130 public bool IsOnline 131 { 132 get 133 { 134 return _isOnline; 135 } 136 set 137 { 138 _isOnline = value; 139 foreach ( StuffItem si in ChildItems ) 140 si.IsOnline = value; 141 } 142 } 143 144 /// <summary> 145 /// True wenn es sich um eine Datei handelt 146 /// </summary> 147 public bool IsFile = false; 148 149 /// <summary> 150 /// Legt das Icon für die Dateien/Ordner fest 151 /// </summary> 152 public TreeNodeImage Icon 153 { 154 get 155 { 156 if ( this.HasReadError ) 157 { 158 if ( this.IsFile ) 159 { 160 return TreeNodeImage.FileError; 161 } 162 else 163 { 164 return TreeNodeImage.BrokenFolder; 165 } 166 } 167 else if ( !this.IsFile ) 168 { 169 return TreeNodeImage.Folder; 170 } 171 else if ( this.IsIgnored ) 172 { 173 return TreeNodeImage.FileIngored; 174 } 175 else if ( this.IsExcluded ) 176 { 177 return TreeNodeImage.FileExcluded; 178 } 179 else if ( this.HasClones ) 180 { 181 return TreeNodeImage.FileRed; 182 } 183 else if ( this.IsNeeded ) 184 { 185 return TreeNodeImage.FileSaugMich; 186 } 187 else if ( this.IsOnForeignDisk ) 188 { 189 return TreeNodeImage.FileHabSchon; 190 } 191 else 192 { 193 return TreeNodeImage.FileWhite; 194 } 195 } 196 } 197 198 /// <summary> 199 /// Liefert den Anzeigetext für TreeNode fest 200 /// </summary> 201 public string Text 202 { 203 get 204 { 205 String dispName = Name.Substring( Name.LastIndexOf( "\\" ) + 1 ); 206 if ( Parent == Program.MainWindow.m_MyDisks || Parent == Program.MainWindow.m_OtherDisks ) 207 { 208 dispName = Name; 209 } 210 211 if ( IsFile && !HasReadError ) 212 { 213 return String.Format( "{0} ({1})", dispName, ReadableSize ); 214 } 215 else 216 { 217 return dispName; 218 } 219 } 220 } 221 222 /// <summary> 223 /// Gibt den ToolTip-Text für die Datei zurück 224 /// </summary> 225 public string ToolTip 226 { 227 get 228 { 229 if ( !this.IsFile ) 230 { 231 return String.Empty; 232 } 233 234 string temp; 235 236 // Standardausgaben 237 temp = "Pfad: " + this.Path + Environment.NewLine; 238 239 // die nachfolgenden Sachen nur anzeigen, wenn keine Lesefehler vorliegen 240 if ( this.HasReadError ) 241 { 242 temp += "Datei hat Lesefehler!"; 243 244 return temp; 245 } 246 247 temp += "Größe: " + this.LongSize + Environment.NewLine + 248 "Hash: " + this.Hash + Environment.NewLine; 249 250 // bei schon auf vorhandenen Dateien auf den fremden Platten, die lokalen 251 // Dateien mit anzeigen 252 if ( IsOnForeignDisk && !IsNeeded && !IsExcluded ) 253 { 254 temp += Environment.NewLine + "Meine Platten: " + Environment.NewLine + 255 String.Join( Environment.NewLine, this.GetLocalFiles.ToArray() ); 256 } 257 258 // bei Dubletten auf den eigenen Platten, diese anzeigen 259 if ( !IsOnForeignDisk && IsFile ) 260 { 261 List<StuffItem> clones = Program.MainWindow.m_MyDisks.GetItemClones( this ); 262 if ( clones.Count > 0 ) 263 { 264 temp += Environment.NewLine + "Dubletten: "; 265 foreach ( StuffItem csi in clones ) 266 { 267 temp += Environment.NewLine + csi.Path; 268 } 269 } 270 } 271 272 return temp; 273 } 274 } 275 276 /// <summary> 277 /// Gibt an, ob die Datei im Tree sichtbar ist 278 /// betrifft nur tatsächliche Dateien auf fremden Platten 279 /// abhängig vom Status der Datei und den eingestellten Optionen 280 /// </summary> 281 public bool IsVisible 282 { 283 get 284 { 285 // wenn keine Datei oder nicht auf fremden Platten - immer sichtbar 286 if ( !IsFile || !IsOnForeignDisk ) 287 { 288 return true; 289 } 290 else 291 { 292 // Dateien die gesperrt sind ausblenden falls Option aktiv 293 if ( IsExcluded && Program.MainWindow.m_Config.IsHideExcludedFiles ) 294 { 295 return false; 296 } 297 // Dateien die nicht gebraucht werden ausblenden falls Option aktiv 298 if ( !IsExcluded && !IsNeeded && Program.MainWindow.m_Config.IsHideExistingFiles ) 299 { 300 return false; 301 } 302 } 303 304 return true; 305 } 306 } 307 308 /// <summary> 309 /// True wenn die Datei ausgeschlossen ist 310 /// </summary> 311 public bool IsExcluded 312 { 313 get 314 { 315 return IsFile && Program.MainWindow.m_Cache.ExcludeCache.Contains( Program.MainWindow.m_Config.MD5FileSize + " " + this.Hash ); 316 } 317 } 318 319 /// <summary> 320 /// True wenn die Datei-Dubletten ignoriert werden 321 /// </summary> 322 public bool IsIgnored 323 { 324 get 325 { 326 return IsFile && !IsOnForeignDisk && HasClones && Program.MainWindow.m_Cache.IgnoreCache.Contains( Program.MainWindow.m_Config.MD5FileSize + " " + this.Hash ); 327 } 328 } 329 330 /// <summary> 331 /// Gibt an, ob beim Lesen des Verzeichnisses/der Datei ein Fehler aufgetreten ist 332 /// </summary> 333 public bool HasReadError = false; 334 335 /// <summary> 336 /// Gibt ab, ob sich die Datei auf einer fremden Platte befindet 337 /// </summary> 338 public bool IsOnForeignDisk = false; 339 340 /// <summary> 341 /// true, wenn die Datei noch nicht auf den eigenen Platten vorhanden ist und nicht 342 /// ausgeschlossen ist 343 /// </summary> 344 public bool IsNeeded 345 { 346 get 347 { 348 return IsFile && IsOnForeignDisk && !IsExcluded && 349 ( Program.MainWindow.m_MyDisks.GetRecursiveItemCount( this ) == 0 ); 350 } 351 } 352 353 /// <summary> 354 /// Gibt alle lokalen Dateien eines StuffItems zurück 355 /// </summary> 356 public List<String> GetLocalFiles 357 { 358 get 359 { 360 List<String> localFiles = new List<String>(); 361 if ( Program.MainWindow.m_MyDisks.GetRecursiveItemCount( this ) > 0 ) 362 { 363 foreach ( StuffItem lsi in Program.MainWindow.m_MyDisks.GetItemsRecursive( this ) ) 364 { 365 localFiles.Add( lsi.Path ); 366 } 367 } 368 return localFiles; 369 } 370 } 371 372 /// <summary> 373 /// Gibt alle Dateien auf fremden Platten eines StuffItems zurück 374 /// </summary> 375 public List<String> GetRemoteFiles 376 { 377 get 378 { 379 List<String> remoteFiles = new List<String>(); 380 if ( Program.MainWindow.m_OtherDisks.GetRecursiveItemCount( this ) > 0 ) 381 { 382 foreach ( StuffItem lsi in Program.MainWindow.m_OtherDisks.GetItemsRecursive( this ) ) 383 { 384 remoteFiles.Add( lsi.Path ); 385 } 386 } 387 return remoteFiles; 388 } 389 } 390 391 public bool HasClones 392 { 393 get 394 { 395 return IsFile && !IsOnForeignDisk && Program.MainWindow.m_MyDisks.GetRecursiveItemCount( this ) > 1; 396 } 397 } 398 399 /// <summary> 400 /// Speicher für Offline-Kopie der Directory-Anfragen 401 /// </summary> 402 virtual public Dictionary<string, List<string>> OfflineDirs 403 { 404 get 405 { 406 return Parent.OfflineDirs; 407 } 408 } 409 410 /// <summary> 411 /// Speicher für Offline-Kopie der Files-Anfragen 412 /// </summary> 413 virtual public Dictionary<string, List<string>> OfflineFiles 414 { 415 get 416 { 417 return Parent.OfflineFiles; 418 } 419 } 420 421 /// <summary> 422 /// Ein StuffItem für einen (Datei-)Pfad hinzufügen, falls 423 /// für diesen Pfad noch keines existiert 424 /// </summary> 425 /// <param name="path">Pfad</param> 426 /// <returns>Das alte oder neue Item</returns> 427 public StuffItem AddOrGetChildItemByPath( string path ) 428 { 429 // Altes Item suchen (nach Pfadnamen) 430 foreach ( StuffItem si in this.ChildItems ) 431 { 432 if ( si.Path.Equals( path ) ) 433 { 434 si.updateCheck = true; 435 return si; 436 } 437 } 438 439 // Neues Item einhängen, wenn das alte nicht exisitert 440 StuffItem new_si = new StuffItem(); 441 new_si.IsOnForeignDisk = this.IsOnForeignDisk; 442 new_si.Name = path; 443 new_si.Path = path; 444 new_si.Parent = this; 445 new_si.IsOnline = IsOnline; 446 new_si.updateCheck = true; 447 this.ChildItems.Add( new_si ); 448 return new_si; 449 } 450 451 #endregion 452 453 #region Aktionen am Item 454 455 /// <summary> 456 /// Datei sperren 457 /// </summary> 458 public void Exclude() 459 { 460 Program.MainWindow.m_Cache.ExcludeCache.Add( Program.MainWindow.m_Config.MD5FileSize + " " + this.Hash ); 461 } 462 463 /// <summary> 464 /// Gesperrte Datei wieder reinnehmen 465 /// </summary> 466 public void Include() 467 { 468 Program.MainWindow.m_Cache.ExcludeCache.Remove( Program.MainWindow.m_Config.MD5FileSize + " " + this.Hash ); 469 } 470 471 /// <summary> 472 /// Datei ignorieren 473 /// </summary> 474 public void Ignore() 475 { 476 Program.MainWindow.m_Cache.IgnoreCache.Add( Program.MainWindow.m_Config.MD5FileSize + " " + this.Hash ); 477 } 478 479 /// <summary> 480 /// Ignorierte Datei wieder reinnehmen 481 /// </summary> 482 public void UnIgnore() 483 { 484 Program.MainWindow.m_Cache.IgnoreCache.Remove( Program.MainWindow.m_Config.MD5FileSize + " " + this.Hash ); 485 } 486 487 #endregion 488 489 #region Platten scannen 490 491 /// <summary> 492 /// ChildItems aktualisieren (background task) 493 /// </summary> 494 public void UpdateChildsBackground() 495 { 496 Program.RunBackgroundTask( this, "UpdateChilds", null ); 497 } 498 499 /// <summary> 500 /// ChildItem aktualisieren und MainWindow neu aufbauen (Background Task) 501 /// </summary> 502 public void UpdateChilds( object state ) 503 { 504 // Statt der RootItems alle deren Kinder scannen 505 if ( this == Program.MainWindow.m_MyDisks || this == Program.MainWindow.m_OtherDisks ) 506 { 507 foreach ( StuffItem si in this.ChildItems.ToArray() ) 508 { 509 si.ScanChilds(); 510 } 511 } 512 else 513 { 514 this.ScanChilds(); 515 } 516 517 // Die Caches des jeweiligen Trees aktualisieren, in der das Item aktualisiert wurde 518 Program.MainWindow.m_MyDisks.CreateStuffItemTreeHash(); 519 Program.MainWindow.m_OtherDisks.CreateStuffItemTreeHash(); 520 521 // Baum neu zeichnen 522 Program.MainWindow.UpdateTrees(); 523 } 524 525 /// <summary> 526 /// ChildItems eines Items von der Platte einlesen (rekursiv) und Hash-Werte ermitteln 527 /// </summary> 528 private void ScanChilds() 529 { 530 try 531 { 532 // Alle Childs markieren, dass sie nicht aktualisiert wurden 533 foreach ( StuffItem si in this.ChildItems ) 534 { 535 si.updateCheck = false; 536 } 537 538 // Verzeichnisse lesen, die nicht "excluded" durch Extension sind 539 string[] dirs = GetDirectories; 540 foreach ( string dirname in dirs ) 541 { 542 if ( !Program.MainWindow.m_Config.IsDirExludedByExtension( dirname ) ) 543 { 544 StuffItem si = this.AddOrGetChildItemByPath( dirname ); 545 si.Path = dirname; 546 si.IsOnForeignDisk = this.IsOnForeignDisk; 547 si.ScanChilds(); 548 } 549 } 550 551 // Files lesen, die nicht excluded sind. 552 // Bei "restricted" extensions werden nur diese gelesen, "excluded" zählt dann nicht 553 string[] files = GetFiles; 554 foreach ( string filename in files ) 555 { 556 if ( !Program.MainWindow.m_Config.IsFileExludedByExtension( filename ) ) 557 { 558 StuffItem si = AddOrGetChildItemByPath( filename ); 559 si.Path = filename; 560 si.IsFile = true; 561 si.IsOnForeignDisk = IsOnForeignDisk; 562 si.Hash = Program.MainWindow.m_Cache.GetHashCodeFromFileHeader( filename ); 563 // wenn kein Hash ermittelt wurde, kann die Datei nicht gelesen werden 564 if ( String.IsNullOrEmpty( si.Hash ) ) 565 { 566 si.HasReadError = true; 567 } 568 else 569 { 570 si.Size = Convert.ToInt64( si.Hash.Substring( 33 ), 16 ); 571 } 572 } 573 } 574 575 // Nun alle Items wegwerfen, die kein Update hatten 576 for ( int i = ChildItems.Count - 1; i >= 0; i-- ) 577 { 578 if ( !ChildItems[ i ].updateCheck ) 579 { 580 ChildItems.RemoveAt( i ); 581 } 582 } 583 this.HasReadError = false; 584 } 585 catch ( Exception e ) 586 { 587 Program.MainWindow.LogError( "Fehler beim Einlesen: " + e.Message ); 588 this.HasReadError = true; 589 } 590 } 591 592 /// <summary> 593 /// Verzeichnisse eines Pfades aus dem SimDirs oder physikalisch lesen. 594 /// </summary> 595 /// <returns></returns> 596 private string[] GetDirectories 597 { 598 get 599 { 600 if ( IsOnline ) 601 { 602 Program.MainWindow.Status( "Lese Verzeichnis (online): " + this.Path + " " ); 603 OfflineDirs[ Path ] = new List<string>( Directory.GetDirectories( Path ) ); 604 } 605 else 606 { 607 Program.MainWindow.Status( "Lese Verzeichnis (offline): " + this.Path + " " ); 608 } 609 if ( OfflineDirs.ContainsKey( Path ) ) 610 { 611 return OfflineDirs[ Path ].ToArray(); 612 } 613 else 614 { 615 return new string[] { }; 616 } 617 } 618 } 619 620 /// <summary> 621 /// Files eines Pfades aus dem SimDirs oder physikalisch lesen. 622 /// </summary> 623 /// <returns></returns> 624 private string[] GetFiles 625 { 626 get 627 { 628 // bei Online-Dateien direkt von der Platte esen 629 if ( IsOnline ) 630 { 631 OfflineFiles[ Path ] = new List<string>( Directory.GetFiles( this.Path ) ); 632 } 633 634 // Bei Offline-Dateien die Hashcaches prüfen 635 if ( OfflineFiles.ContainsKey( Path ) ) 636 { 637 return OfflineFiles[ Path ].ToArray(); 638 } 639 else 640 { 641 return new string[] { }; 642 } 643 } 644 } 645 646 #endregion 647 } 648 }