Aggiungi menu Nuovo estrazione/Guida, rimuovi verifica completezza assiemi
"File -> Nuova estrazione" (Ctrl+N) azzera distinta/raw/verifica per ripartire senza ricaricare DB e cartella di lavoro; "Aiuto -> Guida" (F1) apre una sintesi interattiva delle 5 fasi. Rimossa "Verifica completezza assiemi": bottone, ReportCompletezzaForm e VerificaCompletezzaAssiemi non più necessari. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d9f16f2844
commit
28aa16837b
5 files changed
+149
-195
No files matched your search
+41
-118
@@ -10,7 +10,6 @@ public partial class Form1 : Form
|
||||
private readonly Button _btnCreaRaw = new();
|
||||
private readonly Button _btnTrovaPrt = new();
|
||||
private readonly Button _btnVerifica = new();
|
||||
private readonly Button _btnCompletezza = new();
|
||||
private readonly ListView _lstAnteprimaAsm = new();
|
||||
private readonly Button _btnPulisci = new();
|
||||
private readonly Label _lblStatus = new();
|
||||
@@ -22,6 +21,8 @@ public partial class Form1 : Form
|
||||
private readonly DataGridView _gridRaw = new();
|
||||
private readonly Label _lblImportStatus = new();
|
||||
private readonly ToolTip _tipImportStatus = new();
|
||||
private readonly MenuStrip _menu = new();
|
||||
private readonly ToolStripMenuItem _mnuNuovaEstrazione = new("Nuova estrazione");
|
||||
|
||||
// Wizard: una fase alla volta occupa tutta la finestra, si avanza solo quando quella
|
||||
// corrente è "pronta" (vedi AvantiConsentito). NomiFasi/_panelFasi sono paralleli per indice.
|
||||
@@ -146,10 +147,25 @@ public partial class Form1 : Form
|
||||
// Ordine dei Dock.Bottom: l'ultimo aggiunto è il più esterno (il vero bordo inferiore
|
||||
// della finestra). La barra di stato va tra contenuto e azioni; i bottoni Avanti/Indietro
|
||||
// restano il footer più esterno, come in ogni wizard/dialog standard di Windows.
|
||||
var mnuFile = new ToolStripMenuItem("File");
|
||||
_mnuNuovaEstrazione.ShortcutKeys = Keys.Control | Keys.N;
|
||||
_mnuNuovaEstrazione.Click += (_, _) => NuovaEstrazione();
|
||||
mnuFile.DropDownItems.Add(_mnuNuovaEstrazione);
|
||||
|
||||
var mnuAiuto = new ToolStripMenuItem("Aiuto");
|
||||
var mnuGuida = new ToolStripMenuItem("Guida") { ShortcutKeys = Keys.F1 };
|
||||
mnuGuida.Click += (_, _) => new GuidaForm().ShowDialog(this);
|
||||
mnuAiuto.DropDownItems.Add(mnuGuida);
|
||||
|
||||
_menu.Items.Add(mnuFile);
|
||||
_menu.Items.Add(mnuAiuto);
|
||||
MainMenuStrip = _menu;
|
||||
|
||||
Controls.Add(_faseContainer);
|
||||
Controls.Add(statusPanel);
|
||||
Controls.Add(navContainer);
|
||||
Controls.Add(headerPanel);
|
||||
Controls.Add(_menu);
|
||||
|
||||
DragEnter += (_, e) =>
|
||||
e.Effect = e.Data?.GetDataPresent(DataFormats.FileDrop) == true
|
||||
@@ -236,6 +252,30 @@ public partial class Form1 : Form
|
||||
|
||||
private void AggiornaStatoAvanti() => _btnAvanti.Enabled = AvantiConsentito(_faseAttuale);
|
||||
|
||||
/// <summary>Azzera distinta/raw/verifica (fasi 2-5) per ripartire con una nuova distinta;
|
||||
/// DB indicizzato e cartella di lavoro (fase 1) restano quelli già caricati, non serve
|
||||
/// rifare lo scan del disco per ogni estrazione.</summary>
|
||||
private void NuovaEstrazione()
|
||||
{
|
||||
if (_dbPath is null || _cartellaLavoro is null)
|
||||
{
|
||||
MessageBox.Show(this, "Carica prima il database in fase 1.", "Nuova estrazione",
|
||||
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
return;
|
||||
}
|
||||
|
||||
_percorsoInputCorrente = null;
|
||||
_righeCorrenti = null;
|
||||
_ultimaCartellaRaw = null;
|
||||
_ultimaVerifica = null;
|
||||
_gridImport.Rows.Clear();
|
||||
_gridRaw.Rows.Clear();
|
||||
_lstAnteprimaAsm.Items.Clear();
|
||||
ImpostaStatoImport("", Color.Black);
|
||||
|
||||
VaiAllaFase(1);
|
||||
}
|
||||
|
||||
private Panel BuildFaseDatabase()
|
||||
{
|
||||
var contenuto = new TableLayoutPanel
|
||||
@@ -516,27 +556,6 @@ public partial class Form1 : Form
|
||||
};
|
||||
top.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
|
||||
|
||||
var lblIstruzioniCompletezza = new Label
|
||||
{
|
||||
Dock = DockStyle.Top,
|
||||
AutoSize = true,
|
||||
ForeColor = SystemColors.GrayText,
|
||||
Margin = new Padding(0, 0, 0, 8),
|
||||
Text = "Per ogni assieme della distinta, verifica se tutti i suoi componenti "
|
||||
+ "(ricorsivamente fino ai PRT) sono nell'indice. Nota: la scansione dei .asm "
|
||||
+ "è euristica, quindi qualche falso 'incompleto' è possibile.",
|
||||
};
|
||||
top.Controls.Add(lblIstruzioniCompletezza);
|
||||
|
||||
// Primario: è l'azione principale di questa fase, non una scelta secondaria — prima
|
||||
// era uno stile grigio che si confondeva con lo sfondo.
|
||||
_btnCompletezza.Text = "Verifica completezza assiemi";
|
||||
_btnCompletezza.Margin = new Padding(0, 0, 0, 12);
|
||||
UiStile.Primario(_btnCompletezza);
|
||||
UiStile.Arrotonda(_btnCompletezza);
|
||||
_btnCompletezza.Click += (_, _) => VerificaCompletezzaAssiemi();
|
||||
top.Controls.Add(_btnCompletezza);
|
||||
|
||||
var lblAnteprimaAsm = new Label
|
||||
{
|
||||
AutoSize = true,
|
||||
@@ -1007,102 +1026,6 @@ public partial class Form1 : Form
|
||||
dialog.ShowDialog(this);
|
||||
}
|
||||
|
||||
/// <summary>Per ogni assieme della distinta, verifica ricorsivamente (leggendo i .asm dai
|
||||
/// percorsi originali sulla share) se tutti i componenti fino ai PRT sono nell'indice.
|
||||
/// I risultati di ogni file/codice vengono in cache e condivisi tra gli assiemi controllati
|
||||
/// nella stessa passata, per non rileggere più volte gli stessi sotto-componenti.</summary>
|
||||
private void VerificaCompletezzaAssiemi()
|
||||
{
|
||||
if (_righeCorrenti is null)
|
||||
return;
|
||||
if (_dbPath is null)
|
||||
{
|
||||
ImpostaStatoImport("Nessun database caricato: impossibile verificare la completezza.", Color.DarkRed);
|
||||
return;
|
||||
}
|
||||
|
||||
var codiciNoti = CaricaCodiciNoti(_dbPath);
|
||||
var cacheCodiciFile = new Dictionary<string, HashSet<string>>();
|
||||
|
||||
List<(string Tipo, string Percorso)> CercaComponenti(string codice) =>
|
||||
codiciNoti.TryGetValue(codice, out var trovati) ? trovati : new List<(string, string)>();
|
||||
|
||||
bool AssiemeCompleto(string percorsoAsmIniziale)
|
||||
{
|
||||
var daVisitare = new Queue<string>();
|
||||
daVisitare.Enqueue(percorsoAsmIniziale);
|
||||
var fileVisitati = new HashSet<string> { percorsoAsmIniziale };
|
||||
var codiceIniziale = Path.GetFileName(percorsoAsmIniziale).Split('.')[0];
|
||||
var codiciVisti = new HashSet<string>
|
||||
{
|
||||
codiceIniziale,
|
||||
AssemblyComponentScanner.CodiceRadice(codiceIniziale),
|
||||
};
|
||||
|
||||
while (daVisitare.Count > 0)
|
||||
{
|
||||
var file = daVisitare.Dequeue();
|
||||
if (!cacheCodiciFile.TryGetValue(file, out var codiciReferenziati))
|
||||
{
|
||||
try
|
||||
{
|
||||
codiciReferenziati = EstraiCodiciReferenziati(file, codiciNoti.Keys).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
|
||||
{
|
||||
return false; // file irraggiungibile (share offline) -> non verificabile, per prudenza "incompleto"
|
||||
}
|
||||
cacheCodiciFile[file] = codiciReferenziati;
|
||||
}
|
||||
|
||||
foreach (var codice in codiciReferenziati)
|
||||
{
|
||||
if (!codiciVisti.Add(codice))
|
||||
continue;
|
||||
|
||||
var componenti = CercaComponenti(codice);
|
||||
if (componenti.Count == 0)
|
||||
return false;
|
||||
|
||||
foreach (var (tipo, percorso) in componenti)
|
||||
{
|
||||
if (tipo == "asm" && fileVisitati.Add(percorso))
|
||||
{
|
||||
daVisitare.Enqueue(percorso);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// L'assieme generale è già una riga di _righeCorrenti (vedi DistintaBaseImporter), quindi
|
||||
// la sua completezza viene verificata insieme a quella di tutti gli altri componenti.
|
||||
var righeReport = new List<(string Componente, string Descrizione, bool? Completo)>();
|
||||
foreach (var (componente, descrizione) in _righeCorrenti)
|
||||
{
|
||||
var componenti = CercaComponenti(componente);
|
||||
string? percorsoAsm = componenti.Where(c => c.Tipo == "asm").Select(c => c.Percorso).FirstOrDefault();
|
||||
|
||||
bool? completo = componenti.Count == 0 ? null
|
||||
: percorsoAsm is null ? true // solo prt trovato: nessuna sotto-struttura da verificare
|
||||
: AssiemeCompleto(percorsoAsm);
|
||||
|
||||
righeReport.Add((componente, descrizione, completo));
|
||||
}
|
||||
|
||||
int completi = righeReport.Count(r => r.Completo == true);
|
||||
int incompleti = righeReport.Count(r => r.Completo == false);
|
||||
int nonTrovati = righeReport.Count(r => r.Completo is null);
|
||||
ImpostaStatoImport(
|
||||
$"Completezza assiemi: {completi} completi, {incompleti} incompleti, "
|
||||
+ $"{nonTrovati} non trovati nell'indice.",
|
||||
Color.DarkGreen);
|
||||
|
||||
using var dialogCompletezza = new ReportCompletezzaForm(righeReport);
|
||||
dialogCompletezza.ShowDialog(this);
|
||||
}
|
||||
|
||||
/// <summary>Copia i file trovati nella cartella "raw" indicata, creandola se necessario.
|
||||
/// Ritorna il numero di file copiati con successo. Parallelizzata (grado limitato): il
|
||||
/// collo di bottiglia è la latenza di rete verso la share, non la CPU, quindi poche copie
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
namespace PrepStep;
|
||||
|
||||
/// <summary>Guida interattiva richiamabile da "Aiuto ▸ Guida" (F1): sintesi delle 5 fasi del
|
||||
/// wizard, per chi apre l'app senza aver letto i docs. Il dettaglio completo (formato .asm,
|
||||
/// schema DB, ecc.) resta solo in docs/architettura.md e affini, per non duplicarlo qui.</summary>
|
||||
public class GuidaForm : Form
|
||||
{
|
||||
private static readonly (string Titolo, string Testo)[] Sezioni =
|
||||
{
|
||||
("Panoramica", """
|
||||
Cevolani StepPrep prepara i file CAD Pro-ENGINEER/Creo da passare a Creo
|
||||
Distributed Batch per l'esportazione STEP: indicizza i file di una share di
|
||||
rete e guida attraverso 5 fasi, una alla volta, con "Avanti"/"Indietro".
|
||||
|
||||
"File ▸ Nuova estrazione" (Ctrl+N) azzera distinta/raw/verifica per
|
||||
ripartire con una nuova distinta base, senza dover ricaricare il database.
|
||||
"""),
|
||||
("1. Database", """
|
||||
Carica o aggiorna l'indice "cad_index.db" a partire dalle cartelle di primo
|
||||
livello del disco/share (radice di default X:\). Qui si sceglie anche la
|
||||
cartella di lavoro, dove finiscono CSV, "raw" e "step".
|
||||
"""),
|
||||
("2. Importa Distinta Base", """
|
||||
Converte il file della distinta (trascinabile nella finestra) in un CSV
|
||||
componente;descrizione nella cartella di lavoro. Se il file segue la
|
||||
convenzione del gestionale, aggiunge anche l'assieme generale come riga.
|
||||
"""),
|
||||
("3. Crea cartella raw", """
|
||||
Cerca nell'indice i file CAD dei componenti del CSV e li copia nella
|
||||
sottocartella "raw" della cartella di lavoro.
|
||||
"""),
|
||||
("4. Trova componenti referenziati", """
|
||||
Legge i file .asm già in "raw" per risolvere ricorsivamente sotto-assiemi e
|
||||
parti citate, copiando anche quelli in "raw": componenti soppressi (non in
|
||||
distinta ma necessari per aprire l'assieme) e riferimenti esterni (assembly
|
||||
feature, datum copiati) inclusi.
|
||||
"""),
|
||||
("5. Verifica completezza", """
|
||||
Mostra i file .asm della distinta già in "raw", trascinabili su Creo per
|
||||
l'esportazione STEP (passo manuale, fuori da quest'app). "Verifica
|
||||
completezza assiemi" controlla che tutti i sotto-componenti risultino
|
||||
presenti nell'indice.
|
||||
"""),
|
||||
};
|
||||
|
||||
public GuidaForm()
|
||||
{
|
||||
Text = "Guida";
|
||||
ClientSize = new Size(640, 420);
|
||||
MinimumSize = new Size(480, 320);
|
||||
StartPosition = FormStartPosition.CenterParent;
|
||||
Font = new Font("Segoe UI", 9.5f);
|
||||
|
||||
var lista = new ListBox
|
||||
{
|
||||
Dock = DockStyle.Left,
|
||||
Width = 200,
|
||||
IntegralHeight = false,
|
||||
BorderStyle = BorderStyle.None,
|
||||
};
|
||||
foreach (var (titolo, _) in Sezioni)
|
||||
lista.Items.Add(titolo);
|
||||
|
||||
var testo = new RichTextBox
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
ReadOnly = true,
|
||||
BorderStyle = BorderStyle.None,
|
||||
BackColor = Color.White,
|
||||
Font = new Font(Font.FontFamily, 10f),
|
||||
};
|
||||
|
||||
lista.SelectedIndexChanged += (_, _) =>
|
||||
{
|
||||
if (lista.SelectedIndex >= 0)
|
||||
testo.Text = Sezioni[lista.SelectedIndex].Testo.Trim();
|
||||
};
|
||||
|
||||
var btnChiudi = new Button { Text = "Chiudi", Dock = DockStyle.Bottom, Height = 34 };
|
||||
UiStile.Secondario(btnChiudi);
|
||||
btnChiudi.Click += (_, _) => Close();
|
||||
|
||||
var contenuto = new Panel { Dock = DockStyle.Fill, Padding = new Padding(16) };
|
||||
contenuto.Controls.Add(testo);
|
||||
Controls.Add(contenuto);
|
||||
Controls.Add(lista);
|
||||
Controls.Add(btnChiudi);
|
||||
|
||||
lista.SelectedIndex = 0;
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
namespace PrepStep;
|
||||
|
||||
/// <summary>Mostra, per ogni assieme della distinta base, se tutti i suoi componenti
|
||||
/// (ricorsivamente fino ai PRT) sono presenti nell'indice (v) o mancano (x).</summary>
|
||||
public class ReportCompletezzaForm : Form
|
||||
{
|
||||
public ReportCompletezzaForm(List<(string Componente, string Descrizione, bool? Completo)> righe)
|
||||
{
|
||||
int completi = righe.Count(r => r.Completo == true);
|
||||
int incompleti = righe.Count(r => r.Completo == false);
|
||||
int nonTrovati = righe.Count(r => r.Completo is null);
|
||||
|
||||
Text = "Completezza assiemi";
|
||||
ClientSize = new Size(720, 440);
|
||||
StartPosition = FormStartPosition.CenterParent;
|
||||
Font = new Font("Segoe UI", 9.5f);
|
||||
|
||||
var lblInfo = new Label
|
||||
{
|
||||
Dock = DockStyle.Top,
|
||||
AutoSize = true,
|
||||
Padding = new Padding(12, 8, 12, 8),
|
||||
Text = $"{completi} completi, {incompleti} incompleti, {nonTrovati} non trovati nell'indice "
|
||||
+ $"su {righe.Count} componenti. Nota: la scansione dei .asm è euristica, qualche "
|
||||
+ "falso 'incompleto' è possibile.",
|
||||
};
|
||||
|
||||
var grid = new DataGridView
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
ReadOnly = true,
|
||||
AllowUserToAddRows = false,
|
||||
AllowUserToDeleteRows = false,
|
||||
RowHeadersVisible = false,
|
||||
SelectionMode = DataGridViewSelectionMode.FullRowSelect,
|
||||
AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill,
|
||||
};
|
||||
grid.Columns.Add("componente", "Componente");
|
||||
grid.Columns.Add("descrizione", "Descrizione");
|
||||
grid.Columns.Add("completo", "Completo");
|
||||
grid.Columns["componente"]!.FillWeight = 20;
|
||||
grid.Columns["descrizione"]!.FillWeight = 55;
|
||||
grid.Columns["completo"]!.FillWeight = 25;
|
||||
|
||||
foreach (var (componente, descrizione, completo) in righe.OrderBy(r => r.Completo).ThenBy(r => r.Componente))
|
||||
{
|
||||
string testo = completo switch { true => "✓", false => "✗", null => "?" };
|
||||
int i = grid.Rows.Add(componente, descrizione, testo);
|
||||
grid.Rows[i].DefaultCellStyle.ForeColor = completo switch
|
||||
{
|
||||
true => Color.DarkGreen,
|
||||
false => Color.DarkRed,
|
||||
null => Color.Gray,
|
||||
};
|
||||
grid.Rows[i].Cells["completo"].Style.Alignment = DataGridViewContentAlignment.MiddleCenter;
|
||||
}
|
||||
|
||||
Controls.Add(grid);
|
||||
Controls.Add(lblInfo);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user