using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Data;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using JGBaseForm;
using Win32API;
namespace JGFSControls
{
class JListViewFS : System.Windows.Forms.ListView
{
const int WM_DRAWITEM = 0x002B;
const int WM_MEASUREITEM = 0x002C;
const int WM_INITMENUPOPUP = 0x0117;
const int WM_MENUCHAR = 0x0120;
const int WM_VSCROLL = 0x115;
private bool m_Editing = false;
private bool m_RefreshNeeded = false;
// Drag and Drop
private bool m_Dragging = false;
private bool m_DragCancelled = false;
// Drag and Drop ContextMenu
private ContextMenu m_ctxLVDragDrop;
private DragEventArgs m_DragEventArgs = null;
private FileSystemWatcher m_FSWatcher = null;
// File Extensions
internal System.Collections.Hashtable m_htExtensions = new System.Collections.Hashtable();
internal System.Collections.Hashtable m_htUserExtensions = new System.Collections.Hashtable();
private IContextMenu3 m_IContextMenu3 = null;
private ImageList m_SmallImageList;
private ImageList m_LargeImageList;
private int m_SortColumn = 0;
private int m_WatchInterval = 3000;
private JTagData m_CurrentTagData = null;
private JTagData m_PreviousTagData = null;
private ListViewItem m_lviDrop = null;
private long m_TotalObjectSize = 0;
private SortOrder m_SortOrder = SortOrder.Ascending;
private string m_FileExtension = "*.*";
private Timer timRefresh = new Timer();
private View m_View = View.Details;
private enum ColumnModes
{
None,
DriveMode,
NormalMode
}
private ColumnModes m_ColumnMode = ColumnModes.None;
// Events
internal event FileSelectedEventHandler FileSelected;
protected virtual void OnFileSelected(object sender, JTagData tagData)
{
FileSelectedEventHandler handler = FileSelected;
if (handler != null)
handler(sender, tagData);
}
private void RaiseFileSelectedEvent(object sender, JTagData tagData)
{
OnFileSelected(sender, tagData);
}
internal delegate void ListViewFilledEventHandler(object sender, System.Collections.Hashtable htExtensions);
internal event ListViewFilledEventHandler ListViewFilled;
protected virtual void OnListViewFilled(object sender, System.Collections.Hashtable htExtensions)
{
ListViewFilledEventHandler handler = ListViewFilled;
if (handler != null)
handler(sender, htExtensions);
}
private void RaiseListViewFilledEvent(object sender, System.Collections.Hashtable htExtensions)
{
OnListViewFilled(this, htExtensions);
}
internal delegate void ViewUpdatedEventHandler(object sender, string driveStatusString, string objectStatusString, string selectedObjectStatusString);
internal event ViewUpdatedEventHandler ViewUpdated;
protected virtual void OnViewUpdated(object sender, string driveStatusString, string objectStatusString, string selectedObjectStatusString)
{
ViewUpdatedEventHandler handler = ViewUpdated;
if (handler != null)
handler(this, DriveStatusString, ObjectStatusString, SelectedObjectStatusString);
}
internal void RaiseViewUpdatedEvent()
{
OnViewUpdated(this, DriveStatusString, ObjectStatusString, SelectedObjectStatusString);
}
internal void RaiseViewUpdatedEvent(object sender, string driveStatusString, string objectStatusString, string selectedObjectStatusString)
{
OnViewUpdated(sender, DriveStatusString, ObjectStatusString, SelectedObjectStatusString);
}
internal event CommandKeyEventHandler CommandKeyPressed;
protected virtual void OnCommandKeyPressed(object sender, KeyEventArgs e)
{
CommandKeyEventHandler handler = CommandKeyPressed;
if (handler != null)
handler(sender, e);
}
internal void RaiseCommandKeyPressedEvent(object sender, KeyEventArgs e)
{
OnCommandKeyPressed(sender, e);
}
internal event EventHandler<JMessageArgs> MessageRaised;
protected virtual void OnMessageRaised(object sender, JMessageArgs e)
{
EventHandler<JMessageArgs> handler = MessageRaised;
if (handler != null)
handler(sender, e);
}
internal void RaiseMessageEvent(object sender, string message, bool beep)
{
JMessageArgs e = new JMessageArgs(message, beep);
OnMessageRaised(sender, e);
}
internal event ListViewItemSelectedEventHandler ListViewItemSelected;
protected virtual void OnListViewItemSelected(object sender, ListViewItem e)
{
ListViewItemSelectedEventHandler handler = ListViewItemSelected;
if (handler != null)
handler(sender, e);
}
internal void RaiseListViewItemSelectedEvent(ListViewItem e)
{
OnListViewItemSelected(this, e);
}
public event PathChangedEventHandler PathChanged;
protected virtual void OnPathChanged(object sender, JTagData tagData)
{
PathChangedEventHandler handler = PathChanged;
if (handler != null)
handler(sender, tagData);
}
private void RaisePathChangedEvent(object sender, JTagData tagData)
{
OnPathChanged(sender, tagData);
}
internal event EventHandler<EventArgs> RefreshNeeded;
protected virtual void OnRefreshNeeded(object sender, EventArgs e)
{
EventHandler<EventArgs> handler = RefreshNeeded;
if (handler != null)
handler(sender, e);
}
internal void RaiseRefreshNeededEvent()
{
OnRefreshNeeded(this, null);
}
internal event EventHandler<EventArgs> TimerRefreshNeeded;
protected virtual void OnTimerRefreshNeeded(object sender, EventArgs e)
{
EventHandler<EventArgs> handler = TimerRefreshNeeded;
if (handler != null)
handler(sender, e);
}
internal void RaiseTimerRefreshNeededEvent()
{
OnTimerRefreshNeeded(this, null);
}
public JListViewFS()
: base()
{
ControlInitialise();
}
private void ControlInitialise()
{
this.SetStyle(ControlStyles.DoubleBuffer, true);
this.AllowDrop = true;
this.FullRowSelect = true;
this.HideSelection = false;
this.LabelEdit = true;
base.View = View.Details;
this.m_SmallImageList = new ImageList();
m_SmallImageList.ImageSize = new Size(16, 16);
m_SmallImageList.ColorDepth = ColorDepth.Depth32Bit;
this.m_LargeImageList = new ImageList();
m_LargeImageList.ImageSize = new Size(32, 32);
m_LargeImageList.ColorDepth = ColorDepth.Depth32Bit;
CreateDragDropMenus();
// Set up Timer
timRefresh.Tick += new EventHandler(timRefresh_Tick);
}
private void AddDrives()
{
ListViewItem lvItem;
List<JTagData> listDrives = JDriveData.DriveTagDataList;
List<ListViewItem> listItems = new List<ListViewItem>();
foreach (JTagData current in listDrives)
{
lvItem = CreateLVItem(current);
listItems.Add(lvItem);
}
AddRange(listItems);
}
private void AddFiles(DirectoryInfo diTop)
{
ListViewItem lvItem;
// Put ALL the extensions in the filter menu
SetupFileExtensionsHashtable(diTop);
RaiseListViewFilledEvent(this, m_htExtensions);
// Just show files meeting the require spec
List<JTagData> listFiles = JCommon.GetFiles(diTop, m_FileExtension);
List<ListViewItem> listItems = new List<ListViewItem>();
foreach (JTagData current in listFiles)
{
lvItem = CreateLVItem(current);
m_TotalObjectSize += current.Size;
listItems.Add(lvItem);
}
AddRange(listItems);
}
private void AddFolders(DirectoryInfo diTop)
{
ListViewItem lvItem;
List<JTagData> listFolders = JCommon.GetFolders(diTop);
List<ListViewItem> listItems = new List<ListViewItem>();
foreach (JTagData current in listFolders)
{
lvItem = CreateLVItem(current);
listItems.Add(lvItem);
}
AddRange(listItems);
}
internal void AddRange(List<ListViewItem> listItems)
{
this.Items.AddRange(listItems.ToArray());
AddThumbsToImageList();
SetView();
}
internal void AddThumbsToImageList()
{
int index = 0;
JTagData tagData;
this.m_SmallImageList.Images.Clear();
this.m_LargeImageList.Images.Clear();
foreach (ListViewItem current in this.Items)
{
tagData = (JTagData)current.Tag;
if (tagData.ThumbImage != null)
{
this.m_SmallImageList.Images.Add(tagData.ThumbImage);
this.m_LargeImageList.Images.Add(tagData.ThumbImage);
}
tagData.ThumbImageIndex = index++;
}
}
private bool CopyOrMoveDroppedFiles(FileOps foAction, out bool refresh)
{
bool result = true;
DirectoryInfo diPath;
JTagData tagData;
JShortcuts.ShortCutTypes shortcutType = JShortcuts.ShortCutTypes.NONE;
string destinationDirectory = "";
refresh = true;
if (m_DragEventArgs != null)
{
if (m_lviDrop != null)
{
tagData = (JTagData)m_lviDrop.Tag;
if (tagData.ObjectType == JTagData.ObjectTypes.FOLDER)
destinationDirectory = tagData.Path;
else if (tagData.ObjectType == JTagData.ObjectTypes.LNK)
{
destinationDirectory = JShortcuts.ReadShortcut(tagData.Path, out shortcutType);
if (shortcutType != JShortcuts.ShortCutTypes.FOLDER)
return false;
else
refresh = false;
}
else if (tagData.ObjectType >= JTagData.ObjectTypes.FILE)
{
if (this.CurrentPath != "")
destinationDirectory = this.CurrentPath;
else
return false;
}
}
else if (this.CurrentPath != "")
destinationDirectory = this.CurrentPath;
else
return false;
try
{
diPath = new DirectoryInfo(destinationDirectory);
if (diPath.Exists)
{
destinationDirectory = diPath.FullName;
if (foAction == FileOps.FO_JSHORTCUT)
result = JShortcuts.CreateShortcuts(m_DragEventArgs, destinationDirectory);
else
result = JFSFunctions.DropFiles(this.Handle, m_DragEventArgs, foAction, destinationDirectory);
}
}
catch
{
result = false;
}
}
return result;
}
private void CreateDragDropMenus()
{
MenuItem[] menuArray = {new MenuItem("Copy", new EventHandler(ctxLVDropCopy_Click)),
new MenuItem("Move", new EventHandler(ctxLVDropMove_Click)),
new MenuItem("Create Shortcut", new EventHandler(ctxLVCreateShortcut_Click)),
new MenuItem("Cancel", new EventHandler(ctxLVCancelAction_Click))
};
m_ctxLVDragDrop = new ContextMenu(menuArray);
}
internal bool CreateFolder()
{
return DoCreateFolder(this.CurrentPath);
}
internal bool CreateFolder(string parentPath)
{
return DoCreateFolder(parentPath);
}
private ListViewItem CreateLVItem(JTagData tagData)
{
ListViewItem lvItem;
lvItem = new ListViewItem(tagData.DisplayName, tagData.ImageIndex);
lvItem.SubItems.Add(tagData.TypeName);
if (tagData.ObjectType == JTagData.ObjectTypes.DRIVE)
{
if (tagData.TotalSize > 0)
{
lvItem.SubItems.Add(JCommon.FormatSize(tagData.TotalSize, JCommon.JGSizes.GB, true));
lvItem.SubItems.Add(JCommon.FormatSize(tagData.AvailableFreeSpace, JCommon.JGSizes.GB, true));
}
}
else if (tagData.ObjectType == JTagData.ObjectTypes.FOLDER)
{
lvItem.SubItems.Add("");
lvItem.SubItems.Add(GetDisplayDate(tagData.LastWriteTime));
}
else if (tagData.ObjectType == JTagData.ObjectTypes.FILE)
{
lvItem.SubItems.Add(JCommon.FormatSize(tagData.Size, JCommon.JGSizes.KB, true));
lvItem.SubItems.Add(GetDisplayDate(tagData.LastWriteTime));
}
lvItem.Tag = tagData;
return lvItem;
}
private void ctxLVCancelAction_Click(object sender, System.EventArgs e)
{
m_DragEventArgs = null;
}
private void ctxLVCreateShortcut_Click(object sender, System.EventArgs e)
{
bool refreshView = false;
if (CopyOrMoveDroppedFiles(FileOps.FO_JSHORTCUT, out refreshView))
{
if (refreshView)
RaiseRefreshNeededEvent();
}
}
private void ctxLVDropCopy_Click(object sender, System.EventArgs e)
{
bool refreshView = false;
if (CopyOrMoveDroppedFiles(FileOps.FO_COPY, out refreshView))
{
if (refreshView)
RaiseRefreshNeededEvent();
}
}
private void ctxLVDropMove_Click(object sender, System.EventArgs e)
{
bool refreshView = false;
if (CopyOrMoveDroppedFiles(FileOps.FO_MOVE, out refreshView))
{
if (refreshView)
RaiseRefreshNeededEvent();
}
}
internal bool DeleteSelectedObjects()
{
bool result = DoDeleteSelectedObjects();
if (result)
RefreshView(false);
return result;
}
private bool DoCreateFolder(string parentPath)
{
string errString = "";
JGInputBox.FormInputBox frmNewFolder = new JGInputBox.FormInputBox("Create New Folder", "Enter name of folder to create in " + parentPath, "");
if (frmNewFolder.ShowDialog() != DialogResult.OK)
{
errString = "Action Cancelled";
return false;
}
string newFolderName = frmNewFolder.Result;
bool result = JCommon.CreateFolder(parentPath, newFolderName, out errString);
if (!result)
{
RaiseMessageEvent(this, errString, true);
return false;
}
else
{
RaiseRefreshNeededEvent();
return true;
}
}
private bool DoDeleteSelectedObjects()
{
bool result = false;
if (m_Editing)
return false;
List<string> listSelectedObjectsPaths = GetSelectedObjectsPaths();
if (listSelectedObjectsPaths == null || listSelectedObjectsPaths.Count < 1)
{
RaiseMessageEvent(this, "No marked objects to delete", true);
return false;
}
string szFileList = JFSFunctions.CreateSZFileList(listSelectedObjectsPaths);
if (JFSFunctions.SendToRecycler(this.Handle, szFileList))
{
RaiseRefreshNeededEvent();
result = true;
}
else
{
RaiseMessageEvent(this, "Unable to Delete Items", true);
RaiseRefreshNeededEvent();
result = false;
}
return result;
}
private void DoEditItem()
{
// Only handle if 1 item selected
ListViewItem lvItem = GetSelectedItem();
if (lvItem == null)
{
RaiseMessageEvent(this, "Please Select One Object To Edit", true);
return;
}
m_Editing = true;
lvItem.BeginEdit();
}
private void DoInvertSelection()
{
foreach (ListViewItem current in this.Items)
current.Selected = !current.Selected;
RaiseViewUpdatedEvent();
}
private void DoItemActivate()
{
// Only deal with activate if 1 item selected
JTagData tagData;
string errString = "";
ListViewItem lvItem = GetSelectedItem();
if (lvItem == null)
{
errString = "Please Select An Object";
RaiseMessageEvent(this, errString, true);
return;
}
tagData = (JTagData)lvItem.Tag;
string objectPath = tagData.Path;
if (objectPath == "")
{
errString = "Please Select One Object";
RaiseMessageEvent(this, errString, true);
return;
}
// Need to distinguish between files, links and folders
// Sort the links out HERE
switch (tagData.ObjectType)
{
case JTagData.ObjectTypes.FILE:
case JTagData.ObjectTypes.SCF:
case JTagData.ObjectTypes.URL:
if (!JCommon.StartProcess(objectPath, Path.GetDirectoryName(objectPath).ToString(), out errString))
RaiseMessageEvent(this, errString, true);
break;
case JTagData.ObjectTypes.LNK:
// May be a shortcut to a file or a folder
if (tagData.LinkType == JShortcuts.ShortCutTypes.FOLDER)
{
JTagData tagDataNew = new JTagData(new DirectoryInfo(tagData.LinkPath));
SetCurrentTagData(tagDataNew, true, true);
}
else if (tagData.LinkType == JShortcuts.ShortCutTypes.FILE)
{
if (!JCommon.StartProcess(objectPath, Path.GetDirectoryName(objectPath).ToString(), out errString))
RaiseMessageEvent(this, errString, true);
}
break;
default:
SetCurrentTagData(tagData, true, true);
break;
}
}
private void DoKeyOrMouseUp(bool mouseUp, MouseEventArgs e)
{
// Sets selected object status and shows Context Menu if RMB
// If we are doing drag and drop we don't want context menu to pop up
// Pressing escape sends a mouse up message?
RaiseViewUpdatedEvent();
if (m_DragCancelled)
{
m_DragCancelled = false;
return;
}
if (m_Dragging)
{
m_Dragging = false;
return;
}
if (!mouseUp)
return;
JTagData tagData = null;
ListViewItem lvItem = SelectedItem;
if (lvItem != null)
{
RaiseListViewItemSelectedEvent(lvItem);
tagData = (JTagData)lvItem.Tag;
RaiseFileSelectedEvent(this, tagData);
}
if (e.Button != MouseButtons.Right)
return;
// May have clicked in blank part of LV
if (tagData == null)
tagData = this.m_CurrentTagData;
// OK it's the RMB - we need the Context Menu
Point pt = new Point(e.X, e.Y);
pt = this.PointToScreen(pt);
ShowContextMenu(tagData, pt);
}
private void DoRefreshView(bool reselectItems)
{
List<string> listItems = new List<string>();
if (reselectItems)
listItems = GetSelectedItemsNames();
SetCurrentTagData(m_CurrentTagData, false, false);
if(reselectItems)
{
foreach(string current in listItems)
{
SelectItemByName(current, false);
}
}
}
private void DoSelectAll()
{
foreach (ListViewItem current in this.Items)
current.Selected = true;
RaiseViewUpdatedEvent();
}
private void DoSelectItemByName(string itemName, bool ensureVisible)
{
foreach (ListViewItem current in this.Items)
if (current.Text == itemName)
{
current.Selected = true;
if (ensureVisible)
current.EnsureVisible();
break;
}
RaiseViewUpdatedEvent();
}
private void DoUnSelectAll()
{
foreach (ListViewItem current in this.Items)
current.Selected = false;
RaiseViewUpdatedEvent();
}
internal void EditItem()
{
DoEditItem();
}
private void FileWatcher_Changed(object sender, System.IO.FileSystemEventArgs e)
{
// Trying to refresh from here will cause mayhem, several messages can be sent for each change
// and if we're moving several hundred files the results can be quite interesting
// Set a flag and leave the timer to manage to avoid cross thread issues
m_RefreshNeeded = true;
}
private void FillListView(JTagData tagData)
{
this.Items.Clear();
if (tagData == null)
return;
string newPath = tagData.Path;
if (string.IsNullOrEmpty(newPath))
return;
string currentPath = "";
if (tagData.ObjectType == JTagData.ObjectTypes.COMPUTER)
{
SetColumnsToDriveMode();
AddDrives();
}
else
{
SetColumnsToNormalMode();
// Do this in case it's a link
currentPath = GetCurrentPath();
m_TotalObjectSize = 0L;
string fileSpec = m_FileExtension;
this.BeginUpdate();
// Stop the timer and fsWatcher
StopFileWatcher();
try
{
DirectoryInfo diTop = new DirectoryInfo(currentPath);
if (diTop.Exists)
{
// Folders - all in one
AddFolders(diTop);
// Files - all in one
AddFiles(diTop);
}
}
catch (Exception ex)
{
RaiseMessageEvent(this, ex.ToString(), true);
}
SortListView(0, false);
}
SetIcons();
if (!string.IsNullOrEmpty(currentPath))
{
// Restart timer if required
StartFileWatcher();
}
this.EndUpdate();
RaiseViewUpdatedEvent();
}
private List<string> GetAllFileNames()
{
if (this.Items.Count < 1)
return null;
JTagData tagData;
List<string> listAllFileNames = new List<string>();
foreach (ListViewItem current in this.Items)
{
tagData = (JTagData)current.Tag;
if (tagData.ObjectType >= JTagData.ObjectTypes.FILE)
listAllFileNames.Add(current.Text);
}
return listAllFileNames;
}
private List<string> GetAllFilePaths()
{
if (this.Items.Count < 1)
return null;
JTagData tagData;
List<string> listAllFilePaths = new List<string>();
foreach (ListViewItem current in this.Items)
{
tagData = (JTagData)current.Tag;
if (tagData.ObjectType >= JTagData.ObjectTypes.FILE)
listAllFilePaths.Add(tagData.Path);
}
return listAllFilePaths;
}
private bool GetCanDropHere(ListViewItem lvItem)
{
// In the ListView we can drop in the LV itself or on an LV Item
if (lvItem == null)
return this.DirectoryIsValid;
JTagData tagData = (JTagData)lvItem.Tag;
// May be hovering over a file if space is tight
if (tagData.ObjectType >= JTagData.ObjectTypes.FILE)
return this.DirectoryIsValid;
return tagData.CanDropOnObject;
}
private string GetCurrentPath()
{
string currentPath = "";
if (m_CurrentTagData != null)
{
currentPath = m_CurrentTagData.Path;
if (m_CurrentTagData.ObjectType > JTagData.ObjectTypes.FILE)
currentPath = m_CurrentTagData.LinkPath;
}
return currentPath;
}
private string GetDisplayDate(DateTime daTime)
{
return daTime.ToShortDateString() + " " + daTime.ToShortTimeString();
}
private string GetDriveStatusString()
{
long diskTotalFreeSpace = 0, diskTotalSize = 0;
string statusString = "", driveLetter = "", result = "";
if (m_CurrentTagData.ObjectType == JTagData.ObjectTypes.COMPUTER)
{
return SystemInformation.ComputerName;
}
else
{
try
{
DriveInfo drInfo = new DriveInfo(this.CurrentPath);
diskTotalSize = drInfo.TotalSize;
diskTotalFreeSpace = drInfo.TotalFreeSpace;
statusString = JCommon.FormatSize(diskTotalFreeSpace, JCommon.JGSizes.GB, true) + " free " + " (" + JCommon.FormatSize(diskTotalSize, JCommon.JGSizes.GB, true) + " total)";
driveLetter = drInfo.RootDirectory.ToString();
driveLetter = driveLetter.Replace("\\", "");
result = driveLetter + " " + statusString;
}
catch
{
result = "";
}
}
return result;
}
private int GetFileCount()
{
int fileCount = 0;
JTagData tagData;
foreach (ListViewItem current in this.Items)
{
tagData = (JTagData)current.Tag;
if (tagData.ObjectType >= JTagData.ObjectTypes.FILE)
fileCount++;
}
return fileCount;
}
private string GetObjectStatusString()
{
int numObjects = this.Items.Count;
string result = "";
if (numObjects == 1)
result = "Total " + numObjects.ToString() + " object";
else
result = "Total " + numObjects.ToString() + " objects";
if (m_CurrentTagData.ObjectType != JTagData.ObjectTypes.COMPUTER)
{
// Use a sensible format for sizes
if (m_TotalObjectSize > 1024 * 1024 * 1024)
result += " (" + JCommon.FormatSize(m_TotalObjectSize, JCommon.JGSizes.GB, true) + ")";
else if (m_TotalObjectSize > 1024 * 1024)
result += " (" + JCommon.FormatSize(m_TotalObjectSize, JCommon.JGSizes.MB, true) + ")";
else if (m_TotalObjectSize > 0)
result += " (" + JCommon.FormatSize(m_TotalObjectSize, JCommon.JGSizes.KB, true) + ")";
}
return result;
}
private int GetSelectedFileCount()
{
int selectedFileCount = 0;
JTagData tagData;
foreach (ListViewItem current in this.SelectedItems)
{
tagData = (JTagData)current.Tag;
if (tagData.ObjectType >= JTagData.ObjectTypes.FILE)
selectedFileCount++;
}
return selectedFileCount;
}
private string GetSelectedFilePath()
{
ListViewItem lvItem = GetSelectedItem();
if (lvItem == null)
return "";
JTagData tagData = (JTagData)lvItem.Tag;
if (tagData.ObjectType != JTagData.ObjectTypes.FILE)
return "";
return tagData.Path;
}
private List<string> GetSelectedFilePaths()
{
if (this.SelectedItems.Count < 0)
return null;
JTagData tagData;
List<string> listSelectedFilePaths = new List<string>();
foreach (ListViewItem current in this.SelectedItems)
{
tagData = (JTagData)current.Tag;
if (tagData.ObjectType >= JTagData.ObjectTypes.FILE)
listSelectedFilePaths.Add(tagData.Path);
}
return listSelectedFilePaths;
}
private int GetSelectedFolderCount()
{
int selectedFolderCount = 0;
JTagData tagData;
foreach (ListViewItem current in this.SelectedItems)
{
tagData = (JTagData)current.Tag;
if (tagData.ObjectType == JTagData.ObjectTypes.FOLDER)
selectedFolderCount++;
}
return selectedFolderCount;
}
private List<string> GetSelectedFolderPaths()
{
if (this.SelectedItems.Count < 0)
return null;
JTagData tagData;
List<string> listSelectedFolderPaths = new List<string>();
foreach (ListViewItem current in this.SelectedItems)
{
tagData = (JTagData)current.Tag;
if (tagData.ObjectType == JTagData.ObjectTypes.FOLDER)
listSelectedFolderPaths.Add(tagData.Path);
}
return listSelectedFolderPaths;
}
private ListViewItem GetSelectedItem()
{
if (this.SelectedItems.Count != 1)
return null;
return this.SelectedItems[0];
}
private string GetSelectedItemName()
{
ListViewItem lvItem = GetSelectedItem();
if (lvItem == null)
return "";
else
return lvItem.Text;
}
private List<string> GetSelectedItemsNames()
{
List<string> listNames = new List<string>();
foreach (ListViewItem current in this.SelectedItems)
listNames.Add(current.Text);
return listNames;
}
private string GetSelectedItemPath()
{
JTagData tagData = GetSelectedItemTagData();
if (tagData == null)
return "";
return tagData.Path;
}
private JTagData GetSelectedItemTagData()
{
ListViewItem lvItem = GetSelectedItem();
if (lvItem == null)
return null;
else
{
JTagData tagData = (JTagData)lvItem.Tag;
return tagData;
}
}
private int GetSelectedObjectsCount()
{
return this.SelectedItems.Count;
}
private List<string> GetSelectedObjectsPaths()
{
List<string> listResult = new List<string>();
List<string> listFolders = GetSelectedFolderPaths();
List<string> listFiles = GetSelectedFilePaths();
if (listFolders != null)
{
listResult.AddRange(listFolders);
}
if (listFiles != null)
{
listResult.AddRange(listFiles);
}
return listResult;
}
private string GetSelectedObjectStatusString()
{
int numObjects = this.SelectedItems.Count;
string result = "";
if (numObjects == 1)
result = numObjects.ToString() + " object selected ";
else
result = numObjects.ToString() + " objects selected ";
long totalSize = GetSelectedObjectsTotalSize();
// Use a sensible format for sizes
if (totalSize > 1024 * 1024 * 1024)
result += " (" + JCommon.FormatSize(totalSize, JCommon.JGSizes.GB, true) + ")";
else if (totalSize > 1024 * 1024)
result += " (" + JCommon.FormatSize(totalSize, JCommon.JGSizes.MB, true) + ")";
else if (totalSize > 0)
result += " (" + JCommon.FormatSize(totalSize, JCommon.JGSizes.KB, true) + ")";
return result;
}
private long GetSelectedObjectsTotalSize()
{
JTagData tagData;
long totalSize = 0;
foreach (ListViewItem current in this.SelectedItems)
{
tagData = (JTagData)current.Tag;
totalSize += tagData.Size;
}
return totalSize;
}
internal void InvertSelection()
{
DoInvertSelection();
}
private bool IsThumbView(View viewMode)
{
bool thumbs = false;
switch (viewMode)
{
case View.LargeIcon:
case View.SmallIcon:
case View.Tile:
thumbs = true;
break;
}
return thumbs;
}
protected override void OnAfterLabelEdit(LabelEditEventArgs e)
{
base.OnAfterLabelEdit(e);
m_Editing = false;
bool renameOK = false;
JTagData tagData;
string errString = "";
if (e.Label == "" || e.Label == null || e.Label == string.Empty)
{
e.CancelEdit = true;
RaiseMessageEvent(this, "Name Cannot Be Blank", true);
return;
}
if (this.CurrentPath == "")
{
RaiseMessageEvent(this, "Unable to Rename This Object", true);
e.CancelEdit = true;
return;
}
ListViewItem lvItem = GetSelectedItem();
tagData = (JTagData)lvItem.Tag;
e.CancelEdit = true;
if (tagData.ObjectType == JTagData.ObjectTypes.FOLDER)
{
renameOK = JCommon.RenameFolder(tagData.Path, e.Label, out errString);
}
else if (tagData.ObjectType >= JTagData.ObjectTypes.FILE)
{
renameOK = JCommon.RenameFile(tagData.Path, e.Label, out errString);
}
if (renameOK)
{
RefreshView(true);
SelectItemByName(e.Label, true);
this.Focus();
}
else
{
RaiseMessageEvent(this, errString, true);
}
}
protected override void OnColumnClick(ColumnClickEventArgs e)
{
base.OnColumnClick(e);
SortListView(e.Column, true);
}
protected override void OnDragDrop(DragEventArgs drgevent)
{
base.OnDragDrop(drgevent);
// May be Dropping in the current Folder or contained folder or a Link
m_DragEventArgs = drgevent;
Point pos = this.PointToClient(MousePosition);
m_ctxLVDragDrop.Show(this, pos);
}
protected override void OnDragEnter(DragEventArgs drgevent)
{
base.OnDragEnter(drgevent);
if (drgevent.Data.GetDataPresent(DataFormats.FileDrop) || drgevent.Data.GetDataPresent(DataFormats.Text))
drgevent.Effect = DragDropEffects.Move | DragDropEffects.Copy | DragDropEffects.Link;
else
drgevent.Effect = DragDropEffects.None;
// Make sure we don't drop if Folder is not valid
if (!this.DirectoryIsValid)
drgevent.Effect = DragDropEffects.None;
}
protected override void OnDragLeave(EventArgs e)
{
base.OnDragLeave(e);
if (m_lviDrop != null)
m_lviDrop.Selected = false;
m_lviDrop = null;
}
protected override void OnDragOver(DragEventArgs drgevent)
{
base.OnDragOver(drgevent);
ListViewItem lvItemOver = null;
Point pt = this.PointToClient(new Point(drgevent.X, drgevent.Y));
// Make sure we are within the ListView's boundary
if ((pt.Y > 0) && (pt.Y < this.ClientSize.Height) && (pt.X > 0) && (pt.X < this.ClientSize.Width))
{
lvItemOver = (ListViewItem)this.GetItemAt(pt.X, pt.Y);
// Make sure the item is valid
if (lvItemOver != null)
{
if (!GetCanDropHere(lvItemOver))
{
drgevent.Effect = DragDropEffects.None;
}
else
{
drgevent.Effect = DragDropEffects.Move | DragDropEffects.Copy | DragDropEffects.Link;
}
// Remove previous colouring
if (m_lviDrop != null)
m_lviDrop.Selected = false;
// If we can drop here then colour the item we are over
if (drgevent.Effect != DragDropEffects.None)
lvItemOver.Selected = true;
// Save the drop item
m_lviDrop = lvItemOver;
}
else // Not over a ListViewItem so drop in to LV Itself
{
// Remove previous colouring
if (m_lviDrop != null)
m_lviDrop.Selected = false;
// Set drop item to null
m_lviDrop = null;
// Check if we can drop in LV
if (this.DirectoryIsValid)
{
drgevent.Effect = DragDropEffects.Move | DragDropEffects.Copy | DragDropEffects.Link;
}
else
{
drgevent.Effect = DragDropEffects.None;
}
}
// Scrolling
if (lvItemOver != null)
{
Rectangle tRect = lvItemOver.GetBounds(ItemBoundsPortion.ItemOnly);
int numItems = this.Items.Count;
int numDisplayed = (this.Height / tRect.Height) - 1;
if (numItems > numDisplayed)
{
int index = lvItemOver.Index;
if (index < (numDisplayed / 2))
{
if (index > 1)
this.Items[index - 1].EnsureVisible();
else
this.Items[0].EnsureVisible();
}
else
{
if (index < numItems + 1)
this.Items[index + 1].EnsureVisible();
else
this.Items[numItems - 2].EnsureVisible();
}
}
}
}
}
protected override void OnHandleCreated(EventArgs e)
{
// Need a handle to set the image list
base.OnHandleCreated(e);
SetImageList(false);
}
protected override void OnItemActivate(EventArgs e)
{
base.OnItemActivate(e);
DoItemActivate();
}
protected override void OnItemDrag(ItemDragEventArgs e)
{
base.OnItemDrag(e);
List<string> listDragPaths = GetSelectedObjectsPaths();
if (listDragPaths == null || listDragPaths.Count < 1)
{
RaiseMessageEvent(this, "Cannot drag this item", true);
return;
}
Rectangle rectTemp = this.GetItemRect(this.SelectedItems[0].Index);
Point pt = new Point(rectTemp.Left, rectTemp.Top);
pt = this.PointToScreen(pt);
POINT apipt;
apipt.x = pt.X;
apipt.y = pt.Y;
// Stop the context menu from showing
m_Dragging = true;
DataObject doDrag = JDropFiles.CopyFilesToClipboardForDragDrop(listDragPaths, apipt);
if (doDrag != null)
this.DoDragDrop(doDrag, DragDropEffects.Copy | DragDropEffects.Move | DragDropEffects.Link);
else
RaiseMessageEvent(this, "Unable to copy to ClipBoard", true);
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (e.KeyCode == Keys.Enter)
{
DoItemActivate();
}
else
{
RaiseCommandKeyPressedEvent(this, e);
}
}
protected override void OnKeyUp(KeyEventArgs e)
{
base.OnKeyUp(e);
DoKeyOrMouseUp(false, null);
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
DoKeyOrMouseUp(true, e);
}
protected override void OnQueryContinueDrag(QueryContinueDragEventArgs qcdevent)
{
base.OnQueryContinueDrag(qcdevent);
if (qcdevent.EscapePressed)
m_DragCancelled = true;
}
internal void RefreshView(bool reselectItems)
{
DoRefreshView(reselectItems);
}
internal string RootFolder
{
get
{
if (m_CurrentTagData != null)
{
string path = m_CurrentTagData.Path;
string drive = Path.GetPathRoot(path);
return drive;
}
return "";
}
}
internal void SelectAll()
{
DoSelectAll();
}
internal List<string> SelectedObjectsPaths()
{
return GetSelectedObjectsPaths();
}
internal void SelectItemByName(string name, bool ensureVisible)
{
DoSelectItemByName(name, ensureVisible);
}
private void SetCurrentTagData(JTagData tagData, bool savePrevious, bool raiseEvent)
{
// Need to check for Access Denied
bool accessDenied = false;
if (tagData.ObjectType != JTagData.ObjectTypes.COMPUTER)
{
JUserFileAccessRights acRights = new JUserFileAccessRights(tagData.Path);
if (acRights.ToString() == "None")
{
this.Items.Clear();
RaiseMessageEvent(this, "Access Denied", true);
accessDenied = true;
}
}
if (savePrevious)
this.m_PreviousTagData = this.m_CurrentTagData;
this.m_CurrentTagData = tagData;
if (!accessDenied)
FillListView(tagData);
if (raiseEvent)
RaisePathChangedEvent(this, tagData);
}
private void SetFileFilter(string newFilter)
{
m_FileExtension = newFilter;
RefreshView(false);
}
private void SetFileWatch()
{
DirectoryInfo dInfo;
NotifyFilters nf = new NotifyFilters();
nf = NotifyFilters.Attributes | NotifyFilters.CreationTime | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.LastAccess | NotifyFilters.Size;
if (m_FSWatcher != null)
m_FSWatcher.Dispose();
if (this.CurrentPath != "" && this.DirectoryIsValid)
{
dInfo = new DirectoryInfo(this.CurrentPath);
if (dInfo.Exists)
{
try
{
m_FSWatcher = new FileSystemWatcher();
m_FSWatcher.Path = dInfo.FullName;
m_FSWatcher.NotifyFilter = nf;
// Set filter to "" to watch everything
m_FSWatcher.Filter = "";
m_FSWatcher.IncludeSubdirectories = false;
m_FSWatcher.EnableRaisingEvents = true;
m_FSWatcher.Changed += new System.IO.FileSystemEventHandler(FileWatcher_Changed);
m_FSWatcher.Deleted += new System.IO.FileSystemEventHandler(FileWatcher_Changed);
m_FSWatcher.Created += new FileSystemEventHandler(FileWatcher_Changed);
}
catch
{
}
}
}
}
internal void SetIcons()
{
// Needed to set the correct Icon Mask
JTagData tagData;
LVITEM LV_ITEM;
foreach (ListViewItem current in this.Items)
{
tagData = (JTagData)current.Tag;
if (tagData.Mask != 0)
{
LV_ITEM = new LVITEM();
LV_ITEM.iItem = current.Index;
LV_ITEM.mask = tagData.Mask;
LV_ITEM.stateMask = tagData.StateMask;
LV_ITEM.state = tagData.State;
LV_ITEM.iImage = tagData.ImageIndex;
// Set the icon with its mask(s)
user32.SendMessage(this.Handle, (int)LVM.LVM_SETITEMSTATE, current.Index, ref LV_ITEM);
}
}
}
private void SetImageIndexes(bool thumbs)
{
JTagData tagData;
foreach (ListViewItem current in this.Items)
{
tagData = (JTagData)current.Tag;
if (thumbs)
{
current.ImageIndex = tagData.ThumbImageIndex;
}
else
{
current.ImageIndex = tagData.ImageIndex;
}
}
}
internal void SetImageList(bool thumbs)
{
if (!thumbs)
{
JFSFunctions.SetSmallSystemImageList(this);
JFSFunctions.SetLargeSystemImageList(this);
}
else
{
if (this.m_View == View.SmallIcon)
{
SetLargeImageList(this, m_SmallImageList);
SetSmallImageList(this, m_SmallImageList);
}
else
{
SetLargeImageList(this, m_LargeImageList);
SetSmallImageList(this, m_SmallImageList);
}
}
}
private int SetLargeImageList(ListView lv, ImageList imgList)
{
return user32.SendMessage(lv.Handle, (int)LVM.LVM_SETIMAGELIST, (int)LVSIL.LVSIL_NORMAL, imgList.Handle);
}
private int SetSmallImageList(ListView lv, ImageList imgList)
{
return user32.SendMessage(lv.Handle, (int)LVM.LVM_SETIMAGELIST, (int)LVSIL.LVSIL_SMALL, imgList.Handle);
}
private void SetColumnsToDriveMode()
{
// Back to a clean starting point
// This causes problems if we are not in Details View
if (m_ColumnMode == ColumnModes.DriveMode)
return;
if (this.View == View.Details)
{
this.Columns.Clear();
ColumnHeader colTemp;
colTemp = this.Columns.Add("Name", 132, HorizontalAlignment.Left);
colTemp.Tag = ListViewSortTypes.None;
colTemp = this.Columns.Add("Type", 120, HorizontalAlignment.Left);
colTemp.Tag = ListViewSortTypes.None;
colTemp = this.Columns.Add("Total", 100, HorizontalAlignment.Right);
colTemp.Tag = ListViewSortTypes.None;
colTemp = this.Columns.Add("Available", 100, HorizontalAlignment.Right);
colTemp.Tag = ListViewSortTypes.None;
m_ColumnMode = ColumnModes.DriveMode;
}
}
private void SetColumnsToNormalMode()
{
// Back to a clean starting point
// This causes problems if we are not in Details View
if (m_ColumnMode == ColumnModes.NormalMode)
return;
if (this.View == View.Details)
{
this.Columns.Clear();
ColumnHeader colTemp;
int[] colWidths = { 200, 120, 60, 120 };
string[] normalHeadings = { "Name", "File Type", "Size", "Date Modified" };
colTemp = this.Columns.Add(normalHeadings[0], colWidths[0], HorizontalAlignment.Left);
colTemp.Tag = ListViewSortTypes.Text;
colTemp = this.Columns.Add(normalHeadings[1], colWidths[1], HorizontalAlignment.Left);
colTemp.Tag = ListViewSortTypes.Text;
colTemp = this.Columns.Add(normalHeadings[2], colWidths[2], HorizontalAlignment.Right);
colTemp.Tag = ListViewSortTypes.Number;
colTemp = this.Columns.Add(normalHeadings[3], colWidths[3], HorizontalAlignment.Right);
colTemp.Tag = ListViewSortTypes.DateTime;
m_ColumnMode = ColumnModes.NormalMode;
}
}
private void SetupFileExtensionsHashtable(DirectoryInfo dInfo)
{
m_htExtensions.Clear();
FileInfo[] fiFiles = dInfo.GetFiles();
string key;
foreach (FileInfo current in fiFiles)
{
// Set up Hashtable - ALL extensions go in whether they're shown or not
key = "*" + current.Extension.ToLower();
if (!m_htExtensions.Contains(key))
{
m_htExtensions.Add(key, JFSFunctions.GetFileTypeString(current.FullName));
}
}
}
private void SetView()
{
bool thumbs = IsThumbView(this.m_View);
SetView(thumbs);
}
private void SetView(bool thumbs)
{
SetImageList(thumbs);
SetImageIndexes(thumbs);
}
private void SetViewMode(View newView)
{
// We use View.LargeIcon to show ThumbNails
// The ListView is set to View.LargeIcon then images created
// for each file and stored in an image list
View viewBase = View.Details;
this.m_View = newView;
switch (newView)
{
case View.Details:
viewBase = View.Details;
break;
case View.LargeIcon:
viewBase = View.LargeIcon;
break;
case View.List:
viewBase = View.List;
break;
// Small Icon view is a mess so use LargeIcon with small image list
case View.SmallIcon:
viewBase = View.LargeIcon;
break;
case View.Tile:
viewBase = View.Tile;
break;
}
this.BeginUpdate();
base.View = viewBase;
bool thumbs = IsThumbView(newView);
SetView(thumbs);
this.EndUpdate();
}
private void ShowContextMenu(JTagData tagData, Point pt)
{
List<string> listSelectedItemsPaths;
switch (this.SelectedItems.Count)
{
case 0:
case 1:
JContextMenu.ShowContextMenu(this.Handle, tagData.Path, pt, ref m_IContextMenu3);
break;
default:
listSelectedItemsPaths = GetSelectedObjectsPaths();
if (listSelectedItemsPaths != null && listSelectedItemsPaths.Count > 0)
JContextMenu.ShowContextMenu(this.Handle, listSelectedItemsPaths, pt, ref m_IContextMenu3);
break;
}
RefreshView(true);
}
internal void SortListView(int column, bool changeSortOrder)
{
this.m_SortColumn = column;
ListViewSortTypes sortType = (ListViewSortTypes)this.Columns[column].Tag;
JListViewFSSorter fsSorter = new JListViewFSSorter(this, m_SortColumn, m_SortOrder, sortType);
fsSorter.SortListView(this.m_SortColumn, ref this.m_SortOrder, changeSortOrder);
}
internal void StartFileWatcher()
{
if (m_WatchInterval > 0)
{
SetFileWatch();
timRefresh.Interval = m_WatchInterval;
timRefresh.Enabled = true;
}
}
internal void StopFileWatcher()
{
if (m_FSWatcher != null)
m_FSWatcher.Dispose();
timRefresh.Enabled = false;
}
void timRefresh_Tick(object sender, EventArgs e)
{
if (m_RefreshNeeded)
{
RaiseTimerRefreshNeededEvent();
// Unset flag
m_RefreshNeeded = false;
}
}
internal void UnselectAll()
{
DoUnSelectAll();
}
protected override void WndProc(ref Message message)
{
// Required for the Owner Draw items on the Explorer Context Menu (Open With, Send To)
IntPtr lpResult = IntPtr.Zero;
IntPtr lParam = this.Handle;
switch (message.Msg)
{
case WM_DRAWITEM:
case WM_MEASUREITEM:
case WM_INITMENUPOPUP:
if (m_IContextMenu3 != null)
m_IContextMenu3.HandleMenuMsg((uint)message.Msg, message.WParam, message.LParam);
break;
case WM_MENUCHAR:
if (m_IContextMenu3 != null)
m_IContextMenu3.HandleMenuMsg2((uint)message.Msg, message.WParam, message.LParam, ref lpResult);
break;
case WM_VSCROLL:
// There is a bug in painting gridlines in XP, this is a crude fix
if (this.GridLines)
this.Refresh();
base.WndProc(ref message);
break;
default:
base.WndProc(ref message);
break;
}
}
#region Internal Properties
internal List<string> AllFileNames
{
get { return GetAllFileNames(); }
}
internal List<string> AllFilePaths
{
get { return GetAllFilePaths(); }
}
internal bool CanDropHere
{
get { return GetCanDropHere(GetSelectedItem()); }
}
internal ListViewItem CurrentSelectedItem
{
get { return GetSelectedItem(); }
}
internal string CurrentPath
{
get { return GetCurrentPath(); }
}
internal JTagData CurrentTagData
{
get { return this.m_CurrentTagData; }
set { SetCurrentTagData(value, true, false); }
}
/// <summary>
/// Returns True If A Valid Directory Is Selected;
/// </summary>
internal bool DirectoryIsValid
{
get { return JCommon.DirectoryExists(this.CurrentPath); }
}
internal string DriveStatusString
{
get { return GetDriveStatusString(); }
}
internal int FileCount
{
get { return GetFileCount(); }
}
internal string FileFilter
{
get { return this.m_FileExtension; }
set { SetFileFilter(value); }
}
internal string ObjectStatusString
{
get { return GetObjectStatusString(); }
}
internal JTagData PreviousTagData
{
get { return this.m_PreviousTagData; }
}
internal int SelectedFileCount
{
get { return GetSelectedFileCount(); }
}
internal string SelectedFilePath
{
get { return GetSelectedFilePath(); }
}
internal int SelectedFolderCount
{
get { return GetSelectedFolderCount(); }
}
internal int SelectedObjectsCount
{
get { return GetSelectedObjectsCount(); }
}
internal string SelectedObjectStatusString
{
get { return GetSelectedObjectStatusString(); }
}
/// <summary>
/// Returns the Displayed Name of The Selected Object
/// </summary>
internal string SelectedItemName
{
get { return GetSelectedItemName(); }
}
/// <summary>
/// Returns the Path of The Selected Object
/// </summary>
internal string SelectedItemPath
{
get { return GetSelectedItemPath(); }
}
/// <summary>
/// Returns the cLVItem of The Selected Object
/// </summary>
internal ListViewItem SelectedItem
{
get { return GetSelectedItem(); }
}
internal JTagData SelectedItemTagData
{
get { return GetSelectedItemTagData(); }
}
internal long SelectedObjectsTotalSize
{
get { return GetSelectedObjectsTotalSize(); }
}
internal new View View
{
get { return base.View; }
set { SetViewMode(value); }
}
#endregion
}
}