using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Xml.Serialization;
namespace FileSearch
{
public partial class Form1 : Form
{
string RemoteIndexPath = Application.StartupPath + @"\remote_index_path.txt";
string IndexPath = Application.StartupPath + @"\index.dat";
List<string> RawItems = new List<string>();
System.Collections.Concurrent.ConcurrentBag<string> FilterItems = new System.Collections.Concurrent.ConcurrentBag<string>();
List<SubForm> Children = new List<SubForm>();
int VisibleCount = 1000;
int RawItemCount = 0;
string WriteTime = "";
string Needle = "";
object LockObject = new object();
bool IsExit = true;
public Form1()
{
InitializeComponent();
if (!IndexLoad()) return;
LoadPosition();
var delayExecute = new DelayExecute();
delayExecute.Execute += (s, e) => SetupDatasource();
textBox1.TextChanged += (s, e) =>
{
lock (LockObject)
{
IsExit = false;
}
Needle = textBox1.Text;
delayExecute.ReserveExecute();
};
textBox1.KeyDown += (s, e) => OpenSubForm(s, e);
listBox1.MouseDoubleClick += (s, e) => OpenFile(s, e);
this.SizeChanged += (s, e) =>
{
if (this.WindowState == FormWindowState.Minimized || this.WindowState == FormWindowState.Maximized) return;
SavePosition();
};
this.FormClosing += (s, e) =>
{
if (Children.Count > 0)
{
MessageBox.Show("フォームを全て閉じてください。");
e.Cancel = true;
return;
}
lock (LockObject)
{
if (!IsExit) e.Cancel = true;
}
};
}
private void OpenSubForm(object sender, KeyEventArgs e)
{
lock (LockObject)
{
if (!IsExit) return;
}
if (FilterItems.Count == 0) return;
if (e.Control && e.KeyCode == Keys.Enter)
{
string startTime = "0";
var input = new InputBox();
input.StartPosition = FormStartPosition.Manual;
input.Left = DesktopLocation.X + 10;
input.Top = DesktopLocation.Y + 10;
input.ShowDialog();
if (input.IsClick)
{
int.TryParse(input.Value, out int result);
startTime = result.ToString();
}
var f = new SubForm(textBox1.Text, new List<string>(FilterItems), startTime);
string handle = Guid.NewGuid().ToString("N");
f.Id = handle;
f.FormClosed += (ss, ee) =>
{
Children = new List<SubForm>(Children.Where(x => x.Id != handle));
};
Children.Add(f);
f.Show();
}
}
private bool IndexLoad()
{
string remoteIndexPath = "";
if (File.Exists(RemoteIndexPath))
{
remoteIndexPath = File.ReadAllText(RemoteIndexPath);
}
if (!File.Exists(IndexPath) && !File.Exists(remoteIndexPath)) // ローカル、リモートにない場合
{
MessageBox.Show("インデックスファイルが見つかりませんでした。");
return false;
}
else if (File.Exists(IndexPath) && !File.Exists(remoteIndexPath)) // ローカルにあって、リモートにない場合
{
RawItems = File.ReadAllLines(IndexPath).ToList();
RawItemCount = RawItems.Count();
WriteTime = File.GetLastWriteTime(IndexPath).ToString("yyyy/MM/dd HH:mm:ss");
}
else if (!File.Exists(IndexPath) && File.Exists(remoteIndexPath)) // ローカルになくて、リモートにある場合
{
File.Copy(remoteIndexPath, IndexPath);
RawItems = File.ReadAllLines(IndexPath).ToList();
RawItemCount = RawItems.Count();
WriteTime = File.GetLastWriteTime(IndexPath).ToString("yyyy/MM/dd HH:mm:ss");
}
else if (File.Exists(IndexPath) && File.Exists(remoteIndexPath)) // ローカル、リモートにある場合
{
if (File.GetLastWriteTime(IndexPath) < File.GetLastWriteTime(remoteIndexPath)) // リモートの方が最新の場合
{
if (DialogResult.Yes == MessageBox.Show("最新のインデックスファイルが存在します。更新しますか?","", MessageBoxButtons.YesNo))
{
File.Copy(remoteIndexPath, IndexPath, true);
}
RawItems = File.ReadAllLines(IndexPath).ToList();
RawItemCount = RawItems.Count();
WriteTime = File.GetLastWriteTime(IndexPath).ToString("yyyy/MM/dd HH:mm:ss");
}
else // ローカルの方が最新の場合
{
RawItems = File.ReadAllLines(IndexPath).ToList();
RawItemCount = RawItems.Count();
WriteTime = File.GetLastWriteTime(IndexPath).ToString("yyyy/MM/dd HH:mm:ss");
}
}
return true;
}
private void SetupDatasource()
{
var stopwatch = new Stopwatch();
stopwatch.Start();
IEnumerable<string> items = new List<string>();
if (Needle == "")
{
items = RawItems.Take(VisibleCount);
}
else
{
List<string> tmpList = new List<string>(RawItems);
foreach (string tmpString in Needle.Split('|'))
{
tmpList = tmpList.AsParallel().Where(x => x.ToLower().Contains(tmpString.ToLower())).ToList();
}
items = tmpList.Take(VisibleCount);
}
var itemClassList = new System.Collections.Concurrent.ConcurrentBag<ItemClass>();
FilterItems = new System.Collections.Concurrent.ConcurrentBag<string>();
System.Threading.Tasks.Parallel.ForEach(items, item =>
{
itemClassList.Add(new ItemClass()
{
DisplayItemPath = Path.GetFileName(item) + " . . . ■" + Path.GetDirectoryName(item),
ItemPath = item
});
FilterItems.Add(item);
});
stopwatch.Stop();
Invoke(new Action(() => {
listBox1.DataSource = itemClassList.ToList();
listBox1.DisplayMember = "DisplayItemPath";
Text = items.Count() + "/" + RawItemCount + "件表示 (" + stopwatch.ElapsedMilliseconds.ToString() + "ms):" + WriteTime + "インデックス";
}));
lock (LockObject)
{
IsExit = true;
}
}
private void OpenFile(object sender, MouseEventArgs e)
{
if (listBox1.SelectedItem == null) return;
var itemPath = ((ItemClass)listBox1.SelectedItem).ItemPath;
if (!File.Exists(itemPath))
{
MessageBox.Show("ファイルを開くことができませんでした。");
return;
}
if (ModifierKeys == Keys.Control)
{
var info = new ProcessStartInfo("explorer.exe");
info.Arguments = $"/select, \"{itemPath}\"";
Process.Start(info);
}
else
{
Process.Start(itemPath);
}
}
private void LoadPosition()
{
if (!File.Exists(Application.StartupPath + @"\dat.xml")) return;
this.StartPosition = FormStartPosition.Manual;
XmlSerializer xs = new XmlSerializer(typeof(List<int>));
using (StreamReader sr = new StreamReader(Application.StartupPath + @"\dat.xml", Encoding.UTF8))
{
try
{
List<int> items = (List<int>)xs.Deserialize(sr);
if (0 > (int)items[2])
{
this.StartPosition = FormStartPosition.WindowsDefaultLocation;
return;
}
this.Width = (int)items[0];
this.Height = (int)items[1];
this.Top = (int)items[2];
this.Left = (int)items[3];
}
catch
{
this.StartPosition = FormStartPosition.WindowsDefaultLocation;
}
}
}
private void SavePosition()
{
if (this.WindowState == FormWindowState.Maximized) return;
XmlSerializer xs = new XmlSerializer(typeof(List<int>));
using (StreamWriter sw = new StreamWriter(Application.StartupPath + @"\dat.xml", false, Encoding.UTF8))
{
List<int> items = new List<int>();
items.Add(this.Width);
items.Add(this.Height);
items.Add(this.Top);
items.Add(this.Left);
xs.Serialize(sw, items);
}
}
}
struct ItemClass
{
public string DisplayItemPath { set; get; }
public string ItemPath { set; get; }
}
class DelayExecute
{
public event EventHandler Execute; // SetupDatasource()を登録
private int DelayTime = 500;
System.Threading.Timer Timer;
public DelayExecute()
{
Timer = new System.Threading.Timer(x => {
Execute(this, EventArgs.Empty);
});
}
public void ReserveExecute() // TextChangeで発火
{
Timer.Change(DelayTime, Timeout.Infinite); // Timeout.Infiniteは一度だけ呼ぶ
}
}
}