private void RunQuery()
        {
            ProgressDialog dialog;
            EventHandler<ProgressEventArgs> handler = null;

            // update our internal representation of the search boxes
            m_clauses = GetWhereClauses(m_searchControls);

            // run the query on the asset database again
            try
            {
                // create dialog
                dialog = new ProgressDialog();

                // create the handler for price query updates
                handler = delegate(object sender, ProgressEventArgs e)
                {
                    if (e.Max < 1) return;
                    dialog.Update("Updating market prices...", e.Progress, e.Max);
                };
                Program.PriceProvider.UpdateProgress += handler;

                // initialize the dialog and display it
                dialog.Update(0, 1);
                dialog.AddTask(UpdateAssetTable);
                dialog.Show();

                // display the fresh asset data in the grid
                grid.DataSource = m_assets.DefaultView;
                grid.AutoResizeColumns();
                UpdateAssetCount();
            }
            catch (ProgressException ex)
            {
                ShowException(ex);
            }
            finally
            {
                if (handler != null)
                    Program.PriceProvider.UpdateProgress -= handler;
            }
        }
        private void GenerateReport(string defaultTitle, string fileFilter, string defaultExt, GenerateReportDelegate reportMethod)
        {
            List<WhereClause> clauses;
            DataTable assets;
            ProgressDialog dialog;
            ReportOptionsDialog options;
            ReportOptionsDialog.AssetSourceType sourceType;
            EventHandler<ProgressEventArgs> handler = null;
            int savedSearchID = -1;

            // ask the user some stuff
            options = new ReportOptionsDialog(fileFilter, defaultExt);
            options.ReportTitle = defaultTitle;
            if (options.ShowDialog(this) == DialogResult.Cancel) return;
            sourceType = options.AssetSource;
            if (sourceType == ReportOptionsDialog.AssetSourceType.SavedSearch)
                savedSearchID = options.SavedSearchID;

            // create clauses
            clauses = new List<WhereClause>();

            try
            {
                // create dialog
                dialog = new ProgressDialog();

                // create the handler for price query updates
                handler = delegate(object sender, ProgressEventArgs e)
                {
                    if (e.Max < 1) return;
                    dialog.Update("Updating market prices...", e.Progress, e.Max);
                };
                Program.PriceProvider.UpdateProgress += handler;

                // add the progress task
                dialog.AddTask(delegate(IProgressDialog p)
                {
                    // create our clauses and get assets
                    p.Update("Querying assets...");
                    switch (sourceType)
                    {
                        case ReportOptionsDialog.AssetSourceType.All:
                            assets = AssetCache.GetAssetTable(clauses);
                            break;
                        case ReportOptionsDialog.AssetSourceType.Current:
                            if (m_assets == null) throw new ApplicationException("There are no current search results to use.");
                            assets = m_assets;
                            break;
                        case ReportOptionsDialog.AssetSourceType.SavedSearch:
                            clauses.AddRange(GetWhereClausesForSavedSearch(savedSearchID));
                            assets = AssetCache.GetAssetTable(clauses);
                            break;
                        default:
                            throw new ApplicationException("Don't know how to get assets for source type " + sourceType.ToString());
                    }

                    // generate report
                    p.Update("Generating report...");
                    reportMethod(assets, options.ReportTitle, options.ReportPath);
                });

                // run it!
                dialog.Show();
            }
            catch (Exception ex)
            {
                // let the user know we failed
                ShowException("Failed to generate report:", ex);

                // try to get rid of the partially-written file
                try { if (File.Exists(options.ReportPath)) File.Delete(options.ReportPath); }
                catch { /* pass */ }

                // get outta here, she's gonna blow!
                return;
            }
            finally
            {
                if (handler != null)
                    Program.PriceProvider.UpdateProgress -= handler;
            }

            // open the report
            if (Program.OptionsDialog["Reports.OpenReport"].ValueAsBoolean)
                System.Diagnostics.Process.Start(options.ReportPath);
        }