2 // Copyright (c) 2010-2014 Yves Langisch. All rights reserved.
3 // http://cyberduck.ch/
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.
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.
15 // Bug fixes, suggestions and comments should be sent to:
20 using System
.Collections
.Generic
;
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
;
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
);
59 public override bool Singleton
64 public static TransferController Instance
68 if (_instance
== null)
72 if (_instance
== null)
73 _instance
= new TransferController();
80 public void collectionLoaded()
84 public void collectionItemAdded(object obj
)
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
);
97 public void collectionItemRemoved(object obj
)
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
)
151 for (int i
= 0; i
< _instance
.getActions().size(); i
++)
153 ((BackgroundAction
) _instance
.getActions().get(i
)).cancel();
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())
255 private bool View_ValidateOpenEvent()
257 return ValidateToolbarItem(delegate(Transfer transfer
)
259 if (transfer
.getLocal() != null)
261 if (!transfer
.isComplete())
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())
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
);
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()));
321 /// Validates the selected items in the transfer window against the toolbar validator
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
))
338 private bool View_ValidateResumeEvent()
340 return ValidateToolbarItem(delegate(Transfer transfer
)
342 if (transfer
.isRunning())
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();
396 UpdateBandwidthPopup();
399 private void View_SelectionChangedEvent()
401 Log
.debug("SelectionChanged");
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();
422 View
.Bandwidth
= BandwidthThrottle
.UNLIMITED
;
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
);
443 View
.FileIcon
= IconCache
.Instance
.IconForPath(transfer
.getRoot().remote
,
444 IconCache
.IconSize
.Large
);
449 View
.FileIcon
= ResourcesBundle
.multiple
.ToBitmap();
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();
472 View
.Local
= string.Empty
;
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
))
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
))
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
;
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
);
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
)
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
)
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()
668 if (PreferencesFactory
.get().getBoolean("queue.window.open.transfer.start"))
670 _controller
.View
.Show();
671 _controller
.View
.BringToFront();
675 public override void finish()
678 if (_transfer
.isComplete())
680 _callback
.complete(_transfer
);
684 public override void 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
);