diff --git a/ChatTwo/Resources/Language.Designer.cs b/ChatTwo/Resources/Language.Designer.cs
index 01c8b87..63cc8e5 100755
--- a/ChatTwo/Resources/Language.Designer.cs
+++ b/ChatTwo/Resources/Language.Designer.cs
@@ -1634,6 +1634,33 @@ namespace ChatTwo.Resources {
}
}
+ ///
+ /// Looks up a localized string similar to Clear the message history database.
+ ///
+ internal static string Options_ClearDatabase_Button {
+ get {
+ return ResourceManager.GetString("Options_ClearDatabase_Button", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Successfully cleared the chat database.
+ ///
+ internal static string Options_ClearDatabase_Success {
+ get {
+ return ResourceManager.GetString("Options_ClearDatabase_Success", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Removes all message history. Cannot be restored. Hold Ctrl+Shift to click..
+ ///
+ internal static string Options_ClearDatabase_Tooltip {
+ get {
+ return ResourceManager.GetString("Options_ClearDatabase_Tooltip", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Replace consecutive duplicate messages with a counter appended to the first instance of the message..
///
@@ -1688,6 +1715,69 @@ namespace ChatTwo.Resources {
}
}
+ ///
+ /// Looks up a localized string similar to Click to copy database directory path.
+ ///
+ internal static string Options_Database_Metadata_CopyConfigPath {
+ get {
+ return ResourceManager.GetString("Options_Database_Metadata_CopyConfigPath", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Copied database directory path to clipboard.
+ ///
+ internal static string Options_Database_Metadata_CopyConfigPathNotification {
+ get {
+ return ResourceManager.GetString("Options_Database_Metadata_CopyConfigPathNotification", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Database details:.
+ ///
+ internal static string Options_Database_Metadata_Heading {
+ get {
+ return ResourceManager.GetString("Options_Database_Metadata_Heading", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Log size: {0}.
+ ///
+ internal static string Options_Database_Metadata_LogSize {
+ get {
+ return ResourceManager.GetString("Options_Database_Metadata_LogSize", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Stored messages: {0:N0}/{1:N0}.
+ ///
+ internal static string Options_Database_Metadata_MessageCount {
+ get {
+ return ResourceManager.GetString("Options_Database_Metadata_MessageCount", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Path: {0}.
+ ///
+ internal static string Options_Database_Metadata_Path {
+ get {
+ return ResourceManager.GetString("Options_Database_Metadata_Path", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Size: {0}.
+ ///
+ internal static string Options_Database_Metadata_Size {
+ get {
+ return ResourceManager.GetString("Options_Database_Metadata_Size", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Database.
///
diff --git a/ChatTwo/Resources/Language.resx b/ChatTwo/Resources/Language.resx
index da1ea88..f29ecc8 100644
--- a/ChatTwo/Resources/Language.resx
+++ b/ChatTwo/Resources/Language.resx
@@ -952,4 +952,34 @@
Hide {0} during loading screens.
+
+ Clear the message history database
+
+
+ Successfully cleared the chat database
+
+
+ Removes all message history. Cannot be restored. Hold Ctrl+Shift to click.
+
+
+ Click to copy database directory path
+
+
+ Copied database directory path to clipboard
+
+
+ Database details:
+
+
+ Log size: {0}
+
+
+ Stored messages: {0:N0}/{1:N0}
+
+
+ Path: {0}
+
+
+ Size: {0}
+
diff --git a/ChatTwo/Store.cs b/ChatTwo/Store.cs
index 60a6209..d2695d9 100755
--- a/ChatTwo/Store.cs
+++ b/ChatTwo/Store.cs
@@ -140,9 +140,6 @@ internal class Store : IDisposable {
bson => DateTime.UnixEpoch.AddMilliseconds(bson.AsInt64)
);
Database = Connect();
- Messages.EnsureIndex(msg => msg.Date);
- Messages.EnsureIndex(msg => msg.SortCode);
- Messages.EnsureIndex(msg => msg.ExtraChatChannel);
Plugin.ChatGui.ChatMessageUnhandled += ChatMessage;
Plugin.Framework.Update += GetMessageInfo;
@@ -159,17 +156,26 @@ internal class Store : IDisposable {
Database.Dispose();
}
- private ILiteDatabase Connect() {
+ internal static string DatabasePath()
+ {
var dir = Plugin.Interface.ConfigDirectory;
dir.Create();
+ return Path.Join(dir.FullName, "chat.db");
+ }
- var dbPath = Path.Join(dir.FullName, "chat.db");
+ private LiteDatabase Connect() {
+ var dbPath = DatabasePath();
var connection = Plugin.Config.SharedMode ? "shared" : "direct";
var connString = $"Filename='{dbPath}';Connection={connection}";
- return new LiteDatabase(connString, BsonMapper.Global) {
+ var conn = new LiteDatabase(connString, BsonMapper.Global) {
CheckpointSize = 1_000,
Timeout = TimeSpan.FromSeconds(1),
};
+ var messages = conn.GetCollection("messages");
+ messages.EnsureIndex(msg => msg.Date);
+ messages.EnsureIndex(msg => msg.SortCode);
+ messages.EnsureIndex(msg => msg.ExtraChatChannel);
+ return conn;
}
internal void Reconnect() {
@@ -177,6 +183,26 @@ internal class Store : IDisposable {
Database = Connect();
}
+ internal void ClearDatabase()
+ {
+ Messages.DeleteAll();
+ Database.Rebuild();
+ }
+
+ internal static long DatabaseSize()
+ {
+ var dbPath = DatabasePath();
+ return !File.Exists(dbPath) ? 0 : new FileInfo(dbPath).Length;
+ }
+
+ internal static long DatabaseLogSize()
+ {
+ var dbLogPath = Path.Join(Plugin.Interface.ConfigDirectory.FullName, "chat-log.db");
+ return !File.Exists(dbLogPath) ? 0 : new FileInfo(dbLogPath).Length;
+ }
+
+ internal int MessageCount() => Messages.Count();
+
private void Logout() {
LastContentId = 0;
}
diff --git a/ChatTwo/Ui/Settings.cs b/ChatTwo/Ui/Settings.cs
index d4ae5d4..436a631 100755
--- a/ChatTwo/Ui/Settings.cs
+++ b/ChatTwo/Ui/Settings.cs
@@ -35,7 +35,7 @@ public sealed class SettingsWindow : Window, IUiComponent
new Ui.SettingsTabs.Fonts(Mutable),
new ChatColours(Mutable, Plugin),
new Tabs(Plugin, Mutable),
- new Database(Mutable, Plugin.Store),
+ new Database(Mutable, Plugin),
new Miscellaneous(Mutable),
new About(),
};
diff --git a/ChatTwo/Ui/SettingsTabs/Database.cs b/ChatTwo/Ui/SettingsTabs/Database.cs
index f0814f5..95d4f66 100755
--- a/ChatTwo/Ui/SettingsTabs/Database.cs
+++ b/ChatTwo/Ui/SettingsTabs/Database.cs
@@ -1,22 +1,28 @@
using ChatTwo.Resources;
using ChatTwo.Util;
+using Dalamud.Interface.Internal.Notifications;
using ImGuiNET;
namespace ChatTwo.Ui.SettingsTabs;
internal sealed class Database : ISettingsTab {
private Configuration Mutable { get; }
- private Store Store { get; }
+ private Plugin Plugin { get; }
public string Name => Language.Options_Database_Tab + "###tabs-database";
- internal Database(Configuration mutable, Store store) {
- Store = store;
+ internal Database(Configuration mutable, Plugin plugin) {
+ Plugin = plugin;
Mutable = mutable;
}
private bool _showAdvanced;
+ private long _databaseLastRefreshTicks;
+ private long _databaseSize;
+ private long _databaseLogSize;
+ private int _databaseMessageCount;
+
public void Draw(bool changed) {
if (changed) {
_showAdvanced = ImGui.GetIO().KeyShift;
@@ -46,18 +52,88 @@ internal sealed class Database : ISettingsTab {
);
ImGuiUtil.WarningText(string.Format(Language.Options_SharedMode_Warning, Plugin.PluginName));
+ ImGui.Spacing();
+ ImGui.Separator();
ImGui.Spacing();
- if (_showAdvanced && ImGui.TreeNodeEx(Language.Options_Database_Advanced)) {
+ ImGui.Text(Language.Options_Database_Metadata_Heading);
+ var style = ImGui.GetStyle();
+ ImGui.Indent(style.IndentSpacing);
+
+ // Refresh the database size and message count every 5 seconds to avoid
+ // constant stat calls and spamming the database.
+ if (_databaseLastRefreshTicks + 5 * 1000 < Environment.TickCount64)
+ {
+ _databaseSize = Store.DatabaseSize();
+ _databaseLogSize = Store.DatabaseLogSize();
+ _databaseMessageCount = Plugin.Store.MessageCount();
+ _databaseLastRefreshTicks = Environment.TickCount64;
+ }
+
+ ImGuiUtil.HelpText(string.Format(Language.Options_Database_Metadata_Path, Store.DatabasePath()));
+ if (ImGui.IsItemClicked(ImGuiMouseButton.Left))
+ {
+ // Copy the directory path instead of the file path so people can
+ // paste it into their file explorer.
+ var path = Path.GetDirectoryName(Store.DatabasePath());
+ ImGui.SetClipboardText(path);
+ WrapperUtil.AddNotification(Language.Options_Database_Metadata_CopyConfigPathNotification, NotificationType.Info);
+ }
+ if (ImGui.IsItemHovered())
+ {
+ ImGui.SetMouseCursor(ImGuiMouseCursor.Hand);
+ ImGui.BeginTooltip();
+ ImGui.Text(Language.Options_Database_Metadata_CopyConfigPath);
+ ImGui.EndTooltip();
+ }
+
+ ImGuiUtil.HelpText(string.Format(Language.Options_Database_Metadata_Size, StringUtil.BytesToString(_databaseSize)));
+ if (ImGui.IsItemHovered())
+ {
+ ImGui.BeginTooltip();
+ ImGui.Text(_databaseSize.ToString("N0") + "B");
+ ImGui.EndTooltip();
+ }
+
+ ImGuiUtil.HelpText(string.Format(Language.Options_Database_Metadata_LogSize, StringUtil.BytesToString(_databaseLogSize)));
+ if (ImGui.IsItemHovered())
+ {
+ ImGui.BeginTooltip();
+ ImGui.Text(_databaseLogSize.ToString("N0") + "B");
+ ImGui.EndTooltip();
+ }
+
+ ImGuiUtil.HelpText(string.Format(Language.Options_Database_Metadata_MessageCount, _databaseMessageCount, Store.MessagesLimit));
+
+ if (ImGuiUtil.CtrlShiftButton(Language.Options_ClearDatabase_Button, Language.Options_ClearDatabase_Tooltip))
+ {
+ Plugin.Log.Warning("Clearing database");
+ Plugin.Store.ClearDatabase();
+ foreach (var tab in Plugin.Config.Tabs)
+ {
+ tab.Clear();
+ }
+ // Refresh on next draw
+ _databaseLastRefreshTicks = 0;
+ WrapperUtil.AddNotification(Language.Options_ClearDatabase_Success, NotificationType.Info);
+ }
+
+ ImGui.Unindent(style.IndentSpacing);
+ ImGui.Spacing();
+
+ if (_showAdvanced && ImGui.TreeNodeEx(Language.Options_Database_Advanced))
+ {
ImGui.PushTextWrapPos();
ImGuiUtil.WarningText(Language.Options_Database_Advanced_Warning);
- if (ImGui.Button("Checkpoint")) {
- Store.Database.Checkpoint();
+ if (ImGuiUtil.CtrlShiftButton("Checkpoint", "Ctrl+Shift: Database.Checkpoint()"))
+ {
+ Plugin.Store.Database.Checkpoint();
}
- if (ImGui.Button("Rebuild")) {
- Store.Database.Rebuild();
+ if (ImGuiUtil.CtrlShiftButton("Rebuild", "Ctrl+Shift: Database.Rebuild()"))
+ {
+ Plugin.Store.Database.Rebuild();
}
ImGui.PopTextWrapPos();
diff --git a/ChatTwo/Util/ImGuiUtil.cs b/ChatTwo/Util/ImGuiUtil.cs
index 31c4efc..ffb1534 100755
--- a/ChatTwo/Util/ImGuiUtil.cs
+++ b/ChatTwo/Util/ImGuiUtil.cs
@@ -234,6 +234,22 @@ internal static class ImGuiUtil {
return r;
}
+ internal static bool CtrlShiftButton(string label, string tooltip = "")
+ {
+ var io = ImGui.GetIO();
+ var ctrlShiftHeld = io.KeyCtrl && io.KeyShift;
+ if (!ctrlShiftHeld) ImGui.BeginDisabled();
+ var ret = ImGui.Button(label) && ctrlShiftHeld;
+ if (!ctrlShiftHeld) ImGui.EndDisabled();
+ if (!string.IsNullOrEmpty(tooltip) && ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)) {
+ ImGui.BeginTooltip();
+ ImGui.TextUnformatted(tooltip);
+ ImGui.EndTooltip();
+ }
+
+ return ret;
+ }
+
internal static bool TryToImGui(this VirtualKey key, out ImGuiKey result) {
result = key switch {
VirtualKey.NO_KEY => ImGuiKey.None,
diff --git a/ChatTwo/Util/StringUtil.cs b/ChatTwo/Util/StringUtil.cs
index b92fb62..d54456e 100755
--- a/ChatTwo/Util/StringUtil.cs
+++ b/ChatTwo/Util/StringUtil.cs
@@ -10,4 +10,16 @@ internal static class StringUtil {
bytes[^1] = 0;
return bytes;
}
+
+ // Taken from https://stackoverflow.com/a/4975942
+ internal static String BytesToString(long byteCount) {
+ string[] suf = ["B", "KB", "MB", "GB", "TB", "PB", "EB"]; // Longs run out around EB
+ if (byteCount == 0)
+ return "0" + suf[0];
+
+ var bytes = Math.Abs(byteCount);
+ var place = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024)));
+ var num = Math.Round(bytes / Math.Pow(1024, place), 1);
+ return (Math.Sign(byteCount) * num).ToString("N0") + suf[place];
+ }
}