mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-26 22:10:21 +00:00
79a05caff5
Pipes the Showdown Set description or object detail dump into the accessible property. When the control Enter event is fired, send an Automation notification so that the Narrator narrates what was just tabbed to. Closes #3758
760 lines
26 KiB
C#
760 lines
26 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
using PKHeX.Core;
|
|
using PKHeX.Core.Searching;
|
|
using PKHeX.Drawing.PokeSprite;
|
|
using PKHeX.WinForms.Controls;
|
|
using PKHeX.WinForms.Properties;
|
|
using static PKHeX.Core.MessageStrings;
|
|
|
|
namespace PKHeX.WinForms;
|
|
|
|
public partial class SAV_Database : Form
|
|
{
|
|
private readonly SaveFile SAV;
|
|
private readonly SAVEditor BoxView;
|
|
private readonly PKMEditor PKME_Tabs;
|
|
private readonly EntityInstructionBuilder UC_Builder;
|
|
|
|
public SAV_Database(PKMEditor f1, SAVEditor saveditor)
|
|
{
|
|
InitializeComponent();
|
|
WinFormsUtil.TranslateInterface(this, Main.CurrentLanguage);
|
|
UC_Builder = new EntityInstructionBuilder(() => f1.PreparePKM())
|
|
{
|
|
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right,
|
|
Width = Tab_Advanced.Width,
|
|
Dock = DockStyle.Top,
|
|
ReadOnly = true,
|
|
};
|
|
Tab_Advanced.Controls.Add(UC_Builder);
|
|
UC_Builder.SendToBack();
|
|
|
|
SAV = saveditor.SAV;
|
|
BoxView = saveditor;
|
|
PKME_Tabs = f1;
|
|
|
|
// Preset Filters to only show PKM available for loaded save
|
|
CB_FormatComparator.SelectedIndex = 3; // <=
|
|
|
|
var grid = DatabasePokeGrid;
|
|
var smallWidth = grid.Width;
|
|
var smallHeight = grid.Height;
|
|
grid.InitializeGrid(6, 11, SpriteUtil.Spriter);
|
|
grid.SetBackground(Resources.box_wp_clean);
|
|
var newWidth = grid.Width;
|
|
var newHeight = grid.Height;
|
|
var wdelta = newWidth - smallWidth;
|
|
if (wdelta != 0)
|
|
Width += wdelta;
|
|
var hdelta = newHeight - smallHeight;
|
|
if (hdelta != 0)
|
|
Height += hdelta;
|
|
PKXBOXES = grid.Entries.ToArray();
|
|
|
|
// Enable Scrolling when hovered over
|
|
foreach (var slot in PKXBOXES)
|
|
{
|
|
// Enable Click
|
|
slot.MouseClick += (sender, e) =>
|
|
{
|
|
if (sender == null)
|
|
return;
|
|
switch (ModifierKeys)
|
|
{
|
|
case Keys.Control: ClickView(sender, e); break;
|
|
case Keys.Alt: ClickDelete(sender, e); break;
|
|
case Keys.Shift: ClickSet(sender, e); break;
|
|
}
|
|
};
|
|
|
|
slot.ContextMenuStrip = mnu;
|
|
if (Main.Settings.Hover.HoverSlotShowText)
|
|
slot.MouseEnter += (o, args) => ShowHoverTextForSlot(slot, args);
|
|
slot.Enter += (sender, e) =>
|
|
{
|
|
if (sender is not PictureBox pb)
|
|
return;
|
|
var index = Array.IndexOf(PKXBOXES, sender);
|
|
if (index < 0)
|
|
return;
|
|
index += (SCR_Box.Value * RES_MIN);
|
|
if (index >= Results.Count)
|
|
return;
|
|
|
|
var pk = Results[index];
|
|
pb.AccessibleDescription = ShowdownParsing.GetLocalizedPreviewText(pk.Entity, Main.CurrentLanguage);
|
|
};
|
|
}
|
|
|
|
Counter = L_Count.Text;
|
|
Viewed = L_Viewed.Text;
|
|
L_Viewed.Text = string.Empty; // invisible for now
|
|
PopulateComboBoxes();
|
|
|
|
// Load Data
|
|
B_Search.Enabled = false;
|
|
L_Count.Text = "Loading...";
|
|
var task = new Task(LoadDatabase);
|
|
task.ContinueWith(z =>
|
|
{
|
|
if (!z.IsFaulted)
|
|
return;
|
|
Invoke((MethodInvoker)(() => L_Count.Text = "Failed."));
|
|
if (z.Exception == null)
|
|
return;
|
|
WinFormsUtil.Error("Loading database failed.", z.Exception.InnerException ?? new Exception(z.Exception.Message));
|
|
});
|
|
task.Start();
|
|
|
|
Menu_SearchSettings.DropDown.Closing += (sender, e) =>
|
|
{
|
|
if (e.CloseReason == ToolStripDropDownCloseReason.ItemClicked)
|
|
e.Cancel = true;
|
|
};
|
|
CB_Format.Items[0] = MsgAny;
|
|
CenterToParent();
|
|
}
|
|
|
|
private readonly PictureBox[] PKXBOXES;
|
|
private readonly string DatabasePath = Main.DatabasePath;
|
|
private List<SlotCache> Results = new();
|
|
private List<SlotCache> RawDB = new();
|
|
private int slotSelected = -1; // = null;
|
|
private Image? slotColor;
|
|
private const int RES_MAX = 66;
|
|
private const int RES_MIN = 6;
|
|
private readonly string Counter;
|
|
private readonly string Viewed;
|
|
private const int MAXFORMAT = PKX.Generation;
|
|
private readonly SummaryPreviewer ShowSet = new();
|
|
|
|
private void ClickView(object sender, EventArgs e)
|
|
{
|
|
var pb = WinFormsUtil.GetUnderlyingControl<PictureBox>(sender);
|
|
int index = Array.IndexOf(PKXBOXES, pb);
|
|
if (!GetShiftedIndex(ref index))
|
|
{
|
|
System.Media.SystemSounds.Exclamation.Play();
|
|
return;
|
|
}
|
|
|
|
if (sender == mnu)
|
|
mnu.Hide();
|
|
|
|
slotSelected = index;
|
|
slotColor = SpriteUtil.Spriter.View;
|
|
FillPKXBoxes(SCR_Box.Value);
|
|
L_Viewed.Text = string.Format(Viewed, Results[index].Identify());
|
|
PKME_Tabs.PopulateFields(Results[index].Entity, false);
|
|
}
|
|
|
|
private void ClickDelete(object sender, EventArgs e)
|
|
{
|
|
var pb = WinFormsUtil.GetUnderlyingControl<PictureBox>(sender);
|
|
int index = Array.IndexOf(PKXBOXES, pb);
|
|
if (!GetShiftedIndex(ref index))
|
|
{
|
|
System.Media.SystemSounds.Exclamation.Play();
|
|
return;
|
|
}
|
|
|
|
var entry = Results[index];
|
|
var pk = entry.Entity;
|
|
|
|
if (entry.Source is SlotInfoFile f)
|
|
{
|
|
// Data from Database: Delete file from disk
|
|
var path = f.Path;
|
|
if (File.Exists(path))
|
|
File.Delete(path);
|
|
}
|
|
else if (entry.Source is SlotInfoBox(var box, var slot) && entry.SAV == SAV)
|
|
{
|
|
// Data from Box: Delete from save file
|
|
var change = new SlotInfoBox(box, slot);
|
|
var pkSAV = change.Read(SAV);
|
|
|
|
if (!pkSAV.DecryptedBoxData.SequenceEqual(pk.DecryptedBoxData)) // data still exists in SAV, unmodified
|
|
{
|
|
WinFormsUtil.Error(MsgDBDeleteFailModified, MsgDBDeleteFailWarning);
|
|
return;
|
|
}
|
|
BoxView.EditEnv.Slots.Delete(change);
|
|
}
|
|
else
|
|
{
|
|
WinFormsUtil.Error(MsgDBDeleteFailBackup, MsgDBDeleteFailWarning);
|
|
return;
|
|
}
|
|
// Remove from database.
|
|
RawDB.Remove(entry);
|
|
Results.Remove(entry);
|
|
// Refresh database view.
|
|
L_Count.Text = string.Format(Counter, Results.Count);
|
|
slotSelected = -1;
|
|
FillPKXBoxes(SCR_Box.Value);
|
|
System.Media.SystemSounds.Asterisk.Play();
|
|
}
|
|
|
|
private void ClickSet(object sender, EventArgs e)
|
|
{
|
|
// Don't care what slot was clicked, just add it to the database
|
|
if (!PKME_Tabs.EditsComplete)
|
|
return;
|
|
|
|
PKM pk = PKME_Tabs.PreparePKM();
|
|
Directory.CreateDirectory(DatabasePath);
|
|
|
|
string path = Path.Combine(DatabasePath, Util.CleanFileName(pk.FileName));
|
|
|
|
if (File.Exists(path))
|
|
{
|
|
WinFormsUtil.Alert(MsgDBAddFailExistsFile);
|
|
return;
|
|
}
|
|
|
|
File.WriteAllBytes(path, pk.DecryptedBoxData);
|
|
|
|
var info = new SlotInfoFile(path);
|
|
var entry = new SlotCache(info, pk);
|
|
Results.Add(entry);
|
|
|
|
// Refresh database view.
|
|
L_Count.Text = string.Format(Counter, Results.Count);
|
|
slotSelected = Results.Count - 1;
|
|
slotColor = SpriteUtil.Spriter.Set;
|
|
if ((SCR_Box.Maximum + 1) * 6 < Results.Count)
|
|
SCR_Box.Maximum++;
|
|
SCR_Box.Value = Math.Max(0, SCR_Box.Maximum - (PKXBOXES.Length / 6) + 1);
|
|
FillPKXBoxes(SCR_Box.Value);
|
|
WinFormsUtil.Alert(MsgDBAddFromTabsSuccess);
|
|
}
|
|
|
|
private bool GetShiftedIndex(ref int index)
|
|
{
|
|
if ((uint)index >= RES_MAX)
|
|
return false;
|
|
index += SCR_Box.Value * RES_MIN;
|
|
return index < Results.Count;
|
|
}
|
|
|
|
private void PopulateComboBoxes()
|
|
{
|
|
// Set the Text
|
|
CB_HeldItem.InitializeBinding();
|
|
CB_Species.InitializeBinding();
|
|
CB_Ability.InitializeBinding();
|
|
CB_Nature.InitializeBinding();
|
|
CB_GameOrigin.InitializeBinding();
|
|
CB_HPType.InitializeBinding();
|
|
|
|
var comboAny = new ComboItem(MsgAny, -1);
|
|
|
|
var species = new List<ComboItem>(GameInfo.SpeciesDataSource);
|
|
species.RemoveAt(0);
|
|
species.Insert(0, comboAny);
|
|
CB_Species.DataSource = species;
|
|
|
|
var items = new List<ComboItem>(GameInfo.ItemDataSource);
|
|
items.Insert(0, comboAny);
|
|
CB_HeldItem.DataSource = items;
|
|
|
|
var natures = new List<ComboItem>(GameInfo.NatureDataSource);
|
|
natures.Insert(0, comboAny);
|
|
CB_Nature.DataSource = natures;
|
|
|
|
var abilities = new List<ComboItem>(GameInfo.AbilityDataSource);
|
|
abilities.Insert(0, comboAny);
|
|
CB_Ability.DataSource = abilities;
|
|
|
|
var versions = new List<ComboItem>(GameInfo.VersionDataSource);
|
|
versions.Insert(0, comboAny);
|
|
versions.RemoveAt(versions.Count - 1); // None
|
|
CB_GameOrigin.DataSource = versions;
|
|
|
|
string[] hptypes = new string[GameInfo.Strings.types.Length - 2];
|
|
Array.Copy(GameInfo.Strings.types, 1, hptypes, 0, hptypes.Length);
|
|
var types = Util.GetCBList(hptypes);
|
|
types.Insert(0, comboAny);
|
|
CB_HPType.DataSource = types;
|
|
|
|
// Set the Move ComboBoxes too..
|
|
var moves = new List<ComboItem>(GameInfo.MoveDataSource);
|
|
moves.RemoveAt(0);
|
|
moves.Insert(0, comboAny);
|
|
{
|
|
foreach (ComboBox cb in new[] { CB_Move1, CB_Move2, CB_Move3, CB_Move4 })
|
|
{
|
|
cb.InitializeBinding();
|
|
cb.DataSource = new BindingSource(moves, null);
|
|
}
|
|
}
|
|
|
|
// Trigger a Reset
|
|
ResetFilters(this, EventArgs.Empty);
|
|
}
|
|
|
|
private void ResetFilters(object sender, EventArgs e)
|
|
{
|
|
CHK_Shiny.Checked = CHK_IsEgg.Checked = true;
|
|
CHK_Shiny.CheckState = CHK_IsEgg.CheckState = CheckState.Indeterminate;
|
|
MT_ESV.Text = string.Empty;
|
|
CB_HeldItem.SelectedIndex = 0;
|
|
CB_Species.SelectedIndex = 0;
|
|
CB_Ability.SelectedIndex = 0;
|
|
CB_Nature.SelectedIndex = 0;
|
|
CB_HPType.SelectedIndex = 0;
|
|
|
|
CB_Level.SelectedIndex = 0;
|
|
TB_Level.Text = string.Empty;
|
|
CB_EVTrain.SelectedIndex = 0;
|
|
CB_IV.SelectedIndex = 0;
|
|
|
|
CB_Move1.SelectedIndex = CB_Move2.SelectedIndex = CB_Move3.SelectedIndex = CB_Move4.SelectedIndex = 0;
|
|
|
|
CB_GameOrigin.SelectedIndex = 0;
|
|
CB_Generation.SelectedIndex = 0;
|
|
|
|
MT_ESV.Visible = L_ESV.Visible = false;
|
|
RTB_Instructions.Clear();
|
|
|
|
if (sender != this)
|
|
System.Media.SystemSounds.Asterisk.Play();
|
|
}
|
|
|
|
private void GenerateDBReport(object sender, EventArgs e)
|
|
{
|
|
if (WinFormsUtil.Prompt(MessageBoxButtons.YesNo, MsgDBCreateReportPrompt, MsgDBCreateReportWarning) != DialogResult.Yes)
|
|
return;
|
|
|
|
if (this.OpenWindowExists<ReportGrid>())
|
|
return;
|
|
|
|
ReportGrid reportGrid = new();
|
|
reportGrid.Show();
|
|
reportGrid.PopulateData(Results);
|
|
}
|
|
|
|
private sealed class SearchFolderDetail
|
|
{
|
|
public string Path { get; }
|
|
public bool IgnoreBackupFiles { get; }
|
|
|
|
public SearchFolderDetail(string path, bool ignoreBackupFiles)
|
|
{
|
|
Path = path;
|
|
IgnoreBackupFiles = ignoreBackupFiles;
|
|
}
|
|
}
|
|
|
|
private void LoadDatabase()
|
|
{
|
|
var settings = Main.Settings;
|
|
var otherPaths = new List<SearchFolderDetail>();
|
|
if (settings.EntityDb.SearchExtraSaves)
|
|
otherPaths.AddRange(settings.Backup.OtherBackupPaths.Where(Directory.Exists).Select(z => new SearchFolderDetail(z, true)));
|
|
if (settings.EntityDb.SearchBackups)
|
|
otherPaths.Add(new SearchFolderDetail(Main.BackupPath, false));
|
|
|
|
RawDB = LoadPKMSaves(DatabasePath, SAV, otherPaths, settings.EntityDb.SearchExtraSavesDeep);
|
|
|
|
// Load stats for pk who do not have any
|
|
foreach (var entry in RawDB)
|
|
{
|
|
var pk = entry.Entity;
|
|
pk.ForcePartyData();
|
|
}
|
|
|
|
try
|
|
{
|
|
while (!IsHandleCreated) { }
|
|
BeginInvoke(new MethodInvoker(() => SetResults(RawDB)));
|
|
}
|
|
catch { /* Window Closed? */ }
|
|
}
|
|
|
|
private static List<SlotCache> LoadPKMSaves(string pkmdb, SaveFile sav, List<SearchFolderDetail> otherPaths, bool otherDeep)
|
|
{
|
|
var dbTemp = new ConcurrentBag<SlotCache>();
|
|
var extensions = new HashSet<string>(PKM.Extensions.Select(z => $".{z}"));
|
|
|
|
var files = Directory.EnumerateFiles(pkmdb, "*", SearchOption.AllDirectories);
|
|
Parallel.ForEach(files, file => SlotInfoLoader.AddFromLocalFile(file, dbTemp, sav, extensions));
|
|
|
|
foreach (var folder in otherPaths)
|
|
{
|
|
if (!SaveUtil.GetSavesFromFolder(folder.Path, otherDeep, out IEnumerable<string> paths, folder.IgnoreBackupFiles))
|
|
continue;
|
|
|
|
Parallel.ForEach(paths, file => TryAddPKMsFromSaveFilePath(dbTemp, file));
|
|
}
|
|
|
|
// Fetch from save file
|
|
SlotInfoLoader.AddFromSaveFile(sav, dbTemp);
|
|
var result = new List<SlotCache>(dbTemp);
|
|
result.RemoveAll(z => !z.IsDataValid());
|
|
|
|
if (Main.Settings.EntityDb.FilterUnavailableSpecies)
|
|
{
|
|
static bool IsPresentInGameSV (ISpeciesForm pk) => pk is PK9 || PersonalTable.SV .IsPresentInGame(pk.Species, pk.Form);
|
|
static bool IsPresentInGameSWSH(ISpeciesForm pk) => pk is PK8 || PersonalTable.SWSH.IsPresentInGame(pk.Species, pk.Form);
|
|
static bool IsPresentInGameBDSP(ISpeciesForm pk) => pk is PB8 || PersonalTable.BDSP.IsPresentInGame(pk.Species, pk.Form);
|
|
static bool IsPresentInGamePLA (ISpeciesForm pk) => pk is PA8 || PersonalTable.LA .IsPresentInGame(pk.Species, pk.Form);
|
|
if (sav is SAV9SV)
|
|
result.RemoveAll(z => !IsPresentInGameSV(z.Entity));
|
|
else if (sav is SAV8SWSH)
|
|
result.RemoveAll(z => !IsPresentInGameSWSH(z.Entity));
|
|
else if (sav is SAV8BS)
|
|
result.RemoveAll(z => !IsPresentInGameBDSP(z.Entity));
|
|
else if (sav is SAV8LA)
|
|
result.RemoveAll(z => !IsPresentInGamePLA(z.Entity));
|
|
}
|
|
|
|
var sort = Main.Settings.EntityDb.InitialSortMode;
|
|
if (sort is DatabaseSortMode.SlotIdentity)
|
|
result.Sort();
|
|
else if (sort is DatabaseSortMode.SpeciesForm)
|
|
result.Sort((first, second) => first.CompareToSpeciesForm(second));
|
|
|
|
// Finalize the Database
|
|
return result;
|
|
}
|
|
|
|
private static void TryAddPKMsFromSaveFilePath(ConcurrentBag<SlotCache> dbTemp, string file)
|
|
{
|
|
var sav = SaveUtil.GetVariantSAV(file);
|
|
if (sav == null)
|
|
{
|
|
Debug.WriteLine("Unable to load SaveFile: " + file);
|
|
return;
|
|
}
|
|
|
|
SlotInfoLoader.AddFromSaveFile(sav, dbTemp);
|
|
}
|
|
|
|
// IO Usage
|
|
private void OpenDB(object sender, EventArgs e)
|
|
{
|
|
if (Directory.Exists(DatabasePath))
|
|
Process.Start("explorer.exe", DatabasePath);
|
|
}
|
|
|
|
private void Menu_Export_Click(object sender, EventArgs e)
|
|
{
|
|
if (Results.Count == 0)
|
|
{ WinFormsUtil.Alert(MsgDBCreateReportFail); return; }
|
|
|
|
if (DialogResult.Yes != WinFormsUtil.Prompt(MessageBoxButtons.YesNo, MsgDBExportResultsPrompt))
|
|
return;
|
|
|
|
using var fbd = new FolderBrowserDialog();
|
|
if (DialogResult.OK != fbd.ShowDialog())
|
|
return;
|
|
|
|
string path = fbd.SelectedPath;
|
|
Directory.CreateDirectory(path);
|
|
|
|
foreach (var pk in Results.Select(z => z.Entity))
|
|
File.WriteAllBytes(Path.Combine(path, Util.CleanFileName(pk.FileName)), pk.DecryptedPartyData);
|
|
}
|
|
|
|
private void Menu_Import_Click(object sender, EventArgs e)
|
|
{
|
|
if (!BoxView.GetBulkImportSettings(out var clearAll, out var overwrite, out var noSetb))
|
|
return;
|
|
|
|
int box = BoxView.Box.CurrentBox;
|
|
int ctr = SAV.LoadBoxes(Results.Select(z => z.Entity), out var result, box, clearAll, overwrite, noSetb);
|
|
if (ctr <= 0)
|
|
return;
|
|
|
|
BoxView.SetPKMBoxes();
|
|
BoxView.UpdateBoxViewers();
|
|
WinFormsUtil.Alert(result);
|
|
}
|
|
|
|
// View Updates
|
|
private IEnumerable<SlotCache> SearchDatabase()
|
|
{
|
|
var settings = GetSearchSettings();
|
|
|
|
IEnumerable<SlotCache> res = RawDB;
|
|
|
|
// pre-filter based on the file path (if specified)
|
|
if (!Menu_SearchBoxes.Checked)
|
|
res = res.Where(z => z.SAV != SAV);
|
|
if (!Menu_SearchDatabase.Checked)
|
|
res = res.Where(z => !IsIndividualFilePKMDB(z));
|
|
if (!Menu_SearchBackups.Checked)
|
|
res = res.Where(z => !IsBackupSaveFile(z));
|
|
|
|
// return filtered results
|
|
return settings.Search(res);
|
|
}
|
|
|
|
private SearchSettings GetSearchSettings()
|
|
{
|
|
var settings = new SearchSettings
|
|
{
|
|
Format = MAXFORMAT - CB_Format.SelectedIndex + 1, // 0->(n-1) => 1->n
|
|
SearchFormat = (SearchComparison)CB_FormatComparator.SelectedIndex,
|
|
Generation = CB_Generation.SelectedIndex,
|
|
|
|
Version = WinFormsUtil.GetIndex(CB_GameOrigin),
|
|
HiddenPowerType = WinFormsUtil.GetIndex(CB_HPType),
|
|
|
|
Species = GetU16(CB_Species),
|
|
Ability = WinFormsUtil.GetIndex(CB_Ability),
|
|
Nature = WinFormsUtil.GetIndex(CB_Nature),
|
|
Item = WinFormsUtil.GetIndex(CB_HeldItem),
|
|
|
|
BatchInstructions = RTB_Instructions.Text,
|
|
|
|
Level = int.TryParse(TB_Level.Text, out var lvl) ? lvl : null,
|
|
SearchLevel = (SearchComparison)CB_Level.SelectedIndex,
|
|
EVType = CB_EVTrain.SelectedIndex,
|
|
IVType = CB_IV.SelectedIndex,
|
|
};
|
|
|
|
static ushort GetU16(ListControl cb)
|
|
{
|
|
var val = WinFormsUtil.GetIndex(cb);
|
|
if (val <= 0)
|
|
return 0;
|
|
return (ushort)val;
|
|
}
|
|
|
|
settings.AddMove(GetU16(CB_Move1));
|
|
settings.AddMove(GetU16(CB_Move2));
|
|
settings.AddMove(GetU16(CB_Move3));
|
|
settings.AddMove(GetU16(CB_Move4));
|
|
|
|
if (CHK_Shiny.CheckState != CheckState.Indeterminate)
|
|
settings.SearchShiny = CHK_Shiny.CheckState == CheckState.Checked;
|
|
|
|
if (CHK_IsEgg.CheckState != CheckState.Indeterminate)
|
|
{
|
|
settings.SearchEgg = CHK_IsEgg.CheckState == CheckState.Checked;
|
|
if (int.TryParse(MT_ESV.Text, out int esv))
|
|
settings.ESV = esv;
|
|
}
|
|
|
|
if (Menu_SearchLegal.Checked != Menu_SearchIllegal.Checked)
|
|
settings.SearchLegal = Menu_SearchLegal.Checked;
|
|
|
|
if (Menu_SearchClones.Checked)
|
|
{
|
|
settings.SearchClones = ModifierKeys switch
|
|
{
|
|
Keys.Control => CloneDetectionMethod.HashPID,
|
|
_ => CloneDetectionMethod.HashDetails,
|
|
};
|
|
}
|
|
|
|
return settings;
|
|
}
|
|
|
|
private async void B_Search_Click(object sender, EventArgs e)
|
|
{
|
|
B_Search.Enabled = false;
|
|
var search = SearchDatabase();
|
|
|
|
bool legalSearch = Menu_SearchLegal.Checked ^ Menu_SearchIllegal.Checked;
|
|
bool wordFilter = ParseSettings.CheckWordFilter;
|
|
if (wordFilter && legalSearch && WinFormsUtil.Prompt(MessageBoxButtons.YesNo, MsgDBSearchLegalityWordfilter) == DialogResult.No)
|
|
ParseSettings.CheckWordFilter = false;
|
|
var results = await Task.Run(() => search.ToList()).ConfigureAwait(true);
|
|
ParseSettings.CheckWordFilter = wordFilter;
|
|
|
|
if (results.Count == 0)
|
|
{
|
|
if (!Menu_SearchBoxes.Checked && !Menu_SearchDatabase.Checked && !Menu_SearchBackups.Checked)
|
|
WinFormsUtil.Alert(MsgDBSearchFail, MsgDBSearchNone);
|
|
else
|
|
WinFormsUtil.Alert(MsgDBSearchNone);
|
|
}
|
|
SetResults(results); // updates Count Label as well.
|
|
System.Media.SystemSounds.Asterisk.Play();
|
|
B_Search.Enabled = true;
|
|
}
|
|
|
|
private void UpdateScroll(object sender, ScrollEventArgs e)
|
|
{
|
|
if (e.OldValue != e.NewValue)
|
|
FillPKXBoxes(e.NewValue);
|
|
}
|
|
|
|
private void SetResults(List<SlotCache> res)
|
|
{
|
|
Results = res;
|
|
ShowSet.Clear();
|
|
|
|
SCR_Box.Maximum = (int)Math.Ceiling((decimal)Results.Count / RES_MIN);
|
|
if (SCR_Box.Maximum > 0) SCR_Box.Maximum--;
|
|
|
|
slotSelected = -1; // reset the slot last viewed
|
|
SCR_Box.Value = 0;
|
|
FillPKXBoxes(0);
|
|
|
|
L_Count.Text = string.Format(Counter, Results.Count);
|
|
B_Search.Enabled = true;
|
|
}
|
|
|
|
private void FillPKXBoxes(int start)
|
|
{
|
|
if (Results.Count == 0)
|
|
{
|
|
for (int i = 0; i < RES_MAX; i++)
|
|
{
|
|
PKXBOXES[i].Image = null;
|
|
PKXBOXES[i].BackgroundImage = null;
|
|
}
|
|
return;
|
|
}
|
|
int begin = start*RES_MIN;
|
|
int end = Math.Min(RES_MAX, Results.Count - begin);
|
|
for (int i = 0; i < end; i++)
|
|
PKXBOXES[i].Image = Results[i + begin].Entity.Sprite(SAV, -1, -1, true);
|
|
for (int i = end; i < RES_MAX; i++)
|
|
PKXBOXES[i].Image = null;
|
|
|
|
for (int i = 0; i < RES_MAX; i++)
|
|
PKXBOXES[i].BackgroundImage = SpriteUtil.Spriter.Transparent;
|
|
if (slotSelected != -1 && slotSelected >= begin && slotSelected < begin + RES_MAX)
|
|
PKXBOXES[slotSelected - begin].BackgroundImage = slotColor ?? SpriteUtil.Spriter.View;
|
|
}
|
|
|
|
// Misc Update Methods
|
|
private void ToggleESV(object sender, EventArgs e) => L_ESV.Visible = MT_ESV.Visible = CHK_IsEgg.CheckState == CheckState.Checked;
|
|
|
|
private void ChangeLevel(object sender, EventArgs e)
|
|
{
|
|
if (CB_Level.SelectedIndex == 0)
|
|
TB_Level.Text = string.Empty;
|
|
}
|
|
|
|
private void ChangeGame(object sender, EventArgs e)
|
|
{
|
|
if (CB_GameOrigin.SelectedIndex != 0)
|
|
CB_Generation.SelectedIndex = 0;
|
|
}
|
|
|
|
private void ChangeGeneration(object sender, EventArgs e)
|
|
{
|
|
if (CB_Generation.SelectedIndex != 0)
|
|
CB_GameOrigin.SelectedIndex = 0;
|
|
}
|
|
|
|
private void Menu_Exit_Click(object sender, EventArgs e) => Close();
|
|
|
|
protected override void OnMouseWheel(MouseEventArgs e)
|
|
{
|
|
if (!DatabasePokeGrid.RectangleToScreen(DatabasePokeGrid.ClientRectangle).Contains(MousePosition))
|
|
return;
|
|
int oldval = SCR_Box.Value;
|
|
int newval = oldval + (e.Delta < 0 ? 1 : -1);
|
|
if (newval >= SCR_Box.Minimum && SCR_Box.Maximum >= newval)
|
|
FillPKXBoxes(SCR_Box.Value = newval);
|
|
}
|
|
|
|
private void ChangeFormatFilter(object sender, EventArgs e)
|
|
{
|
|
if (CB_FormatComparator.SelectedIndex == 0)
|
|
{
|
|
CB_Format.Visible = false; // !any
|
|
CB_Format.SelectedIndex = 0;
|
|
}
|
|
else
|
|
{
|
|
CB_Format.Visible = true;
|
|
int index = MAXFORMAT - SAV.Generation + 1;
|
|
CB_Format.SelectedIndex = index < CB_Format.Items.Count ? index : 0; // SAV generation (offset by 1 for "Any")
|
|
}
|
|
}
|
|
|
|
private void Menu_DeleteClones_Click(object sender, EventArgs e)
|
|
{
|
|
var dr = WinFormsUtil.Prompt(MessageBoxButtons.YesNo,
|
|
MsgDBDeleteCloneWarning + Environment.NewLine +
|
|
MsgDBDeleteCloneAdvice, MsgContinue);
|
|
|
|
if (dr != DialogResult.Yes)
|
|
return;
|
|
|
|
var deleted = 0;
|
|
var db = RawDB.Where(IsIndividualFilePKMDB)
|
|
.OrderByDescending(GetRevisedTime);
|
|
|
|
const CloneDetectionMethod method = CloneDetectionMethod.HashDetails;
|
|
var hasher = SearchUtil.GetCloneDetectMethod(method);
|
|
var duplicates = SearchUtil.GetExtraClones(db, z => hasher(z.Entity));
|
|
foreach (var entry in duplicates)
|
|
{
|
|
var src = entry.Source;
|
|
var path = ((SlotInfoFile)src).Path;
|
|
if (!File.Exists(path))
|
|
continue;
|
|
|
|
try { File.Delete(path); ++deleted; }
|
|
catch (Exception ex) { WinFormsUtil.Error(MsgDBDeleteCloneFail + Environment.NewLine + ex.Message + Environment.NewLine + path); }
|
|
}
|
|
|
|
var boxClear = new BoxManipClearDuplicate<string>(BoxManipType.DeleteClones, pk => SearchUtil.GetCloneDetectMethod(method)(pk));
|
|
var param = new BoxManipParam(0, SAV.BoxCount - 1);
|
|
int count = boxClear.Execute(SAV, param);
|
|
deleted += count;
|
|
|
|
if (deleted == 0)
|
|
{ WinFormsUtil.Alert(MsgDBDeleteCloneNone); return; }
|
|
|
|
WinFormsUtil.Alert(string.Format(MsgFileDeleteCount, deleted), MsgWindowClose);
|
|
BoxView.ReloadSlots();
|
|
|
|
Close();
|
|
}
|
|
|
|
private static DateTime GetRevisedTime(SlotCache arg)
|
|
{
|
|
var src = arg.Source;
|
|
if (src is not SlotInfoFile f)
|
|
return DateTime.Now;
|
|
return File.GetLastWriteTimeUtc(f.Path);
|
|
}
|
|
|
|
private bool IsBackupSaveFile(SlotCache pk) => pk.SAV is not FakeSaveFile && pk.SAV != SAV;
|
|
private bool IsIndividualFilePKMDB(SlotCache pk) => pk.Source is SlotInfoFile f && f.Path.StartsWith(DatabasePath + Path.DirectorySeparatorChar, StringComparison.Ordinal);
|
|
|
|
private void L_Viewed_MouseEnter(object sender, EventArgs e) => hover.SetToolTip(L_Viewed, L_Viewed.Text);
|
|
|
|
private void ShowHoverTextForSlot(object sender, EventArgs e)
|
|
{
|
|
var pb = (PictureBox)sender;
|
|
int index = Array.IndexOf(PKXBOXES, pb);
|
|
if (!GetShiftedIndex(ref index))
|
|
return;
|
|
|
|
ShowSet.Show(pb, Results[index].Entity);
|
|
}
|
|
|
|
private void B_Add_Click(object sender, EventArgs e)
|
|
{
|
|
var s = UC_Builder.Create();
|
|
if (s.Length == 0)
|
|
{ WinFormsUtil.Alert(MsgBEPropertyInvalid); return; }
|
|
|
|
// If we already have text, add a new line (except if the last line is blank).
|
|
var tb = RTB_Instructions;
|
|
var batchText = tb.Text;
|
|
if (batchText.Length > 0 && !batchText.EndsWith('\n'))
|
|
tb.AppendText(Environment.NewLine);
|
|
tb.AppendText(s);
|
|
}
|
|
}
|