Generated
+90
@@ -1634,6 +1634,33 @@ namespace ChatTwo.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Clear the message history database.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Options_ClearDatabase_Button {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Options_ClearDatabase_Button", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Successfully cleared the chat database.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Options_ClearDatabase_Success {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Options_ClearDatabase_Success", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Removes all message history. Cannot be restored. Hold Ctrl+Shift to click..
|
||||||
|
/// </summary>
|
||||||
|
internal static string Options_ClearDatabase_Tooltip {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Options_ClearDatabase_Tooltip", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Replace consecutive duplicate messages with a counter appended to the first instance of the message..
|
/// Looks up a localized string similar to Replace consecutive duplicate messages with a counter appended to the first instance of the message..
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1688,6 +1715,69 @@ namespace ChatTwo.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Click to copy database directory path.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Options_Database_Metadata_CopyConfigPath {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Options_Database_Metadata_CopyConfigPath", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Copied database directory path to clipboard.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Options_Database_Metadata_CopyConfigPathNotification {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Options_Database_Metadata_CopyConfigPathNotification", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Database details:.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Options_Database_Metadata_Heading {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Options_Database_Metadata_Heading", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Log size: {0}.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Options_Database_Metadata_LogSize {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Options_Database_Metadata_LogSize", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Stored messages: {0:N0}/{1:N0}.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Options_Database_Metadata_MessageCount {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Options_Database_Metadata_MessageCount", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Path: {0}.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Options_Database_Metadata_Path {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Options_Database_Metadata_Path", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Size: {0}.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Options_Database_Metadata_Size {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Options_Database_Metadata_Size", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Database.
|
/// Looks up a localized string similar to Database.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -952,4 +952,34 @@
|
|||||||
<data name="Options_HideInLoadingScreens_Description" xml:space="preserve">
|
<data name="Options_HideInLoadingScreens_Description" xml:space="preserve">
|
||||||
<value>Hide {0} during loading screens.</value>
|
<value>Hide {0} during loading screens.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Options_ClearDatabase_Button">
|
||||||
|
<value>Clear the message history database</value>
|
||||||
|
</data>
|
||||||
|
<data name="Options_ClearDatabase_Success">
|
||||||
|
<value>Successfully cleared the chat database</value>
|
||||||
|
</data>
|
||||||
|
<data name="Options_ClearDatabase_Tooltip">
|
||||||
|
<value>Removes all message history. Cannot be restored. Hold Ctrl+Shift to click.</value>
|
||||||
|
</data>
|
||||||
|
<data name="Options_Database_Metadata_CopyConfigPath">
|
||||||
|
<value>Click to copy database directory path</value>
|
||||||
|
</data>
|
||||||
|
<data name="Options_Database_Metadata_CopyConfigPathNotification">
|
||||||
|
<value>Copied database directory path to clipboard</value>
|
||||||
|
</data>
|
||||||
|
<data name="Options_Database_Metadata_Heading">
|
||||||
|
<value>Database details:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Options_Database_Metadata_LogSize">
|
||||||
|
<value>Log size: {0}</value>
|
||||||
|
</data>
|
||||||
|
<data name="Options_Database_Metadata_MessageCount">
|
||||||
|
<value>Stored messages: {0:N0}/{1:N0}</value>
|
||||||
|
</data>
|
||||||
|
<data name="Options_Database_Metadata_Path">
|
||||||
|
<value>Path: {0}</value>
|
||||||
|
</data>
|
||||||
|
<data name="Options_Database_Metadata_Size">
|
||||||
|
<value>Size: {0}</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
+32
-6
@@ -140,9 +140,6 @@ internal class Store : IDisposable {
|
|||||||
bson => DateTime.UnixEpoch.AddMilliseconds(bson.AsInt64)
|
bson => DateTime.UnixEpoch.AddMilliseconds(bson.AsInt64)
|
||||||
);
|
);
|
||||||
Database = Connect();
|
Database = Connect();
|
||||||
Messages.EnsureIndex(msg => msg.Date);
|
|
||||||
Messages.EnsureIndex(msg => msg.SortCode);
|
|
||||||
Messages.EnsureIndex(msg => msg.ExtraChatChannel);
|
|
||||||
|
|
||||||
Plugin.ChatGui.ChatMessageUnhandled += ChatMessage;
|
Plugin.ChatGui.ChatMessageUnhandled += ChatMessage;
|
||||||
Plugin.Framework.Update += GetMessageInfo;
|
Plugin.Framework.Update += GetMessageInfo;
|
||||||
@@ -159,17 +156,26 @@ internal class Store : IDisposable {
|
|||||||
Database.Dispose();
|
Database.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ILiteDatabase Connect() {
|
internal static string DatabasePath()
|
||||||
|
{
|
||||||
var dir = Plugin.Interface.ConfigDirectory;
|
var dir = Plugin.Interface.ConfigDirectory;
|
||||||
dir.Create();
|
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 connection = Plugin.Config.SharedMode ? "shared" : "direct";
|
||||||
var connString = $"Filename='{dbPath}';Connection={connection}";
|
var connString = $"Filename='{dbPath}';Connection={connection}";
|
||||||
return new LiteDatabase(connString, BsonMapper.Global) {
|
var conn = new LiteDatabase(connString, BsonMapper.Global) {
|
||||||
CheckpointSize = 1_000,
|
CheckpointSize = 1_000,
|
||||||
Timeout = TimeSpan.FromSeconds(1),
|
Timeout = TimeSpan.FromSeconds(1),
|
||||||
};
|
};
|
||||||
|
var messages = conn.GetCollection<Message>("messages");
|
||||||
|
messages.EnsureIndex(msg => msg.Date);
|
||||||
|
messages.EnsureIndex(msg => msg.SortCode);
|
||||||
|
messages.EnsureIndex(msg => msg.ExtraChatChannel);
|
||||||
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Reconnect() {
|
internal void Reconnect() {
|
||||||
@@ -177,6 +183,26 @@ internal class Store : IDisposable {
|
|||||||
Database = Connect();
|
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() {
|
private void Logout() {
|
||||||
LastContentId = 0;
|
LastContentId = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public sealed class SettingsWindow : Window, IUiComponent
|
|||||||
new Ui.SettingsTabs.Fonts(Mutable),
|
new Ui.SettingsTabs.Fonts(Mutable),
|
||||||
new ChatColours(Mutable, Plugin),
|
new ChatColours(Mutable, Plugin),
|
||||||
new Tabs(Plugin, Mutable),
|
new Tabs(Plugin, Mutable),
|
||||||
new Database(Mutable, Plugin.Store),
|
new Database(Mutable, Plugin),
|
||||||
new Miscellaneous(Mutable),
|
new Miscellaneous(Mutable),
|
||||||
new About(),
|
new About(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,22 +1,28 @@
|
|||||||
using ChatTwo.Resources;
|
using ChatTwo.Resources;
|
||||||
using ChatTwo.Util;
|
using ChatTwo.Util;
|
||||||
|
using Dalamud.Interface.Internal.Notifications;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
|
||||||
namespace ChatTwo.Ui.SettingsTabs;
|
namespace ChatTwo.Ui.SettingsTabs;
|
||||||
|
|
||||||
internal sealed class Database : ISettingsTab {
|
internal sealed class Database : ISettingsTab {
|
||||||
private Configuration Mutable { get; }
|
private Configuration Mutable { get; }
|
||||||
private Store Store { get; }
|
private Plugin Plugin { get; }
|
||||||
|
|
||||||
public string Name => Language.Options_Database_Tab + "###tabs-database";
|
public string Name => Language.Options_Database_Tab + "###tabs-database";
|
||||||
|
|
||||||
internal Database(Configuration mutable, Store store) {
|
internal Database(Configuration mutable, Plugin plugin) {
|
||||||
Store = store;
|
Plugin = plugin;
|
||||||
Mutable = mutable;
|
Mutable = mutable;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool _showAdvanced;
|
private bool _showAdvanced;
|
||||||
|
|
||||||
|
private long _databaseLastRefreshTicks;
|
||||||
|
private long _databaseSize;
|
||||||
|
private long _databaseLogSize;
|
||||||
|
private int _databaseMessageCount;
|
||||||
|
|
||||||
public void Draw(bool changed) {
|
public void Draw(bool changed) {
|
||||||
if (changed) {
|
if (changed) {
|
||||||
_showAdvanced = ImGui.GetIO().KeyShift;
|
_showAdvanced = ImGui.GetIO().KeyShift;
|
||||||
@@ -46,18 +52,88 @@ internal sealed class Database : ISettingsTab {
|
|||||||
);
|
);
|
||||||
ImGuiUtil.WarningText(string.Format(Language.Options_SharedMode_Warning, Plugin.PluginName));
|
ImGuiUtil.WarningText(string.Format(Language.Options_SharedMode_Warning, Plugin.PluginName));
|
||||||
|
|
||||||
|
ImGui.Spacing();
|
||||||
|
ImGui.Separator();
|
||||||
ImGui.Spacing();
|
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();
|
ImGui.PushTextWrapPos();
|
||||||
ImGuiUtil.WarningText(Language.Options_Database_Advanced_Warning);
|
ImGuiUtil.WarningText(Language.Options_Database_Advanced_Warning);
|
||||||
|
|
||||||
if (ImGui.Button("Checkpoint")) {
|
if (ImGuiUtil.CtrlShiftButton("Checkpoint", "Ctrl+Shift: Database.Checkpoint()"))
|
||||||
Store.Database.Checkpoint();
|
{
|
||||||
|
Plugin.Store.Database.Checkpoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui.Button("Rebuild")) {
|
if (ImGuiUtil.CtrlShiftButton("Rebuild", "Ctrl+Shift: Database.Rebuild()"))
|
||||||
Store.Database.Rebuild();
|
{
|
||||||
|
Plugin.Store.Database.Rebuild();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.PopTextWrapPos();
|
ImGui.PopTextWrapPos();
|
||||||
|
|||||||
@@ -234,6 +234,22 @@ internal static class ImGuiUtil {
|
|||||||
return r;
|
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) {
|
internal static bool TryToImGui(this VirtualKey key, out ImGuiKey result) {
|
||||||
result = key switch {
|
result = key switch {
|
||||||
VirtualKey.NO_KEY => ImGuiKey.None,
|
VirtualKey.NO_KEY => ImGuiKey.None,
|
||||||
|
|||||||
@@ -10,4 +10,16 @@ internal static class StringUtil {
|
|||||||
bytes[^1] = 0;
|
bytes[^1] = 0;
|
||||||
return bytes;
|
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];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user