Upstream tarball 20080603
[amule.git] / src / remote-gui.net / DownloadControl.cs
blobbffd4732068917fe6d336237dca5ba66298b3b8a
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2003-2008 lfroen ( lfroen@gmail.com / http://www.amule.org )
6 //
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
9 // respective authors.
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 using System;
27 using System.Collections.Generic;
28 using System.ComponentModel;
29 using System.Data;
30 using System.Drawing;
31 using System.Text;
32 using System.Windows.Forms;
33 using System.Configuration;
35 namespace amule.net {
37 [SettingsGroupNameAttribute("XferControl")]
38 public class amuleXferControlSettings : ApplicationSettingsBase {
39 [UserScopedSetting()]
40 [DefaultSettingValueAttribute("true")]
41 public bool FilenameVisible
43 get { return (bool)this["FilenameVisible"]; }
44 set { this["FilenameVisible"] = value; }
46 [UserScopedSetting()]
47 [DefaultSettingValueAttribute("200")]
48 public int FilenameWidth
50 get { return (int)this["FilenameWidth"]; }
51 set { this["FilenameWidth"] = value; }
54 [UserScopedSetting()]
55 [DefaultSettingValueAttribute("true")]
56 public bool StatusVisible
58 get { return (bool)this["StatusVisible"]; }
59 set { this["StatusVisible"] = value; }
61 [UserScopedSetting()]
62 [DefaultSettingValueAttribute("100")]
63 public int StatusWidth
65 get { return (int)this["StatusWidth"]; }
66 set { this["StatusWidth"] = value; }
69 [UserScopedSetting()]
70 [DefaultSettingValueAttribute("true")]
71 public bool SizeVisible
73 get { return (bool)this["SizeVisible"]; }
74 set { this["StatusVisible"] = value; }
76 [UserScopedSetting()]
77 [DefaultSettingValueAttribute("100")]
78 public int SizeWidth
80 get { return (int)this["SizeWidth"]; }
81 set { this["StatusWidth"] = value; }
84 [UserScopedSetting()]
85 [DefaultSettingValueAttribute("true")]
86 public bool SpeedVisible
88 get { return (bool)this["SpeedVisible"]; }
89 set { this["SpeedVisible"] = value; }
91 [UserScopedSetting()]
92 [DefaultSettingValueAttribute("100")]
93 public int SpeedWidth
95 get { return (int)this["SpeedWidth"]; }
96 set { this["SpeedWidth"] = value; }
99 [UserScopedSetting()]
100 [DefaultSettingValueAttribute("true")]
101 public bool CompletedVisible
103 get { return (bool)this["CompletedVisible"]; }
104 set { this["CompletedVisible"] = value; }
106 [UserScopedSetting()]
107 [DefaultSettingValueAttribute("100")]
108 public int CompletedWidth
110 get { return (int)this["CompletedWidth"]; }
111 set { this["CompletedWidth"] = value; }
114 [UserScopedSetting()]
115 [DefaultSettingValueAttribute("true")]
116 public bool SourcesVisible
118 get { return (bool)this["SourcesVisible"]; }
119 set { this["SourcesVisible"] = value; }
121 [UserScopedSetting()]
122 [DefaultSettingValueAttribute("100")]
123 public int SourcesWidth
125 get { return (int)this["SourcesWidth"]; }
126 set { this["SourcesWidth"] = value; }
130 public delegate void DownloadStatusListEventHandler();
132 public class amuleDownloadStatusList : amuleListView, IContainerUI {
133 DownloadQueueContainer m_item_container;
134 amuleXferControlSettings m_settings = new amuleXferControlSettings();
136 enum DOWNLOAD_CTRL_COL_ID {
137 COL_FILENAME_ID = 0,
138 COL_STATUS_ID,
139 COL_SIZE_ID,
140 COL_COMPLETED_ID,
141 COL_SPEED_ID,
142 COL_SOURCES_ID,
144 COL_LAST_ID,
147 private ContextMenuStrip m_ctx_menu = new ContextMenuStrip();
149 public event DownloadStatusListEventHandler OnCancelItem, OnPauseItem, OnResumeItem;
151 void UpdateColumnIndexes()
153 int i = 0;
154 m_column_index[(int)DOWNLOAD_CTRL_COL_ID.COL_FILENAME_ID] = i;
155 if ( m_settings.FilenameVisible ) i++;
156 m_column_index[(int)DOWNLOAD_CTRL_COL_ID.COL_STATUS_ID] = i;
157 if ( m_settings.StatusVisible ) i++;
158 m_column_index[(int)DOWNLOAD_CTRL_COL_ID.COL_SIZE_ID] = i;
159 if ( m_settings.SizeVisible ) i++;
160 m_column_index[(int)DOWNLOAD_CTRL_COL_ID.COL_COMPLETED_ID] = i;
161 if ( m_settings.CompletedVisible ) i++;
162 m_column_index[(int)DOWNLOAD_CTRL_COL_ID.COL_SPEED_ID] = i;
163 if ( m_settings.SpeedVisible ) i++;
164 m_column_index[(int)DOWNLOAD_CTRL_COL_ID.COL_SOURCES_ID] = i;
165 if ( m_settings.SourcesVisible ) i++;
168 void SaveSettigs()
170 if ( m_settings.FilenameVisible ) {
171 m_settings.FilenameWidth =
172 Columns[m_column_index[(int)DOWNLOAD_CTRL_COL_ID.COL_FILENAME_ID]].Width;
174 if ( m_settings.StatusVisible ) {
175 m_settings.StatusWidth =
176 Columns[(int)DOWNLOAD_CTRL_COL_ID.COL_STATUS_ID].Width;
178 m_settings.Save();
181 public amuleDownloadStatusList()
183 OwnerDraw = true;
185 DrawColumnHeader +=
186 new DrawListViewColumnHeaderEventHandler(amuleDownloadStatusList_DrawColumnHeader);
188 DrawSubItem += new DrawListViewSubItemEventHandler(amuleDownloadStatusList_DrawSubItem);
189 DownloadQueueItem.InitDraw3DModifiers(FontHeight + 1);
191 MouseClick += new MouseEventHandler(amuleDownloadStatusList_MouseClickHandler);
192 ColumnClick += new ColumnClickEventHandler(amuleDownloadStatusList_ColumtClickHandler);
194 m_ctx_menu.Opening += new System.ComponentModel.CancelEventHandler(cms_Opening);
195 m_ctx_menu.Items.Add(new ToolStripLabel("Downloads"));
196 m_ctx_menu.Items.Add(new ToolStripSeparator());
198 ToolStripButton it_pause = new ToolStripButton("Pause");
199 it_pause.Click += new EventHandler(it_pause_Click);
200 m_ctx_menu.Items.Add(it_pause);
201 ContextMenuStrip = m_ctx_menu;
203 ToolStripButton it_resume = new ToolStripButton("Resume");
204 it_resume.Click += new EventHandler(it_resume_Click);
205 m_ctx_menu.Items.Add(it_resume);
207 ToolStripButton it_cancel = new ToolStripButton("Cancel");
208 it_cancel.Click += new EventHandler(it_cancel_Click);
209 m_ctx_menu.Items.Add(it_cancel);
211 m_ctx_menu.Items.Add(new ToolStripSeparator());
213 // Init columns
215 m_column_index = new int[(int)DOWNLOAD_CTRL_COL_ID.COL_LAST_ID];
216 UpdateColumnIndexes();
217 // File name
218 if ( m_settings.FilenameVisible ) {
219 CreateColumtAt("File name", m_settings.FilenameWidth,
220 (int)DOWNLOAD_CTRL_COL_ID.COL_FILENAME_ID);
222 AppendItemToCtxMenu(m_ctx_menu, "File name", DOWNLOAD_CTRL_COL_ID.COL_FILENAME_ID,
223 m_settings.FilenameVisible, new EventHandler(column_Click));
224 // Status
225 if ( m_settings.StatusVisible ) {
226 CreateColumtAt("Status", m_settings.StatusWidth,
227 (int)DOWNLOAD_CTRL_COL_ID.COL_STATUS_ID);
229 AppendItemToCtxMenu(m_ctx_menu, "Status", DOWNLOAD_CTRL_COL_ID.COL_STATUS_ID,
230 m_settings.StatusVisible, new EventHandler(column_Click));
231 // Size
232 if ( m_settings.SizeVisible ) {
233 CreateColumtAt("Size", m_settings.SizeWidth,
234 (int)DOWNLOAD_CTRL_COL_ID.COL_SIZE_ID);
236 AppendItemToCtxMenu(m_ctx_menu, "Size", DOWNLOAD_CTRL_COL_ID.COL_SIZE_ID,
237 m_settings.SizeVisible, new EventHandler(column_Click));
238 // Completed size
239 if ( m_settings.CompletedVisible ) {
240 CreateColumtAt("Completed", m_settings.CompletedWidth,
241 (int)DOWNLOAD_CTRL_COL_ID.COL_COMPLETED_ID);
243 AppendItemToCtxMenu(m_ctx_menu, "Completed", DOWNLOAD_CTRL_COL_ID.COL_COMPLETED_ID,
244 m_settings.CompletedVisible, new EventHandler(column_Click));
245 // Speed
246 if ( m_settings.SpeedVisible ) {
247 CreateColumtAt("Speed", m_settings.SpeedWidth,
248 (int)DOWNLOAD_CTRL_COL_ID.COL_SPEED_ID);
250 AppendItemToCtxMenu(m_ctx_menu, "Speed", DOWNLOAD_CTRL_COL_ID.COL_SPEED_ID,
251 m_settings.SpeedVisible, new EventHandler(column_Click));
252 // Sources
253 if ( m_settings.SourcesVisible ) {
254 CreateColumtAt("Sources", m_settings.SourcesWidth,
255 m_column_index[(int)DOWNLOAD_CTRL_COL_ID.COL_SOURCES_ID]);
257 AppendItemToCtxMenu(m_ctx_menu, "Sources", DOWNLOAD_CTRL_COL_ID.COL_SOURCES_ID,
258 m_settings.SizeVisible, new EventHandler(column_Click));
260 ContextMenuStrip = m_ctx_menu;
264 // Click on column visibility checkbox in context menu
266 void column_Click(object sender, EventArgs e)
268 ToolStripMenuItem col = sender as ToolStripMenuItem;
269 DOWNLOAD_CTRL_COL_ID col_id = (DOWNLOAD_CTRL_COL_ID)col.Tag;
270 bool status = !col.Checked;
271 col.Checked = status;
272 if ( !status ) {
273 RemoveColumnAt((int)col_id);
275 switch ( col_id ) {
276 case DOWNLOAD_CTRL_COL_ID.COL_FILENAME_ID:
277 m_settings.FilenameVisible = status;
278 UpdateColumnIndexes();
279 if ( status ) {
280 CreateColumtAt("File name", m_settings.FilenameWidth, (int)col_id);
282 break;
283 case DOWNLOAD_CTRL_COL_ID.COL_STATUS_ID:
284 m_settings.StatusVisible = status;
285 UpdateColumnIndexes();
286 if ( status ) {
287 CreateColumtAt("Status", m_settings.StatusWidth, (int)col_id);
289 break;
290 case DOWNLOAD_CTRL_COL_ID.COL_SIZE_ID:
291 m_settings.SizeVisible = status;
292 UpdateColumnIndexes();
293 if ( status ) {
294 CreateColumtAt("Size", m_settings.SizeWidth, (int)col_id);
296 break;
297 case DOWNLOAD_CTRL_COL_ID.COL_COMPLETED_ID:
298 m_settings.CompletedVisible = status;
299 UpdateColumnIndexes();
300 if ( status ) {
301 CreateColumtAt("Completed", m_settings.CompletedWidth, (int)col_id);
303 break;
304 case DOWNLOAD_CTRL_COL_ID.COL_SPEED_ID:
305 m_settings.SpeedVisible = status;
306 UpdateColumnIndexes();
307 if ( status ) {
308 CreateColumtAt("Speed", m_settings.SpeedWidth, (int)col_id);
310 break;
311 case DOWNLOAD_CTRL_COL_ID.COL_SOURCES_ID:
312 m_settings.SourcesVisible = status;
313 UpdateColumnIndexes();
314 if ( status ) {
315 CreateColumtAt("Sources", m_settings.SourcesWidth, (int)col_id);
317 break;
318 default:
319 break;
321 Items.Clear();
322 foreach ( DownloadQueueItem i in m_item_container.Items ) {
323 DoInsertItem(i);
328 // "Cancel" command in context menu
330 void it_cancel_Click(object sender, EventArgs e)
332 OnCancelItem();
336 // "Resume" command in context menu
338 void it_resume_Click(object sender, EventArgs e)
340 OnResumeItem();
344 // "Pause" command in context menu
346 void it_pause_Click(object sender, EventArgs e)
348 OnPauseItem();
351 public void SelectedItemsToCommand(ecProto.ecPacket cmd)
353 foreach ( ListViewItem i in SelectedItems ) {
354 DownloadQueueItem it = i.Tag as DownloadQueueItem;
355 ecProto.ecTagMD5 tag = new ecProto.ecTagMD5(ECTagNames.EC_TAG_PARTFILE, it.ID);
356 cmd.AddSubtag(tag);
361 // Context menu - on opening. Can support dynamic menu creation
363 void cms_Opening(object sender, System.ComponentModel.CancelEventArgs e)
366 e.Cancel = false;
369 protected override void OnHandleDestroyed(EventArgs e)
371 SaveSettigs();
372 base.OnHandleDestroyed(e);
374 public DownloadQueueContainer ItemContainer
376 get { return m_item_container; }
379 m_item_container = value;
380 m_item_container.NewItemStatusLineLength = Columns[1].Width;
384 override protected void OnColumnWidthChanged(ColumnWidthChangedEventArgs e)
386 int status_index = m_column_index[(int)DOWNLOAD_CTRL_COL_ID.COL_STATUS_ID];
387 if ( (e.ColumnIndex == status_index) && m_settings.StatusVisible) {
388 int new_size = Columns[status_index].Width + 1;
389 m_item_container.NewItemStatusLineLength = new_size;
391 foreach ( ListViewItem i in Items ) {
392 DownloadQueueItem it = i.Tag as DownloadQueueItem;
393 it.AllocColorLine(new_size);
394 it.DrawLine();
399 void amuleDownloadStatusList_MouseClickHandler(object o, MouseEventArgs e)
401 if ( e.Button == MouseButtons.Right ) {
406 void amuleDownloadStatusList_ColumtClickHandler(object o, ColumnClickEventArgs e)
410 unsafe void DrawStatusBar(DownloadQueueItem it, Graphics g, Rectangle posR)
413 // Bitmap is created as 32bpp (rgb+alpha)
415 Bitmap status_bmp = new Bitmap(posR.Width, posR.Height,
416 System.Drawing.Imaging.PixelFormat.Format32bppArgb);
418 System.Drawing.Imaging.BitmapData bmd = status_bmp.LockBits(
419 new Rectangle(0, 0, status_bmp.Width, status_bmp.Height),
420 System.Drawing.Imaging.ImageLockMode.ReadWrite,
421 System.Drawing.Imaging.PixelFormat.Format32bppArgb);
423 RGB[] item_color_line = it.ColorLine;
424 byte[] modifiers = DownloadQueueItem.Get_3D_Modifiers();
426 for ( int y = 0; y < bmd.Height; y++ ) {
427 byte* row = (byte*)bmd.Scan0 + (y * bmd.Stride);
429 for ( int x = 0; x < bmd.Width; x++ ) {
430 UInt32* pixel_ptr = (UInt32*)(row + x * 4);
431 //row[x * 3 + 2] = 255;
432 //*pixel_ptr = 0xff0000; //RED
433 //*pixel_ptr = 0x00ff00; //GREEN
434 //*pixel_ptr = 0x1f0000ff; // BLUE
435 //*pixel_ptr = item_color_line[x] | (x << 24);
436 item_color_line[x].WriteToBuffWithModifier(pixel_ptr, modifiers[y]);
441 status_bmp.UnlockBits(bmd);
443 g.DrawImage(status_bmp, posR);
444 status_bmp.Dispose();
447 void amuleDownloadStatusList_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
449 if ( (e.ColumnIndex == m_column_index[(int)DOWNLOAD_CTRL_COL_ID.COL_STATUS_ID])
450 && m_settings.StatusVisible ) {
451 // status is colored bar
452 Rectangle r = e.Bounds;
453 DownloadQueueItem it = e.Item.Tag as DownloadQueueItem;
454 DrawStatusBar(it, e.Graphics, r);
455 e.DrawDefault = false;
457 else {
458 e.DrawBackground();
460 e.DrawText();
461 if ( e.Item.Selected ) {
462 e.DrawFocusRectangle(e.Bounds);
466 void amuleDownloadStatusList_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
468 e.DrawBackground();
469 e.DrawText();
473 // interface to core
475 void DoInsertItem(DownloadQueueItem i)
477 string first_col_txt;
478 if ( m_settings.FilenameVisible ) {
479 first_col_txt = i.Name;
480 } else if ( m_settings.StatusVisible ) {
481 first_col_txt = i.PercentDone;
482 } else if ( m_settings.SizeVisible ) {
483 first_col_txt = i.Size;
484 } else if ( m_settings.CompletedVisible ) {
485 first_col_txt = i.SizeDone;
486 } else if ( m_settings.SpeedVisible ) {
487 first_col_txt = i.Speed;
488 } else if ( m_settings.SourcesVisible ) {
489 first_col_txt = i.Sources;
490 } else {
491 first_col_txt = "all columns hidden";
494 ListViewItem it = new ListViewItem(first_col_txt);
496 if ( m_settings.StatusVisible ) {
497 it.SubItems.Add(new ListViewItem.ListViewSubItem(it, i.PercentDone));
499 if ( m_settings.SizeVisible ) {
500 it.SubItems.Add(new ListViewItem.ListViewSubItem(it, i.Size));
502 if ( m_settings.CompletedVisible ) {
503 it.SubItems.Add(new ListViewItem.ListViewSubItem(it, i.SizeDone));
505 if ( m_settings.SpeedVisible ) {
506 it.SubItems.Add(new ListViewItem.ListViewSubItem(it, i.Speed));
508 if ( m_settings.SourcesVisible ) {
509 it.SubItems.Add(new ListViewItem.ListViewSubItem(it, i.Sources));
512 if ( m_settings.StatusVisible ) {
513 it.SubItems[m_column_index[(int)DOWNLOAD_CTRL_COL_ID.COL_STATUS_ID]].ForeColor = Color.White;
514 Columns[(int)DOWNLOAD_CTRL_COL_ID.COL_STATUS_ID].TextAlign = HorizontalAlignment.Center;
517 it.Tag = i;
519 Items.Add(it);
521 i.UiItem = it;
524 void DoUpdateItem(DownloadQueueItem i)
526 ListViewItem it = i.UiItem as ListViewItem;
527 int idx = m_column_index[(int)DOWNLOAD_CTRL_COL_ID.COL_STATUS_ID];
528 if ( it.SubItems[idx].Text != i.PercentDone ) {
529 it.SubItems[idx].Text = i.PercentDone;
531 idx = (int)DOWNLOAD_CTRL_COL_ID.COL_COMPLETED_ID;
532 if ( it.SubItems[idx].Text != i.SizeDone ) {
533 it.SubItems[idx].Text = i.SizeDone;
535 idx = (int)DOWNLOAD_CTRL_COL_ID.COL_SPEED_ID;
536 if ( it.SubItems[idx].Text != i.Speed ) {
537 it.SubItems[idx].Text = i.Speed;
539 //Items
542 #region IContainerUI Members
544 delegate void UpdateCallback();
546 public void MyEndUpdate()
548 if ( InvokeRequired ) {
549 UpdateCallback d = new UpdateCallback(EndUpdate);
550 Invoke(d);
552 else {
553 EndUpdate();
557 public void MyBeginUpdate()
559 if ( InvokeRequired ) {
560 UpdateCallback d = new UpdateCallback(BeginUpdate);
561 Invoke(d);
563 else {
564 BeginUpdate();
568 delegate void ItemCallback(DownloadQueueItem i);
570 public void InsertItem(object i)
572 DownloadQueueItem it = i as DownloadQueueItem;
573 if ( InvokeRequired ) {
574 ItemCallback d = new ItemCallback(DoInsertItem);
575 Invoke(d, it);
577 else {
578 DoInsertItem(it);
582 public void UpdateItem(object i)
584 DownloadQueueItem it = i as DownloadQueueItem;
585 if ( InvokeRequired ) {
586 ItemCallback d = new ItemCallback(DoUpdateItem);
587 Invoke(d, it);
589 else {
590 DoUpdateItem(it);
594 #endregion