WingMan

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 22  →  ?path2? @ 23
/trunk/WingMan/AutoCompletion/AutoCompletion.cs
@@ -0,0 +1,168 @@
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Mono.Data.Sqlite;
 
namespace WingMan.AutoCompletion
{
public class AutoCompletion : IDisposable
{
public delegate void LoadFailed(object sender, AutoCompletionFailedEventArgs args);
 
 
public delegate void SaveFailed(object sender, AutoCompletionFailedEventArgs args);
 
public AutoCompletion()
{
}
 
public AutoCompletion(TaskScheduler taskScheduler, CancellationToken cancellationToken) : this()
{
TaskScheduler = taskScheduler;
CancellationToken = cancellationToken;
}
 
private TaskScheduler TaskScheduler { get; }
private CancellationToken CancellationToken { get; }
 
public void Dispose()
{
}
 
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetDllDirectory(string lpPathName);
 
public event SaveFailed OnSaveFailed;
 
public event LoadFailed OnLoadFailed;
 
public async Task Save(string name, AutoCompleteStringCollection autoCompleteStringCollection)
{
SetDllDirectory(Environment.Is64BitOperatingSystem ? "x64" : "x86");
 
try
{
using (var sqliteConnection =
new SqliteConnection($"URI=file:{"Autocomplete.db"}"))
{
await sqliteConnection.OpenAsync(CancellationToken);
 
// Create table if it does not exist.
using (var sqliteCommand =
new SqliteCommand($"CREATE TABLE IF NOT EXISTS {name} (data text UNIQUE NOT NULL)",
sqliteConnection))
{
using (var dbtransaction = sqliteConnection.BeginTransaction())
{
try
{
await sqliteCommand.ExecuteReaderAsync(CancellationToken);
 
dbtransaction.Commit();
}
catch
{
dbtransaction.Rollback();
throw;
}
}
}
 
// Add all items to the database.
await Task.Delay(0, CancellationToken).ContinueWith(async _ =>
{
foreach (var sourceItem in autoCompleteStringCollection)
{
var data = sourceItem.ToString();
 
using (var sqliteCommand =
new SqliteCommand($"REPLACE INTO {name} (data) VALUES (:data)",
sqliteConnection))
{
sqliteCommand
.Parameters
.Add(new SqliteParameter("data", data));
 
using (var dbtransaction = sqliteConnection.BeginTransaction())
{
try
{
await sqliteCommand.ExecuteReaderAsync(CancellationToken);
 
dbtransaction.Commit();
}
catch
{
dbtransaction.Rollback();
throw;
}
}
}
}
}, CancellationToken,
TaskContinuationOptions.None, TaskScheduler);
}
}
catch (Exception ex)
{
await Task.Delay(0, CancellationToken).ContinueWith(_ => OnSaveFailed?.Invoke(this,
new AutoCompletionFailedEventArgs(AutoCompletionFailedType.Save, name, ex)), CancellationToken,
TaskContinuationOptions.None, TaskScheduler);
}
}
 
public async Task Load(string name, AutoCompleteStringCollection autoCompleteStringCollection)
{
SetDllDirectory(Environment.Is64BitOperatingSystem ? "x64" : "x86");
 
try
{
using (var sqliteConnection =
new SqliteConnection($"URI=file:{"Autocomplete.db"}"))
{
await sqliteConnection.OpenAsync(CancellationToken);
using (var sqliteCommand =
new SqliteCommand($"SELECT data FROM {name}", sqliteConnection))
{
using (var dbtransaction = sqliteConnection.BeginTransaction())
{
try
{
using (var reader = await sqliteCommand.ExecuteReaderAsync(CancellationToken))
{
while (await reader.ReadAsync(CancellationToken))
for (var i = 0; i < reader.FieldCount; ++i)
{
var value = reader.GetString(i);
if (string.IsNullOrEmpty(value))
continue;
 
await Task.Delay(0, CancellationToken).ContinueWith(
_ => autoCompleteStringCollection.Add(value), CancellationToken,
TaskContinuationOptions.None, TaskScheduler);
}
}
 
dbtransaction.Commit();
}
catch
{
dbtransaction.Rollback();
throw;
}
}
}
}
}
catch (Exception ex)
{
await Task.Delay(0, CancellationToken).ContinueWith(_ => OnLoadFailed?.Invoke(this,
new AutoCompletionFailedEventArgs(AutoCompletionFailedType.Load, name, ex)), CancellationToken,
TaskContinuationOptions.None, TaskScheduler);
}
}
}
}