Fix transcript in transfer window.
[cyberduck.git] / source / ch / cyberduck / ui / controller / TransferController.cs
blobef3f367fb5b2178396c0f2822f33f10668da0208
1 //
2 // Copyright (c) 2010-2014 Yves Langisch. All rights reserved.
3 // http://cyberduck.ch/
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // Bug fixes, suggestions and comments should be sent to:
16 // yves@cyberduck.ch
17 //
19 using System;
20 using System.Collections.Generic;
21 using System.Drawing;
22 using System.Windows.Forms;
23 using ch.cyberduck.core;
24 using ch.cyberduck.core.formatter;
25 using ch.cyberduck.core.io;
26 using ch.cyberduck.core.local;
27 using ch.cyberduck.core.preferences;
28 using ch.cyberduck.core.ssl;
29 using ch.cyberduck.core.threading;
30 using ch.cyberduck.core.transfer;
31 using Ch.Cyberduck.Ui.Controller.Threading;
32 using org.apache.log4j;
33 using StructureMap;
35 namespace Ch.Cyberduck.Ui.Controller
37 public class TransferController : WindowController<ITransferView>, TranscriptListener, CollectionListener
39 private static readonly Logger Log = Logger.getLogger(typeof (TransferController).FullName);
40 private static readonly object SyncRoot = new Object();
41 private static volatile TransferController _instance;
43 private readonly IDictionary<Transfer, ProgressController> _transferMap =
44 new Dictionary<Transfer, ProgressController>();
46 private TransferController()
48 View = ObjectFactory.GetInstance<ITransferView>();
49 lock (TransferCollection.defaultCollection())
51 foreach (Transfer transfer in TransferCollection.defaultCollection())
53 collectionItemAdded(transfer);
56 Init();
59 public override bool Singleton
61 get { return true; }
64 public static TransferController Instance
66 get
68 if (_instance == null)
70 lock (SyncRoot)
72 if (_instance == null)
73 _instance = new TransferController();
76 return _instance;
80 public void collectionLoaded()
84 public void collectionItemAdded(object obj)
86 Invoke(delegate
88 Transfer transfer = obj as Transfer;
89 ProgressController progressController = new ProgressController(transfer);
90 _transferMap.Add(new KeyValuePair<Transfer, ProgressController>(transfer, progressController));
91 IProgressView progressView = progressController.View;
92 View.AddTransfer(progressView);
93 View.SelectTransfer(progressView);
94 });
97 public void collectionItemRemoved(object obj)
99 Invoke(delegate
101 Transfer transfer = obj as Transfer;
102 if (null != transfer)
104 ProgressController progressController;
105 if (_transferMap.TryGetValue(transfer, out progressController))
107 View.RemoveTransfer(progressController.View);
113 public void collectionItemChanged(object obj)
117 public override void log(bool request, string transcript)
119 if (View.TranscriptVisible)
121 invoke(new LogAction(this, request, transcript));
125 public ProgressController GetController(Transfer transfer)
127 ProgressController progressController;
128 if (!_transferMap.TryGetValue(transfer, out progressController))
130 progressController = new ProgressController(transfer);
131 _transferMap.Add(transfer, new ProgressController(transfer));
133 return progressController;
136 public static bool ApplicationShouldTerminate()
138 if (null != _instance)
140 //Saving state of transfer window
141 PreferencesFactory.get().setProperty("queue.window.open.default", _instance.Visible);
142 if (TransferCollection.defaultCollection().numberOfRunningTransfers() > 0)
144 DialogResult result = _instance.QuestionBox(LocaleFactory.localizedString("Transfer in progress"),
145 LocaleFactory.localizedString("There are files currently being transferred. Quit anyway?"), null,
146 String.Format("{0}", LocaleFactory.localizedString("Exit")), true //Cancel
148 if (DialogResult.OK == result)
150 // Quit
151 for (int i = 0; i < _instance.getActions().size(); i++)
153 ((BackgroundAction) _instance.getActions().get(i)).cancel();
155 return true;
157 // Cancel
158 return false;
161 return true;
164 private void Init()
166 TransferCollection.defaultCollection().addListener(this);
168 PopulateBandwithList();
170 View.PositionSizeRestoredEvent += delegate
172 View.TranscriptVisible = PreferencesFactory.get().getBoolean("queue.transcript.open");
173 View.TranscriptHeight = PreferencesFactory.get().getInteger("queue.transcript.size.height");
175 View.ToggleTranscriptEvent += View_ToggleTranscriptEvent;
176 View.TranscriptHeightChangedEvent += View_TranscriptHeightChangedEvent;
178 View.QueueSize = PreferencesFactory.get().getInteger("queue.maxtransfers");
179 View.BandwidthEnabled = false;
181 View.ResumeEvent += View_ResumeEvent;
182 View.ReloadEvent += View_ReloadEvent;
183 View.StopEvent += View_StopEvent;
184 View.RemoveEvent += View_RemoveEvent;
185 View.CleanEvent += View_CleanEvent;
186 View.OpenEvent += View_OpenEvent;
187 View.ShowEvent += View_ShowEvent;
188 View.TrashEvent += View_TrashEvent;
189 View.SelectionChangedEvent += View_SelectionChangedEvent;
190 View.BandwidthChangedEvent += View_BandwidthChangedEvent;
191 View.QueueSizeChangedEvent += View_QueueSizeChangedEvent;
193 View.ValidateResumeEvent += View_ValidateResumeEvent;
194 View.ValidateReloadEvent += View_ValidateReloadEvent;
195 View.ValidateStopEvent += View_ValidateStopEvent;
196 View.ValidateRemoveEvent += View_ValidateRemoveEvent;
197 View.ValidateCleanEvent += View_ValidateCleanEvent;
198 View.ValidateOpenEvent += View_ValidateOpenEvent;
199 View.ValidateShowEvent += View_ValidateShowEvent;
202 private void View_TrashEvent()
204 foreach (IProgressView progressView in View.SelectedTransfers)
206 Transfer transfer = GetTransferFromView(progressView);
207 if (!transfer.isRunning())
209 for (int i = 0; i < transfer.getRoots().size(); i++)
211 TransferItem item = (TransferItem) transfer.getRoots().get(i);
214 LocalTrashFactory.get().trash(item.local);
216 catch (Exception exception)
218 Log.warn(String.Format("Failure trashing file {0} {1}", item.local, exception.Message));
225 private void View_TranscriptHeightChangedEvent()
227 PreferencesFactory.get().setProperty("queue.transcript.size.height", View.TranscriptHeight);
230 private void View_ToggleTranscriptEvent()
232 View.TranscriptVisible = !View.TranscriptVisible;
233 PreferencesFactory.get().setProperty("queue.transcript.open", View.TranscriptVisible);
236 private bool View_ValidateShowEvent()
238 return ValidateToolbarItem(delegate(Transfer transfer)
240 if (transfer.getLocal() != null)
242 for (int i = 0; i < transfer.getRoots().size(); i++)
244 TransferItem t = (TransferItem) transfer.getRoots().get(i);
245 if (t.local.exists())
247 return true;
251 return false;
255 private bool View_ValidateOpenEvent()
257 return ValidateToolbarItem(delegate(Transfer transfer)
259 if (transfer.getLocal() != null)
261 if (!transfer.isComplete())
263 return false;
265 if (!transfer.isRunning())
267 for (int i = 0; i < transfer.getRoots().size(); i++)
269 TransferItem item = (TransferItem) transfer.getRoots().get(i);
270 if (item.local.exists())
272 return true;
277 return false;
281 private bool View_ValidateCleanEvent()
283 return _transferMap.Count > 0;
286 private void View_CleanEvent()
288 IList<Transfer> toRemove = new List<Transfer>();
289 foreach (KeyValuePair<Transfer, ProgressController> pair in _transferMap)
291 Transfer t = pair.Key;
292 if (!t.isRunning() && t.isComplete())
294 TransferCollection.defaultCollection().remove(t);
295 toRemove.Add(t);
298 foreach (Transfer t in toRemove)
300 _transferMap.Remove(t);
302 TransferCollection.defaultCollection().save();
305 private bool View_ValidateRemoveEvent()
307 return View.SelectedTransfers.Count > 0;
310 private bool View_ValidateStopEvent()
312 return ValidateToolbarItem(transfer => transfer.isRunning());
315 private bool View_ValidateReloadEvent()
317 return ValidateToolbarItem(transfer => (transfer.getType().isReloadable() && !transfer.isRunning()));
320 /// <summary>
321 /// Validates the selected items in the transfer window against the toolbar validator
322 /// </summary>
323 /// <param name="validate"></param>
324 /// <returns>True if one or more of the selected items passes the validation test</returns>
325 private bool ValidateToolbarItem(TransferToolbarValidator validate)
327 foreach (IProgressView selectedTransfer in View.SelectedTransfers)
329 Transfer transfer = GetTransferFromView(selectedTransfer);
330 if (validate(transfer))
332 return true;
335 return false;
338 private bool View_ValidateResumeEvent()
340 return ValidateToolbarItem(delegate(Transfer transfer)
342 if (transfer.isRunning())
344 return false;
346 return !transfer.isComplete();
350 private void PopulateBandwithList()
352 IList<KeyValuePair<float, string>> list = new List<KeyValuePair<float, string>>();
353 list.Add(new KeyValuePair<float, string>(BandwidthThrottle.UNLIMITED,
354 LocaleFactory.localizedString("Unlimited Bandwidth", "Preferences")));
355 foreach (String option in
356 PreferencesFactory.get()
357 .getProperty("queue.bandwidth.options")
358 .Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries))
360 list.Add(new KeyValuePair<float, string>(Convert.ToInt32(option.Trim()),
361 (SizeFormatterFactory.get(true).format(Convert.ToInt32(option.Trim())) + "/s")));
363 View.PopulateBandwidthList(list);
366 private void View_QueueSizeChangedEvent()
368 PreferencesFactory.get().setProperty("queue.maxtransfers", View.QueueSize);
369 QueueFactory.get().resize(PreferencesFactory.get().getInteger("queue.maxtransfers"));
372 private void View_BandwidthChangedEvent()
374 foreach (IProgressView progressView in View.SelectedTransfers)
376 Transfer transfer = GetTransferFromView(progressView);
377 transfer.setBandwidth(View.Bandwidth);
378 if (transfer.isRunning())
380 BackgroundActionRegistry registry = getActions();
381 // Find matching background task
382 for (int i = 0; i < registry.size(); i++)
384 if (registry.get(i) is TransferBackgroundAction)
386 TransferBackgroundAction t = (TransferBackgroundAction) registry.get(i);
387 if (t.getTransfer().Equals(transfer))
389 TransferSpeedometer meter = t.getMeter();
390 meter.reset();
396 UpdateBandwidthPopup();
399 private void View_SelectionChangedEvent()
401 Log.debug("SelectionChanged");
402 UpdateLabels();
403 UpdateIcon();
404 UpdateBandwidthPopup();
407 private void UpdateBandwidthPopup()
409 Log.debug("UpdateBandwidthPopup");
410 IList<IProgressView> selectedTransfers = View.SelectedTransfers;
411 View.BandwidthEnabled = selectedTransfers.Count > 0;
413 foreach (IProgressView progressView in View.SelectedTransfers)
415 Transfer transfer = GetTransferFromView(progressView);
416 if (transfer.getBandwidth().getRate() != BandwidthThrottle.UNLIMITED)
418 View.Bandwidth = transfer.getBandwidth().getRate();
420 else
422 View.Bandwidth = BandwidthThrottle.UNLIMITED;
424 return;
428 private void UpdateIcon()
430 IList<IProgressView> selectedTransfers = View.SelectedTransfers;
431 if (1 == selectedTransfers.Count)
433 Transfer transfer = GetTransferFromView(selectedTransfers[0]);
434 if (transfer.getRoots().size() == 1)
436 if (transfer.getLocal() != null)
438 View.FileIcon = IconCache.Instance.IconForFilename(transfer.getRoot().local.getAbsolute(),
439 IconCache.IconSize.Large);
441 else
443 View.FileIcon = IconCache.Instance.IconForPath(transfer.getRoot().remote,
444 IconCache.IconSize.Large);
447 else
449 View.FileIcon = ResourcesBundle.multiple.ToBitmap();
452 else
454 View.FileIcon = null;
458 private void UpdateLabels()
460 IList<IProgressView> selectedTransfers = View.SelectedTransfers;
461 if (1 == selectedTransfers.Count)
463 Transfer transfer = GetTransferFromView(selectedTransfers[0]);
464 View.Url = transfer.getRemote().getUrl();
465 //Workaround to prevent NullReferenceException
466 if (transfer.getLocal() != null)
468 View.Local = transfer.getLocal();
470 else
472 View.Local = string.Empty;
475 else
477 View.Url = string.Empty;
478 View.Local = string.Empty;
482 private void View_ShowEvent()
484 foreach (IProgressView progressView in View.SelectedTransfers)
486 Transfer transfer = GetTransferFromView(progressView);
487 for (int i = 0; i < transfer.getRoots().size(); i++)
489 TransferItem item = (TransferItem) transfer.getRoots().get(i);
490 RevealServiceFactory.get().reveal(item.local);
495 private void View_OpenEvent()
497 IList<IProgressView> selected = View.SelectedTransfers;
498 if (selected.Count == 1)
500 Transfer transfer = GetTransferFromView(selected[0]);
502 for (int i = 0; i < transfer.getRoots().size(); i++)
504 TransferItem item = (TransferItem) transfer.getRoots().get(i);
505 Local l = item.local;
506 if (ApplicationLauncherFactory.get().open(l))
508 break;
514 private void View_RemoveEvent()
516 foreach (IProgressView progressView in View.SelectedTransfers)
518 Transfer transfer = GetTransferFromView(progressView);
519 if (!transfer.isRunning())
521 TransferCollection.defaultCollection().remove(transfer);
524 TransferCollection.defaultCollection().save();
527 private void View_StopEvent()
529 foreach (IProgressView progressView in View.SelectedTransfers)
531 Transfer transfer = GetTransferFromView(progressView);
532 BackgroundActionRegistry registry = getActions();
533 if (transfer.isRunning())
535 // Find matching background task
536 for (int i = 0; i < registry.size(); i++)
538 if (registry.get(i) is TransferBackgroundAction)
540 TransferBackgroundAction t = (TransferBackgroundAction) registry.get(i);
541 if (t.getTransfer().Equals(transfer))
543 t.cancel();
551 private void View_ReloadEvent()
553 foreach (IProgressView progressView in View.SelectedTransfers)
555 Transfer transfer = GetTransferFromView(progressView);
556 if (!transfer.isRunning())
558 TransferOptions options = new TransferOptions();
559 options.resumeRequested = false;
560 options.reloadRequested = true;
561 StartTransfer(transfer, options);
566 private Transfer GetTransferFromView(IProgressView view)
568 foreach (KeyValuePair<Transfer, ProgressController> pair in _transferMap)
570 if (pair.Value.View == view) return pair.Key;
572 return null;
575 private void View_ResumeEvent()
577 foreach (IProgressView progressView in View.SelectedTransfers)
579 Transfer transfer = GetTransferFromView(progressView);
580 if (!transfer.isRunning())
582 TransferOptions options = new TransferOptions();
583 options.resumeRequested = true;
584 options.reloadRequested = false;
585 StartTransfer(transfer, options);
590 /// <summary>
591 ///
592 /// </summary>
593 /// <param name="transfer"></param>
594 public void StartTransfer(Transfer transfer)
596 StartTransfer(transfer, new TransferOptions());
599 public void StartTransfer(Transfer transfer, TransferOptions options)
601 StartTransfer(transfer, options, new NoopTransferCallback());
604 public void StartTransfer(Transfer transfer, TransferOptions options, TransferCallback callback)
606 if (!TransferCollection.defaultCollection().contains(transfer))
608 TransferCollection.defaultCollection().add(transfer);
610 ProgressController progressController;
611 _transferMap.TryGetValue(transfer, out progressController);
612 background(new TransferBackgroundAction(this, transfer, options, callback));
615 public void TaskbarOverlayIcon(Icon icon, string description)
617 Invoke(delegate { View.TaskbarOverlayIcon(icon, description); });
620 private class LogAction : WindowMainAction
622 private readonly string _msg;
623 private readonly bool _request;
625 public LogAction(TransferController c, bool request, string msg) : base(c)
627 _request = request;
628 _msg = msg;
631 public override void run()
633 ((TransferController) Controller).View.AddTranscriptEntry(_request, _msg);
637 private class NoopTransferCallback : TransferCallback
639 public void complete(Transfer t)
645 private class TransferBackgroundAction : TransferCollectionBackgroundAction
647 private readonly TransferCallback _callback;
648 private readonly TransferController _controller;
649 private readonly Transfer _transfer;
651 public TransferBackgroundAction(TransferController controller, Transfer transfer, TransferOptions options,
652 TransferCallback callback)
653 : base(
654 controller,
655 SessionFactory.create(transfer.getHost(),
656 new KeychainX509TrustManager(new DefaultTrustManagerHostnameCallback(transfer.getHost())),
657 new KeychainX509KeyManager()), controller.GetController(transfer),
658 controller.GetController(transfer), controller, transfer, options)
660 _transfer = transfer;
661 _callback = callback;
662 _controller = controller;
665 public override void init()
667 base.init();
668 if (PreferencesFactory.get().getBoolean("queue.window.open.transfer.start"))
670 _controller.View.Show();
671 _controller.View.BringToFront();
675 public override void finish()
677 base.finish();
678 if (_transfer.isComplete())
680 _callback.complete(_transfer);
684 public override void cleanup()
686 base.cleanup();
687 if (_transfer.isComplete() && _transfer.isReset())
689 if (PreferencesFactory.get().getBoolean("queue.window.open.transfer.stop"))
691 if (!(TransferCollection.defaultCollection().numberOfRunningTransfers() > 0))
693 _controller.View.Close();
700 private delegate bool TransferToolbarValidator(Transfer transfer);