Index Unificati/Commerciali, merge cleanup buttons, report unmatched components
- Add 'Unificati' and 'Commerciali' as indexed root folders alongside the existing four, updating Indexer.CartelleRadice and the docs. - Replace the separate "Pulisci cartella raw" / "Pulisci cartella step" buttons with a single "Pulisci raw e step" that clears both under one confirmation; falls back to a folder picker when no path is known yet in the session instead of staying disabled. - "Trova componenti referenziati" now also writes a persistent summary (PRT/sub-assemblies found and copied, codes not found) to the main window's status line, not just the popup dialog, and reports clearly when no database is loaded instead of failing silently. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e56a3be5b4
commit
146ce78eae
4 files changed
+92
-8
No files matched your search
@@ -5,9 +5,9 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
||||
## Cos'è questo progetto
|
||||
|
||||
`CadSearchGui` è un'app Windows Forms (.NET 10, WinForms) che indicizza e permette di
|
||||
cercare i file CAD Pro-ENGINEER/Creo contenuti in quattro cartelle di un disco/share
|
||||
di rete (`__Accessori`, `__B.end`, `__Corpi`, `__Fondi` sotto una radice, di default
|
||||
`X:\`), salvando i metadati in un DB SQLite locale (`cad_index.db`).
|
||||
cercare i file CAD Pro-ENGINEER/Creo contenuti in sei cartelle di un disco/share
|
||||
di rete (`__Accessori`, `__B.end`, `__Corpi`, `__Fondi`, `Unificati`, `Commerciali` sotto una radice,
|
||||
di default `X:\`), salvando i metadati in un DB SQLite locale (`cad_index.db`).
|
||||
|
||||
## Comandi
|
||||
|
||||
@@ -39,7 +39,7 @@ entrambi rimossi: ora l'unico programma è questo, con GUI e indicizzazione inte
|
||||
`_grid`, ecc.). `Form1.Designer.cs` contiene solo lo scheletro minimo
|
||||
(`InitializeComponent`/`Dispose`) generato dal template.
|
||||
- **Indexer.cs** — logica di scansione del disco e scrittura/aggiornamento del DB
|
||||
SQLite (`Indexer.ScanAsync`). Cammina le 4 cartelle radice (`Indexer.CartelleRadice`)
|
||||
SQLite (`Indexer.ScanAsync`). Cammina le 6 cartelle radice (`Indexer.CartelleRadice`)
|
||||
con un walk manuale a stack (`Walk`, più veloce di `EnumerateFiles(..., AllDirectories)`
|
||||
su share di rete con centinaia di migliaia di file), estrae da ogni nome file il
|
||||
pattern Pro-E `<codice>.<tipo>.<versione>` via regex, e fa un upsert incrementale
|
||||
|
||||
+86
-2
@@ -9,6 +9,7 @@ public partial class Form1 : Form
|
||||
private readonly Button _btnAggiorna = new();
|
||||
private readonly Button _btnCreaRaw = new();
|
||||
private readonly Button _btnTrovaPrt = new();
|
||||
private readonly Button _btnPulisci = new();
|
||||
private readonly Label _lblStatus = new();
|
||||
private readonly Label _lblDb = new();
|
||||
private readonly DataGridView _gridImport = new();
|
||||
@@ -221,6 +222,22 @@ public partial class Form1 : Form
|
||||
_btnTrovaPrt.Click += (_, _) => TrovaPrtReferenziati();
|
||||
contenuto.Controls.Add(_btnTrovaPrt);
|
||||
|
||||
var lblManutenzione = new Label
|
||||
{
|
||||
AutoSize = true,
|
||||
ForeColor = SystemColors.GrayText,
|
||||
Margin = new Padding(0, 16, 0, 0),
|
||||
Text = "Manutenzione: svuota le cartelle 'raw' e 'step' nella root prima di un "
|
||||
+ "nuovo giro (non tocca l'indice, solo le copie locali).",
|
||||
};
|
||||
contenuto.Controls.Add(lblManutenzione);
|
||||
|
||||
_btnPulisci.Text = "Pulisci raw e step";
|
||||
_btnPulisci.Size = new Size(200, 30);
|
||||
_btnPulisci.Margin = new Padding(0, 6, 0, 0);
|
||||
_btnPulisci.Click += (_, _) => PulisciRawEStep();
|
||||
contenuto.Controls.Add(_btnPulisci);
|
||||
|
||||
return new GroupBox
|
||||
{
|
||||
Text = "2-4. Importa Distinta Base, crea la cartella raw e risolvi i componenti referenziati",
|
||||
@@ -305,6 +322,61 @@ public partial class Form1 : Form
|
||||
Color.DarkGreen);
|
||||
}
|
||||
|
||||
/// <summary>Svuota in un colpo solo le cartelle "raw" e "step" nella root (stessa cartella
|
||||
/// base del file distinta importato), previa un'unica conferma. Non tocca l'indice CAD: solo
|
||||
/// le copie locali generate dalla pipeline.</summary>
|
||||
private void PulisciRawEStep()
|
||||
{
|
||||
string radice;
|
||||
if (_ultimaCartellaRaw is not null)
|
||||
{
|
||||
radice = Path.GetDirectoryName(_ultimaCartellaRaw)!;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Non abbiamo ancora una cartella nota in questa sessione (es. app appena riaperta):
|
||||
// si chiede all'utente di indicare la root invece di tenere il pulsante disabilitato.
|
||||
using var dialog = new FolderBrowserDialog { Description = "Seleziona la cartella root (contiene 'raw' e 'step')" };
|
||||
if (dialog.ShowDialog(this) != DialogResult.OK)
|
||||
return;
|
||||
radice = dialog.SelectedPath;
|
||||
}
|
||||
|
||||
var cartelle = new[] { Path.Combine(radice, "raw"), Path.Combine(radice, "step") }
|
||||
.Where(Directory.Exists)
|
||||
.ToList();
|
||||
if (cartelle.Count == 0)
|
||||
{
|
||||
ImpostaStatoImport($"Nessuna cartella 'raw' o 'step' trovata in {radice}.", Color.DarkRed);
|
||||
return;
|
||||
}
|
||||
|
||||
var conferma = MessageBox.Show(this,
|
||||
$"Eliminare tutti i file in:\n{string.Join("\n", cartelle)}\n\nL'operazione non è reversibile.",
|
||||
"Pulisci raw e step", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
||||
if (conferma != DialogResult.Yes)
|
||||
return;
|
||||
|
||||
int eliminati = 0;
|
||||
foreach (var cartella in cartelle)
|
||||
{
|
||||
foreach (var file in Directory.GetFiles(cartella))
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(file);
|
||||
eliminati++;
|
||||
}
|
||||
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
|
||||
{
|
||||
// ponytail: file in uso (es. aperto in Creo) -> si salta, non blocca gli altri
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImpostaStatoImport($"{eliminati} file eliminati da {string.Join(" e ", cartelle)}.", Color.DarkGreen);
|
||||
}
|
||||
|
||||
/// <summary>Risolve ricorsivamente l'albero dei componenti a partire dagli .asm in "raw":
|
||||
/// per ogni assieme legge i codici referenziati al suo interno, li cerca nell'indice, copia
|
||||
/// in "raw" quelli trovati e, se sono a loro volta assiemi, li accoda per essere scansionati
|
||||
@@ -314,6 +386,12 @@ public partial class Form1 : Form
|
||||
if (_ultimaCartellaRaw is null || !Directory.Exists(_ultimaCartellaRaw))
|
||||
return;
|
||||
|
||||
if (_dbPath is null)
|
||||
{
|
||||
ImpostaStatoImport("Nessun database caricato: impossibile risolvere i componenti referenziati.", Color.DarkRed);
|
||||
return;
|
||||
}
|
||||
|
||||
var daScansionare = new Queue<string>(
|
||||
Directory.GetFiles(_ultimaCartellaRaw).Where(f => Path.GetFileName(f).Contains(".asm.")));
|
||||
var codiciVisti = new HashSet<string>(daScansionare.Select(f => Path.GetFileName(f).Split('.')[0]));
|
||||
@@ -321,9 +399,8 @@ public partial class Form1 : Form
|
||||
var trovati = new List<(string Codice, string Tipo, string Percorso)>();
|
||||
int codiciNonTrovati = 0;
|
||||
|
||||
if (_dbPath is not null)
|
||||
using (var connection = new SqliteConnection($"Data Source={_dbPath};Mode=ReadOnly"))
|
||||
{
|
||||
using var connection = new SqliteConnection($"Data Source={_dbPath};Mode=ReadOnly");
|
||||
connection.Open();
|
||||
using var command = connection.CreateCommand();
|
||||
command.CommandText = "SELECT tipo_file, percorso_completo FROM files_ultima_versione "
|
||||
@@ -367,6 +444,13 @@ public partial class Form1 : Form
|
||||
}
|
||||
}
|
||||
|
||||
int numPrt = trovati.Count(r => r.Tipo == "prt");
|
||||
int numAsm = trovati.Count(r => r.Tipo == "asm");
|
||||
ImpostaStatoImport(
|
||||
$"Componenti referenziati: {numPrt} PRT e {numAsm} sotto-assiemi trovati e copiati in raw, "
|
||||
+ $"{codiciNonTrovati} codici referenziati non trovati nell'indice.",
|
||||
Color.DarkGreen);
|
||||
|
||||
using var dialog = new PrtMancantiForm(trovati, codiciNonTrovati, _ultimaCartellaRaw);
|
||||
dialog.ShowDialog(this);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ public sealed record ScanProgress(
|
||||
|
||||
public static class Indexer
|
||||
{
|
||||
public static readonly string[] CartelleRadice = { "__Accessori", "__B.end", "__Corpi", "__Fondi" };
|
||||
public static readonly string[] CartelleRadice = { "__Accessori", "__B.end", "__Corpi", "__Fondi", "Unificati", "Commerciali" };
|
||||
|
||||
private static readonly Regex FilenameRegex =
|
||||
new(@"^(?<codice>.+)\.(?<tipo>[A-Za-z0-9]+)\.(?<versione>\d+)$", RegexOptions.Compiled);
|
||||
|
||||
@@ -11,7 +11,7 @@ CAD di ogni componente.
|
||||
presente accanto all'eseguibile). Se manca, si può selezionare un DB
|
||||
esistente con **Apri DB...** o generarne uno nuovo con **Aggiorna
|
||||
indice**, che scansiona il disco (di default `X:\`, cartelle
|
||||
`__Accessori`, `__B.end`, `__Corpi`, `__Fondi`) e indicizza tutti i file.
|
||||
`__Accessori`, `__B.end`, `__Corpi`, `__Fondi`, `Unificati`, `Commerciali`) e indicizza tutti i file.
|
||||
2. **Importa Distinta Base** — trascina (o scegli da file) l'estrazione
|
||||
`.xls`/`.xml` del gestionale (foglio "Distinta Base", colonne
|
||||
Componente/Descrizione): viene generato un CSV con anteprima in griglia.
|
||||
|
||||
Reference in new issue
Block a user