MainForm.cs (66309B)
1 using System; 2 using System.Collections; 3 using System.Collections.Generic; 4 using System.Diagnostics; 5 using System.Drawing; 6 using System.IO; 7 using System.Text.RegularExpressions; 8 using System.Windows.Forms; 9 using LanTool.Classes; 10 11 namespace LanTool 12 { 13 public partial class MainForm : Form 14 { 15 #region Konstanten 16 17 internal const string DefaultHeader = "LanTool 1.6 - LumpLan #1 Edition"; 18 19 #endregion 20 21 #region Felder 22 23 internal StuffItemTree m_MyDisks = new StuffItemTree("Meine Platten", false); 24 25 internal StuffItemTree m_OtherDisks = new StuffItemTree("Fremde Platten", true); 26 27 // Zähler für die Anzahl der Kopierthreads 28 int copyThreadCount = 0; 29 30 // Zähler für das Maximum des Fortschrittsbalkens 31 float maxProgressMB = 0; 32 float currentProgressMB = 0; 33 34 /// <summary> 35 /// Pfad für Config/Exclude-Files etc. 36 /// </summary> 37 private static string basePath = "c:\\"; 38 39 /// <summary> 40 /// Alle Konfigurationsdaten 41 /// </summary> 42 internal Config m_Config; 43 44 /// <summary> 45 /// Die Caches für das Hauptfenster 46 /// </summary> 47 internal GlobalCache m_Cache; 48 49 #endregion 50 51 #region Hilfsfelder für die Suche 52 53 /// <summary> 54 /// Speichert das zuletzt benutzte TreeView 55 /// </summary> 56 TreeView lastUsedView = null; 57 /// <summary> 58 /// Liste mit StuffItems, die bereits angezeigt wurden 59 /// </summary> 60 List<string> itemsAlreadyFound = new List<string>(); 61 /// <summary> 62 /// Suchstring, nachdem zuletzt gesucht wurde 63 /// </summary> 64 string lastSearchString = string.Empty; 65 66 #endregion 67 68 #region Windows 7-Spezialitäten 69 /// <summary> 70 /// Zugriff auf Windows 7-Superbar 71 /// </summary> 72 ITaskbarList3 tbl = null; 73 74 private bool IsWin7 = Environment.OSVersion.Version.ToString().StartsWith("6.1"); 75 76 #endregion 77 78 /// <summary> 79 /// Konstruktor für das Formular 80 /// </summary> 81 public MainForm() 82 { 83 InitializeComponent(); 84 } 85 86 /// <summary> 87 /// On Load Config ausführen 88 /// </summary> 89 /// <param name="sender"></param> 90 /// <param name="e"></param> 91 private void MainForm_Load(object sender, EventArgs e) 92 { 93 // Pfad zur Datei ermitteln 94 basePath = Application.ExecutablePath.Substring(0, Application.ExecutablePath.LastIndexOf("\\") + 1); 95 96 // Konfiguration von Platte einlesen 97 m_Config = new Config(basePath); 98 99 // Programm mit niedriger Priorität ausführen 100 if (m_Config.IsLowerPriority) 101 { 102 Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.BelowNormal; 103 } 104 105 // Fenstertitel setzen 106 if (!string.IsNullOrEmpty(m_Config.HeaderExtension)) 107 { 108 Text = String.Format("[{0}] {1}", m_Config.HeaderExtension, DefaultHeader); 109 } 110 else 111 { 112 Text = DefaultHeader; 113 } 114 115 // Daten von der Platte einlesen 116 m_Cache = new GlobalCache(basePath); 117 118 // Menüs erweitern 119 AddFremdePlattenMenu(MainMenuFremdePlatten.DropDownItems); 120 AddEigenePlattenMenu(MainMenuEigenePlatten.DropDownItems); 121 122 // wenn eine DefaultOfflineDatei hinterlegt ist 123 if (!String.IsNullOrEmpty(m_Config.DefaultOfflineFile)) 124 { 125 if (File.Exists(m_Config.DefaultOfflineFile)) 126 { 127 m_MyDisks.LoadOfflineCacheFromFile(m_Config.DefaultOfflineFile); 128 } 129 else 130 { 131 LogError("DefaultOfflineDatei " + m_Config.DefaultOfflineFile + " existiert nicht."); 132 } 133 } 134 135 // Standardeinstellungen für den "Meine Platten"-Tree anlegen 136 myDisksTree.AfterCheck += new TreeViewEventHandler(TransferCheckToStuffItem); 137 myDisksTree.TreeViewNodeSorter = (IComparer)new StuffItemSorter(); 138 139 // Standardeinstellungen für den "Andere Platten"-Tree anlegen 140 otherDisksTree.AfterCheck += new TreeViewEventHandler(TransferCheckToStuffItem); 141 otherDisksTree.TreeViewNodeSorter = (IComparer)new StuffItemSorter(); 142 143 StartUpdate(); 144 145 // nur Windows 7/Server 2008 R2 146 if (IsWin7) 147 { 148 tbl = (ITaskbarList3)new TaskbarList(); 149 } 150 } 151 152 /// <summary> 153 /// Kopiert eine Liste von Dateien an den angegebenen Zielort 154 /// </summary> 155 /// <param name="state"></param> 156 public void CopyFiles(object state) 157 { 158 // Thread-Zähler erhöhen 159 copyThreadCount++; 160 161 // Fehlerzähler 162 int errorCount = 0; 163 // Zähler für die kopierten Dateien 164 int copiedFileCount = 0; 165 float copiedFileSizeMB = 0; 166 167 List<StuffItemPair> copylist = (List<StuffItemPair>)state; 168 169 if (copylist.Count < 1) 170 return; 171 172 // Größe aller Dateien für die Einrichtung des Fortschrittsbalkens ermitteln 173 float allFileSizeMB = 0; 174 foreach (StuffItemPair pair in copylist) 175 { 176 try 177 { 178 FileInfo sourceInfo = new FileInfo(pair.Source.Path); 179 allFileSizeMB += sourceInfo.Length / 1024 / 1024; 180 } 181 catch { } 182 { 183 // mit 1 vorbelegen wegen division durch 0 184 if (allFileSizeMB == 0) 185 allFileSizeMB = 1; 186 } 187 } 188 189 // Setzen des Maximalwerts des Fortschrittsbalkens 190 maxProgressMB += allFileSizeMB; 191 192 Progress(copyThreadCount + "|0"); 193 194 DateTime startTime = DateTime.Now; 195 196 // jede Datei kopieren 197 foreach (StuffItemPair sip in copylist) 198 { 199 float sourceSizeMB = 0; 200 try 201 { 202 // Quelle und Ziel bestimmen 203 string source = sip.Source.Path; 204 string target = Path.Combine(sip.Target.Path, Path.GetFileName(sip.Source.Path)); 205 206 // Dateigröße der Quelldatei bestimmen 207 try 208 { 209 FileInfo sourceInfo = new FileInfo(source); 210 sourceSizeMB = (sourceInfo.Length / 1024 / 1024); 211 } 212 catch (Exception ex) 213 { 214 sourceSizeMB = 0; 215 LogWarning("Fehler: Größe der Datei " + source + " konnte nicht ermittelt werden: " + ex.Message); 216 } 217 218 // Dateianzahl erhöhen 219 copiedFileCount++; 220 221 Status("Kopiere Datei " + copiedFileCount.ToString() + " von " + copylist.Count.ToString() + ": " + source + " -> " + target + " (" + sourceSizeMB.ToString() + " MB)"); 222 Log("Kopiere Datei " + copiedFileCount.ToString() + " von " + copylist.Count.ToString() + ": " + source + " -> " + target + " (" + sourceSizeMB.ToString() + " MB)"); 223 try 224 { 225 Directory.CreateDirectory(sip.Target.Path); 226 } 227 catch (Exception ee) 228 { 229 LogError("Fehler beim Erstellen des Verzeichnisses: " + ee.Message); 230 } 231 File.Copy(source, target); 232 // Markierung entfernen 233 sip.Source.Checked = false; 234 } 235 catch (Exception e) 236 { 237 LogError("Fehler beim Kopieren der Datei " + sip.Source.Path + " : " + e.Message); 238 errorCount++; 239 } 240 finally 241 { 242 // Fortschritt aktualisieren 243 copiedFileSizeMB += sourceSizeMB; 244 Progress(copyThreadCount + "|" + sourceSizeMB); 245 } 246 } 247 248 // Thread-Zähler verringern 249 copyThreadCount--; 250 251 // Fortschrittsbalkenmaximum verringern 252 maxProgressMB -= allFileSizeMB; 253 currentProgressMB -= copiedFileSizeMB; 254 255 // Fortschrittsbalken zurücksetzen 256 Progress(copyThreadCount + "|0"); 257 258 DateTime endTime = DateTime.Now; 259 260 // Anzeige der eigenen Platten aktualisieren 261 m_MyDisks.UpdateChildsBackground(); 262 263 Status("Kopieren abgeschlossen! " + errorCount.ToString() + " von " + copylist.Count.ToString() + " Dateien konnten nicht kopiert werden."); 264 265 // Meldung über Kopiervorgang anzeigen 266 TimeSpan copyTime = endTime - startTime; 267 LogHighlight("Kopiervorgang abgeschlossen! Dateien kopiert: " + copiedFileCount + " - Gesamtgröße: " + String.Format("{0:F2}", copiedFileSizeMB) + " MB - Dauer: " + String.Format("{0:F0}:{1:D2}:{2:D2}", copyTime.TotalHours, copyTime.Minutes, copyTime.Seconds) + " - Transferrate: " + String.Format("{0:F2}", copiedFileSizeMB / copyTime.TotalSeconds) + " MB/s"); 268 Message("Kopiervorgang abgeschlossen!" + Environment.NewLine + Environment.NewLine + "Dateien kopiert:\t" + copiedFileCount + Environment.NewLine + "Gesamtgröße:\t" + String.Format("{0:F2}", copiedFileSizeMB) + " MB" + Environment.NewLine + "Dauer:\t\t" + String.Format("{0:F0}:{1:D2}:{2:D2}", copyTime.TotalHours, copyTime.Minutes, copyTime.Seconds) + Environment.NewLine + "Transferrate:\t" + String.Format("{0:F2}", copiedFileSizeMB / copyTime.TotalSeconds) + " MB/s"); 269 } 270 271 #region Klicks auf Menuepunkte 272 273 /// <summary> 274 /// KLick auf Exit 275 /// </summary> 276 /// <param name="sender"></param> 277 /// <param name="e"></param> 278 private void exitToolStripMenuItem_Click(object sender, EventArgs e) 279 { 280 Application.Exit(); 281 } 282 283 /// <summary> 284 /// Klick auf "Ordner aktualisieren" 285 /// </summary> 286 /// <param name="sender"></param> 287 /// <param name="e"></param> 288 private void UpdateFolderClick(object sender, EventArgs e) 289 { 290 GetStuffItem(sender).UpdateChildsBackground(); 291 } 292 293 /// <summary> 294 /// Klick auf "Löschen des Logs" 295 /// </summary> 296 /// <param name="sender"></param> 297 /// <param name="e"></param> 298 private void protokollausgabeLöschenToolStripMenuItem_Click(object sender, EventArgs e) 299 { 300 logTextBox.Clear(); 301 } 302 303 /// <summary> 304 /// Konfiguration aufrufen und bei OK gleich scannen 305 /// </summary> 306 /// <param name="sender"></param> 307 /// <param name="e"></param> 308 private void konfigurationToolStripMenuItem_Click(object sender, EventArgs e) 309 { 310 if (m_Config.EditConfig()) 311 { 312 StartUpdate(); 313 } 314 } 315 316 /// <summary> 317 /// Eigene Platten erneut einlesen (z.zt nur default Konfiguration) 318 /// </summary> 319 /// <param name="sender"></param> 320 /// <param name="e"></param> 321 private void eigenePlattenAktualisierenToolStripMenuItem_Click(object sender, EventArgs e) 322 { 323 m_MyDisks.UpdateChildsBackground(); 324 } 325 326 /// <summary> 327 /// Erneutes einlesen der fremden Platte 328 /// </summary> 329 /// <param name="sender"></param> 330 /// <param name="e"></param> 331 private void fremdePlatteAktualisierenToolStripMenuItem_Click(object sender, EventArgs e) 332 { 333 Program.MainWindow.m_OtherDisks.UpdateChildsBackground(); 334 } 335 336 /// <summary> 337 /// Löschen des Hash-Caches (Datei löschen ginge auch ;-) 338 /// </summary> 339 /// <param name="sender"></param> 340 /// <param name="e"></param> 341 private void hashCacheLöschenToolStripMenuItem_Click(object sender, EventArgs e) 342 { 343 m_Cache.Clear(); 344 } 345 346 #endregion 347 348 #region Aktualisierung der Bäume (von Hintergrundthread aufrufbar) 349 350 /// <summary> 351 /// Henkel um von einem Background-Prozess die Trees wieder zu aktualisieren 352 /// </summary> 353 public void UpdateTrees() 354 { 355 if ( InvokeRequired ) 356 { 357 Invoke( new MethodInvoker(UpdateTrees)); 358 } 359 else 360 { 361 UpdateMyDisksTreesInvoked(false); 362 UpdateOtherDisksTreesInvoked(false); 363 } 364 } 365 366 /// <summary> 367 /// Henkel um von einem Background-Prozess die Trees wieder zu aktualisieren 368 /// Dabei werden unmarkierte und Zweige ohne Fehler zugeklappt 369 /// </summary> 370 public void CollapseMyDisks() 371 { 372 if ( InvokeRequired ) 373 { 374 Invoke( new MethodInvoker(CollapseMyDisks)); 375 } 376 else 377 { 378 UpdateMyDisksTreesInvoked(true); 379 } 380 } 381 382 /// <summary> 383 /// Henkel um von einem Background-Prozess die Trees wieder zu aktualisieren 384 /// Dabei werden unmarkierte und Zweige ohne Fehler zugeklappt 385 /// </summary> 386 public void CollapseOtherDisks() 387 { 388 if ( InvokeRequired ) 389 { 390 Invoke( new MethodInvoker(CollapseOtherDisks)); 391 } 392 else 393 { 394 UpdateOtherDisksTreesInvoked(true); 395 } 396 } 397 398 /// <summary> 399 /// Nur im Invoke-Zyklus rufbar! 400 /// </summary> 401 /// <param name="autoCollapse"></param> 402 private void UpdateMyDisksTreesInvoked(bool autoCollapse) 403 { 404 if ( InvokeRequired ) 405 { 406 throw new Exception("Dieser Aufruf ist nur im Invoke-Zylus erlaubt"); 407 } 408 409 myDisksTree.BeginUpdate(); 410 411 if (myDisksTree.Nodes.Count == 0) 412 { 413 myDisksTree.Nodes.Add(new TreeNode()); 414 } 415 416 UpdateTreeRecursive( myDisksTree.Nodes[ 0 ], m_MyDisks, autoCollapse ); 417 418 myDisksTree.Nodes[0].Expand(); 419 myDisksTree.Sort(); 420 421 myDisksTree.EndUpdate(); 422 Status("Aktualisierung abgeschlossen!"); 423 } 424 425 /// <summary> 426 /// Nur im Invoke-Zyklus rufbar! 427 /// </summary> 428 /// <param name="autoCollapse"></param> 429 private void UpdateOtherDisksTreesInvoked(bool autoCollapse) 430 { 431 if (this.InvokeRequired) 432 { 433 throw new Exception("Dieser Aufruf ist nur im Invoke-Zylus erlaubt"); 434 } 435 //---Rechter Baum 436 437 otherDisksTree.BeginUpdate(); 438 if (otherDisksTree.Nodes.Count == 0) 439 { 440 otherDisksTree.Nodes.Add(new TreeNode()); 441 } 442 443 UpdateTreeRecursive(otherDisksTree.Nodes[0], Program.MainWindow.m_OtherDisks, autoCollapse); 444 445 otherDisksTree.Nodes[0].Expand(); 446 otherDisksTree.Sort(); 447 otherDisksTree.EndUpdate(); 448 Status("Aktualisierung abgeschlossen!"); 449 } 450 451 /// <summary> 452 /// Checkboxstatus bei Änderungen in StuffItem (im Tag) übertragen 453 /// </summary> 454 /// <param name="sender"></param> 455 /// <param name="e"></param> 456 void TransferCheckToStuffItem(object sender, TreeViewEventArgs e) 457 { 458 StuffItem si = (StuffItem)e.Node.Tag; 459 460 if (si != null) 461 { 462 si.Checked = e.Node.Checked; 463 } 464 } 465 466 /// <summary> 467 /// TreeNode aus StuffItem aktualisieren (Rekursiv) 468 /// </summary> 469 /// <param name="tn">Node</param> 470 /// <param name="si">Item</param> 471 /// <param name="autoCollapse">Automatisch zuklappen</param> 472 private void UpdateTreeRecursive(TreeNode tn, StuffItem si, Boolean autoCollapse) 473 { 474 List<string> delKeys = new List<string>(); 475 476 // StuffItem immer in Tag hängen 477 tn.Tag = si; 478 // Mit AutoCollapse erst mal alles zuklappen und nur bei Bedarf wieder öffnen 479 if (autoCollapse) 480 { 481 tn.Collapse(); 482 } 483 // Sicherstellen, dass Fehler und Markierungen immer sichtbar sind, 484 // erlaubte Dubletten nicht immer sichtbar machen 485 if ((si.HasClones && (!si.IsIgnored || m_Config.IsShowIgnoredClones)) || si.IsNeeded || si.Checked) 486 { 487 TreeNode pn = tn.Parent; 488 while (pn != null) 489 { 490 pn.Expand(); 491 pn = pn.Parent; 492 } 493 } 494 495 tn.Text = si.Text; 496 tn.ImageIndex = tn.SelectedImageIndex = (int)si.Icon; 497 tn.ToolTipText = si.ToolTip; 498 499 // Checkboxes aus StuffItems setzen 500 tn.Checked = si.Checked; 501 502 // Offline duch Textfarbe anzeigen 503 tn.ForeColor = si.IsOnline ? Color.Black : Color.SteelBlue; 504 505 // Alle ChildItems durchlaufen, ggf. hinzufügen und rekursiv aktualisieren 506 foreach (StuffItem csi in si.ChildItems.ToArray()) 507 { 508 // Wenn die Datei gesperrt/vorhanden ist und keine gesperrten/vorhandenen Dateien 509 // angezeigt werden sollen, dann gar nicht erst hinzufügen 510 if (!csi.IsVisible) 511 { 512 if (tn.Nodes.ContainsKey(csi.Path)) 513 { 514 delKeys.Add(csi.Path); 515 } 516 continue; 517 } 518 519 // neuen Node anlegen, wenn noch nicht bekannt 520 if (!tn.Nodes.ContainsKey(csi.Path)) 521 { 522 tn.Nodes.Add(csi.Path, csi.Name); 523 } 524 TreeNode ntn = tn.Nodes[csi.Path]; 525 UpdateTreeRecursive(ntn, csi, autoCollapse); 526 } 527 528 // Alle TreeNodes löschen, die nicht mehr in den ChildItems sind (Das TreeNode.Tag zeigt auf das StuffItem) 529 foreach (TreeNode ntn in tn.Nodes) 530 { 531 if (!si.ChildItems.Contains((StuffItem)ntn.Tag)) 532 { 533 delKeys.Add(((StuffItem)ntn.Tag).Path); 534 } 535 } 536 537 // Zweistufiges rauswerfen, damit die Liste nicht beim Durchlaufen manipuliert wird 538 foreach (string k in delKeys) 539 { 540 tn.Nodes.RemoveByKey(k); 541 } 542 } 543 544 #endregion 545 546 #region Logging/Messagebox/Status/Progress (auch von Hintergrundthreads nutzbar) 547 548 private delegate void MethodInvokerWithString(string s); 549 550 /// <summary> 551 /// Logausgabe. Diese Methode kann von Hintergrundthreads gerufen werden 552 /// </summary> 553 /// <param name="logText"></param> 554 public void Log(string logText) 555 { 556 if (this.InvokeRequired) 557 { 558 this.Invoke(new MethodInvokerWithString(Log), "*BG* " + logText); 559 } 560 else 561 { 562 logTextBox.SelectionColor = Color.Black; 563 LogMessage(logText); 564 } 565 } 566 567 /// <summary> 568 /// Logausgabe in Grün als Highlight. Diese Methode kann von Hintergrundthreads gerufen werden 569 /// </summary> 570 /// <param name="log"></param> 571 public void LogHighlight(string log) 572 { 573 if (this.InvokeRequired) 574 { 575 this.Invoke(new MethodInvokerWithString(LogHighlight), "*BG* " + log); 576 } 577 else 578 { 579 logTextBox.SelectionColor = Color.DarkGreen; 580 LogMessage(log); 581 } 582 } 583 584 /// <summary> 585 /// Logausgabe in Gelb als Warnung. Diese Methode kann von Hintergrundthreads gerufen werden 586 /// </summary> 587 /// <param name="log"></param> 588 public void LogWarning(string log) 589 { 590 if (this.InvokeRequired) 591 { 592 this.Invoke(new MethodInvokerWithString(LogWarning), "*BG* " + log); 593 } 594 else 595 { 596 logTextBox.SelectionColor = Color.Orange; 597 LogMessage(log); 598 } 599 } 600 601 /// <summary> 602 /// Logausgabe in Rot als Fehler. Diese Methode kann von Hintergrundthreads gerufen werden 603 /// </summary> 604 /// <param name="log"></param> 605 public void LogError(string log) 606 { 607 if (this.InvokeRequired) 608 { 609 this.Invoke(new MethodInvokerWithString(LogError), "*BG* " + log); 610 } 611 else 612 { 613 logTextBox.SelectionColor = Color.Red; 614 LogMessage(log); 615 } 616 } 617 618 private void LogMessage(string message) 619 { 620 if (String.IsNullOrEmpty(message)) 621 logTextBox.AppendText("\r\n"); 622 else 623 logTextBox.AppendText("\r\n" + DateTime.Now.ToString() + " | " + message); 624 625 logTextBox.ScrollToCaret(); 626 logTextBox.Refresh(); 627 } 628 629 /// <summary> 630 /// Statustext ausgeben 631 /// </summary> 632 /// <param name="message">Nachricht, die in der Statuszeile ausgegeben werden soll</param> 633 public void Status(string message) 634 { 635 if (this.InvokeRequired) 636 { 637 this.Invoke(new MethodInvokerWithString(Status), message); 638 } 639 else 640 { 641 stsStatus.Items[0].Text = message; 642 } 643 } 644 645 /// <summary> 646 /// Messagebox ausgeben 647 /// </summary> 648 public void Message(string messageText) 649 { 650 if (this.InvokeRequired) 651 { 652 this.Invoke(new MethodInvokerWithString(Message), messageText); 653 } 654 else 655 { 656 MessageBox.Show(messageText, "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); 657 } 658 } 659 660 /// <summary> 661 /// Progress anzeigen 662 /// </summary> 663 /// <param name="value">|</param> 664 public void Progress(string value) 665 { 666 if (this.InvokeRequired) 667 { 668 this.Invoke(new MethodInvokerWithString(Progress), value); 669 } 670 else 671 { 672 try 673 { 674 if (value is String) 675 { 676 String[] args = value.Split("|".ToCharArray()); 677 678 if (args[0].Equals("0")) 679 { 680 statusProgress.Value = 0; 681 682 // nur Windows 7/Server 2008 R2 683 if (IsWin7) 684 { 685 tbl.SetProgressState(this.Handle, TBPFLAG.TBPF_NOPROGRESS); 686 } 687 688 689 } 690 else 691 { 692 // Fortschrittsbalken 693 if (maxProgressMB > 0) 694 { 695 // neuen Fortschritt an Hand der Dateigröße berechnen 696 currentProgressMB += Convert.ToInt32(args[1]); 697 int progressValue = (int)((currentProgressMB * 100) / maxProgressMB); 698 statusProgress.Value = progressValue; 699 statusProgress.ToolTipText = "Fortschritt: " + progressValue + " % (" + currentProgressMB + 700 " MB von " + maxProgressMB + " MB"; 701 702 // nur Windows 7/Server 2008 R2 703 if (IsWin7) 704 { 705 tbl.SetProgressValue(this.Handle, (ulong)progressValue, 100); 706 } 707 } 708 } 709 710 // Anzahl Threads 711 statusThreads.Text = "T: " + args[0]; 712 } 713 } 714 catch 715 { 716 // ignore 717 } 718 } 719 } 720 721 #endregion 722 723 #region Drag & Drop 724 725 private void otherDisksTree_ItemDrag(object sender, ItemDragEventArgs e) 726 { 727 TreeNode tn = (TreeNode)e.Item; 728 if (tn != null /*&& ((StuffItem)tn.Tag).IsNeeded*/) 729 { 730 DoDragDrop(e.Item, DragDropEffects.Move); 731 } 732 } 733 734 private void myDisksTree_DragEnter(object sender, DragEventArgs e) 735 { 736 TreeNode trgt = myDisksTree.GetNodeAt(myDisksTree.PointToClient(new Point(e.X, e.Y))); 737 if (trgt != null && trgt.ImageIndex == (int)TreeNodeImage.Folder) 738 { 739 e.Effect = DragDropEffects.Move; 740 } 741 else 742 { 743 e.Effect = DragDropEffects.None; 744 } 745 } 746 747 private void myDisksTree_DragDrop(object sender, DragEventArgs e) 748 { 749 // Source und Target aus dem Drag&Drog-Object ermitteln 750 TreeNode src = (TreeNode)e.Data.GetData(typeof(TreeNode)); 751 TreeNode trgt = myDisksTree.GetNodeAt(myDisksTree.PointToClient(new Point(e.X, e.Y))); 752 List<StuffItemPair> copylist = new List<StuffItemPair>(); 753 copylist.Add(new StuffItemPair()); 754 copylist[0].Source = ((StuffItem)src.Tag); 755 copylist[0].Target = ((StuffItem)trgt.Tag); 756 757 Program.RunBackgroundTask(this, "CopyFiles", copylist); 758 } 759 760 #endregion 761 762 #region Funktionen für die Arbeit mit MainMenü / PopupMenü 763 764 /// <summary> 765 /// Einhängen eines Menüpunktes mit Event, Bild (opt) und StuffItem 766 /// </summary> 767 private void AddToMenuCollection(ToolStripItemCollection menuCollection, string name, string image, EventHandler eventHandler, StuffItem stuffItem) 768 { 769 ToolStripItem ts = menuCollection.Add(name); 770 ts.Click += eventHandler; 771 ts.Tag = stuffItem; 772 if (image != null && fileSystemImageList.Images.ContainsKey(image)) 773 { 774 ts.Image = fileSystemImageList.Images[image]; 775 } 776 } 777 778 /// <summary> 779 /// StuffItem aus ToolStripItem oder MenuItem extrahieren (damit können Events 780 /// von beiden Menüs aus verwendet werden) 781 /// </summary> 782 /// <param name="menuItem"></param> 783 /// <returns></returns> 784 private static StuffItem GetStuffItem(object menuItem) 785 { 786 if (menuItem is MenuItem) 787 { 788 return (StuffItem)((MenuItem)menuItem).Tag; 789 } 790 791 if (menuItem is ToolStripItem) 792 { 793 return (StuffItem)((ToolStripItem)menuItem).Tag; 794 } 795 796 return null; 797 } 798 799 /// <summary> 800 /// Menü für eigene Platten aufbauen (Hauptmenü und Popup-Menü) 801 /// </summary> 802 /// <param name="menuCollection"></param> 803 private void AddEigenePlattenMenu(ToolStripItemCollection menuCollection) 804 { 805 // Konfiguration öffnen 806 AddToMenuCollection(menuCollection, "Platten hinzufügen oder entfernen...", "Hinzufuegen.png", new EventHandler(konfigurationToolStripMenuItem_Click), m_MyDisks); 807 // Menüpunkt für Aktualisieren links 808 AddToMenuCollection(menuCollection, "Meine Platten aktualisieren", "Aktualisieren.png", new EventHandler(eigenePlattenAktualisierenToolStripMenuItem_Click), m_MyDisks); 809 // Online / Offline Wechsel 810 AddToMenuCollection( menuCollection, "Meine Platten " + ( m_MyDisks.IsOnline ? "offline" : "online" ) + " schalten", m_MyDisks.IsOnline ? "DateiWeiss.png" : "DateiGruen.png", new EventHandler( ToggleOnline ), m_MyDisks ); 811 // Separator 812 menuCollection.Add("-"); 813 // Markieren aller Dateien ab Root, die gelöscht werden können 814 AddToMenuCollection(menuCollection, "Dubletten zum Löschen markieren (eine bleibt)", "Markieren.png", new EventHandler(ContextMarkDoubleEntries), m_MyDisks); 815 // Allgemeines Menü für alle Platten dazu 816 AddAllePlattenMenu( menuCollection, m_MyDisks ); 817 // Löschen aller links makierten Dateien 818 AddToMenuCollection(menuCollection, "Alle markierten Dateien sperren und löschen", "DateiExcludedAndDeleted.png", new EventHandler(ContextExcludeAndDeleteAllMarkedFiles), m_MyDisks); 819 AddToMenuCollection(menuCollection, "Alle markierten Dateien löschen", "DateiLoeschen.png", new EventHandler(ContextDeleteAllMarkedFiles), m_MyDisks); 820 } 821 822 /// <summary> 823 /// Menü für fremde Platten aufbauen (Hauptmenü und Popup-Menü) 824 /// </summary> 825 /// <param name="menuCollection"></param> 826 private void AddFremdePlattenMenu(ToolStripItemCollection menuCollection) 827 { 828 // Konfiguration öffnen 829 AddToMenuCollection(menuCollection, "Platten hinzufügen oder entfernen...", "Hinzufuegen.png", new EventHandler(konfigurationToolStripMenuItem_Click), Program.MainWindow.m_OtherDisks); 830 // AddToMenuCollection(menuCollection, "Fremde Platte hinzufügen...", "Hinzufuegen.png", new EventHandler(FremdePlatteAuswaehlenClick), Program.MainWindow.m_OtherDisks); 831 // Menüpunkt für Aktualisieren rechts 832 AddToMenuCollection(menuCollection, "Fremde Platten aktualisieren", "Aktualisieren.png", new EventHandler(fremdePlatteAktualisierenToolStripMenuItem_Click), Program.MainWindow.m_OtherDisks); 833 // Online / Offline Wechsel 834 AddToMenuCollection(menuCollection, "Fremde Platten " + (Program.MainWindow.m_OtherDisks.IsOnline ? "offline" : "online") + " schalten", Program.MainWindow.m_OtherDisks.IsOnline ? "DateiWeiss.png" : "DateiGruen.png", new EventHandler(ToggleOnline), Program.MainWindow.m_OtherDisks); 835 // Separator 836 menuCollection.Add("-"); 837 // Markieren aller zu saugenden Dateien ab Root 838 AddToMenuCollection(menuCollection, "Alle fehlenden Dateien markieren", "Markieren.png", new EventHandler(ContextMarkMissingFiles), Program.MainWindow.m_OtherDisks); 839 // Allgemeines Menü für alle Platten dazu 840 AddAllePlattenMenu(menuCollection, Program.MainWindow.m_OtherDisks); 841 } 842 843 /// <summary> 844 /// Menü für beide Platten, wird von AddFremde/EigenenPlattenMenu verwendet 845 /// </summary> 846 /// <param name="menuCollection"></param> 847 /// <param name="stuffItem"></param> 848 private void AddAllePlattenMenu(ToolStripItemCollection menuCollection, StuffItem stuffItem) 849 { 850 // Markieren aller Dateien ab Root 851 AddToMenuCollection(menuCollection, "Alle Dateien markieren", "Markieren.png", new EventHandler(ContextMark), stuffItem); 852 // Markierung mit Suchfilter setzen 853 AddToMenuCollection(menuCollection, "Dateien mit Suchfilter markieren...", "Markieren.png", new EventHandler(ContextMarkByFilter), stuffItem); 854 // Markierung entfernen aller Dateien ab Root 855 AddToMenuCollection(menuCollection, "Alle Markierungen entfernen", "Demarkieren.png", new EventHandler(ContextRemoveMark), stuffItem); 856 // Separator 857 menuCollection.Add("-"); 858 // Unbenötigte Teile zuklappen 859 AddToMenuCollection(menuCollection, "Alle Ordner ohne Markierungen/Hinweise zuklappen", "Zuklappen.png", new EventHandler(ContextCollapse), stuffItem); 860 // Separator 861 menuCollection.Add("-"); 862 // Markieren/Demarkieren 863 AddToMenuCollection(menuCollection, "Alle markierten Dateien entsperren", "DateiFrischGesaugt.png", new EventHandler(ContextIncludeMarkers), stuffItem); 864 AddToMenuCollection(menuCollection, "Alle markierten Dateien sperren", "DateiExcluded.png", new EventHandler(ContextExcludeMarkers), stuffItem); 865 } 866 867 /// <summary> 868 /// Kontextmenu aufbauen 869 /// </summary> 870 /// <param name="sender"></param> 871 /// <param name="e"></param> 872 private void tree_MouseUp( object sender, MouseEventArgs e ) 873 { 874 TreeView tv = ( TreeView )sender; 875 if ( e.Button != MouseButtons.Right ) 876 { 877 return; 878 } 879 880 Point clickPoint = new Point( e.X, e.Y ); 881 TreeNode clickNode = tv.GetNodeAt( clickPoint ); 882 if ( clickNode == null ) 883 { 884 return; 885 } 886 887 StuffItem clickItem = ( StuffItem )clickNode.Tag; 888 bool isRoot = clickItem.Equals( m_MyDisks ) || clickItem.Equals( Program.MainWindow.m_OtherDisks ); 889 // Convert from Tree coordinates to Screen coordinates 890 Point ScreenPoint = tv.PointToScreen( clickPoint ); 891 // Convert from Screen coordinates to Form coordinates 892 Point FormPoint = this.PointToClient( ScreenPoint ); 893 894 // Show context menu 895 ContextMenuStrip contextmenu = new ContextMenuStrip(); 896 contextmenu.Items.Clear(); 897 // Fremde Platte entfernen 898 899 // Menüs für die 900 if ( isRoot ) 901 { 902 if ( !clickItem.IsOnForeignDisk ) 903 { 904 AddEigenePlattenMenu( contextmenu.Items ); 905 } 906 else 907 { 908 AddFremdePlattenMenu( contextmenu.Items ); 909 } 910 } 911 else 912 { 913 if ( !clickItem.IsFile ) 914 { 915 AddToMenuCollection( contextmenu.Items, "Ordner " + clickItem.Path + " aktualisieren" + ( clickItem.IsOnline ? "" : " (offline)" ), "Aktualisieren.png", new EventHandler( UpdateFolderClick ), clickItem ); 916 AddToMenuCollection( contextmenu.Items, "Ordner " + clickItem.Path + ( clickItem.IsOnline ? " offline" : " online" ) + " schalten", clickItem.IsOnline ? "DateiWeiss.png" : "DateiGruen.png", new EventHandler( ToggleOnline ), clickItem ); 917 contextmenu.Items.Add( "-" ); 918 } 919 // Menüpunkt für Ansehen 920 if ( !clickItem.HasReadError ) 921 { 922 AddToMenuCollection( contextmenu.Items, "Öffnen", "Oeffnen.png", new EventHandler( ContextExecute ), clickItem ); 923 // Öffnen mit Anbieten bei Dateien 924 if ( clickItem.IsFile ) 925 { 926 AddToMenuCollection( contextmenu.Items, "Öffnen mit...", "Oeffnen.png", new EventHandler( ContextExecuteWith ), clickItem ); 927 } 928 } 929 930 // Ordner mit Unterordnern 931 if ( !clickItem.IsFile && clickItem.ChildItems.Count > 0 ) 932 { 933 contextmenu.Items.Add( "-" ); 934 // Markieren aller Dateien ab Folder 935 AddToMenuCollection( contextmenu.Items, "Alle Dateien unterhalb " + clickItem.Path + " markieren", "Markieren.png", new EventHandler( ContextMark ), clickItem ); 936 // Markieren aller Dateien ab Folder mit Filter 937 AddToMenuCollection( contextmenu.Items, "Dateien unterhalb " + clickItem.Path + " mit Suchfilter markieren...", "Markieren.png", new EventHandler( ContextMarkByFilter ), clickItem ); 938 // Markieren aller zu saugenden Dateien ab Folder 939 if ( clickItem.IsOnForeignDisk ) 940 { 941 AddToMenuCollection( contextmenu.Items, "Alle fehlenden Dateien unterhalb " + clickItem.Path + " markieren", "Markieren.png", new EventHandler( ContextMarkMissingFiles ), clickItem ); 942 } 943 // Markierung entfernen aller Dateien ab Folder 944 AddToMenuCollection( contextmenu.Items, "Alle Markierungen unterhalb " + clickItem.Path + " entfernen", "Demarkieren.png", new EventHandler( ContextRemoveMark ), clickItem ); 945 } 946 947 if ( !clickItem.IsOnForeignDisk && !clickItem.IsFile && !clickItem.HasReadError ) 948 { 949 contextmenu.Items.Add( "-" ); 950 // Kopieren aller rechts markierten Dateien in einen Folder (flat) 951 AddToMenuCollection( contextmenu.Items, "Alle fremden selektierten Dateien direkt in diesen Ordner kopieren (flat)", "DateiSaugen.png", new EventHandler( ContextCopyAllClick ), clickItem ); 952 // Kopieren aller rechts markierten Dateien in einen Folder (hierarchisch) 953 AddToMenuCollection( contextmenu.Items, "Alle fremden selektierten Dateien mit Ordnerstruktur in diesen Ordner kopieren", "DateiSaugen.png", new EventHandler( ContextCopyAllWithFoldersClick ), clickItem ); 954 // Ordner anlegen 955 AddToMenuCollection( contextmenu.Items, "Neuen Ordner unterhalb " + clickItem.Path + " anlegen", "Ordner.png", new EventHandler( ContextNewFolder ), clickItem ); 956 957 } 958 959 if ( clickItem.IsFile && clickItem.HasClones ) 960 { 961 contextmenu.Items.Add( "-" ); 962 963 List<StuffItem> clones = Program.MainWindow.m_MyDisks.GetItemClones( clickItem ); 964 for ( int i = 0 ; i < clones.Count ; i++ ) 965 { 966 if ( !clones[ i ].Equals( clickItem ) ) 967 { 968 AddToMenuCollection( contextmenu.Items, "Öffnen Dublette " + clones[ i ].Path, "Oeffnen.png", new EventHandler( ContextExecute ), clones[ i ] ); 969 } 970 } 971 972 AddToMenuCollection( contextmenu.Items, "Markieren aller Dubletten dieser Datei", "Markieren.png", new EventHandler( ContextMarkClones ), clickItem ); 973 // Dubletten ignorieren ja/nein 974 if ( !clickItem.IsIgnored ) 975 { 976 AddToMenuCollection( contextmenu.Items, "Dubletten dieser Datei erlauben", "", new EventHandler( ContextIgnore ), clickItem ); 977 } 978 else 979 { 980 AddToMenuCollection( contextmenu.Items, "Dubletten dieser Datei wieder markieren", "", new EventHandler( ContextUnIgnore ), clickItem ); 981 } 982 983 // Für Dubletten Menüs anbieten (auf rot) 984 for ( int i = 0 ; i < clones.Count ; i++ ) 985 { 986 if ( !clones[ i ].Equals( clickItem ) ) 987 { 988 AddToMenuCollection( contextmenu.Items, "Löschen Dublette " + clones[ i ].Path, "DateiLoeschen.png", new EventHandler( ContextDeleteFile ), clones[ i ] ); 989 } 990 } 991 992 } 993 // Datei in die Sperrliste ein-/austragen 994 if ( clickItem.IsFile ) 995 { 996 // Linie nach Markieren 997 contextmenu.Items.Add( "-" ); 998 if ( !clickItem.IsExcluded ) 999 { 1000 AddToMenuCollection( contextmenu.Items, "Sperren der Datei", "DateiExcluded.png", new EventHandler( ContextExclude ), clickItem ); 1001 } 1002 else 1003 { 1004 AddToMenuCollection( contextmenu.Items, "Entsperren der Datei", "DateiFrischGesaugt.png", new EventHandler( ContextInclude ), clickItem ); 1005 } 1006 // Sperren und zugleich löschen 1007 if ( !clickItem.IsExcluded && !clickItem.IsOnForeignDisk ) 1008 { 1009 AddToMenuCollection( contextmenu.Items, "Sperren und Löschen der Datei", "DateiExcludedAndDeleted.png", new EventHandler( ContextExcludeAndDelete ), clickItem ); 1010 } 1011 // Löschen einer Einzeldatei, nur links 1012 if ( !clickItem.IsOnForeignDisk ) 1013 { 1014 AddToMenuCollection( contextmenu.Items, "Löschen der Datei", "DateiLoeschen.png", new EventHandler( ContextDeleteFile ), clickItem ); 1015 } 1016 } 1017 // Löschen eines (leeren) Ordners 1018 if ( !clickItem.HasReadError && !clickItem.IsOnForeignDisk && !clickItem.IsFile && clickItem.ChildItems.Count == 0 ) 1019 { 1020 AddToMenuCollection( contextmenu.Items, "Ordner löschen", "OrdnerLoeschen.png", new EventHandler( ContextDeleteFolder ), clickItem ); 1021 } 1022 // Sperren/Entsperren multi 1023 if ( !clickItem.IsFile && clickItem.ChildItems.Count > 0 ) 1024 { 1025 // Linie nach Markieren 1026 contextmenu.Items.Add( "-" ); 1027 AddToMenuCollection( contextmenu.Items, "Alle markierten Dateien entsperren", "DateiFrischGesaugt.png", new EventHandler( ContextIncludeMarkers ), clickItem ); 1028 AddToMenuCollection( contextmenu.Items, "Alle markierten Dateien sperren", "DateiExcluded.png", new EventHandler( ContextExcludeMarkers ), clickItem ); 1029 AddToMenuCollection( contextmenu.Items, "Alle markierten Dateien sperren und löschen", "DateiExcludedAndDeleted.png", new EventHandler( ContextExcludeAndDeleteAllMarkedFiles ), clickItem ); 1030 // Löschen aller links markierten Dateien 1031 if ( !clickItem.IsOnForeignDisk ) 1032 { 1033 AddToMenuCollection( contextmenu.Items, "Alle markierten Dateien unterhalb " + clickItem.Path + " löschen", "DateiLoeschen.png", new EventHandler( ContextDeleteAllMarkedFiles ), clickItem ); 1034 } 1035 } 1036 } 1037 contextmenu.Show( this, FormPoint ); 1038 } 1039 1040 #endregion 1041 1042 #region Popup Menü Aktionen 1043 1044 /// <summary> 1045 /// Teilbaum von Offline auf Online und umgekehrt setzen 1046 /// </summary> 1047 /// <param name="sender"></param> 1048 /// <param name="e"></param> 1049 void ToggleOnline(object sender, EventArgs e) 1050 { 1051 // StuffItem ermitteln 1052 StuffItem si = GetStuffItem(sender); 1053 if (si == null) 1054 { 1055 return; 1056 } 1057 1058 // Onlinestatus umsetzen 1059 if (si.IsOnline) 1060 { 1061 Log("Setze Offline: " + si.Path); 1062 si.IsOnline = false; 1063 } 1064 else 1065 { 1066 Log("Setze Online: " + si.Path); 1067 si.IsOnline = true; 1068 } 1069 1070 // Menüs bauen sich dabei um! 1071 MainMenuFremdePlatten.DropDownItems.Clear(); 1072 AddFremdePlattenMenu(MainMenuFremdePlatten.DropDownItems); 1073 MainMenuEigenePlatten.DropDownItems.Clear(); 1074 AddEigenePlattenMenu(MainMenuEigenePlatten.DropDownItems); 1075 1076 UpdateTrees(); 1077 } 1078 1079 /// <summary> 1080 /// Eine Datei excluden 1081 /// </summary> 1082 /// <param name="sender"></param> 1083 /// <param name="e"></param> 1084 void ContextExclude(object sender, EventArgs e) 1085 { 1086 try 1087 { 1088 StuffItem si = GetStuffItem(sender); 1089 // wenn kein StuffItem ausgewählt wurde, dann tun wir hier nix 1090 if (si == null) 1091 { 1092 return; 1093 } 1094 1095 // Datei sperren 1096 si.Exclude(); 1097 Log("Sperre Datei: " + si.Path); 1098 1099 UpdateTreeNodeIcon(si); 1100 } 1101 catch (Exception e2) 1102 { 1103 LogError("Fehler beim Sperren: " + e2.Message); 1104 } 1105 } 1106 1107 /// <summary> 1108 /// Eine Datei excluden und löschen 1109 /// </summary> 1110 /// <param name="sender"></param> 1111 /// <param name="e"></param> 1112 void ContextExcludeAndDelete( object sender, EventArgs e ) 1113 { 1114 try 1115 { 1116 StuffItem si = GetStuffItem( sender ); 1117 if ( si == null ) 1118 { 1119 return; 1120 } 1121 DialogResult res = MessageBox.Show( "Datei " + si.Name + " wirklich sperren und löschen?", 1122 "Vorsicht, sie trennen sich von Material!", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation ); 1123 if ( res == DialogResult.OK ) 1124 { 1125 Log( "Sperre und lösche Datei: " + si.Path ); 1126 si.Exclude(); 1127 File.Delete( si.Path ); 1128 1129 RemoveStuffItemFromMyDisksTree( si ); 1130 } 1131 } 1132 catch ( Exception e2 ) 1133 { 1134 LogError( "Fehler beim Sperren und Löschen: " + e2.Message ); 1135 } 1136 } 1137 1138 /// <summary> 1139 /// Eine Datei includen 1140 /// </summary> 1141 /// <param name="sender"></param> 1142 /// <param name="e"></param> 1143 void ContextInclude(object sender, EventArgs e) 1144 { 1145 try 1146 { 1147 StuffItem si = GetStuffItem(sender); 1148 if (si == null) 1149 { 1150 return; 1151 } 1152 1153 Log("Entsperre Datei: " + si.Path); 1154 si.Include(); 1155 1156 UpdateTreeNodeIcon(si); 1157 } 1158 catch (Exception ex) 1159 { 1160 LogError("Fehler beim Entsperren: " + ex.Message); 1161 } 1162 } 1163 1164 1165 /// <summary> 1166 /// Eine Datei ignorieren 1167 /// </summary> 1168 /// <param name="sender"></param> 1169 /// <param name="e"></param> 1170 void ContextIgnore(object sender, EventArgs e) 1171 { 1172 try 1173 { 1174 StuffItem si = GetStuffItem(sender); 1175 if (si == null) 1176 { 1177 return; 1178 } 1179 1180 Log("Erlaube Dubletten der Datei: " + si.Path); 1181 si.Ignore(); 1182 1183 // Icon der Datei und möglicher Clones anpassen 1184 UpdateTreeNodeIcon(si); 1185 } 1186 catch (Exception ex) 1187 { 1188 LogError("Fehler beim Erlauben: " + ex.Message); 1189 } 1190 } 1191 1192 /// <summary> 1193 /// Eine Datei un-ignorieren 1194 /// </summary> 1195 /// <param name="sender"></param> 1196 /// <param name="e"></param> 1197 void ContextUnIgnore(object sender, EventArgs e) 1198 { 1199 try 1200 { 1201 StuffItem si = GetStuffItem(sender); 1202 if (si == null) 1203 { 1204 return; 1205 } 1206 1207 Log("Markiere Dubletten der Datei: " + si.Path); 1208 si.UnIgnore(); 1209 1210 // Icon der Datei und möglicher Clones anpassen 1211 UpdateTreeNodeIcon( si ); 1212 } 1213 catch (Exception ex) 1214 { 1215 LogError("Fehler beim Markieren: " + ex.Message); 1216 } 1217 } 1218 1219 /// <summary> 1220 /// Eine Datei ausführen durch Menüeintrag 1221 /// </summary> 1222 /// <param name="sender"></param> 1223 /// <param name="e"></param> 1224 void ContextExecute(object sender, EventArgs e) 1225 { 1226 try 1227 { 1228 StuffItem si = GetStuffItem(sender); 1229 if ( si == null ) 1230 { 1231 return; 1232 } 1233 if ( si.IsFile ) 1234 { 1235 Status( "Starte Datei: " + si.Path ); 1236 } 1237 else 1238 { 1239 Status( "Öffne Verzeichnis: " + si.Path ); 1240 } 1241 1242 try 1243 { 1244 Process.Start(si.Path); 1245 } 1246 catch 1247 { 1248 ContextExecuteWith(sender, e); 1249 } 1250 } 1251 catch (Exception e2) 1252 { 1253 LogError("Fehler beim Ausführen: " + e2.Message); 1254 } 1255 } 1256 1257 /// <summary> 1258 /// Eine Datei ausführen mit Auswahl durch Programm durch Menüeintrag 1259 /// </summary> 1260 /// <param name="sender"></param> 1261 /// <param name="e"></param> 1262 void ContextExecuteWith(object sender, EventArgs e) 1263 { 1264 try 1265 { 1266 StuffItem si = GetStuffItem(sender); 1267 if ( si == null ) 1268 { 1269 return; 1270 } 1271 if ( si.IsFile ) 1272 { 1273 Status( "Starte Datei: " + si.Path ); 1274 } 1275 else 1276 { 1277 Status( "Öffne Verzeichnis: " + si.Path ); 1278 } 1279 1280 using (Process p = new Process()) 1281 { 1282 ProcessStartInfo pi = new ProcessStartInfo("rundll32.exe"); 1283 pi.UseShellExecute = false; 1284 pi.RedirectStandardOutput = true; 1285 pi.Arguments = "shell32.dll,OpenAs_RunDLL " + si.Path; 1286 p.StartInfo = pi; 1287 p.Start(); 1288 } 1289 } 1290 catch (Exception e2) 1291 { 1292 LogError("Fehler beim Ausführen: " + e2.Message); 1293 } 1294 } 1295 1296 /// <summary> 1297 /// Eine Datei löschen 1298 /// </summary> 1299 /// <param name="sender"></param> 1300 /// <param name="e"></param> 1301 void ContextDeleteFile(object sender, EventArgs e) 1302 { 1303 try 1304 { 1305 StuffItem si = GetStuffItem(sender); 1306 if (si == null) 1307 { 1308 return; 1309 } 1310 1311 if (MessageBox.Show("Datei " + si.Name + " wirklich löschen?", "Vorsicht, sie trennen sich von Material!", 1312 MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation) == DialogResult.OK) 1313 { 1314 // Datei löschen 1315 Log("Lösche Datei: " + si.Path); 1316 File.Delete(si.Path); 1317 1318 RemoveStuffItemFromMyDisksTree( si ); 1319 } 1320 } 1321 catch (Exception e2) 1322 { 1323 LogError("Fehler beim Löschen: " + e2.Message); 1324 } 1325 } 1326 1327 /// <summary> 1328 /// Eine leeren Ordner löschen 1329 /// </summary> 1330 /// <param name="sender"></param> 1331 /// <param name="e"></param> 1332 void ContextDeleteFolder(object sender, EventArgs e) 1333 { 1334 try 1335 { 1336 StuffItem si = GetStuffItem(sender); 1337 if ( si == null ) 1338 { 1339 return; 1340 } 1341 1342 DialogResult res = System.Windows.Forms.MessageBox.Show("Ordner " + si.Name + " wirklich löschen?", "Leeren Ordner löschen", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation); 1343 if (res == DialogResult.OK) 1344 { 1345 Log("Lösche Ordner: " + si.Path); 1346 Directory.Delete(si.Path); 1347 1348 RemoveStuffItemFromMyDisksTree( si ); 1349 } 1350 } 1351 catch (Exception e2) 1352 { 1353 LogError("Fehler beim Löschen: " + e2.Message); 1354 } 1355 } 1356 /// <summary> 1357 /// Alle markierten unterhalb eines Ordners löschen 1358 /// </summary> 1359 /// <param name="sender"></param> 1360 /// <param name="e"></param> 1361 void ContextDeleteAllMarkedFiles(object sender, EventArgs e) 1362 { 1363 StuffItem si = GetStuffItem(sender); 1364 if (si == null || si.IsFile || si.IsOnForeignDisk) 1365 { 1366 return; 1367 } 1368 1369 string meld = ""; 1370 if (si.Parent == null) 1371 { 1372 meld = "Alle markierten Dateien wirklich löschen?"; 1373 } 1374 else 1375 { 1376 meld = "Alle markierten Dateien unterhalb " + si.Path + " wirklich löschen?"; 1377 } 1378 1379 DialogResult res = MessageBox.Show(meld, "Vorsicht, sie trennen sich von Material!", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning); 1380 if (res == DialogResult.OK) 1381 { 1382 DeleteAllMarkedFilesRecursive(si); 1383 } 1384 } 1385 1386 /// <summary> 1387 /// Alle markierten unterhalb eines Ordners sperren und löschen 1388 /// </summary> 1389 /// <param name="sender"></param> 1390 /// <param name="e"></param> 1391 void ContextExcludeAndDeleteAllMarkedFiles(object sender, EventArgs e) 1392 { 1393 StuffItem si = GetStuffItem(sender); 1394 if (si == null || si.IsFile ||si.IsOnForeignDisk) 1395 { 1396 return; 1397 } 1398 1399 string meld = ""; 1400 if (si.Parent == null) 1401 { 1402 meld = "Alle markierten Dateien wirklich sperren und löschen?"; 1403 } 1404 else 1405 { 1406 meld = "Alle markierten Dateien unterhalb " + si.Path + " wirklich sperren und löschen?"; 1407 } 1408 1409 if (MessageBox.Show(meld, "Vorsicht, sie trennen sich von Material!", 1410 MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.OK) 1411 { 1412 Recursive_ExcludeMarkers(si, true); 1413 DeleteAllMarkedFilesRecursive(si); 1414 } 1415 } 1416 1417 /// <summary> 1418 /// Hilfsfunktion um alle markierten Dateien rekrusiv zu löschen 1419 /// </summary> 1420 /// <param name="si"></param> 1421 private void DeleteAllMarkedFilesRecursive(StuffItem si) 1422 { 1423 try 1424 { 1425 if ( si.IsFile ) 1426 { 1427 if ( !si.Checked ) 1428 { 1429 return; 1430 } 1431 // Datei löschen 1432 Log( "Datei wird gelöscht: " + si.Path ); 1433 File.Delete( si.Path ); 1434 1435 // aus der StuffItem-Liste löschen 1436 RemoveStuffItemFromMyDisksTree( si ); 1437 } 1438 else 1439 { 1440 // Rückwärts durchlaufen wegen Löschen 1441 for ( int j = si.ChildItems.Count - 1 ; j >= 0 ; j-- ) 1442 { 1443 StuffItem csi = si.ChildItems[ j ]; 1444 DeleteAllMarkedFilesRecursive( csi ); 1445 } 1446 1447 // Leeres Verzeichnis löschen 1448 if ( si.ChildItems.Count == 0 && si.Checked ) 1449 { 1450 Log( "Leeres Verzeichnis wird gelöscht: " + si.Path ); 1451 Directory.Delete( si.Path ); 1452 1453 RemoveStuffItemFromMyDisksTree( si ); 1454 } 1455 } 1456 } 1457 catch (Exception e2) 1458 { 1459 LogError("Fehler beim Löschen: " + e2.Message); 1460 } 1461 } 1462 1463 private void RemoveStuffItemFromMyDisksTree( StuffItem si ) 1464 { 1465 // Verweis vom Elternteil entfernen 1466 si.Parent.ChildItems.Remove( si ); 1467 1468 // Datei aus dem Tree entfernen 1469 myDisksTree.FindSingleNode(si.Path).Remove(); 1470 1471 // Einträge auch aus der MyDisksByHash-Liste entfernen 1472 m_MyDisks.RemoveStuffItemFromHashes( si ); 1473 1474 // Anzeige aktualisieren 1475 UpdateTreeNodeIcon( si ); 1476 } 1477 1478 /// <summary> 1479 /// Alle markierten unterhalb eines Ordners sperren 1480 /// </summary> 1481 /// <param name="sender"></param> 1482 /// <param name="e"></param> 1483 void ContextExcludeMarkers(object sender, EventArgs e) 1484 { 1485 StuffItem si = GetStuffItem(sender); 1486 if (si == null || si.IsFile) 1487 { 1488 return; 1489 } 1490 Recursive_ExcludeMarkers(si, true); 1491 1492 // Markierungen entfernen, falls gewünscht 1493 if (m_Config.IsRemoveMarks) 1494 { 1495 // Markierungen im aktuellen Tree entfernen 1496 ContextRemoveMark(sender, e); 1497 } 1498 } 1499 1500 /// <summary> 1501 /// Alle markierten unterhalb eines Ordners entsperren 1502 /// </summary> 1503 /// <param name="sender"></param> 1504 /// <param name="e"></param> 1505 void ContextIncludeMarkers(object sender, EventArgs e) 1506 { 1507 StuffItem si = GetStuffItem(sender); 1508 if (si == null || si.IsFile) 1509 { 1510 return; 1511 } 1512 Recursive_ExcludeMarkers(si, false); 1513 1514 // Markierungen entfernen, falls gewünscht 1515 if (m_Config.IsRemoveMarks) 1516 { 1517 // Markierungen im aktuellen Tree entfernen 1518 ContextRemoveMark(sender, e); 1519 } 1520 } 1521 1522 /// <summary> 1523 /// Hilfsfunktion um alle markierten Dateien rekursiv zu sperren 1524 /// </summary> 1525 /// <param name="si"></param> 1526 /// <param name="exclude">true für Dateien sperren, false wenn die Dateien entsperren</param> 1527 private void Recursive_ExcludeMarkers( StuffItem si, bool exclude ) 1528 { 1529 try 1530 { 1531 if ( si.IsFile ) 1532 { 1533 if ( si.Checked ) 1534 { 1535 if ( exclude ) 1536 { 1537 Log( "Datei gesperrt: " + si.Path ); 1538 si.Exclude(); 1539 } 1540 else 1541 { 1542 Log( "Datei entsperrt: " + si.Path ); 1543 si.Include(); 1544 } 1545 1546 // TreeNodeIcon aktualisieren 1547 UpdateTreeNodeIcon( si ); 1548 } 1549 } 1550 else 1551 { 1552 foreach ( StuffItem csi in si.ChildItems ) 1553 { 1554 Recursive_ExcludeMarkers( csi, exclude ); 1555 } 1556 } 1557 } 1558 catch ( Exception e2 ) 1559 { 1560 LogError( "Fehler beim Sperren/Entsperren: " + e2.Message ); 1561 } 1562 } 1563 1564 /// <summary> 1565 /// Alle markierten Items in Kopierliste zusammenfassen und im Hintergrund kopieren 1566 /// </summary> 1567 /// <param name="sender"></param> 1568 /// <param name="e"></param> 1569 void ContextCopyAllClick(object sender, EventArgs e) 1570 { 1571 StuffItem trgt = GetStuffItem(sender); 1572 if (trgt == null || trgt.IsFile) 1573 return; 1574 List<StuffItemPair> copylist = new List<StuffItemPair>(); 1575 ContextCopyAllClickAddChecked(copylist, otherDisksTree.Nodes[0]); 1576 1577 // Markierungen entfernen, falls gewünscht 1578 // beim Kopieren schon jetzt, denn entfällt das manuelle Demarkieren 1579 if (m_Config.IsRemoveMarks) 1580 { 1581 // Markierung immer im Tree "Fremde Platten" entfernen 1582 ContextRemoveMark(otherDisksTree.Nodes[0].Tag, e); 1583 } 1584 1585 foreach (StuffItemPair pair in copylist) 1586 { 1587 pair.Target = trgt; 1588 } 1589 // Kopieraktion starten 1590 Program.RunBackgroundTask(this, "CopyFiles", copylist); 1591 } 1592 1593 /// <summary> 1594 /// Alle markierten Items in Kopierliste zusammenfassen und mit Pfad kopieren 1595 /// </summary> 1596 /// <param name="sender"></param> 1597 /// <param name="e"></param> 1598 void ContextCopyAllWithFoldersClick(object sender, EventArgs e) 1599 { 1600 StuffItem trgt = GetStuffItem(sender); 1601 if (trgt == null || trgt.IsFile) 1602 return; 1603 1604 List<StuffItemPair> copylist = new List<StuffItemPair>(); 1605 ContextCopyAllClickAddChecked(copylist, otherDisksTree.Nodes[0]); 1606 foreach (StuffItemPair pair in copylist) 1607 { 1608 FileInfo fi = new FileInfo(pair.Source.Path); 1609 string subpath = fi.DirectoryName.Replace(":", "").Replace("\\\\", ""); 1610 pair.Target = new StuffItem(); 1611 pair.Target.Path = trgt.Path + "\\" + subpath; 1612 } 1613 1614 // Markierungen entfernen, falls gewünscht 1615 // beim Kopieren schon jetzt, denn entfällt das manuelle Demarkieren 1616 // beim Kopieren immer im Tree "Fremde Platten" 1617 if (m_Config.IsRemoveMarks) 1618 { 1619 ContextRemoveMark(otherDisksTree.Nodes[0].Tag, e); 1620 } 1621 1622 // Dateien kopieren 1623 Program.RunBackgroundTask(this, "CopyFiles", copylist); 1624 } 1625 1626 /// <summary> 1627 /// Hilfsfunktion zum rekursiven Kopieren (ohne Erhalt der Hierarchie) 1628 /// </summary> 1629 /// <param name="copylist"></param> 1630 /// <param name="node"></param> 1631 void ContextCopyAllClickAddChecked(List<StuffItemPair> copylist, TreeNode node) 1632 { 1633 if (node.Checked) 1634 { 1635 StuffItem item = (StuffItem)node.Tag; 1636 if (item != null && item.IsFile) 1637 { 1638 copylist.Add(new StuffItemPair()); 1639 copylist[copylist.Count - 1].Source = item; 1640 } 1641 } 1642 foreach (TreeNode n in node.Nodes) 1643 { 1644 ContextCopyAllClickAddChecked(copylist, n); 1645 } 1646 } 1647 1648 /// <summary> 1649 /// Aktualisiert das Icon eines bestimmten StuffItems in den TreeViews 1650 /// </summary> 1651 /// <param name="si">StuffItem, welches es zu aktualisieren gilt</param> 1652 void UpdateTreeNodeIcon(StuffItem si) 1653 { 1654 TreeView currentTree = si.IsOnForeignDisk ? otherDisksTree : myDisksTree; 1655 TreeNode tn = currentTree.FindSingleNode( si.Path ); 1656 if ( tn != null ) 1657 { 1658 tn.ImageIndex = tn.SelectedImageIndex = ( int )si.Icon; 1659 } 1660 1661 // lokale Dateien eines entfernten StuffItems ebenfalls anpassen 1662 if ( si.IsOnForeignDisk ) 1663 { 1664 foreach ( String localpath in si.GetLocalFiles ) 1665 { 1666 tn = myDisksTree.FindSingleNode( localpath ); 1667 tn.ImageIndex = tn.SelectedImageIndex = ( int )( ( StuffItem )tn.Tag ).Icon; 1668 } 1669 } 1670 else 1671 { 1672 // ggf. den anderen Tree auch anpassen (wg. Exludes) 1673 foreach ( String remotepath in si.GetRemoteFiles ) 1674 { 1675 tn = otherDisksTree.FindSingleNode( remotepath ); 1676 tn.ImageIndex = tn.SelectedImageIndex = ( int )( ( StuffItem )tn.Tag ).Icon; 1677 } 1678 // TODO: bei Excludes und aktiver Option zum Ausblenden von Items, dann muss das Ding ganz raus 1679 } 1680 } 1681 1682 #endregion 1683 1684 #region Markierungen setzen und entfernen (Kontextmenu) 1685 1686 /// <summary> 1687 /// Alle Zweige ohne Markierung zuklappen 1688 /// </summary> 1689 /// <param name="sender"></param> 1690 /// <param name="e"></param> 1691 private void ContextCollapse(object sender, EventArgs e) 1692 { 1693 StuffItem si = GetStuffItem(sender); 1694 if (si == null) 1695 { 1696 return; 1697 } 1698 if (si.IsOnForeignDisk) 1699 { 1700 CollapseOtherDisks(); 1701 } 1702 else 1703 { 1704 CollapseMyDisks(); 1705 } 1706 } 1707 1708 /// <summary> 1709 /// Alle markieren, die zu saugen sind 1710 /// </summary> 1711 /// <param name="sender"></param> 1712 /// <param name="e"></param> 1713 private void ContextMarkMissingFiles(object sender, EventArgs e) 1714 { 1715 StuffItem si = GetStuffItem(sender); 1716 if (si == null) 1717 { 1718 return; 1719 } 1720 1721 Recursive_UpdateMark( si, true ); 1722 Recursive_MarkMissingFiles(si); 1723 } 1724 1725 /// <summary> 1726 /// Alle Dateien die ein Clone einer anderen sind markieren 1727 /// </summary> 1728 private void ContextMarkClones(object sender, EventArgs e) 1729 { 1730 StuffItem si = GetStuffItem(sender); 1731 if (si == null) 1732 { 1733 return; 1734 } 1735 1736 si.Checked = false; 1737 foreach ( StuffItem clone in Program.MainWindow.m_MyDisks.GetItemClones( si ) ) 1738 { 1739 TreeNode node = myDisksTree.FindSingleNode( clone.Path ); 1740 node.Checked = true; 1741 node.Expand(); 1742 } 1743 } 1744 1745 /// <summary> 1746 /// Alle Dateien unterhalb eines Knotens markieren 1747 /// </summary> 1748 /// <param name="sender"></param> 1749 /// <param name="e"></param> 1750 private void ContextMark(object sender, EventArgs e) 1751 { 1752 StuffItem si = GetStuffItem(sender); 1753 if (si == null) 1754 { 1755 return; 1756 } 1757 1758 Recursive_UpdateMark( si, true ); 1759 } 1760 1761 /// <summary> 1762 /// Alle Markierungen entfernen 1763 /// </summary> 1764 /// <param name="sender"></param> 1765 /// <param name="e"></param> 1766 private void ContextRemoveMark(object sender, EventArgs e) 1767 { 1768 StuffItem si = GetStuffItem(sender); 1769 if (si == null) 1770 { 1771 return; 1772 } 1773 1774 Recursive_UpdateMark( si, false ); 1775 } 1776 1777 /// <summary> 1778 /// Alle markieren, die zu gelöscht werden können, weil doppelt 1779 /// Das klappt nur auf dem Root-Node, dehalb nur da anbieten 1780 /// </summary> 1781 /// <param name="sender"></param> 1782 /// <param name="e"></param> 1783 private void ContextMarkDoubleEntries(object sender, EventArgs e) 1784 { 1785 StuffItem se = GetStuffItem(sender); 1786 if (se == null) 1787 { 1788 return; 1789 } 1790 Recursive_UpdateMark( se, false ); 1791 Recursive_MarkDoubleEntries(se); 1792 } 1793 1794 1795 /// <summary> 1796 /// Alle Dateien unterhalb eines Knotens mit einem manuellen Filterstring markieren 1797 /// </summary> 1798 /// <param name="sender"></param> 1799 /// <param name="e"></param> 1800 private void ContextMarkByFilter(object sender, EventArgs e) 1801 { 1802 // Ohne Startitem gehts nicht 1803 StuffItem si = GetStuffItem(sender); 1804 if (si == null) 1805 { 1806 return; 1807 } 1808 1809 // Dialog aufbauen / abfragen 1810 using (LanTool.FilterDialog filterDlg = new LanTool.FilterDialog()) 1811 { 1812 filterDlg.Text = "Filtern unterhalb \"" + si.Path + "\""; 1813 1814 if (filterDlg.ShowDialog() == DialogResult.OK) 1815 { 1816 string filter = filterDlg.Expression; 1817 // RegExp-Sonderzeichen per backslash quoten 1818 string[] quote = new string[] { "\\", ".", "(", ")", "[", "]" }; 1819 foreach (string q in quote) 1820 filter = filter.Replace(q, "\\" + q); 1821 1822 // Dos Wildcards durch RegExp ersetzen 1823 filter = filter.Replace("*", ".*").Replace("?", "."); 1824 1825 // Losfiltern ab Item 1826 Recursive_MarkByFilter(si, filter); 1827 } 1828 } 1829 } 1830 1831 /// <summary> 1832 /// Rekursion zum Markieren mit einem Filterstring 1833 /// </summary> 1834 /// <param name="si">aktuellles StuffItem</param> 1835 /// <param name="filter">String-Filter</param> 1836 private void Recursive_MarkByFilter(StuffItem si, string filter) 1837 { 1838 TreeView currenttree = si.IsOnForeignDisk ? otherDisksTree : myDisksTree; 1839 1840 foreach (StuffItem csi in si.ChildItems) 1841 { 1842 // wenn der Filter zutrifft, dann markieren 1843 if (Regex.IsMatch(csi.Name, filter, RegexOptions.IgnoreCase)) 1844 { 1845 currenttree.FindSingleNode(csi.Path).Checked = true; 1846 } 1847 // wenn Ordner, dann weiter rekursiv durch 1848 if (!csi.IsFile) 1849 { 1850 Recursive_MarkByFilter(csi, filter); 1851 } 1852 } 1853 } 1854 1855 /// <summary> 1856 /// Rekursion zum Markieren fürs Saugen 1857 /// </summary> 1858 private void Recursive_MarkMissingFiles(StuffItem si) 1859 { 1860 TreeView currenttree = si.IsOnForeignDisk ? otherDisksTree : myDisksTree; 1861 1862 // alle TreeNodes finden 1863 foreach ( StuffItem csi in si.ChildItems ) 1864 { 1865 TreeNode node = currenttree.FindSingleNode( csi.Path ); 1866 node.Checked = csi.IsNeeded; 1867 if ( csi.IsNeeded ) 1868 { 1869 node.Expand(); 1870 } 1871 1872 if ( !csi.IsFile ) 1873 { 1874 Recursive_MarkMissingFiles( csi ); 1875 } 1876 } 1877 } 1878 1879 /// <summary> 1880 /// Rekursiv alle untergeordneten Nodes de-/markieren 1881 /// </summary> 1882 private void Recursive_UpdateMark( StuffItem si, Boolean setMark ) 1883 { 1884 TreeView currenttree = si.IsOnForeignDisk ? otherDisksTree : myDisksTree; 1885 1886 // alle TreeNodes finden 1887 TreeNode node = currenttree.FindSingleNode( si.Path ); 1888 node.Checked = setMark; 1889 if ( setMark ) 1890 { 1891 node.Expand(); 1892 } 1893 1894 foreach ( StuffItem csi in si.ChildItems ) 1895 { 1896 Recursive_UpdateMark( csi, setMark ); 1897 } 1898 } 1899 1900 /// <summary> 1901 /// Die nachfolgenden Duplikate markieren, d.h. das erste bleibt erhalten 1902 /// Das kann nur klappen wenn auf RootNode begonnen wird und vorher alle Markierungen 1903 /// zurückgesetzt werden! 1904 /// </summary> 1905 /// <param name="si"></param> 1906 private void Recursive_MarkDoubleEntries(StuffItem si) 1907 { 1908 // nur bei den eigenen Platten 1909 if (!si.IsOnForeignDisk) 1910 { 1911 // nur bei Dateien 1912 if (si.IsFile) 1913 { 1914 if (!si.Checked && si.HasClones) 1915 { 1916 foreach ( StuffItem csi in Program.MainWindow.m_MyDisks.GetItemClones( si ) ) 1917 { 1918 TreeNode node = myDisksTree.FindSingleNode( csi.Path ); 1919 1920 node.Checked = true; 1921 node.Expand(); 1922 1923 } 1924 } 1925 } 1926 else 1927 { 1928 foreach (StuffItem csi in si.ChildItems) 1929 { 1930 Recursive_MarkDoubleEntries(csi); 1931 } 1932 } 1933 } 1934 } 1935 1936 #endregion 1937 1938 #region Suchen 1939 1940 /// <summary> 1941 /// Suche 1942 /// </summary> 1943 private bool ContextSearchRecursive(StuffItem si, string filter) 1944 { 1945 foreach (StuffItem se2 in si.ChildItems) 1946 { 1947 if (Regex.IsMatch(se2.Path, filter, RegexOptions.IgnoreCase) && !itemsAlreadyFound.Contains(se2.Path)) 1948 { 1949 // Item zur Liste "bereits gefunden" hinzufügen 1950 itemsAlreadyFound.Add(se2.Path); 1951 1952 // gesuchtes Item gefunden, dann 1953 TreeNode fn = FindNode(lastUsedView.Nodes[0].Nodes, se2.Path); 1954 if (fn == null) 1955 { 1956 return false; 1957 } 1958 else 1959 { 1960 lastUsedView.SelectedNode = fn; 1961 return true; 1962 } 1963 } 1964 else 1965 { 1966 // keine Datei, dann die childs untersuchen 1967 if (!se2.IsFile) 1968 if (ContextSearchRecursive(se2, filter)) 1969 return true; 1970 } 1971 } 1972 1973 return false; 1974 } 1975 private TreeNode FindNode(TreeNodeCollection tncoll, String strText) 1976 { 1977 TreeNode tnFound = null; 1978 foreach (TreeNode tnCurr in tncoll) 1979 { 1980 if (String.Equals(tnCurr.Name, strText, StringComparison.CurrentCultureIgnoreCase)) 1981 { 1982 return tnCurr; 1983 } 1984 if (tnCurr.Nodes.Count > 0) 1985 tnFound = FindNode(tnCurr.Nodes, strText); 1986 if (tnFound != null) 1987 { 1988 return tnFound; 1989 } 1990 } 1991 return null; 1992 } 1993 1994 /// <summary> 1995 /// Im Suchfeld wurde eine Taste betätigt 1996 /// </summary> 1997 /// <param name="sender"></param> 1998 /// <param name="e"></param> 1999 private void searchField_KeyUp(object sender, KeyEventArgs e) 2000 { 2001 if (e.KeyCode == Keys.Return) 2002 { 2003 // wenn es um eine neue Suche handelt, dann die bereits gefunden Liste zurücksetzen 2004 if (!String.Equals(lastSearchString, searchField.Text, StringComparison.CurrentCultureIgnoreCase)) 2005 { 2006 itemsAlreadyFound.Clear(); 2007 2008 lastSearchString = searchField.Text; 2009 } 2010 2011 String filter = searchField.Text; 2012 2013 // wenn kein Suchtext angegeben wurde, dann wird auch nichts gesucht 2014 if (!String.IsNullOrEmpty(filter)) 2015 { 2016 2017 // RegExp-Sonderzeichen per backslash quoten 2018 string[] quote = new string[] { "\\", ".", "(", ")", "[", "]" }; 2019 foreach (string q in quote) 2020 filter = filter.Replace(q, "\\" + q); 2021 2022 // Dos Wildcards durch RegExp ersetzen 2023 filter = filter.Replace("*", ".*").Replace("?", "."); 2024 2025 StuffItem si = (StuffItem)lastUsedView.Nodes[0].Tag; 2026 2027 // Suche beim aktuellen Item starten 2028 if (!ContextSearchRecursive(si, filter)) 2029 { 2030 Status("Keine (weiteren) Treffer."); 2031 // Bereits gefunden Liste zurücksetzen 2032 itemsAlreadyFound.Clear(); 2033 } 2034 2035 // damit das ganze auch sichtbar wird, den TreeView fokusieren 2036 lastUsedView.Focus(); 2037 } 2038 else 2039 { 2040 searchField.Focus(); 2041 } 2042 } 2043 } 2044 2045 /// <summary> 2046 /// Suchen-Button im Menü 2047 /// </summary> 2048 /// <param name="sender"></param> 2049 /// <param name="e"></param> 2050 private void suchenToolStripMenuItem_Click(object sender, EventArgs e) 2051 { 2052 // gleiche Funktion wie Enter im Suchfeld 2053 searchField_KeyUp(sender, new KeyEventArgs(Keys.Return)); 2054 } 2055 2056 #endregion 2057 2058 /// <summary> 2059 /// Neuen Ordner anlegen 2060 /// </summary> 2061 /// <param name="sender"></param> 2062 /// <param name="e"></param> 2063 private void ContextNewFolder(object sender, EventArgs e) 2064 { 2065 // Ohne Startitem gehts nicht 2066 StuffItem si = GetStuffItem(sender); 2067 if (si == null) 2068 { 2069 return; 2070 } 2071 2072 // Dialog aufbauen / abfragen 2073 using (NewFolderDialog folderDlg = new NewFolderDialog()) 2074 { 2075 folderDlg.Text = "Neuen Ordner anlegen unterhalb \"" + si.Path + "\":"; 2076 if (folderDlg.ShowDialog() == DialogResult.OK) 2077 { 2078 string folder = folderDlg.NewFolderName; 2079 // Sonderzeichen durch _ ersetzen 2080 foreach ( char q in Path.GetInvalidPathChars() ) 2081 { 2082 folder = folder.Replace( q, '_' ); 2083 } 2084 // Losfiltern ab Item 2085 Directory.CreateDirectory(Path.Combine(si.Path, folder)); 2086 2087 si.AddOrGetChildItemByPath( Path.Combine( si.Path, folder ) ); 2088 2089 UpdateTreeRecursive( myDisksTree.Nodes[si.Path], si, false); 2090 } 2091 } 2092 } 2093 2094 #region Speichern und laden einer Fileliste als Ersatz für dem MyDisk-Filesystem Scan 2095 2096 /// <summary> 2097 /// Verzeichnisse exportieren (werden durch realen Scan aufgebaut) 2098 /// </summary> 2099 /// <param name="sender"></param> 2100 /// <param name="e"></param> 2101 private void verzeichnisFürMeinePlattenExportierenToolStripMenuItem_Click(object sender, EventArgs e) 2102 { 2103 using (SaveFileDialog fd = new SaveFileDialog()) 2104 { 2105 fd.Filter = "LanTool-Verzeichnis-Export (*.files)|*.files|Textdateien (*.txt)|*.txt"; 2106 fd.DefaultExt = "*.files"; 2107 fd.FileName = "MeinePlatten.files"; 2108 fd.InitialDirectory = MainForm.basePath; 2109 fd.CheckFileExists = false; 2110 fd.CheckPathExists = true; 2111 fd.AutoUpgradeEnabled = true; 2112 if (fd.ShowDialog(this).Equals(DialogResult.OK)) 2113 { 2114 Log(String.Format("Offline-Datei {0} wurde gespeichert.", fd.FileName)); 2115 m_MyDisks.SaveOfflineCacheToFile(fd.FileName); 2116 } 2117 } 2118 } 2119 2120 /// <summary> 2121 /// Einlesen einer Cache-Datei für den Offline-Betrieb 2122 /// </summary> 2123 /// <param name="sender"></param> 2124 /// <param name="e"></param> 2125 private void verzeichnisFürMeinePlattenImportierenToolStripMenuItem_Click(object sender, EventArgs e) 2126 { 2127 using (OpenFileDialog fd = new OpenFileDialog()) 2128 { 2129 fd.Filter = "LanTool-Verzeichnis-Export (*.files)|*.files|Textdateien (*.txt)|*.txt"; 2130 fd.DefaultExt = "*.files"; 2131 fd.FileName = "MeinePlatten.files"; 2132 fd.InitialDirectory = MainForm.basePath; 2133 fd.CheckFileExists = true; 2134 fd.CheckPathExists = true; 2135 fd.Multiselect = false; 2136 fd.AutoUpgradeEnabled = true; 2137 if (fd.ShowDialog(this) == DialogResult.OK) 2138 { 2139 m_MyDisks.LoadOfflineCacheFromFile(fd.FileName); 2140 m_MyDisks.IsOnline = false; 2141 2142 Log(String.Format("Offline-Datei {0} wurde eingelesen.", fd.FileName)); 2143 2144 UpdateTrees(); 2145 } 2146 } 2147 } 2148 2149 private void offlineCacheLöschenToolStripMenuItem_Click(object sender, EventArgs e) 2150 { 2151 m_MyDisks.ResetOfflineCaches(); 2152 m_MyDisks.IsOnline = true; 2153 2154 UpdateTrees(); 2155 } 2156 2157 #endregion 2158 2159 /// <summary> 2160 /// Speichern welcher TreeView zuletzt aufgerufen wurde 2161 /// </summary> 2162 /// <param name="sender"></param> 2163 /// <param name="e"></param> 2164 private void DisksTree_Enter(object sender, EventArgs e) 2165 { 2166 lastUsedView = (TreeView)sender; 2167 } 2168 2169 /// <summary> 2170 /// Ausführen einer Datei durch Doppelklick 2171 /// </summary> 2172 private void tree_MouseDoubleClick(object sender, MouseEventArgs e) 2173 { 2174 try 2175 { 2176 // nur bei Linksklick reagieren 2177 if (e.Button.Equals(MouseButtons.Left)) 2178 { 2179 Point clickPoint = new Point(e.X, e.Y); 2180 2181 // Objekt unter der Maus holen 2182 TreeNode clickNode = ((TreeView)sender).GetNodeAt(clickPoint); 2183 // ins leere geklickt -> nichts tun 2184 if ( clickNode == null || clickNode.Tag == null ) 2185 { 2186 return; 2187 } 2188 2189 StuffItem tn = (StuffItem)clickNode.Tag; 2190 // kein StuffItem dran oder keine Datei 2191 if ( tn == null || !tn.IsFile ) 2192 { 2193 return; 2194 } 2195 2196 // Datei ausführen 2197 Status("Starte Datei: " + tn.Path); 2198 Process.Start(tn.Path); 2199 } 2200 } 2201 catch (Exception e2) 2202 { 2203 LogError("Fehler beim Ausführen: " + e2.Message); 2204 } 2205 } 2206 2207 /// <summary> 2208 /// Hotkeys behandeln 2209 /// </summary> 2210 /// <param name="sender"></param> 2211 /// <param name="e"></param> 2212 private void MainForm_KeyUp(object sender, KeyEventArgs e) 2213 { 2214 // ins Suchfeld springen bei Strg+F 2215 if (e.KeyCode == Keys.F && Control.ModifierKeys == Keys.Control) 2216 { 2217 searchField.Focus(); 2218 } 2219 // gleiche Funktion wie Enter im Suchfeld 2220 else if (e.KeyCode == Keys.F3) 2221 { 2222 searchField_KeyUp(sender, new KeyEventArgs(Keys.Return)); 2223 } 2224 } 2225 2226 private void MainForm_FormClosing(object sender, FormClosingEventArgs e) 2227 { 2228 // Caches auf die Platte schreiben 2229 m_Cache.Dispose(); 2230 } 2231 2232 /// <summary> 2233 /// Nach Auswahl eines Elementes den Pfad zum Element in der Textbox anzeigen 2234 /// </summary> 2235 private void myDisksTree_AfterSelect(object sender, TreeViewEventArgs e) 2236 { 2237 StuffItem selectedStuffItem = (StuffItem)myDisksTree.SelectedNode.Tag; 2238 if (selectedStuffItem.IsFile) 2239 { 2240 myDisksPath.Text = Path.GetDirectoryName(selectedStuffItem.Path); 2241 } 2242 else 2243 { 2244 myDisksPath.Text = selectedStuffItem.Path; 2245 } 2246 } 2247 2248 /// <summary> 2249 /// Nach Auswahl eines Elementes den Pfad zum Element in der Textbox anzeigen 2250 /// </summary> 2251 private void otherDisksTree_AfterSelect(object sender, TreeViewEventArgs e) 2252 { 2253 StuffItem selectedStuffItem = (StuffItem)otherDisksTree.SelectedNode.Tag; 2254 if (selectedStuffItem.IsFile) 2255 { 2256 otherDisksPath.Text = Path.GetDirectoryName(selectedStuffItem.Path); 2257 } 2258 else 2259 { 2260 otherDisksPath.Text = selectedStuffItem.Path; 2261 } 2262 } 2263 2264 #region Pfad-Felder über den TreeViews 2265 2266 private void DisksPath_OpenPath(object sender, MouseEventArgs e) 2267 { 2268 String path = ((TextBox)sender).Text; 2269 2270 // Links -> Pfad im Explorer öffnen 2271 if (e.Button == MouseButtons.Left) 2272 { 2273 try 2274 { 2275 // Nach oben suchen bis ein Text entsteht, der als Verzeichnis existiert 2276 while ( !Directory.Exists( path ) && path.Length > 0 ) 2277 { 2278 path = path.Substring( 0, path.LastIndexOf( @"\" ) ); 2279 } 2280 2281 // im Explorer öffnen 2282 if ( !Directory.Exists( path ) ) 2283 { 2284 return; 2285 } 2286 2287 Status( "Öffne Verzeichnis: " + path ); 2288 Process.Start( path ); 2289 } 2290 catch { } 2291 } 2292 // Rechtsklick -> in die Zwischenablage 2293 if (e.Button == MouseButtons.Right) 2294 { 2295 Clipboard.SetDataObject(path, true); 2296 } 2297 } 2298 2299 private void DisksPath_KeyUp(object sender, KeyEventArgs e) 2300 { 2301 if (e.KeyCode == Keys.Enter) 2302 DisksPath_OpenPath(sender, new MouseEventArgs(MouseButtons.Left, 2, 0, 0, 0)); 2303 } 2304 2305 #endregion 2306 2307 #region Info-Menü 2308 2309 private void lanToolForumToolStripMenuItem_Click(object sender, EventArgs e) 2310 { 2311 Process.Start("http://www.rw-net.de/bbl/index.php?page=Board&boardID=21"); 2312 } 2313 2314 private void lanToolTippsTricksToolStripMenuItem_Click(object sender, EventArgs e) 2315 { 2316 Process.Start("http://www.rw-net.de/LanTool_Tipps.txt"); 2317 } 2318 2319 private void lanToolChangeLogToolStripMenuItem_Click(object sender, EventArgs e) 2320 { 2321 Process.Start("http://www.rw-net.de/LanTool_ChangeLog.txt"); 2322 } 2323 2324 private void überToolStripMenuItem_Click(object sender, EventArgs e) 2325 { 2326 new AboutBox().ShowDialog(); 2327 } 2328 2329 private void fTPMitDemLanToolNetDriveToolStripMenuItem_Click(object sender, EventArgs e) 2330 { 2331 try 2332 { 2333 if (File.Exists("NetDrive-Setup.exe")) 2334 Process.Start("NetDrive-Setup.exe"); 2335 else 2336 Process.Start("http://www.netdrive.net"); 2337 } 2338 catch 2339 { } 2340 } 2341 2342 #endregion 2343 2344 /// <summary> 2345 /// Aktualisierung der beiden TreeViews starten 2346 /// </summary> 2347 private void StartUpdate() 2348 { 2349 // Auto Scan anwerfen 2350 if (m_Config.IsAutoScanMyDisks) 2351 { 2352 m_MyDisks.UpdateChildsBackground(); 2353 } 2354 if (m_Config.IsAutoScanOtherDisks) 2355 { 2356 Program.MainWindow.m_OtherDisks.UpdateChildsBackground(); 2357 } 2358 2359 Program.MainWindow.UpdateTrees(); 2360 } 2361 } 2362 }