private void listBox_MeasureItem(object sender, MeasureItemEventArgs e)
        {
            if (e.Index < 0 || e.Index >= listBox.Items.Count)
            {
                return;
            }
            ProgressItem pi = listBox.Items[e.Index] as ProgressItem;

            if (pi == null)
            {
                return;
            }
            e.ItemHeight = 10;
            if (pi.Title != null)
            {
                e.ItemHeight += 16;
            }
            if (pi.Info != null)
            {
                e.ItemHeight += 14;
            }
            if (pi.IsEnding)
            {
                e.ItemHeight = (int)(e.ItemHeight * (1 - pi.GetEndRatio()));
            }
        }
        public ProgressItem Add(string _title, string _info, float _min, float _max)
        {
            ProgressItem pi = new ProgressItem()
            {
                Title = _title, Info = _info, Min = _min, Max = _max
            };

            pi.OnUpdate += OnProgressItemUpdate;
            pi.OnEnded  += OnProgressItemEnded;
            listBox.Items.Add(pi);
            NeedRefresh = true;
            Application.DoEvents();
            return(pi);
        }
        private void listBox_DrawItem(object sender, DrawItemEventArgs e)
        {
            if (e.Index < 0 || e.Index >= listBox.Items.Count)
            {
                return;
            }
            ProgressItem pi = listBox.Items[e.Index] as ProgressItem;

            if (pi == null)
            {
                return;
            }
            e.Graphics.FillRectangle(Brushes.DimGray, e.Bounds);
            e.Graphics.Clip = new Region(e.Bounds);

            int height = 10;

            if (pi.Title != null)
            {
                height += 16;
                PointF pos = new PointF(e.Bounds.Left + 4, e.Bounds.Top + 2);
                e.Graphics.DrawString(pi.Title, _FontTitle, Brushes.WhiteSmoke, pos);
            }

            if (pi.Info != null)
            {
                height += 14;
                PointF pos = new PointF(e.Bounds.Left + 20, e.Bounds.Top + 16);
                e.Graphics.DrawString(pi.Info, _FontInfo, Brushes.Gainsboro, pos);
            }

            Rectangle barRect = e.Bounds;

            barRect.X     += 4;
            barRect.Width -= 8;
            barRect.Y     += height - 8;
            barRect.Height = 5;
            e.Graphics.FillRectangle(Brushes.Black, barRect);
            barRect.Width = (int)(pi.Ratio * barRect.Width);
            e.Graphics.FillRectangle(Brushes.Green, barRect);

            e.Graphics.DrawLine(Pens.Silver, new Point(e.Bounds.Left, e.Bounds.Bottom - 1), new Point(e.Bounds.Right, e.Bounds.Bottom - 1));
        }
        private void RefreshTimer_Tick(object sender, EventArgs e)
        {
            if (HasEndings)
            {
                HasEndings = false;
                ProgressItem piToRemove = null;
                foreach (ProgressItem pi in listBox.Items.OfType <ProgressItem>())
                {
                    if (pi.IsEnding)
                    {
                        HasEndings  = true;
                        NeedRefresh = true;
                        if (pi.GetEndRatio() >= 1)
                        {
                            piToRemove = pi;
                            break;
                        }
                    }
                }
                if (piToRemove != null)
                {
                    listBox.Items.Remove(piToRemove);
                }

                if (HasEndings)
                {
                    listBox.DrawMode = DrawMode.Normal;
                    listBox.DrawMode = DrawMode.OwnerDrawVariable;
                    Application.DoEvents();
                }
            }

            if (NeedRefresh)
            {
                NeedRefresh = false;
                listBox.Invalidate();
                Application.DoEvents();
            }
        }
        private void buttonGenerate_Click(object sender, EventArgs e)
        {
            if (!CheckFolder())
            {
                return;
            }

            using (ProgressDialog progressDlg = new ProgressDialog())
            {
                progressDlg.StartPosition = FormStartPosition.CenterScreen;
                progressDlg.Show();

                string folder   = BuildFolder();
                string filename = labelTaxon.Text + ".tol";

                string logFile     = Path.Combine(folder, "generate.log");
                string treeFileTol = Path.Combine(folder, filename);
                string treeFileXml = Path.ChangeExtension(treeFileTol, "xml");

                bool comments   = checkBoxExportComments.Checked;
                bool photos     = checkBoxExportPhotos.Checked;
                bool sounds     = checkBoxExportSounds.Checked;
                bool exe        = checkBoxExe.Checked;
                bool ascendants = checkBoxExportAscendants.Checked;


                using (StreamWriter log = new StreamWriter(logFile))
                {
                    log.WriteLine("Start generate data for ");
                    log.WriteLine("  taxon   : " + _Taxon.Desc.RefMainName);
                    log.WriteLine("  in graph: " + TaxonUtils.MainGraph?.Description);

                    TaxonTreeNode nodeToExport = _Taxon;
                    if (ascendants)
                    {
                        TaxonTreeNode Current = _Taxon;
                        while (Current != null && Current.Father != null)
                        {
                            TaxonTreeNode fatherNode = new TaxonTreeNode();
                            fatherNode.Father = Current.Father.Father;
                            fatherNode.Desc   = Current.Father.Desc;
                            fatherNode.Children.Add(nodeToExport);
                            nodeToExport = fatherNode;
                            Current      = Current.Father;
                        }
                    }

                    ProgressItem piSaveData = progressDlg.Add("Saving main file", null, 0, 3);
                    log.WriteLine("");
                    log.WriteLine("Save tree in " + treeFileXml);
                    TaxonUtils.Save(nodeToExport, treeFileXml);
                    piSaveData.Update(1);
                    log.WriteLine("Save tree in " + treeFileTol);
                    TaxonUtils.Save(nodeToExport, treeFileTol);
                    piSaveData.Update(2);

                    int count = 0;
                    nodeToExport.ParseNode((node) => { count++; });
                    piSaveData.Update(3);
                    piSaveData.End();

                    log.WriteLine("");
                    log.WriteLine("Total nodes    : " + count);
                    log.WriteLine("Export ascendants: " + ascendants);
                    log.WriteLine("Export comments: " + comments);
                    log.WriteLine("Export images  : " + photos);
                    log.WriteLine("Export sounds  : " + sounds);

                    ExportData exportData = new ExportData(TaxonUtils.GetTaxonPath(), folder, log);

                    if (comments)
                    {
                        log.WriteLine("");
                        log.WriteLine("Exporting comments");
                        exportData.ProgressItem = progressDlg.Add("Exporting comments", "", 0, count - 1);
                        nodeToExport.ParseNode((node) => ExportComments(node, exportData));
                        exportData.ProgressItem.End();
                    }

                    if (photos)
                    {
                        log.WriteLine("");
                        log.WriteLine("Exporting photos");
                        exportData.ProgressItem = progressDlg.Add("Exporting photos", "", 0, count - 1);
                        nodeToExport.ParseNodeDesc((desc) => ExportPhotos(desc, exportData));
                        exportData.ProgressItem.End();
                    }

                    if (sounds)
                    {
                        log.WriteLine("");
                        log.WriteLine("Exporting sounds");
                        exportData.ProgressItem = progressDlg.Add("Exporting sounds", "", 0, count - 1);
                        nodeToExport.ParseNodeDesc((desc) => ExportSounds(desc, exportData));
                        exportData.ProgressItem.End();
                    }

                    if (exe)
                    {
                        exportData.ProgressItem = progressDlg.Add("Exporting exe/config", "", 0, 2);
                        string sourceExe = Assembly.GetEntryAssembly().Location;
                        string destExe   = Path.Combine(exportData.NewPath, Path.GetFileName(sourceExe));
                        File.Copy(sourceExe, destExe);
                        exportData.ProgressItem.Update(1);

                        string sourceConfig = TaxonUtils.GetConfigFileName(TaxonUtils.MyConfig.Name);
                        string destConfig   = Path.Combine(exportData.NewPath, "Config", Path.GetFileName(sourceConfig));

                        string saveFileName = TaxonUtils.MyConfig.TaxonFileName;
                        string savePath     = TaxonUtils.MyConfig.TaxonPath;
                        TaxonUtils.MyConfig.TaxonFileName = filename;
                        TaxonUtils.MyConfig.TaxonPath     = folder;
                        TaxonUtils.MyConfig.Save(destConfig, destExe);
                        TaxonUtils.MyConfig.TaxonFileName = saveFileName;
                        TaxonUtils.MyConfig.TaxonPath     = savePath;
                        exportData.ProgressItem.Update(2);
                        exportData.ProgressItem.End();
                    }
                }

                MessageBox.Show("Generate done");
            }
            Close();
        }