Add raw-folder step, redesign UI, remember last DB path, add README
- Split the import flow into explicit steps: import/preview CSV, then a separate "Crea cartella raw" button that looks up CAD paths and copies matched files into raw/ next to the source distinta file. - Redesign the top panel with grouped, auto-sized sections (database vs. import) instead of hand-tuned row heights, fixing overlap/clipping bugs; style the primary action button and polish the results grid. - Remember the last successfully loaded database path in %AppData%\CadSearchGui\ultimo_db.txt so it reloads automatically on future launches regardless of the working directory. - Ignore the /step/ working folder. - Add a README with build/run/publish instructions and project overview. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
98c513dd64
commit
97d53a16dd
3 files changed
+327
-62
No files matched your search
+4
-1
@@ -20,8 +20,11 @@ publish/
|
|||||||
# Stato locale degli strumenti agentici
|
# Stato locale degli strumenti agentici
|
||||||
.claude/
|
.claude/
|
||||||
|
|
||||||
# File Excel/XML della Distinta Base (esportati dal gestionale) e il CSV generato
|
# File Excel/XML della Distinta Base (esportati dal gestionale), il CSV generato
|
||||||
|
# e la cartella con le copie dei file CAD trovati
|
||||||
/*.xls
|
/*.xls
|
||||||
/*.xlsx
|
/*.xlsx
|
||||||
/*.xls.xml
|
/*.xls.xml
|
||||||
/*.csv
|
/*.csv
|
||||||
|
/raw/
|
||||||
|
/step/
|
||||||
+242
-61
@@ -7,15 +7,19 @@ public partial class Form1 : Form
|
|||||||
{
|
{
|
||||||
private readonly Button _btnApriDb = new();
|
private readonly Button _btnApriDb = new();
|
||||||
private readonly Button _btnAggiorna = new();
|
private readonly Button _btnAggiorna = new();
|
||||||
|
private readonly Button _btnCreaRaw = new();
|
||||||
private readonly Label _lblStatus = new();
|
private readonly Label _lblStatus = new();
|
||||||
private readonly Label _lblDb = new();
|
private readonly Label _lblDb = new();
|
||||||
private readonly DataGridView _gridImport = new();
|
private readonly DataGridView _gridImport = new();
|
||||||
private readonly Label _lblImportStatus = new();
|
private readonly Label _lblImportStatus = new();
|
||||||
|
private readonly ToolTip _tipImportStatus = new();
|
||||||
|
|
||||||
private static readonly string[] TipiPredefiniti = { "prt", "asm" };
|
private static readonly string[] TipiPredefiniti = { "prt", "asm" };
|
||||||
private const string RadiceDiscoDefault = @"X:\";
|
private const string RadiceDiscoDefault = @"X:\";
|
||||||
|
|
||||||
private string? _dbPath;
|
private string? _dbPath;
|
||||||
|
private string? _percorsoInputCorrente;
|
||||||
|
private List<(string Componente, string Descrizione)>? _righeCorrenti;
|
||||||
|
|
||||||
public Form1()
|
public Form1()
|
||||||
{
|
{
|
||||||
@@ -24,84 +28,72 @@ public partial class Form1 : Form
|
|||||||
Load += (_, _) => InizializzaDatabase();
|
Load += (_, _) => InizializzaDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Palette: blu primario per l'azione principale del flusso ("Crea cartella raw"),
|
||||||
|
// il resto resta ai colori di sistema per restare coerente col tema Windows dell'utente.
|
||||||
|
private static readonly Color ColorePrimario = Color.FromArgb(0, 99, 177);
|
||||||
|
|
||||||
private void BuildUi()
|
private void BuildUi()
|
||||||
{
|
{
|
||||||
AllowDrop = true;
|
AllowDrop = true;
|
||||||
Text = "Distinta Base -> CSV con percorsi CAD";
|
Text = "Distinta Base -> CSV con percorsi CAD";
|
||||||
|
MinimumSize = new Size(760, 480);
|
||||||
|
Font = new Font("Segoe UI", 9.5f);
|
||||||
|
|
||||||
var topPanel = new TableLayoutPanel
|
var contenutoTop = new TableLayoutPanel
|
||||||
{
|
{
|
||||||
Dock = DockStyle.Top,
|
Dock = DockStyle.Top,
|
||||||
Height = 108,
|
AutoSize = true,
|
||||||
ColumnCount = 3,
|
AutoSizeMode = AutoSizeMode.GrowAndShrink,
|
||||||
RowCount = 3,
|
ColumnCount = 1,
|
||||||
Padding = new Padding(8),
|
Padding = new Padding(12, 12, 12, 0),
|
||||||
};
|
};
|
||||||
topPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
|
contenutoTop.Controls.Add(BuildGruppoDatabase());
|
||||||
topPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 130));
|
contenutoTop.Controls.Add(BuildGruppoImporta());
|
||||||
topPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 130));
|
|
||||||
|
|
||||||
var lblIstruzioni = new Label
|
|
||||||
{
|
|
||||||
Dock = DockStyle.Fill,
|
|
||||||
AutoSize = false,
|
|
||||||
Text = "Trascina qui il file .xls/.xml esportato dal gestionale (foglio 'Distinta "
|
|
||||||
+ "Base'), oppure scegli il file col pulsante 'Scegli file...'. Viene generato "
|
|
||||||
+ "un CSV con Componente/Descrizione e, per ogni componente, il percorso del "
|
|
||||||
+ "file CAD corrispondente trovato nell'indice.",
|
|
||||||
};
|
|
||||||
topPanel.SetColumnSpan(lblIstruzioni, 3);
|
|
||||||
topPanel.Controls.Add(lblIstruzioni, 0, 0);
|
|
||||||
|
|
||||||
var btnSfoglia = new Button { Text = "Scegli file distinta...", Dock = DockStyle.Fill };
|
|
||||||
btnSfoglia.Click += (_, _) => ScegliFileDistinta();
|
|
||||||
topPanel.Controls.Add(btnSfoglia, 0, 1);
|
|
||||||
|
|
||||||
_btnApriDb.Text = "Apri DB...";
|
|
||||||
_btnApriDb.Dock = DockStyle.Fill;
|
|
||||||
_btnApriDb.Click += (_, _) => ScegliDatabase();
|
|
||||||
topPanel.Controls.Add(_btnApriDb, 1, 1);
|
|
||||||
|
|
||||||
_btnAggiorna.Text = "Aggiorna indice";
|
|
||||||
_btnAggiorna.Dock = DockStyle.Fill;
|
|
||||||
_btnAggiorna.Click += (_, _) => AggiornaIndice();
|
|
||||||
topPanel.Controls.Add(_btnAggiorna, 2, 1);
|
|
||||||
|
|
||||||
_lblDb.Dock = DockStyle.Fill;
|
|
||||||
_lblDb.AutoSize = false;
|
|
||||||
_lblDb.ForeColor = SystemColors.GrayText;
|
|
||||||
_lblDb.TextAlign = ContentAlignment.MiddleLeft;
|
|
||||||
topPanel.SetColumnSpan(_lblDb, 3);
|
|
||||||
topPanel.Controls.Add(_lblDb, 0, 2);
|
|
||||||
|
|
||||||
_lblImportStatus.Dock = DockStyle.Top;
|
_lblImportStatus.Dock = DockStyle.Top;
|
||||||
_lblImportStatus.Height = 24;
|
_lblImportStatus.AutoSize = false;
|
||||||
_lblImportStatus.Padding = new Padding(8, 4, 8, 4);
|
_lblImportStatus.AutoEllipsis = true;
|
||||||
|
_lblImportStatus.Height = 28;
|
||||||
|
_lblImportStatus.Padding = new Padding(12, 6, 12, 6);
|
||||||
_lblImportStatus.ForeColor = SystemColors.GrayText;
|
_lblImportStatus.ForeColor = SystemColors.GrayText;
|
||||||
|
|
||||||
_gridImport.Dock = DockStyle.Fill;
|
_gridImport.Dock = DockStyle.Fill;
|
||||||
_gridImport.ReadOnly = true;
|
_gridImport.ReadOnly = true;
|
||||||
|
_gridImport.BorderStyle = BorderStyle.None;
|
||||||
|
_gridImport.BackgroundColor = SystemColors.Window;
|
||||||
|
_gridImport.RowHeadersVisible = false;
|
||||||
_gridImport.AllowUserToAddRows = false;
|
_gridImport.AllowUserToAddRows = false;
|
||||||
_gridImport.AllowUserToDeleteRows = false;
|
_gridImport.AllowUserToDeleteRows = false;
|
||||||
|
_gridImport.AllowUserToResizeRows = false;
|
||||||
_gridImport.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
_gridImport.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||||
_gridImport.MultiSelect = false;
|
_gridImport.MultiSelect = false;
|
||||||
_gridImport.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
|
_gridImport.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
|
||||||
|
_gridImport.ColumnHeadersHeight = 32;
|
||||||
|
_gridImport.ColumnHeadersDefaultCellStyle.Font = new Font(Font, FontStyle.Bold);
|
||||||
|
_gridImport.ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft;
|
||||||
|
_gridImport.RowTemplate.Height = 26;
|
||||||
|
_gridImport.AlternatingRowsDefaultCellStyle.BackColor = Color.FromArgb(245, 247, 250);
|
||||||
|
_gridImport.DefaultCellStyle.SelectionBackColor = ColorePrimario;
|
||||||
|
_gridImport.DefaultCellStyle.Padding = new Padding(4, 0, 4, 0);
|
||||||
_gridImport.Columns.Add("componente", "Componente");
|
_gridImport.Columns.Add("componente", "Componente");
|
||||||
_gridImport.Columns.Add("descrizione", "Descrizione");
|
_gridImport.Columns.Add("descrizione", "Descrizione");
|
||||||
_gridImport.Columns.Add("percorso", "Percorso CAD");
|
_gridImport.Columns.Add("percorso", "Percorso CAD");
|
||||||
|
_gridImport.Columns["componente"]!.FillWeight = 20;
|
||||||
|
_gridImport.Columns["descrizione"]!.FillWeight = 40;
|
||||||
|
_gridImport.Columns["percorso"]!.FillWeight = 40;
|
||||||
_gridImport.CellDoubleClick += (_, _) => ApriCartellaFileSelezionato();
|
_gridImport.CellDoubleClick += (_, _) => ApriCartellaFileSelezionato();
|
||||||
|
|
||||||
var statusPanel = new Panel { Dock = DockStyle.Bottom, Height = 28 };
|
var statusPanel = new Panel { Dock = DockStyle.Bottom, Height = 28, BackColor = SystemColors.ControlLight };
|
||||||
_lblStatus.Dock = DockStyle.Fill;
|
_lblStatus.Dock = DockStyle.Fill;
|
||||||
_lblStatus.TextAlign = ContentAlignment.MiddleLeft;
|
_lblStatus.TextAlign = ContentAlignment.MiddleLeft;
|
||||||
_lblStatus.Padding = new Padding(8, 0, 0, 0);
|
_lblStatus.Padding = new Padding(12, 0, 0, 0);
|
||||||
_lblStatus.Text = "Pronto.";
|
_lblStatus.Text = "Pronto.";
|
||||||
statusPanel.Controls.Add(_lblStatus);
|
statusPanel.Controls.Add(_lblStatus);
|
||||||
|
|
||||||
Controls.Add(_gridImport);
|
Controls.Add(_gridImport);
|
||||||
Controls.Add(_lblImportStatus);
|
Controls.Add(_lblImportStatus);
|
||||||
Controls.Add(statusPanel);
|
Controls.Add(statusPanel);
|
||||||
Controls.Add(topPanel);
|
Controls.Add(contenutoTop);
|
||||||
|
|
||||||
DragEnter += (_, e) =>
|
DragEnter += (_, e) =>
|
||||||
e.Effect = e.Data?.GetDataPresent(DataFormats.FileDrop) == true
|
e.Effect = e.Data?.GetDataPresent(DataFormats.FileDrop) == true
|
||||||
@@ -114,6 +106,112 @@ public partial class Form1 : Form
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private GroupBox BuildGruppoDatabase()
|
||||||
|
{
|
||||||
|
var contenuto = new TableLayoutPanel
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Top,
|
||||||
|
AutoSize = true,
|
||||||
|
AutoSizeMode = AutoSizeMode.GrowAndShrink,
|
||||||
|
ColumnCount = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
_lblDb.AutoSize = true;
|
||||||
|
_lblDb.AutoEllipsis = true;
|
||||||
|
_lblDb.MaximumSize = new Size(900, 0);
|
||||||
|
_lblDb.ForeColor = SystemColors.GrayText;
|
||||||
|
_lblDb.Margin = new Padding(0, 0, 0, 8);
|
||||||
|
contenuto.Controls.Add(_lblDb);
|
||||||
|
|
||||||
|
var bottoni = new FlowLayoutPanel { AutoSize = true, FlowDirection = FlowDirection.LeftToRight };
|
||||||
|
|
||||||
|
_btnApriDb.Text = "Apri DB...";
|
||||||
|
_btnApriDb.Size = new Size(120, 32);
|
||||||
|
_btnApriDb.Margin = new Padding(0, 0, 8, 0);
|
||||||
|
_btnApriDb.Click += (_, _) => ScegliDatabase();
|
||||||
|
bottoni.Controls.Add(_btnApriDb);
|
||||||
|
|
||||||
|
_btnAggiorna.Text = "Aggiorna indice";
|
||||||
|
_btnAggiorna.Size = new Size(120, 32);
|
||||||
|
_btnAggiorna.Click += (_, _) => AggiornaIndice();
|
||||||
|
bottoni.Controls.Add(_btnAggiorna);
|
||||||
|
|
||||||
|
contenuto.Controls.Add(bottoni);
|
||||||
|
|
||||||
|
return new GroupBox
|
||||||
|
{
|
||||||
|
Text = "1. Indice CAD (caricato automaticamente all'avvio)",
|
||||||
|
Dock = DockStyle.Top,
|
||||||
|
AutoSize = true,
|
||||||
|
AutoSizeMode = AutoSizeMode.GrowAndShrink,
|
||||||
|
Padding = new Padding(12, 8, 12, 12),
|
||||||
|
Margin = new Padding(0, 0, 0, 10),
|
||||||
|
Controls = { contenuto },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private GroupBox BuildGruppoImporta()
|
||||||
|
{
|
||||||
|
var contenuto = new TableLayoutPanel
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Top,
|
||||||
|
AutoSize = true,
|
||||||
|
AutoSizeMode = AutoSizeMode.GrowAndShrink,
|
||||||
|
ColumnCount = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
var lblIstruzioni1 = new Label
|
||||||
|
{
|
||||||
|
AutoSize = true,
|
||||||
|
ForeColor = SystemColors.GrayText,
|
||||||
|
Margin = new Padding(0, 0, 0, 0),
|
||||||
|
Text = "2. Trascina qui il file .xls/.xml esportato dal gestionale (foglio 'Distinta "
|
||||||
|
+ "Base'), oppure scegli il file col pulsante sotto: genera un CSV con Componente "
|
||||||
|
+ "e Descrizione, in anteprima nella griglia.",
|
||||||
|
};
|
||||||
|
contenuto.Controls.Add(lblIstruzioni1);
|
||||||
|
|
||||||
|
var btnSfoglia = new Button
|
||||||
|
{
|
||||||
|
Text = "Scegli file distinta...",
|
||||||
|
Size = new Size(220, 32),
|
||||||
|
Margin = new Padding(0, 8, 0, 16),
|
||||||
|
};
|
||||||
|
btnSfoglia.Click += (_, _) => ScegliFileDistinta();
|
||||||
|
contenuto.Controls.Add(btnSfoglia);
|
||||||
|
|
||||||
|
var lblIstruzioni2 = new Label
|
||||||
|
{
|
||||||
|
AutoSize = true,
|
||||||
|
ForeColor = SystemColors.GrayText,
|
||||||
|
Text = "3. Premi qui sotto per cercare il percorso CAD di ogni componente "
|
||||||
|
+ "nell'indice e copiare i file trovati in una cartella 'raw'.",
|
||||||
|
};
|
||||||
|
contenuto.Controls.Add(lblIstruzioni2);
|
||||||
|
|
||||||
|
_btnCreaRaw.Text = "Crea cartella raw";
|
||||||
|
_btnCreaRaw.Size = new Size(220, 36);
|
||||||
|
_btnCreaRaw.Margin = new Padding(0, 8, 0, 0);
|
||||||
|
_btnCreaRaw.Enabled = false;
|
||||||
|
_btnCreaRaw.FlatStyle = FlatStyle.Flat;
|
||||||
|
_btnCreaRaw.FlatAppearance.BorderSize = 0;
|
||||||
|
_btnCreaRaw.BackColor = ColorePrimario;
|
||||||
|
_btnCreaRaw.ForeColor = Color.White;
|
||||||
|
_btnCreaRaw.Font = new Font(Font, FontStyle.Bold);
|
||||||
|
_btnCreaRaw.Click += (_, _) => CreaCartellaRaw();
|
||||||
|
contenuto.Controls.Add(_btnCreaRaw);
|
||||||
|
|
||||||
|
return new GroupBox
|
||||||
|
{
|
||||||
|
Text = "2-3. Importa Distinta Base e crea la cartella raw",
|
||||||
|
Dock = DockStyle.Top,
|
||||||
|
AutoSize = true,
|
||||||
|
AutoSizeMode = AutoSizeMode.GrowAndShrink,
|
||||||
|
Padding = new Padding(12, 8, 12, 12),
|
||||||
|
Controls = { contenuto },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private void ScegliFileDistinta()
|
private void ScegliFileDistinta()
|
||||||
{
|
{
|
||||||
using var dialog = new OpenFileDialog
|
using var dialog = new OpenFileDialog
|
||||||
@@ -130,31 +228,82 @@ public partial class Form1 : Form
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var (csv, righe) = DistintaBaseImporter.ConvertiInCsv(percorso);
|
var (csv, righe) = DistintaBaseImporter.ConvertiInCsv(percorso);
|
||||||
var percorsiTrovati = TrovaPercorsiCad(righe.Select(r => r.Componente));
|
_percorsoInputCorrente = percorso;
|
||||||
|
_righeCorrenti = righe;
|
||||||
|
|
||||||
_gridImport.Rows.Clear();
|
_gridImport.Rows.Clear();
|
||||||
int trovati = 0;
|
|
||||||
foreach (var (componente, descrizione) in righe)
|
foreach (var (componente, descrizione) in righe)
|
||||||
{
|
{
|
||||||
string percorsoCad = percorsiTrovati.TryGetValue(componente, out var lista)
|
_gridImport.Rows.Add(componente, descrizione, "");
|
||||||
? string.Join("; ", lista)
|
|
||||||
: "";
|
|
||||||
if (percorsoCad.Length > 0)
|
|
||||||
trovati++;
|
|
||||||
_gridImport.Rows.Add(componente, descrizione, percorsoCad);
|
|
||||||
}
|
}
|
||||||
|
_btnCreaRaw.Enabled = righe.Count > 0;
|
||||||
|
|
||||||
_lblImportStatus.ForeColor = Color.DarkGreen;
|
ImpostaStatoImport($"CSV generato ({righe.Count} righe): {csv}", Color.DarkGreen);
|
||||||
_lblImportStatus.Text = $"CSV generato ({righe.Count} righe, {trovati} con percorso CAD trovato): {csv}";
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
_percorsoInputCorrente = null;
|
||||||
|
_righeCorrenti = null;
|
||||||
|
_btnCreaRaw.Enabled = false;
|
||||||
_gridImport.Rows.Clear();
|
_gridImport.Rows.Clear();
|
||||||
_lblImportStatus.ForeColor = Color.DarkRed;
|
ImpostaStatoImport($"Errore durante la conversione: {ex.Message}", Color.DarkRed);
|
||||||
_lblImportStatus.Text = $"Errore durante la conversione: {ex.Message}";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Imposta testo/colore dello stato import e il tooltip con il testo completo
|
||||||
|
/// (la label tronca con "..." quando il percorso non ci sta in una riga).</summary>
|
||||||
|
private void ImpostaStatoImport(string testo, Color colore)
|
||||||
|
{
|
||||||
|
_lblImportStatus.ForeColor = colore;
|
||||||
|
_lblImportStatus.Text = testo;
|
||||||
|
_tipImportStatus.SetToolTip(_lblImportStatus, testo);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreaCartellaRaw()
|
||||||
|
{
|
||||||
|
if (_percorsoInputCorrente is null || _righeCorrenti is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var percorsiTrovati = TrovaPercorsiCad(_righeCorrenti.Select(r => r.Componente));
|
||||||
|
|
||||||
|
for (int i = 0; i < _righeCorrenti.Count; i++)
|
||||||
|
{
|
||||||
|
string percorsoCad = percorsiTrovati.TryGetValue(_righeCorrenti[i].Componente, out var lista)
|
||||||
|
? string.Join("; ", lista)
|
||||||
|
: "";
|
||||||
|
_gridImport.Rows[i].Cells[2].Value = percorsoCad;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cartellaRaw = Path.Combine(Path.GetDirectoryName(Path.GetFullPath(_percorsoInputCorrente))!, "raw");
|
||||||
|
int copiati = CopiaFileTrovati(percorsiTrovati.Values.SelectMany(p => p).Distinct(), cartellaRaw);
|
||||||
|
|
||||||
|
ImpostaStatoImport(
|
||||||
|
$"{percorsiTrovati.Count} componenti con percorso CAD trovato su {_righeCorrenti.Count}. "
|
||||||
|
+ $"{copiati} file copiati in {cartellaRaw}",
|
||||||
|
Color.DarkGreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Copia i file trovati nella cartella "raw" indicata, creandola se necessario.
|
||||||
|
/// Ritorna il numero di file copiati con successo.</summary>
|
||||||
|
private static int CopiaFileTrovati(IEnumerable<string> percorsi, string cartellaRaw)
|
||||||
|
{
|
||||||
|
int copiati = 0;
|
||||||
|
foreach (var percorso in percorsi)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(cartellaRaw);
|
||||||
|
File.Copy(percorso, Path.Combine(cartellaRaw, Path.GetFileName(percorso)), overwrite: true);
|
||||||
|
copiati++;
|
||||||
|
}
|
||||||
|
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
|
||||||
|
{
|
||||||
|
// ponytail: file non raggiungibile (share offline, permessi) -> lo si salta, non blocca gli altri
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return copiati;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Cerca, per ogni codice componente, i percorsi dei file CAD (ultima versione,
|
/// <summary>Cerca, per ogni codice componente, i percorsi dei file CAD (ultima versione,
|
||||||
/// solo prt/asm) corrispondenti nell'indice.</summary>
|
/// solo prt/asm) corrispondenti nell'indice.</summary>
|
||||||
private Dictionary<string, List<string>> TrovaPercorsiCad(IEnumerable<string> codici)
|
private Dictionary<string, List<string>> TrovaPercorsiCad(IEnumerable<string> codici)
|
||||||
@@ -195,19 +344,23 @@ public partial class Form1 : Form
|
|||||||
return risultato;
|
return risultato;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly string PercorsoImpostazioni = Path.Combine(
|
||||||
|
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "CadSearchGui", "ultimo_db.txt");
|
||||||
|
|
||||||
private void InizializzaDatabase()
|
private void InizializzaDatabase()
|
||||||
{
|
{
|
||||||
var candidati = new[]
|
var candidati = new[]
|
||||||
{
|
{
|
||||||
|
LeggiUltimoDbUsato(),
|
||||||
Path.Combine(AppContext.BaseDirectory, "cad_index.db"),
|
Path.Combine(AppContext.BaseDirectory, "cad_index.db"),
|
||||||
Path.Combine(Directory.GetCurrentDirectory(), "cad_index.db"),
|
Path.Combine(Directory.GetCurrentDirectory(), "cad_index.db"),
|
||||||
};
|
};
|
||||||
_dbPath = candidati.FirstOrDefault(File.Exists);
|
_dbPath = candidati.FirstOrDefault(p => p is not null && File.Exists(p));
|
||||||
|
|
||||||
if (_dbPath is null)
|
if (_dbPath is null)
|
||||||
{
|
{
|
||||||
_lblStatus.Text = "Database non trovato. Usa 'Apri DB...' per selezionarlo.";
|
_lblStatus.Text = "Database non trovato. Usa 'Apri DB...' per selezionarlo oppure 'Aggiorna indice' per crearlo.";
|
||||||
_lblDb.Text = "Nessun database caricato.";
|
_lblDb.Text = "Nessun database caricato. Premi 'Aggiorna indice' per crearlo da X:\\, oppure 'Apri DB...' se ne hai gi\u00e0 uno.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,6 +392,7 @@ public partial class Form1 : Form
|
|||||||
_dbPath = path;
|
_dbPath = path;
|
||||||
_lblDb.Text = $"Database: {path} ({totale:N0} file indicizzati)";
|
_lblDb.Text = $"Database: {path} ({totale:N0} file indicizzati)";
|
||||||
_lblStatus.Text = "Pronto.";
|
_lblStatus.Text = "Pronto.";
|
||||||
|
SalvaUltimoDbUsato(path);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -247,6 +401,33 @@ public partial class Form1 : Form
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Ricorda l'ultimo DB caricato con successo, così al prossimo avvio si
|
||||||
|
/// ricarica automaticamente anche se l'eseguibile gira da una cartella diversa.</summary>
|
||||||
|
private static string? LeggiUltimoDbUsato()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return File.Exists(PercorsoImpostazioni) ? File.ReadAllText(PercorsoImpostazioni).Trim() : null;
|
||||||
|
}
|
||||||
|
catch (IOException)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SalvaUltimoDbUsato(string path)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(Path.GetDirectoryName(PercorsoImpostazioni)!);
|
||||||
|
File.WriteAllText(PercorsoImpostazioni, path);
|
||||||
|
}
|
||||||
|
catch (IOException)
|
||||||
|
{
|
||||||
|
// ponytail: non critico se non si riesce a salvare, si torna a chiedere "Apri DB..." la prossima volta
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async void AggiornaIndice()
|
private async void AggiornaIndice()
|
||||||
{
|
{
|
||||||
string dbPath = _dbPath ?? Path.Combine(AppContext.BaseDirectory, "cad_index.db");
|
string dbPath = _dbPath ?? Path.Combine(AppContext.BaseDirectory, "cad_index.db");
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
# CadSearchGui
|
||||||
|
|
||||||
|
App Windows Forms (.NET 10) per indicizzare, cercare e recuperare i file CAD
|
||||||
|
Pro-ENGINEER/Creo di un disco/share di rete, e per trasformare l'estrazione
|
||||||
|
"Distinta Base" del gestionale (file `.xls`/`.xml`) in un CSV con il percorso
|
||||||
|
CAD di ogni componente.
|
||||||
|
|
||||||
|
## Funzionalità
|
||||||
|
|
||||||
|
1. **Indice CAD** — all'avvio carica automaticamente `cad_index.db` (se
|
||||||
|
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.
|
||||||
|
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.
|
||||||
|
3. **Crea cartella raw** — cerca nell'indice il percorso CAD di ogni
|
||||||
|
componente importato e copia i file trovati in una cartella `raw/`
|
||||||
|
accanto al file di distinta originale.
|
||||||
|
|
||||||
|
## Requisiti
|
||||||
|
|
||||||
|
- Windows
|
||||||
|
- [.NET 10 SDK](https://dotnet.microsoft.com/download) (per build/run da sorgente)
|
||||||
|
- Accesso alla share di rete con i file CAD (`X:\` di default) per
|
||||||
|
l'indicizzazione
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cd CadSearchGui
|
||||||
|
dotnet build -c Release
|
||||||
|
```
|
||||||
|
|
||||||
|
## Avvio
|
||||||
|
|
||||||
|
Da sorgente:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cd CadSearchGui
|
||||||
|
dotnet run -c Release
|
||||||
|
```
|
||||||
|
|
||||||
|
Oppure l'eseguibile già compilato:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cd CadSearchGui\bin\Release\net10.0-windows
|
||||||
|
.\CadSearchGui.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
## Pubblicazione (eseguibile standalone)
|
||||||
|
|
||||||
|
Genera un `.exe` self-contained per Windows x64, senza bisogno del runtime
|
||||||
|
.NET installato sulla macchina di destinazione:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cd CadSearchGui
|
||||||
|
dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -o publish
|
||||||
|
```
|
||||||
|
|
||||||
|
L'eseguibile risultante è in `CadSearchGui\publish\CadSearchGui.exe`.
|
||||||
|
|
||||||
|
## Struttura del progetto
|
||||||
|
|
||||||
|
Tutto il codice è in `CadSearchGui/` (unico progetto nella solution, GUI e
|
||||||
|
indicizzazione integrate):
|
||||||
|
|
||||||
|
- `Program.cs` — entry point.
|
||||||
|
- `Form1.cs` — finestra principale (indice CAD, import Distinta Base, griglia
|
||||||
|
risultati); UI costruita interamente in codice, nessun designer visuale.
|
||||||
|
- `Indexer.cs` — scansione del disco e scrittura/aggiornamento del DB SQLite.
|
||||||
|
- `DistintaBaseImporter.cs` — parsing del file Distinta Base (SpreadsheetML
|
||||||
|
XML o Excel binario/OpenXML tramite ExcelDataReader) e generazione CSV.
|
||||||
|
- `ProgressForm.cs` — dialog di avanzamento durante l'aggiornamento indice.
|
||||||
|
|
||||||
|
Il database generato (`cad_index.db`), i file Excel/CSV della distinta
|
||||||
|
trascinati nella root e la cartella `raw/` sono rigenerabili e non sono
|
||||||
|
tracciati in git (vedi `.gitignore`).
|
||||||
|
|
||||||
|
Non ci sono test automatizzati nel repo.
|
||||||
Reference in new issue
Block a user