/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); |
} |
} |
} |
} |