DownloadPage.cs :  » Business-Application » DC » DCSharp » GUI » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Business Application » DC 
DC » DCSharp » GUI » DownloadPage.cs
/*
 * Copyright (C) 2006-2007 Eskil Bylund
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

using System;
using System.Collections.Generic;

using Gtk;
using Glade;
using Mono.Unix;

using DCSharp.Backend.Connections;
using DCSharp.Backend.Objects;
using DCSharp.Backend.Managers;

namespace DCSharp.GUI{
  public class DownloadPage : Page
  {
    private DownloadManager downloadManager;
    
    private DownloadStore downloadStore;
    private TreePath virtualRoot;
    
    private DownloadView directoryView;
    private DownloadView downloadView;
    private bool handleSelectionChanged;
    private bool showSources;
    
    private VisibleColumnsWindow columnsWindow;
    
    private List<DownloadFileInfo> addQueue;
    private List<DownloadFileInfo> activeDownloads;
    
    private uint timeout;
    private uint updateId;
    
    [Widget]
    private HPaned hpaned;
    
    [Widget]
    private ScrolledWindow scrolledWindow;
    
    [Widget]
    private ScrolledWindow scrolledWindowTree;
    
    [Widget]
    private HBox actionBox;
    
    [Widget]
    private CheckButton directoryTreeCheckButton;
    
    [Widget]
    private CheckButton sourcesCheckButton;
    
    [Widget]
    private Button cancelButton;
    
    [Widget]
    private Button clearButton;
    
    #region Constructors
    
    public DownloadPage(ConnectionManager connectionManager,
      DownloadManager downloadManager) : base("DownloadPage.glade")
    {
      if (connectionManager == null)
      {
        throw new ArgumentNullException("connectionManager");
      }
      if (downloadManager == null)
      {
        throw new ArgumentNullException("downloadManager");
      }
      this.downloadManager = downloadManager;
      
      activeDownloads = new List<DownloadFileInfo>();
      addQueue = new List<DownloadFileInfo>();
      
      handleSelectionChanged = true;
      
      // User interface
      ActionEntry[] entries = new ActionEntry[] {
        new ActionEntry("VisibleColumns", null, Catalog.GetString("_Visible Columns..."), null,
          Catalog.GetString("Edit visible columns"),
          OnVisibleColumns),
      };
      
      actionGroup = new ActionGroup("DownloadPageActions");
      actionGroup.Add(entries);
      
      // Model
      downloadStore = new DownloadStore();
      
      // Directory tree
      TreeModelFilter filterModel = new TreeModelFilter(downloadStore, null);
      filterModel.VisibleFunc = DirectoryVisibleFunc;
      
      TreeModelSort sortModel = new TreeModelSort(filterModel);
      sortModel.SetSortColumnId((int)DownloadStore.Column.Name,
        SortType.Ascending);
      
      directoryView = new DownloadView(connectionManager, downloadManager,
        sortModel);
      directoryView.KeyPressEvent += OnDirectoryKeyPressEvent;
      directoryView.Selection.Mode = SelectionMode.Single;
      directoryView.Selection.Changed += OnDirectorySelectionChanged;
      directoryView.SetSizeRequest(140, 0);
      directoryView.HeadersVisible = false;
      directoryView.Show();
      
      scrolledWindowTree.Add(directoryView);
      
      // Hide all but the first column
      for (int i = 1; i < directoryView.Columns.Length; i++)
      {
        TreeViewColumn column = directoryView.Columns[i];
        column.Visible = false;
      }
      
      // Directory tree remove action
      Action removeAction = new Action("Remove", null, null, Stock.Remove);
      removeAction.Activated += OnDirectoryRemoveSelected;
      ActionGroup viewActions = new ActionGroup("DownloadPageDirectoryViewActions");
      viewActions.Add(removeAction);
      
      directoryView.Uim.InsertActionGroup(viewActions, 0);
      
      // Download view
      downloadView = new DownloadView(connectionManager, downloadManager);
      downloadView.KeyPressEvent += OnKeyPressEvent;
      downloadView.RowActivated += OnRowActivated;
      downloadView.RowExpanded += OnRowExpanded;
      downloadView.Selection.Changed += OnSelectionChanged;
      downloadView.Show();
      
      scrolledWindow.Add(downloadView);
      
      UpdateDownloadViewModel(null);
      
      // Download view remove action
      removeAction = new Action("Remove", null, null, Stock.Remove);
      removeAction.Activated += OnRemoveSelected;
      viewActions = new ActionGroup("DownloadPageViewActions");
      viewActions.Add(removeAction);
      
      downloadView.Uim.InsertActionGroup(viewActions, 0);
      
      // Events
      directoryTreeCheckButton.Toggled += OnDirectoryTreeCheckButtonToggled;
      sourcesCheckButton.Toggled += OnSourcesCheckButtonToggled;
      cancelButton.Clicked += OnCancelButtonClicked;
      clearButton.Clicked += OnClearButtonClicked;
      
      // Initialize
      lock (downloadManager.SyncRoot)
      {
        foreach (DownloadFileInfo download in downloadManager)
        {
          if (!download.IsFileList)
          {
            IdleAdd(download);
          }
        }
        downloadManager.DownloadAdded += OnDownloadAdded;
        downloadManager.DownloadRemoved += OnDownloadRemoved;
      }
    }
    
    #endregion
    
    #region Properties
    
    public override string Title
    {
      get { return Catalog.GetString("Downloads"); }
    }
    
    public override Gdk.Pixbuf Icon
    {
      get { return RenderIcon(Stock.GoDown, IconSize.Menu, null); }
    }
    
    public override string Tooltip
    {
      get
      {
        if (IsWorking)
        {
          return Catalog.GetString("Loading downloads...");
        }
        
        int downloading = 0;
        foreach (DownloadFileInfo download in downloadManager)
        {
          if (download.Active)
          {
            downloading++;
          }
        }
        int remaining = downloadManager.Count - downloading;
        
        string tooltip = String.Format(Catalog.GetPluralString(
          "{0} file downloading", "{0} files downloading", downloading),
          downloading);
        
        tooltip += ". ";
        tooltip += String.Format(Catalog.GetPluralString(
          "{0} file waiting", "{0} files waiting", remaining),
          remaining);
        
        return String.Format(tooltip, downloadManager.Count);
      }
    }
    
    public override string Status
    {
      get { return Tooltip; }
    }
    
    public override ActionGroup Actions
    {
      get { return actionGroup; }
    }
    private ActionGroup actionGroup;
    
    public int PanePosition
    {
      get { return hpaned.Position; }
      set { hpaned.Position = value; }
    }
    
    public bool DirectoryTreeVisible
    {
      get { return directoryTreeCheckButton.Active; }
      set { directoryTreeCheckButton.Active = value; }
    }
    
    public bool SourcesVisible
    {
      get { return sourcesCheckButton.Active; }
      set { sourcesCheckButton.Active = value; }
    }
    
    public int VisibleColumns
    {
      get { return Util.GetVisibleColumns(downloadView.Columns); }
      set { Util.SetVisibleColumns(downloadView.Columns, value | 1); }
    }
    
    #endregion
    
    #region Methods
    
    public override void Dispose()
    {
      downloadManager.DownloadAdded -= OnDownloadAdded;
      downloadManager.DownloadRemoved -= OnDownloadRemoved;
      
      if (timeout != 0)
      {
        GLib.Source.Remove(timeout);
        timeout = 0;
      }
      if (updateId != 0)
      {
        GLib.Source.Remove(updateId);
        updateId = 0;
      }
      
      if (columnsWindow != null)
      {
        columnsWindow.Destroy();
        columnsWindow = null;
      }
      base.Dispose();
    }
    
    protected override bool OnKeyPressEvent(Gdk.EventKey evnt)
    {
      if (evnt.Key == Gdk.Key.BackSpace)
      {
        TreeIter iter;
        if (scrolledWindowTree.Visible && directoryView.Selection.GetSelected(out iter))
        {
          if (directoryView.Model.IterParent(out iter, iter))
          {
            TreePath path = directoryView.Model.GetPath(iter);
            
            directoryView.Selection.SelectPath(path);
            directoryView.ScrollToCell(path, null, false, 0f, 0f);
          }
          else
          {
            directoryView.Selection.UnselectAll();
          }
          return true;
        }
      }
      return base.OnKeyPressEvent(evnt);
    }
    
    private void Add(DownloadFileInfo download)
    {
      downloadStore.Add(download);
      
      download.ActiveChanged += OnActiveChanged;
      download.SourceAdded += OnSourceAdded;
      download.SourceRemoved += OnSourceRemoved;
      
      TreeIter iter = downloadStore.GetIter(download);
      TreeIter parent;
      if (downloadStore.IterParent(out parent, iter))
      {
        bool loaded = (bool)downloadStore.GetValue(parent, (int)DownloadStore.Column.Loaded);
        if (loaded)
        {
          // Add the sources
          foreach (SourceInfo source in download.SourceInfos)
          {
            downloadStore.AppendValues(iter, source, source.Nick);
          }
          downloadStore.SetValue(iter, (int)DownloadStore.Column.Loaded, true);
        }
      }
      
      if (download.Active)
      {
        activeDownloads.Add(download);
        if (timeout == 0)
        {
          timeout = GLib.Timeout.Add(1000, OnRefreshTimeout);
        }
      }
    }
    
    private void Remove(DownloadFileInfo download)
    {
      activeDownloads.Remove(download);
      
      download.ActiveChanged -= OnActiveChanged;
      download.SourceAdded -= OnSourceAdded;
      download.SourceRemoved -= OnSourceRemoved;
      
      downloadStore.Remove(download);
    }
    
    private void Remove(IList<DownloadFileInfo> downloads)
    {
      // Get the selected path
      TreeIter iter;
      TreePath selectedPath = null;
      if (directoryView.Selection.GetSelected(out iter))
      {
        selectedPath = directoryView.Model.GetPath(iter);
      }
      
      handleSelectionChanged = false;
      
      // Remove downloads
      foreach (DownloadFileInfo download in downloads)
      {
        Remove(download);
      }
      
      handleSelectionChanged = true;
      
      // Select the next or parent directory
      if (selectedPath != null &&
        !directoryView.Selection.PathIsSelected(selectedPath))
      {
        SelectPathOrParent(directoryView, selectedPath);
      }
      
      UpdateSensitivity();
    }
    
    private void IdleAdd(DownloadFileInfo download)
    {
      lock (addQueue)
      {
        addQueue.Add(download);
        if (addQueue.Count == 1)
        {
          GLib.Idle.Add(AddDownloadsInQueue);
        }
      }
    }
    
    private bool AddDownloadsInQueue()
    {
      IsWorking = true;
      actionBox.Sensitive = false;
      
      long ticks = DateTime.Now.Ticks;
      
      while (addQueue.Count > 0)
      {
        DownloadFileInfo download;
        lock (addQueue)
        {
          if (addQueue.Count == 0)
          {
            break;
          }
          download = addQueue[0];
          addQueue.Remove(download);
        }
        
        Add(download);
        
        // Are we blocking the GUI?
        if ((DateTime.Now.Ticks - ticks) >= 500000)
        {
          return true;
        }
      }
      
      IsWorking = false;
      actionBox.Sensitive = true;
      return false;
    }
    
    private void UpdateDownloadViewModel(TreePath virtualRoot)
    {
      this.virtualRoot = virtualRoot;
      
      SortType order = SortType.Ascending;
      int sortColumnId = (int)DownloadStore.Column.Name;
      
      TreeModelFilter filterModel;
      TreeModelSort sortModel = (TreeModelSort)downloadView.Model;
      
      if (sortModel != null)
      {
        sortModel.GetSortColumnId(out sortColumnId, out order);
        filterModel = (TreeModelFilter)sortModel.Model;
        
        sortModel.Dispose();
        filterModel.Dispose();
      }
      
      // Create the new models
      filterModel = new TreeModelFilter(downloadStore, virtualRoot);
      filterModel.VisibleFunc = DownloadVisibleFunc;
      
      sortModel = new TreeModelSort(filterModel);
      sortModel.SetSortFunc((int)DownloadStore.Column.Name, SortFunc);
      sortModel.SetSortColumnId(sortColumnId, order);
      
      downloadView.Model = sortModel;
      
      UpdateClearButtonSensitivity();
    }
    
    private void UpdateSensitivity()
    {
      UpdateCancelButtonSensitivity();
      UpdateClearButtonSensitivity();
    }
    
    private void UpdateCancelButtonSensitivity()
    {
      DownloadFileInfo[] downloads = downloadView.GetSelectedDownloads(true);
      foreach (DownloadFileInfo download in downloads)
      {
        if (downloadManager.Contains(download))
        {
          cancelButton.Sensitive = true;
          return;
        }
      }
      cancelButton.Sensitive = false;
    }
    
    private void UpdateClearButtonSensitivity()
    {
      clearButton.Sensitive = false;
      
      downloadView.Model.Foreach(delegate(TreeModel model,
        TreePath path, TreeIter i)
      {
        DownloadFileInfo download = model.GetValue(i,
          (int)DownloadStore.Column.Object) as DownloadFileInfo;
        
        if (download != null && !downloadManager.Contains(download))
        {
          clearButton.Sensitive = true;
          return true;
        }
        return false;
      });
    }
    
    private void LoadSourcesInDir(TreeStore store, TreeIter dirIter)
    {
      TreeIter iter;
      if (!store.IterChildren(out iter, dirIter))
      {
        return;
      }
      
      bool loaded = (bool)store.GetValue(dirIter, (int)DownloadStore.Column.Loaded);
      if (loaded)
      {
        return;
      }
      
      do
      {
        DownloadFileInfo download = store.GetValue(iter,
          (int)DownloadStore.Column.Object) as DownloadFileInfo;
        if (download != null)
        {
          loaded = (bool)store.GetValue(iter, (int)DownloadStore.Column.Loaded);
          if (!loaded)
          {
            // Add the sources
            foreach (SourceInfo source in download.SourceInfos)
            {
              store.AppendValues(iter, source, source.Nick);
            }
            store.SetValue(iter, (int)DownloadStore.Column.Loaded, true);
          }
        }
      }
      while (store.IterNext(ref iter));
      
      store.SetValue(dirIter, (int)DownloadStore.Column.Loaded, true);
    }
    
    private void HandleRemoveRecursive(TreeModel model, params TreeIter[] iters)
    {
      if (iters.Length == 0)
      {
        return;
      }
      
      List<DownloadFileInfo> aborted = new List<DownloadFileInfo>();
      
      Queue<TreeIter> queue = new Queue<TreeIter>();
      foreach (TreeIter i in iters)
      {
        queue.Enqueue(i);
      }
      
      // Iterate through the iters and remove all downloads and sources
      TreeIter iter, childIter, parent;
      do
      {
        iter = queue.Dequeue();
        object o = model.GetValue(iter, (int)DownloadStore.Column.Object);
        
        DownloadFileInfo download = o as DownloadFileInfo;
        SourceInfo source = o as SourceInfo;
        
        if (download != null)
        {
          if (!aborted.Contains(download))
          {
            downloadManager.Remove(download);
            aborted.Add(download);
          }
        }
        else if (source != null)
        {
          if (model.IterParent(out parent, iter))
          {  
            download = (DownloadFileInfo)model.GetValue(parent,
              (int)DownloadStore.Column.Object);
            
            download.Remove(source);
          }
        }
        else if (model.IterChildren(out childIter, iter))
        {
          do
          {
            queue.Enqueue(childIter);
          }
          while (model.IterNext(ref childIter));
        }
      }
      while (queue.Count > 0);
      
      // Remove aborted downloads from the model
      if (aborted.Count > 0)
      {
        Remove(aborted);
      }
    }
    
    private void OnVisibleColumns(object obj, EventArgs args)
    {
      if (columnsWindow == null)
      {
        columnsWindow = new VisibleColumnsWindow(downloadView.Columns,
          Toplevel as Window, downloadView.Columns[0]);
        
        columnsWindow.Window.Destroyed += delegate
        {
          columnsWindow = null;
        };
      }
      columnsWindow.Show();
    }
    
    private void OnDirectoryRemoveSelected(object obj, EventArgs args)
    {
      TreeIter iter;
      if (directoryView.Selection.GetSelected(out iter))
      {
        TreeModelSort sortModel = (TreeModelSort)directoryView.Model;
        TreeModelFilter filterModel = (TreeModelFilter)sortModel.Model;
        
        // Get the downloadStore iter
        iter = sortModel.ConvertIterToChildIter(iter);
        iter = filterModel.ConvertIterToChildIter(iter);
        
        HandleRemoveRecursive(downloadStore, iter);
      }
    }
    
    private void OnRemoveSelected(object obj, EventArgs args)
    {
      HandleRemoveRecursive(downloadView.Model, downloadView.GetSelectedIters());
    }
    
    private void OnDirectoryKeyPressEvent(object obj, KeyPressEventArgs args)
    {
      if (args.Event.Key == Gdk.Key.Delete)
      {
        OnDirectoryRemoveSelected(obj, EventArgs.Empty);
      }
    }
    
    private void OnDirectorySelectionChanged(object obj, EventArgs args)
    {
      if (!handleSelectionChanged)
      {
        return;
      }
      
      TreePath virtualRoot = null;
      
      TreeIter iter;
      if (directoryView.Selection.GetSelected(out iter))
      {
        TreeModelSort sortModel = (TreeModelSort)directoryView.Model;
        TreeModelFilter filterModel = (TreeModelFilter)sortModel.Model;
        
        // Get the downloadStore iter
        iter = sortModel.ConvertIterToChildIter(iter);
        iter = filterModel.ConvertIterToChildIter(iter);
        
        LoadSourcesInDir(downloadStore, iter);
        
        virtualRoot = downloadStore.GetPath(iter);
      }
      
      UpdateDownloadViewModel(virtualRoot);
    }
    
    private void OnKeyPressEvent(object obj, KeyPressEventArgs args)
    {
      if (args.Event.Key == Gdk.Key.Delete)
      {
        OnRemoveSelected(obj, EventArgs.Empty);
      }
    }
    
    private void OnRowActivated(object obj, RowActivatedArgs args)
    {
      TreeModelSort sortModel = (TreeModelSort)downloadView.Model;
      TreeModelFilter filterModel = (TreeModelFilter)sortModel.Model;
      
      if (!scrolledWindowTree.Visible)
      {
        return;
      }
      
      // Get the path for the downloadStore. The path is null if the
      // virtual root has changed.
      TreePath path = sortModel.ConvertPathToChildPath(args.Path);
      if (path != null)
      {
        path = filterModel.ConvertPathToChildPath(path);
        
        sortModel = (TreeModelSort)directoryView.Model;
        filterModel = (TreeModelFilter)sortModel.Model;
        
        // Get the path for directoryView model. The path is null if
        // it's not a directory.
        path = filterModel.ConvertChildPathToPath(path);
        if (path != null)
        {
          path = sortModel.ConvertChildPathToPath(path);
          
          directoryView.ExpandToPath(path);
          directoryView.Selection.SelectPath(path);
          directoryView.ScrollToCell(path, null, false, 0f, 0f);
        }
      }
    }
    
    private void OnRowExpanded(object obj, RowExpandedArgs args)
    {
      TreeModelSort sortModel = (TreeModelSort)downloadView.Model;
      TreeModelFilter filterModel = (TreeModelFilter)sortModel.Model;
      
      TreePath path = sortModel.ConvertPathToChildPath(args.Path);
      path = filterModel.ConvertPathToChildPath(path);
      
      TreeIter iter;
      if (downloadStore.GetIter(out iter, path))
      {
        LoadSourcesInDir(downloadStore, iter);
      }
    }
    
    private void OnSelectionChanged(object obj, EventArgs args)
    {
      if (!handleSelectionChanged)
      {
        return;
      }
      UpdateCancelButtonSensitivity();
    }
    
    private void OnDirectoryTreeCheckButtonToggled(object obj, EventArgs args)
    {
      bool visible = directoryTreeCheckButton.Active;
      
      scrolledWindowTree.Visible = visible;
      if (!visible)
      {
        directoryView.Selection.UnselectAll();
      }
    }
    
    private void OnSourcesCheckButtonToggled(object obj, EventArgs args)
    {
      TreeModelSort sortModel = (TreeModelSort)downloadView.Model;
      TreeModelFilter filterModel = (TreeModelFilter)sortModel.Model;
      
      showSources = sourcesCheckButton.Active;
      filterModel.Refilter();
    }
    
    private void OnCancelButtonClicked(object obj, EventArgs args)
    {
      DownloadFileInfo[] downloads = downloadView.GetSelectedDownloads(true);
      foreach (DownloadFileInfo download in downloads)
      {
        downloadManager.Remove(download);
      }
    }
    
    private void OnClearButtonClicked(object obj, EventArgs args)
    {
      List<DownloadFileInfo> aborted = new List<DownloadFileInfo>();
      
      downloadView.Model.Foreach(delegate(TreeModel model,
        TreePath path, TreeIter i)
      {
        DownloadFileInfo download = model.GetValue(i,
          (int)DownloadStore.Column.Object) as DownloadFileInfo;
        
        if (download != null && !downloadManager.Contains(download))
        {
          aborted.Add(download);
        }
        return false;
      });
      
      Remove(aborted);
    }
    
    private void SelectPathOrParent(TreeView treeView, TreePath path)
    {
      do
      {
        TreeIter iter;
        if (treeView.Model.GetIter(out iter, path))
        {
          treeView.Selection.SelectPath(path);
          return;
        }
      }
      while (path.Up() && path.Depth > 0);
      
      treeView.Selection.SelectPath(TreePath.NewFirst());
    }
    
    private void OnDownloadAdded(object obj, DownloadEventArgs args)
    {
      if (!args.Download.IsFileList)
      {
        IdleAdd(args.Download);
      }
    }
    
    private void OnDownloadRemoved(object obj, DownloadEventArgs args)
    {
      DownloadFileInfo download = args.Download;
      if (download.IsFileList)
      {
        return;
      }
      
      if (updateId != 0)
      {
        return;
      }
      updateId = GLib.Idle.Add(delegate
      {
        // A redraw is enough since we use CellDataFuncs to render the state.
        QueueDraw();
        
        OnPageChanged();
        UpdateSensitivity();
        
        updateId = 0;
        return false;
      });
    }
    
    private void OnActiveChanged(object obj, EventArgs args)
    {
      DownloadFileInfo download = (DownloadFileInfo)obj;
      if (download.IsFileList)
      {
        return;
      }
      
      Application.Invoke(delegate
      {
        QueueDraw();
        
        downloadStore.UpdateDownload(download);
        UpdateDirectories();
        
        if (download.Active)
        {
          if (!activeDownloads.Contains(download))
          {
            activeDownloads.Add(download);
            if (timeout == 0)
            {
              timeout = GLib.Timeout.Add(1000, OnRefreshTimeout);
            }
          }
        }
        else
        {
          activeDownloads.Remove(download);
        }
      });
    }
    
    private void OnSourceAdded(object obj, SourceEventArgs args)
    {
      DownloadFileInfo download = (DownloadFileInfo)obj;
      SourceInfo source = args.Source;
      
      Application.Invoke(delegate
      {
        if (!downloadStore.Contains(download))
        {
          return;
        }
        
        TreeIter iter = downloadStore.GetIter(download);
        
        bool loaded = (bool)downloadStore.GetValue(iter, (int)DownloadStore.Column.Loaded);
        if (loaded)
        {
          // Add the source
          downloadStore.AppendValues(iter, source, source.Nick);
          downloadStore.UpdateDownload(download);
          
          OnPageChanged();
        }
      });
    }
    
    private void OnSourceRemoved(object obj, SourceEventArgs args)
    {
      DownloadFileInfo download = (DownloadFileInfo)obj;
      SourceInfo source = args.Source;
      
      Application.Invoke(delegate
      {
        // The download might have been removed since this code is
        // run in an idle handler. Eg. when selecting a download and
        // its sources and pressing delete.
        if (!downloadStore.Contains(download))
        {
          return;
        }
        
        TreeIter iter = downloadStore.GetIter(download);
        TreeIter sourceIter;
        
        // Ignore selection changes when removing a source. 
        handleSelectionChanged = false;
        
        // Find and remove the source
        if (downloadStore.IterChildren(out sourceIter, iter))
        {
          do
          {
            SourceInfo tsource = downloadStore.GetValue(
              sourceIter, (int)DownloadStore.Column.Object) as SourceInfo;
            if (tsource == source)
            {
              downloadStore.Remove(ref sourceIter);
              break;
            }
          }
          while (downloadStore.IterNext(ref sourceIter)); 
        }
        
        handleSelectionChanged = true;
        
        downloadStore.UpdateDownload(download);
        OnPageChanged();
      });
    }
    
    private bool DirectoryVisibleFunc(TreeModel model, TreeIter iter)
    {
      // NOTE: This does NOT work. TreeModelFilter does not seem to like
      // hidden parents (the downloads) and visible children (the sources).
      //
      //DownloadFileInfo download = model.GetValue(iter,
      //  (int)DownloadStore.Column.Object) as DownloadFileInfo;
      //
      //return download == null;
      
      // obj is null only when the row is a directory
      object obj = model.GetValue(iter, (int)DownloadStore.Column.Object);
      return obj == null;
    }
    
    private bool DownloadVisibleFunc(TreeModel model, TreeIter iter)
    {
      SourceInfo source = model.GetValue(iter,
        (int)DownloadStore.Column.Object) as SourceInfo;
      
      if (source != null)
      {
        return showSources;
      }
      return true;
    }
    
    private int SortFunc(TreeModel model, TreeIter tia, TreeIter tib)
    {
      object obja = model.GetValue(tia, (int)DownloadStore.Column.Object);
      object objb = model.GetValue(tib, (int)DownloadStore.Column.Object);
      
      if (obja == null && objb is DownloadFileInfo)
      {
        return -1;
      }
      if (obja is DownloadFileInfo && objb == null)
      {
        return 1;
      }
      
      string namea = model.GetValue(tia, (int)DownloadStore.Column.Name) as string;
      string nameb = model.GetValue(tib, (int)DownloadStore.Column.Name) as string;
      
      return String.Compare(namea, nameb);
    }
    
    #region DownloadStore Updating
    
    private bool OnRefreshTimeout()
    {
      if (activeDownloads.Count > 0)
      {
        Update();
        return true;
      }
      timeout = 0;
      return false;
    }
    
    private void Update()
    {
      foreach (DownloadFileInfo download in activeDownloads)
      {
        // Only update the downloads below the root
        if (virtualRoot != null)
        {
          TreeIter iter = downloadStore.GetIter(download);
          TreePath path = downloadStore.GetPath(iter);
          
          if (path.IsDescendant(virtualRoot))
          {
            downloadStore.UpdateDownload(download);
          }
        }
        else
        {
          downloadStore.UpdateDownload(download);
        }
      }
      
      // Update all the directories
      UpdateDirectories();
    }
    
    private void UpdateDirectories()
    {
      TreeIter iter;
      if (downloadStore.GetIterFirst(out iter))
      {
        do
        {
          UpdateDirectory(iter);
        }
        while (downloadStore.IterNext(ref iter));
      }
    }
    
    private void UpdateDirectory(TreeIter iter)
    {
      TreeIter childIter;
      if (downloadStore.IterChildren(out childIter, iter))
      {
        do
        {
          UpdateDirectory(childIter);
        }
        while (downloadStore.IterNext(ref childIter));
        
        downloadStore.UpdateDirectory(iter);
      }
    }
    
    #endregion
    
    #endregion
  }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.