private void Rebuild()
        {
            WPFDoEvents.AssertThisCodeIsRunningInTheUIThread();

            ObjDocumentViewer.Document             = null;
            ObjTooManyAnnotationsButton.Visibility = Visibility.Collapsed;

            AugmentedBindable <PDFDocument> pdf_document_bindable = DataContext as AugmentedBindable <PDFDocument>;

            if (null != pdf_document_bindable)
            {
                PDFDocument pdf_document = pdf_document_bindable.Underlying;

                SafeThreadPool.QueueUserWorkItem(o =>
                {
                    // TODO: [GHo] what are these 'heuristic' conditions good for?!?!
                    if (pdf_document.GetAnnotations().Count > 50 || pdf_document.Highlights.Count > 1000)
                    {
                        WPFDoEvents.InvokeAsyncInUIThread(() =>
                        {
                            ObjTooManyAnnotationsButton.Visibility = Visibility.Visible;
                            ObjTooManyAnnotationsButton.Tag        = pdf_document;
                        });
                    }
                    else
                    {
                        PopulateWithAnnotationReport(pdf_document);
                    }
                });
            }
        }
        private static void DoPostUpgrade()
        {
            WPFDoEvents.AssertThisCodeIs_NOT_RunningInTheUIThread();

            // NB NB NB NB: You CANT USE ANYTHING IN THE USER CONFIG AT THIS POINT - it is not yet decided until LOGIN has completed...

            WPFDoEvents.InvokeInUIThread(() =>
            {
                StatusManager.Instance.UpdateStatus("AppStart", "Loading themes");
                Theme.Initialize();
                DualTabbedLayout.GetWindowOverride = delegate() { return(new StandardWindow()); };

                // Force tooltips to stay open
                ToolTipService.ShowDurationProperty.OverrideMetadata(typeof(DependencyObject), new FrameworkPropertyMetadata(3600000));
            });

            // Make sure the data directories exist...
            if (!Directory.Exists(ConfigurationManager.Instance.BaseDirectoryForUser))
            {
                Directory.CreateDirectory(ConfigurationManager.Instance.BaseDirectoryForUser);
            }

            // and kick off the Login Dialog to start the application proper:
            WPFDoEvents.InvokeAsyncInUIThread(() => ShowLoginDialog());

            // NB NB NB NB: You CANT USE ANYTHING IN THE USER CONFIG AT THIS POINT - it is not yet decided until LOGIN has completed...
        }
        private void MenuForgetLegacyAnnotations_Click(object sender, RoutedEventArgs e)
        {
            popup.Close();

            SafeThreadPool.QueueUserWorkItem(o =>
            {
                FeatureTrackingManager.Instance.UseFeature(Features.Library_ForgetLegacyAnnotations);
                foreach (var pdf_document in pdf_documents)
                {
                    try
                    {
                        LegacyAnnotationConvertor.ForgetLegacyAnnotations(pdf_document);
                    }
                    catch (Exception ex)
                    {
                        Logging.Error(ex, "Error while forgetting legacy annotations.");
                    }
                }

                WPFDoEvents.InvokeAsyncInUIThread(() =>
                {
                    MessageBoxes.Info("Legacy annotations removed.");
                });
            });
        }
Beispiel #4
0
        private static void DoInterestingAnalysis_GoogleScholar(PDFReadingControl pdf_reading_control, PDFDocument pdf_document)
        {
            bool attempt_scrape = Qiqqa.Common.Configuration.ConfigurationManager.Instance.ConfigurationRecord.GoogleScholar_DoExtraBackgroundQueries;

            if (attempt_scrape)
            {
                Logging.Info("You are accessing Google Scholar in the background as you have the 'Send extra background queries to Google Scholar' Configuration option ticked. Be aware that this can lead to a quick denial of service response by Google in the form of a 40x HTTP Error or RECAPTCHA page instead of the search response you seek! Also refer to GitHub issues #225 & #113.");

                // Get the GoogleScholar similar documents
                try
                {
                    string title = pdf_document.TitleCombined;
                    if (Constants.TITLE_UNKNOWN != title)
                    {
                        GoogleScholarScrapePaperSet gssp_set = GoogleScholarScrapePaperSet.GenerateFromQuery(title, 10);

                        WPFDoEvents.InvokeAsyncInUIThread(() =>
                        {
                            pdf_reading_control?.SimilarDocsControl.SpecifyPaperSet(gssp_set);
                        });
                    }
                    else
                    {
                        Logging.Info("We don't have a title, so skipping GoogleScholar similar documents");
                    }
                }
                catch (Exception ex)
                {
                    Logging.Error(ex, "There was a problem getting the GoogleScholar similar documents for document {0}", pdf_document.Fingerprint);
                }
            }
        }
Beispiel #5
0
        private void word_connector_ContextChanged_BACKGROUND_FindRecommendations()
        {
            while (true)
            {
                // Get the next context to search for, and if there is none, then exit the background thread
                string context;

                // Utilities.LockPerfTimer l1_clk = Utilities.LockPerfChecker.Start();
                lock (context_thread_lock)
                {
                    // l1_clk.LockPerfTimerStop();
                    context = context_thread_next_context;
                    context_thread_next_context = null;

                    if (null == context)
                    {
                        context_thread_running = false;
                        break;
                    }
                }

                // Now that we have the context, do the query
                List <PDFDocument> context_pdf_documents = new List <PDFDocument>();
                {
                    WebLibraryDetail web_library_detail = this.default_library;
                    if (null != web_library_detail)
                    {
                        string context_search_string = PolishContextForLucene(context);
                        context_search_string = context_search_string.Trim();
                        if (!String.IsNullOrEmpty(context_search_string))
                        {
                            List <IndexResult> fingerprints = LibrarySearcher.FindAllFingerprintsMatchingQuery(web_library_detail, context_search_string);
                            if (null != fingerprints && 0 != fingerprints.Count)
                            {
                                foreach (var fingerprint in fingerprints)
                                {
                                    if (20 <= context_pdf_documents.Count)
                                    {
                                        break;
                                    }

                                    PDFDocument pdf_document = web_library_detail.Xlibrary.GetDocumentByFingerprint(fingerprint.fingerprint);
                                    if (null != pdf_document)
                                    {
                                        context_pdf_documents.Add(pdf_document);
                                    }
                                }
                            }
                        }
                    }
                }

                // And get the GUI to update with the results
                WPFDoEvents.InvokeAsyncInUIThread(() =>
                {
                    word_connector_ContextChanged_BACKGROUND_PopulateRecommendations(context_pdf_documents);
                }, DispatcherPriority.Background);
            }
        }
 public void Download(object obj)
 {
     WPFDoEvents.InvokeAsyncInUIThread(() =>
     {
         MainWindowServiceDispatcher.Instance.ShowBundleLibraryJoiningControl(manifest_latest);
     }
                                       );
 }
 private void ipc_server_IPCServerMessage(string message)
 {
     WPFDoEvents.InvokeAsyncInUIThread(() =>
     {
         MainWindowServiceDispatcher.Instance.ProcessCommandLineFile(message);
     }
                                       );
 }
        public static void Popup()
        {
            FeatureTrackingManager.Instance.UseFeature(Features.InCite_OpenPopup);

            WPFDoEvents.InvokeAsyncInUIThread(() =>
            {
                Popup_DISPATCHER();
            }
                                              );
        }
Beispiel #9
0
        private void word_connector_CitationClusterChanged(CitationCluster context_citation_cluster)
        {
            Logging.Debug特("InCite: CitationClusterChanged: {0}", context_citation_cluster);

            WPFDoEvents.InvokeAsyncInUIThread(() =>
            {
                ObjCitationClusterEditorControl.SetCitationCluster(context_citation_cluster);
            }
                                              );
        }
Beispiel #10
0
        private void NotifySceneRenderingControl()
        {
            WPFDoEvents.InvokeAsyncInUIThread(() =>
            {
                SceneRenderingControl scene_rendering_control = SceneRenderingControl;

                if (scene_rendering_control != null)
                {
                    scene_rendering_control.RecalculateAllNodeControlDimensions();
                }
            }, DispatcherPriority.Background);
        }
Beispiel #11
0
        public RegionWebLibraries()
        {
            InitializeComponent();

            ObjWebLibraryListControl.OnWebLibrarySelected += ObjWebLibraryListControl_OnWebLibrarySelected;

            SafeThreadPool.QueueUserWorkItem(o =>
            {
                // This particular action would BLOCK a very long time on `WebLibraryManager.Instance` as another background
                // task is busy loading all libraries as part of the WebLibraryManager initialization.
                WebLibraryManager.Instance.WebLibrariesChanged += Instance_WebLibrariesChanged;

                WPFDoEvents.InvokeAsyncInUIThread(() => Refresh());
            });
        }
        private void RepopulatePanels()
        {
            WPFDoEvents.AssertThisCodeIs_NOT_RunningInTheUIThread();

            var outbound = pdf_document.PDFDocumentCitationManager.GetOutboundCitations();
            var inbound  = pdf_document.PDFDocumentCitationManager.GetInboundCitations();

            WPFDoEvents.InvokeAsyncInUIThread(() =>
            {
                WPFDoEvents.AssertThisCodeIsRunningInTheUIThread();

                PopulatePanelWithCitations(DocsPanel_Outbound, pdf_document, outbound, Features.Citations_OpenDoc);
                PopulatePanelWithCitations(DocsPanel_Inbound, pdf_document, inbound, Features.Citations_OpenDoc);
            });
        }
Beispiel #13
0
        private static void DoInterestingAnalysis_SimilarAuthors(PDFReadingControl pdf_reading_control, PDFDocument pdf_document)
        {
            // Populate the similar authors
            try
            {
                List <NameTools.Name>          authors           = SimilarAuthors.GetAuthorsForPDFDocument(pdf_document);
                MultiMap <string, PDFDocument> authors_documents = SimilarAuthors.GetDocumentsBySameAuthors(pdf_document.LibraryRef, pdf_document, authors);

                WPFDoEvents.InvokeAsyncInUIThread(() => {
                    pdf_reading_control.SimilarAuthorsControl.SetItems(authors_documents);
                });
            }
            catch (Exception ex)
            {
                Logging.Error(ex, "There was a problem creating the tag cloud for document {0}", pdf_document.Fingerprint);
            }
        }
Beispiel #14
0
        private static void DoInterestingAnalysis_TagCloud(PDFReadingControl pdf_reading_control, PDFDocument pdf_document)
        {
            // Populate the tag cloud
            try
            {
                List <TagCloudEntry> tag_cloud_entries = PDFDocumentTagCloudBuilder.BuildTagCloud(pdf_document.LibraryRef, pdf_document);

                WPFDoEvents.InvokeAsyncInUIThread(() =>
                {
                    pdf_reading_control.TagCloud.SpecifyEntries(tag_cloud_entries);
                });
            }
            catch (Exception ex)
            {
                Logging.Error(ex, "There was a problem creating the tag cloud for document {0}", pdf_document.Fingerprint);
            }
        }
Beispiel #15
0
        public void SetPDFDocument(PDFDocument doc)
        {
            WPFDoEvents.AssertThisCodeIs_NOT_RunningInTheUIThread();

            pdf_document = doc;

            WPFDoEvents.InvokeAsyncInUIThread(() =>
            {
                ObjPDFDocuments.ItemsSource = null;

                string query = ObjSearchBox.Text;

                SafeThreadPool.QueueUserWorkItem(o =>
                {
                    ReSearch(doc, query);
                    RepopulatePanels(doc);
                });
            });
        }
Beispiel #16
0
        private void StatusManager_OnStatusEntryUpdate(StatusManager.StatusEntry status_entry)
        {
            bool do_invoke = false;

            //Utilities.LockPerfTimer l1_clk = Utilities.LockPerfChecker.Start();
            lock (status_entries_still_to_process_lock)
            {
                //l1_clk.LockPerfTimerStop();
                status_entries_still_to_process[status_entry.key] = status_entry;
                if (!status_entries_still_to_process_fresh_thread_running)
                {
                    status_entries_still_to_process_fresh_thread_running = true;
                    do_invoke = true;
                }
            }

            if (do_invoke)
            {
                WPFDoEvents.InvokeAsyncInUIThread(() => StatusManager_OnStatusEntryUpdate_GUI(), DispatcherPriority.Background);
            }
        }
Beispiel #17
0
        private void word_connector_ContextChanged(string context_word, string context_backward, string context_surround)
        {
            Logging.Debug特("InCite: ContextChanged");

            WPFDoEvents.InvokeAsyncInUIThread(() =>
            {
                word_connector_ContextChanged_BACKGROUND_UpdateButtonEnabledness(context_word, context_backward, context_surround);
            }, DispatcherPriority.Background);

            // Utilities.LockPerfTimer l1_clk = Utilities.LockPerfChecker.Start();
            lock (context_thread_lock)
            {
                // l1_clk.LockPerfTimerStop();
                context_thread_next_context = context_backward;
                if (!context_thread_running)
                {
                    context_thread_running = true;
                    SafeThreadPool.QueueUserWorkItem(o => word_connector_ContextChanged_BACKGROUND_FindRecommendations());
                }
            }
        }
        public void RebuildVisual()
        {
            WPFDoEvents.AssertThisCodeIsRunningInTheUIThread();

            //Logging.Info("+HighlightsRenderer RebuildVisual() on page {0}", page);

            if (null == pdf_document)
            {
                Source = null;
                return;
            }

            if (double.IsNaN(Width) || double.IsNaN(Height))
            {
                Source = null;
                return;
            }

            // We use a smaller image than necessary as we do not need high resolution to represent the highlights
            double scaled_capped_width  = Math.Min(Width, 300);
            double scaled_capped_height = Height * scaled_capped_width / Width;

            SafeThreadPool.QueueUserWorkItem(o =>
            {
                BitmapSource bmp;

                using (Bitmap raster_bitmap = PDFOverlayRenderer.RenderHighlights((int)scaled_capped_width, (int)scaled_capped_height, pdf_document, page))
                {
                    bmp = BitmapImageTools.FromBitmap(raster_bitmap);
                }

                WPFDoEvents.InvokeAsyncInUIThread(() =>
                {
                    Source = bmp;
                });

                //Logging.Info("-HighlightsRenderer RebuildVisual() on page {0}", page);
            });
        }
        private void drag_area_tracker_OnDragComplete(bool button_left_pressed, bool button_right_pressed, Point mouse_down_point, Point mouse_up_point)
        {
            FeatureTrackingManager.Instance.UseFeature(Features.Document_Camera);

            double width_page  = Math.Abs(mouse_up_point.X - mouse_down_point.X);
            double height_page = Math.Abs(mouse_up_point.Y - mouse_down_point.Y);

            if (3 <= width_page && 3 <= height_page)
            {
                DocPageInfo page_info = new DocPageInfo {
                    pdf_document = @pdf_document,
                    page         = @page,
                    ActualHeight = @ActualHeight,
                    ActualWidth  = @ActualWidth
                };

                SafeThreadPool.QueueUserWorkItem(o =>
                {
                    // GetSnappedImage() invokes the background renderer, hence run it in a background thread itself:
                    BitmapSource image = GetSnappedImage(page_info, mouse_up_point, mouse_down_point);
                    List <Word> words  = GetSnappedWords(page_info, mouse_up_point, mouse_down_point);
                    string raw_text    = SelectedWordsToFormattedTextConvertor.ConvertToParagraph(words);
                    string tabled_text = SelectedWordsToFormattedTextConvertor.ConvertToTable(words);

                    WPFDoEvents.InvokeAsyncInUIThread(() =>
                    {
                        CameraActionChooserDialog cacd = new CameraActionChooserDialog();
                        cacd.SetLovelyDetails(image, raw_text, tabled_text);
                        cacd.ShowDialog();
                    });
                });
            }
            else
            {
                Logging.Info("Region too small to screen grab");
            }
        }
 private void library_OnDocumentsChanged()
 {
     WPFDoEvents.InvokeAsyncInUIThread(() => UpdateLibraryStatistics());
 }
        private void BackgroundThread(object arg)
        {
            Daemon daemon = (Daemon)arg;

            try
            {
                // NOTE: while one might wonder why `playing` is not protected by a lock, while it
                // is used by two threads: this is by design.
                //
                // `playing` is only ever changed by a single thread (Main) and any temporary collision
                // between reading `playing` while the boolean is being changed by the main thread
                // is NOT A PROBLEM.
                // Yes, an Exception MAY be thrown then, but we have to reckon with failures inside
                // the loop anyway (https://github.com/jimmejardine/qiqqa-open-source/issues/42) as
                // the `playing = false` STOP instruction MAY occur while Dispose()-ing this class
                // instance: *that* action MAY very well happen while we're *somewhere* inside the
                // play loop executing stuff... which will surely CRASH with an Exception, e.g.
                // https://github.com/jimmejardine/qiqqa-open-source/issues/42
                // hence we NEED the Exception handling anyway and any unsafe checking of `playing`
                // is but one potential failure mode, all of whom will be correctly caught by the
                // outer `try...catch`, hence no critical section lock coding effort for `playing`:
                while (playing)
                {
                    int current_wpm = 0;

                    // Interrogate the GUI
                    WPFDoEvents.InvokeInUIThread(() =>
                    {
                        current_wpm = (int)SliderWPM.Value;
                    }
                                                 );


                    // Sleep a bit to reflect the WPM
                    int sleep_time_ms = (60 * 1000 / (current_wpm + 1));
                    daemon.Sleep(sleep_time_ms);

                    int current_position = 0;
                    int current_maximum  = 0;
                    // Interrogate the GUI
                    WPFDoEvents.InvokeAsyncInUIThread(() =>
                    {
                        current_position = (int)SliderLocation.Value;
                        current_maximum  = (int)SliderLocation.Maximum;
                    }
                                                      );

                    // Can we move onto the next word?
                    if (current_position < current_maximum)
                    {
                        string current_word       = words[current_position];
                        string current_word_left  = "";
                        string current_word_right = "";
                        for (int i = 1; i <= 3; ++i)
                        {
                            if (current_position - i >= 0 && current_position - i < words.Count)
                            {
                                current_word_left += words[current_position - i] + " ";
                            }
                            if (current_position + i >= 0 && current_position + i < words.Count)
                            {
                                current_word_right += " " + words[current_position + i];
                            }
                        }

                        ++current_position;

                        WPFDoEvents.InvokeAsyncInUIThread(() =>
                        {
                            SliderLocation.Value      = current_position;
                            TextCurrentWord.Text      = current_word;
                            TextCurrentWordLeft.Text  = current_word_left;
                            TextCurrentWordRight.Text = current_word_right;
                        }
                                                          );
                    }
                    else
                    {
                        WPFDoEvents.InvokeAsyncInUIThread(() =>
                        {
                            TogglePlayPause(force_stop: true);
                        }
                                                          );
                    }
                }
            }
            catch (Exception ex)
            {
                // all sorts of nasty stuff can happen. If it happens while `Dispose()`
                // was invoked on the mainline, it's hunky-dory. So we merely rate this
                // DEBUG level diagnostics.
                Logging.Debug特(ex, "VERY PROBABLY HARMLESS AND EXPECTED crash in SpeedReader: if you just closed/quit the panel, this is due to Dispose() invocation in the Main thread and expected behaviour.");
            }
        }
        private static void BackgroundRenderImages_BACKGROUND(FlowDocument flow_document, List <AnnotationWorkGenerator.AnnotationWork> annotation_works, AnnotationReportOptions annotation_report_options)
        {
            WPFDoEvents.AssertThisCodeIs_NOT_RunningInTheUIThread();

            ShutdownableManager.Sleep(annotation_report_options.InitialRenderDelayMilliseconds);

            PDFDocument last_pdf_document = null;

            StatusManager.Instance.ClearCancelled("AnnotationReportBackground");
            for (int j = 0; j < annotation_works.Count; ++j)
            {
                if (ShutdownableManager.Instance.IsShuttingDown)
                {
                    Logging.Error("Canceling creation of Annotation Report due to signaled application shutdown");
                    StatusManager.Instance.SetCancelled("AnnotationReportBackground");
                }

                StatusManager.Instance.UpdateStatus("AnnotationReportBackground", "Building annotation report image", j, annotation_works.Count, true);
                if (StatusManager.Instance.IsCancelled("AnnotationReportBackground"))
                {
                    Logging.Warn("User canceled annotation report generation");
                    break;
                }

                AnnotationWorkGenerator.AnnotationWork annotation_work = annotation_works[j];
                PDFDocument pdf_document = annotation_work.pdf_document;

                // Clear down our previously caches pages
                if (null != last_pdf_document && last_pdf_document != pdf_document)
                {
                    if (last_pdf_document.DocumentExists)
                    {
                        last_pdf_document.FlushCachedPageRenderings();
                    }
                }

                // Remember this PDF document so we can flush it if necessary
                last_pdf_document = pdf_document;

                // Now render each image
                PDFAnnotation pdf_annotation = annotation_work.pdf_annotation;
                if (null != pdf_annotation)
                {
                    try
                    {
                        // Clear the waiting for processing text
                        WPFDoEvents.InvokeAsyncInUIThread(() =>
                        {
                            annotation_work.processing_error.Text = "";
                        });


                        if (pdf_document.DocumentExists)
                        {
                            // Fill in the paragraph text
                            if (null != annotation_work.annotation_paragraph)
                            {
                                WPFDoEvents.InvokeAsyncInUIThread(() =>
                                {
                                    BuildAnnotationWork_FillAnnotationText(pdf_document, pdf_annotation, annotation_work);
                                });
                            }

                            if (null != annotation_work.report_floater)
                            {
                                try
                                {
                                    System.Drawing.Image annotation_image   = PDFAnnotationToImageRenderer.RenderAnnotation(pdf_document, pdf_annotation, 80);
                                    BitmapSource         cropped_image_page = BitmapImageTools.FromImage(annotation_image);

                                    WPFDoEvents.InvokeAsyncInUIThread(() =>
                                    {
                                        annotation_work.report_image.Source  = cropped_image_page;
                                        annotation_work.report_floater.Width = new FigureLength(cropped_image_page.PixelWidth / 1);
                                    });
                                }
                                catch (Exception ex)
                                {
                                    Logging.Warn(ex, "There was a problem while rendering an annotation.");
                                    WPFDoEvents.InvokeAsyncInUIThread(() =>
                                    {
                                        annotation_work.report_image.Source   = Icons.GetAppIcon(Icons.AnnotationReportImageError);
                                        annotation_work.processing_error.Text = "There was a problem while rendering this annotation.";
                                    });
                                }
                            }
                        }
                        else
                        {
                            WPFDoEvents.InvokeAsyncInUIThread(() =>
                            {
                                if (null != annotation_work.report_image)
                                {
                                    annotation_work.report_image.Source = Icons.GetAppIcon(Icons.AnnotationReportImageError);
                                }

                                annotation_work.processing_error.Text = "Can't show image: The PDF does not exist locally.";
                            });
                        }
                    }
                    catch (Exception ex)
                    {
                        Logging.Error(ex, "There was an error while rendering page {0} for document {1} for the annotation report", pdf_annotation.Page, pdf_annotation.DocumentFingerprint);

                        WPFDoEvents.InvokeAsyncInUIThread(() =>
                        {
                            if (null != annotation_work.report_image)
                            {
                                annotation_work.report_image.Source = Icons.GetAppIcon(Icons.AnnotationReportImageError);
                            }

                            annotation_work.processing_error.Text = "Can't show image: There was an error rendering the metadata image.";
                        });
                    }
                }
            }

            // And flush the rendering cache of the last document
            if (null != last_pdf_document)
            {
                if (last_pdf_document.DocumentExists)
                {
                    last_pdf_document.FlushCachedPageRenderings();
                }
            }

            StatusManager.Instance.ClearStatus("AnnotationReportBackground");
        }
        private void UpdateLibraryStatistics_Stats_Background_Charts()
        {
            // The chart of the recently read and the recently added...
            const int WEEK_HISTORY = 4 * 3;
            DateTime  NOW          = DateTime.UtcNow;

            // Get the buckets for the past few weeks of READING
            CountingDictionary <DateTime> date_buckets_read = new CountingDictionary <DateTime>();
            {
                List <DateTime> recently_reads = web_library_detail.library.RecentlyReadManager.GetRecentlyReadDates();
                foreach (DateTime recently_read in recently_reads)
                {
                    for (int week = 1; week < WEEK_HISTORY; ++week)
                    {
                        DateTime cutoff = NOW.AddDays(-7 * week);
                        if (recently_read >= cutoff)
                        {
                            date_buckets_read.TallyOne(cutoff);
                            break;
                        }
                    }
                }
            }

            // Get the buckets for the past few weeks of ADDING
            CountingDictionary <DateTime> date_buckets_added = new CountingDictionary <DateTime>();
            {
                foreach (PDFDocument pdf_document in web_library_detail.library.PDFDocuments)
                {
                    for (int week = 1; week < WEEK_HISTORY; ++week)
                    {
                        DateTime cutoff = NOW.AddDays(-7 * week);
                        if (pdf_document.DateAddedToDatabase >= cutoff)
                        {
                            date_buckets_added.TallyOne(cutoff);
                            break;
                        }
                    }
                }
            }

            // Plot the pretty pretty
            List <ChartItem> chart_items_read  = new List <ChartItem>();
            List <ChartItem> chart_items_added = new List <ChartItem>();

            for (int week = 1; week < WEEK_HISTORY; ++week)
            {
                DateTime cutoff    = NOW.AddDays(-7 * week);
                int      num_read  = date_buckets_read.GetCount(cutoff);
                int      num_added = date_buckets_added.GetCount(cutoff);

                chart_items_read.Add(new ChartItem {
                    Title = "Read", Timestamp = cutoff, Count = num_read
                });
                chart_items_added.Add(new ChartItem {
                    Title = "Added", Timestamp = cutoff, Count = num_added
                });
            }

            WPFDoEvents.InvokeAsyncInUIThread(() => UpdateLibraryStatistics_Stats_Background_GUI(chart_items_read, chart_items_added));
        }
Beispiel #24
0
        public static void RestoreDesktop()
        {
            WPFDoEvents.AssertThisCodeIs_NOT_RunningInTheUIThread();

            try
            {
                // Get the remembrances
                if (File.Exists(Filename))
                {
                    string[] restore_settings = File.ReadAllLines(Filename);
                    foreach (string restore_setting in restore_settings)
                    {
                        try
                        {
                            if (restore_setting.StartsWith("PDF_LIBRARY"))
                            {
                                string[] parts      = restore_setting.Split(',');
                                string   library_id = parts[1];

                                WebLibraryDetail web_library_detail = WebLibraryManager.Instance.GetLibrary(library_id);
                                if (null == web_library_detail)
                                {
                                    Logging.Warn("RestoreDesktop: Cannot find library anymore for Id {0}", library_id);
                                }
                                else
                                {
                                    WPFDoEvents.InvokeInUIThread(() => MainWindowServiceDispatcher.Instance.OpenLibrary(web_library_detail));
                                }
                            }
                            else if (restore_setting.StartsWith("PDF_DOCUMENT"))
                            {
                                string[] parts                = restore_setting.Split(',');
                                string   library_id           = parts[1];
                                string   document_fingerprint = parts[2];

                                WebLibraryDetail web_library_detail = WebLibraryManager.Instance.GetLibrary(library_id);
                                if (null == web_library_detail)
                                {
                                    Logging.Warn("RestoreDesktop: Cannot find library anymore for Id {0}", library_id);
                                }
                                else
                                {
                                    PDFDocument pdf_document = web_library_detail.Xlibrary.GetDocumentByFingerprint(document_fingerprint);
                                    if (null == pdf_document)
                                    {
                                        Logging.Warn("RestoreDesktop: Cannot find document anymore for fingerprint {0}", document_fingerprint);
                                    }
                                    else
                                    {
                                        WPFDoEvents.InvokeAsyncInUIThread(() =>
                                        {
                                            try
                                            {
                                                MainWindowServiceDispatcher.Instance.OpenDocument(pdf_document);
                                            }
                                            catch (Exception ex)
                                            {
                                                Logging.Error(ex, "RestoreDesktop: Error occurred while attempting to restore the view (tab) for document fingerprint {0}, library Id {1}", document_fingerprint, library_id);
                                            }
                                        });
                                    }
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            Logging.Warn(ex, "There was a problem restoring desktop with state {0}", restore_setting);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logging.Error(ex, "There was a problem restoring the saved desktop state.");
            }

            Logging.Warn("Finished restoring desktop.");
        }
        private void DisplayThumbnail()
        {
            ImageThumbnail.Source = null;
            TxtAbstract.Text      = "";

            if (null == pdf_document)
            {
                return;
            }

            SafeThreadPool.QueueUserWorkItem(o =>
            {
                try
                {
                    if (pdf_document.DocumentExists)
                    {
                        const double IMAGE_PERCENTAGE = 0.5;

                        using (MemoryStream ms = new MemoryStream(SoraxPDFRenderer.GetPageByHeightAsImage(pdf_document.DocumentPath, pdf_document.PDFPassword, page, (int)Math.Round(ImageThumbnail.Height / IMAGE_PERCENTAGE), (int)Math.Round(ImageThumbnail.Width / IMAGE_PERCENTAGE))))
                        {
                            Bitmap image = (Bitmap)Image.FromStream(ms);
                            PDFOverlayRenderer.RenderAnnotations(image, pdf_document, page, specific_pdf_annotation);
                            PDFOverlayRenderer.RenderHighlights(image, pdf_document, page);
                            PDFOverlayRenderer.RenderInks(image, pdf_document, page);

                            image = image.Clone(new RectangleF {
                                Width = image.Width, Height = (int)Math.Round(image.Height * IMAGE_PERCENTAGE)
                            }, image.PixelFormat);
                            BitmapSource image_page = BitmapImageTools.CreateBitmapSourceFromImage(image);

                            WPFDoEvents.InvokeAsyncInUIThread(() =>
                            {
                                ImageThumbnail.Source = image_page;

                                if (null != ImageThumbnail.Source)
                                {
                                    ImageThumbnail.Visibility = Visibility.Visible;
                                }
                                else
                                {
                                    ImageThumbnail.Visibility = Visibility.Collapsed;
                                }
                            });
                        }
                    }
                    else
                    {
                        string abstract_text = pdf_document.Abstract;
                        if (PDFAbstractExtraction.CANT_LOCATE != abstract_text)
                        {
                            WPFDoEvents.InvokeAsyncInUIThread(() =>
                            {
                                TxtAbstract.Text = abstract_text;
                            });
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logging.Error(ex, "There was a problem showing the PDF thumbnail");
                }
            });
        }
Beispiel #26
0
        private void LibraryCatalogOverviewControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            // Make the button semi-transparent if our new document is not actually on the harddrive
            PanelSearchScore.Visibility   = Visibility.Collapsed;
            ListSearchDetails.DataContext = null;
            ObjLookInsidePanel.Visibility = Visibility.Collapsed;
            ButtonThemeSwatch.Visibility  = Visibility.Collapsed;
            ObjFavouriteImage.Visibility  = Visibility.Collapsed;
            ButtonOpen.Background         = Brushes.Transparent;
            TextTitle.Foreground          = Brushes.Black;
            TextTitle.FontSize            = TextAuthors.FontSize;

            // No more work if our context is null
            if (null == PDFDocumentBindable)
            {
                return;
            }

            // The wizard
            if ("The Qiqqa Manual" == PDFDocumentBindable.Underlying.TitleCombined)
            {
                WizardDPs.SetPointOfInterest(TextTitle, "GuestLibraryQiqqaManualTitle");
                WizardDPs.SetPointOfInterest(ButtonOpen, "GuestLibraryQiqqaManualOpenButton");
            }
            else
            {
                WizardDPs.ClearPointOfInterest(TextTitle);
                WizardDPs.ClearPointOfInterest(ButtonOpen);
            }

            // Choose the icon depending on the reference type
            if (PDFDocumentBindable.Underlying.IsVanillaReference)
            {
                ButtonOpen.Icon    = Icons.GetAppIcon(Icons.LibraryCatalogOpenVanillaReference);
                ButtonOpen.Opacity = 1.0;
            }
            else
            {
                ButtonOpen.Icon    = Icons.GetAppIcon(Icons.LibraryCatalogOpen);
                ButtonOpen.Opacity = PDFDocumentBindable.Underlying.DocumentExists ? 1.0 : 0.5;
            }

            // Favourite?
            if (PDFDocumentBindable.Underlying.IsFavourite ?? false)
            {
                ObjFavouriteImage.Visibility = Visibility.Visible;
            }

            // Colour
            if (Colors.Transparent != PDFDocumentBindable.Underlying.Color)
            {
                ButtonOpen.Background = new SolidColorBrush(ColorTools.MakeTransparentColor(PDFDocumentBindable.Underlying.Color, 64));
            }

            // Rating
            if (!String.IsNullOrEmpty(PDFDocumentBindable.Underlying.Rating))
            {
                double rating;
                if (Double.TryParse(PDFDocumentBindable.Underlying.Rating, out rating))
                {
                    TextTitle.FontSize = TextAuthors.FontSize + rating;
                }
            }

            // Reading stage
            switch (PDFDocumentBindable.Underlying.ReadingStage)
            {
            case Choices.ReadingStages_TOP_PRIORITY:
                TextTitle.Foreground = Brushes.DarkRed;
                break;

            case Choices.ReadingStages_READ_AGAIN:
            case Choices.ReadingStages_INTERRUPTED:
            case Choices.ReadingStages_STARTED_READING:
                TextTitle.Foreground = Brushes.DarkGreen;
                break;

            case Choices.ReadingStages_SKIM_READ:
            case Choices.ReadingStages_BROWSED:
            case Choices.ReadingStages_INTEREST_ONLY:
                TextTitle.Foreground = Brushes.DarkBlue;
                break;

            case Choices.ReadingStages_FINISHED_READING:
            case Choices.ReadingStages_DUPLICATE:
                TextTitle.Foreground = Brushes.DarkGray;
                break;

            case Choices.ReadingStages_UNREAD:
                TextTitle.Foreground = Brushes.Black;
                break;

            default:
                TextTitle.Foreground = Brushes.Black;
                break;
            }

            // Populate the score if we have them
            if (null != LibraryCatalogControl)
            {
                Dictionary <string, double> search_scores = LibraryCatalogControl.SearchScores;
                if (null != search_scores)
                {
                    PanelSearchScore.Visibility = Visibility.Visible;

                    double score;
                    search_scores.TryGetValue(PDFDocumentBindable.Underlying.Fingerprint, out score);

                    string score_string = String.Format("{0:0}%", score * 100);
                    ButtonSearchInside.Caption  = "" + score_string + "";
                    ButtonSearchInside.ToolTip  = String.Format("Search score is {0}. Click here to see why...", score_string);
                    ButtonSearchInside.Cursor   = Cursors.Hand;
                    ButtonSearchInside.MinWidth = 0;
                    Color color = Color.FromRgb(255, (byte)(255 - 150 * score), 100);
                    ButtonSearchInside.Background = new SolidColorBrush(color);
                }
            }

            // Populate the theme swatch
            ButtonThemeSwatch.Visibility = Visibility.Visible;
            ButtonThemeSwatch.Background = ThemeBrushes.GetBrushForDocument(PDFDocumentBindable.Underlying);

            // Populate the linked documents
            PDFDocument pdf_document = PDFDocumentBindable.Underlying;

            SafeThreadPool.QueueUserWorkItem(o =>
            {
                WPFDoEvents.AssertThisCodeIs_NOT_RunningInTheUIThread();

                var links = pdf_document.PDFDocumentCitationManager.GetLinkedDocuments();

                WPFDoEvents.InvokeAsyncInUIThread(() =>
                {
                    WPFDoEvents.AssertThisCodeIsRunningInTheUIThread();

                    CitationsUserControl.PopulatePanelWithCitations(DocsPanel_Linked, pdf_document, links, Features.LinkedDocument_Library_OpenDoc, " » ", false);
                });
            });
        }
        private void ExpeditionPaperThemesControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            // Clear the old
            ObjSeriesTopics.DataSource        = null;
            TxtPleaseRunExpedition.Visibility = Visibility.Visible;
            ChartTopics.Visibility            = Visibility.Collapsed;

            AugmentedBindable <PDFDocument> pdf_document_bindable = DataContext as AugmentedBindable <PDFDocument>;

            if (null == pdf_document_bindable)
            {
                return;
            }

            PDFDocument pdf_document = pdf_document_bindable.Underlying;

            SafeThreadPool.QueueUserWorkItem(o =>
            {
                ExpeditionDataSource eds = pdf_document.LibraryRef.Xlibrary?.ExpeditionManager?.ExpeditionDataSource;

                if (null == eds)
                {
                    return;
                }
                else
                {
                    LDAAnalysis lda_analysis = eds.LDAAnalysis;

                    // Draw the pie chart
                    try
                    {
                        if (!eds.docs_index.ContainsKey(pdf_document.Fingerprint))
                        {
                            return;
                        }

                        int doc_id = eds.docs_index[pdf_document.Fingerprint];
                        TopicProbability[] topics = lda_analysis.DensityOfTopicsInDocsSorted[doc_id];

                        int ITEMS_IN_CHART = Math.Min(topics.Length, 3);

                        WPFDoEvents.InvokeAsyncInUIThread(() =>
                        {
                            Brush[] brushes = new Brush[ITEMS_IN_CHART + 1];

                            List <ChartItem> chart_items        = new List <ChartItem>();
                            double remaining_segment_percentage = 1.0;
                            for (int t = 0; t < ITEMS_IN_CHART; ++t)
                            {
                                string topic_name = eds.GetDescriptionForTopic(topics[t].topic);
                                double percentage = topics[t].prob;

                                chart_items.Add(new ChartItem {
                                    Topic = topic_name, Percentage = percentage
                                });
                                brushes[t] = new SolidColorBrush(eds.Colours[topics[t].topic]);

                                remaining_segment_percentage -= percentage;
                            }

                            chart_items.Add(new ChartItem {
                                Topic = "Others", Percentage = remaining_segment_percentage
                            });
                            brushes[ITEMS_IN_CHART] = new SolidColorBrush(Colors.White);

                            ObjChartTopicsArea.ColorModel.CustomPalette = brushes;
                            ObjChartTopicsArea.ColorModel.Palette       = ChartColorPalette.Custom;
                            ObjSeriesTopics.DataSource = chart_items;

                            // Silly
                            ObjSeriesTopics.AnimationDuration = TimeSpan.FromMilliseconds(1000);
                            ObjSeriesTopics.EnableAnimation   = false;
                            ObjSeriesTopics.AnimateOneByOne   = true;
                            ObjSeriesTopics.AnimateOption     = AnimationOptions.Fade;
                            ObjSeriesTopics.EnableAnimation   = true;

                            TxtPleaseRunExpedition.Visibility = Visibility.Collapsed;
                            ChartTopics.Visibility            = Visibility.Visible;
                        });
                    }
                    catch (Exception ex)
                    {
                        Logging.Error(ex, "There was a problem while generating the topics chart for document {0}", pdf_document.Fingerprint);
                    }
                }
            });
        }
        public PDFRendererControl(PDFDocument pdf_document, bool remember_last_read_page, ZoomType force_zoom_type)
        {
            WPFDoEvents.AssertThisCodeIsRunningInTheUIThread();

            Theme.Initialize();

            InitializeComponent();

            //Unloaded += PDFRendererControl_Unloaded;
            Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted;

            pdf_renderer_control_stats   = new PDFRendererControlStats(pdf_document);
            this.remember_last_read_page = remember_last_read_page;

            ObjPagesPanel.Background = ThemeColours.Background_Brush_Blue_LightToDark;

            PageRenderArea.SizeChanged += PDFRendererControl_SizeChanged;
            KeyUp             += PDFRendererControl_KeyUp;
            KeyDown           += PDFRendererControl_KeyDown;
            TextInput         += PDFRendererControl_TextInput;
            PreviewMouseWheel += PDFRendererControl_MouseWheel;

            ScrollPages.PreviewMouseDown += ScrollPages_PreviewMouseDown;
            ScrollPages.ScrollChanged    += ScrollPages_ScrollChanged;

            KeyboardNavigation.SetDirectionalNavigation(this, KeyboardNavigationMode.None);
            KeyboardNavigation.SetDirectionalNavigation(ScrollPages, KeyboardNavigationMode.None);
            KeyboardNavigation.SetDirectionalNavigation(ObjPagesPanel, KeyboardNavigationMode.None);

            // Set the initial zoom
            ZoomType zoom_type = ZoomType.Other;

            switch (ConfigurationManager.Instance.ConfigurationRecord.GUI_LastPagesUp)
            {
            case "1":
                zoom_type = ZoomType.Zoom1Up;
                break;

            case "2":
                zoom_type = ZoomType.Zoom2Up;
                break;

            case "N":
                zoom_type = ZoomType.ZoomNUp;
                break;

            case "W":
                zoom_type = ZoomType.ZoomWholeUp;
                break;

            default:
                zoom_type = ZoomType.Zoom1Up;
                break;
            }

            // Is the zoom type forced? (e.g. by the metadata panel or the sniffer)
            if (ZoomType.Other != force_zoom_type)
            {
                zoom_type = force_zoom_type;
            }

            PageZoom(zoom_type);

            var doc = pdf_renderer_control_stats.pdf_document;

            SafeThreadPool.QueueUserWorkItem(o =>
            {
                // Add the child pages
                bool add_bells_and_whistles = (doc.PageCount > 0 && doc.PageCount < 50);

                WPFDoEvents.InvokeAsyncInUIThread(() =>
                {
                    Logging.Info("+Creating child page controls");
                    for (int page = 1; page <= doc.PageCount; ++page)
                    {
                        PDFRendererPageControl page_control = new PDFRendererPageControl(this, page, add_bells_and_whistles);
                        ObjPagesPanel.Children.Add(page_control);
                    }
                    Logging.Info("-Creating child page controls");
                });
            });

            Logging.Info("+Setting initial viewport");
            ReconsiderOperationMode(OperationMode.Hand);

            SetSearchKeywords();  // Eventually this should move into the ReconsiderOperationMode
            ScrollPages.Focus();

            Logging.Info("-Setting initial viewport");
        }
        private void Regenerate()
        {
            WPFDoEvents.AssertThisCodeIsRunningInTheUIThread();

            HashSet <string> parent_fingerprints = null;

            if (null != PDFDocuments && 0 < PDFDocuments.Count)
            {
                parent_fingerprints = new HashSet <string>();
                foreach (var pdf_document in PDFDocuments)
                {
                    parent_fingerprints.Add(pdf_document.Fingerprint);
                }
            }

            string map_y_axis_name = (string)ObjYAxis.SelectedItem;
            string map_x_axis_name = (string)ObjXAxis.SelectedItem;
            string identifier_name = (string)ObjIdentifier.SelectedItem;

            SafeThreadPool.QueueUserWorkItem(o =>
            {
                MultiMapSet <string, string> map_y_axis = LibraryPivotReportBuilder.GenerateAxisMap(map_y_axis_name, LibraryRef, parent_fingerprints);
                MultiMapSet <string, string> map_x_axis = LibraryPivotReportBuilder.GenerateAxisMap(map_x_axis_name, LibraryRef, parent_fingerprints);

                WPFDoEvents.InvokeAsyncInUIThread(() =>
                {
                    LibraryPivotReportBuilder.IdentifierImplementations.IdentifierImplementationDelegate identifier_implementation = LibraryPivotReportBuilder.IdentifierImplementations.GetIdentifierImplementation(identifier_name);

                    LibraryPivotReportBuilder.PivotResult pivot_result = LibraryPivotReportBuilder.GeneratePivot(map_y_axis, map_x_axis);

                    GridControl ObjGridControl       = new GridControl();
                    ObjGridControlHolder.Content     = ObjGridControl;
                    ObjGridControl.Model.RowCount    = map_y_axis.Count + 2;
                    ObjGridControl.Model.ColumnCount = map_x_axis.Count + 2;

                    // ROW/COLUMN Titles
                    for (int y = 0; y < pivot_result.y_keys.Count; ++y)
                    {
                        ObjGridControl.Model[y + 1, 0].CellValue     = pivot_result.y_keys[y];
                        ObjGridControl.Model[y + 1, 0].CellValueType = typeof(string);
                    }
                    for (int x = 0; x < pivot_result.x_keys.Count; ++x)
                    {
                        ObjGridControl.Model[0, x + 1].CellValue     = pivot_result.x_keys[x];
                        ObjGridControl.Model[0, x + 1].CellValueType = typeof(string);
                    }

                    // Grid contents
                    StatusManager.Instance.ClearCancelled("LibraryPivot");
                    for (int y = 0; y < pivot_result.y_keys.Count; ++y)
                    {
                        if (General.HasPercentageJustTicked(y, pivot_result.y_keys.Count))
                        {
                            StatusManager.Instance.UpdateStatus("LibraryPivot", "Building library pivot grid", y, pivot_result.y_keys.Count, true);

                            if (StatusManager.Instance.IsCancelled("LibraryPivot"))
                            {
                                Logging.Warn("User cancelled library pivot grid generation");
                                break;
                            }
                        }

                        for (int x = 0; x < pivot_result.x_keys.Count; ++x)
                        {
                            identifier_implementation(LibraryRef, pivot_result.common_fingerprints[y, x], ObjGridControl.Model[y + 1, x + 1]);
                        }
                    }
                    StatusManager.Instance.UpdateStatus("LibraryPivot", "Finished library pivot");

                    // ROW/COLUMN Totals
                    {
                        int y_total = 0;
                        {
                            for (int y = 0; y < pivot_result.y_keys.Count; ++y)
                            {
                                int total = 0;
                                for (int x = 0; x < pivot_result.x_keys.Count; ++x)
                                {
                                    if (null != pivot_result.common_fingerprints[y, x])
                                    {
                                        total += pivot_result.common_fingerprints[y, x].Count;
                                    }
                                }

                                ObjGridControl.Model[y + 1, pivot_result.x_keys.Count + 1].CellValue     = total;
                                ObjGridControl.Model[y + 1, pivot_result.x_keys.Count + 1].CellValueType = typeof(int);

                                y_total += total;
                            }
                        }

                        int x_total = 0;
                        {
                            for (int x = 0; x < pivot_result.x_keys.Count; ++x)
                            {
                                int total = 0;
                                for (int y = 0; y < pivot_result.y_keys.Count; ++y)
                                {
                                    if (null != pivot_result.common_fingerprints[y, x])
                                    {
                                        total += pivot_result.common_fingerprints[y, x].Count;
                                    }
                                }

                                ObjGridControl.Model[pivot_result.y_keys.Count + 1, x + 1].CellValue     = total;
                                ObjGridControl.Model[pivot_result.y_keys.Count + 1, x + 1].CellValueType = typeof(int);

                                x_total += total;
                            }
                        }

                        int common_total = (x_total + y_total) / 2;
                        if (common_total != x_total || common_total != y_total)
                        {
                            throw new GenericException("X and Y totals do not match?!");
                        }
                        ObjGridControl.Model[pivot_result.y_keys.Count + 1, pivot_result.x_keys.Count + 1].CellValue     = common_total;
                        ObjGridControl.Model[pivot_result.y_keys.Count + 1, pivot_result.x_keys.Count + 1].CellValueType = typeof(int);

                        ObjGridControl.Model[0, pivot_result.x_keys.Count + 1].CellValue     = "TOTAL";
                        ObjGridControl.Model[0, pivot_result.x_keys.Count + 1].CellValueType = typeof(string);
                        ObjGridControl.Model[pivot_result.y_keys.Count + 1, 0].CellValue     = "TOTAL";
                        ObjGridControl.Model[pivot_result.y_keys.Count + 1, 0].CellValueType = typeof(string);
                    }

                    // Store the results for the toolbar buttons
                    last_pivot_result   = pivot_result;
                    last_ObjGridControl = ObjGridControl;
                });
            });
        }
        private void UpdateLibraryStatistics_Stats_Background_CoverFlow()
        {
            // The list of recommended items
            DocumentDisplayWorkManager ddwm = new DocumentDisplayWorkManager();
            {
                {
                    int ITEMS_IN_LIST = 5;

                    // Upcoming reading is:
                    //  interrupted
                    //  top priority
                    //  read again
                    //  recently added and no status

                    List <PDFDocument> pdf_documents_all = web_library_detail.library.PDFDocuments;
                    pdf_documents_all.Sort(PDFDocumentListSorters.DateAddedToDatabase);

                    foreach (string reading_stage in new string[] { Choices.ReadingStages_INTERRUPTED, Choices.ReadingStages_TOP_PRIORITY, Choices.ReadingStages_READ_AGAIN })
                    {
                        foreach (PDFDocument pdf_document in pdf_documents_all)
                        {
                            if (!pdf_document.DocumentExists)
                            {
                                continue;
                            }

                            if (pdf_document.ReadingStage == reading_stage)
                            {
                                if (!ddwm.ContainsPDFDocument(pdf_document))
                                {
                                    ddwm.AddDocumentDisplayWork(DocumentDisplayWork.StarburstColor.Pink, reading_stage, pdf_document);

                                    if (ddwm.Count >= ITEMS_IN_LIST)
                                    {
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }

                {
                    int ITEMS_IN_LIST = 3;

                    // Recently added
                    {
                        List <PDFDocument> pdf_documents = web_library_detail.library.PDFDocuments;
                        pdf_documents.Sort(PDFDocumentListSorters.DateAddedToDatabase);

                        int num_added = 0;
                        foreach (PDFDocument pdf_document in pdf_documents)
                        {
                            if (!pdf_document.DocumentExists)
                            {
                                continue;
                            }

                            if (!ddwm.ContainsPDFDocument(pdf_document))
                            {
                                ddwm.AddDocumentDisplayWork(DocumentDisplayWork.StarburstColor.Green, "Added Recently", pdf_document);

                                if (++num_added >= ITEMS_IN_LIST)
                                {
                                    break;
                                }
                            }
                        }
                    }

                    // Recently read
                    {
                        List <PDFDocument> pdf_documents = web_library_detail.library.PDFDocuments;
                        pdf_documents.Sort(PDFDocumentListSorters.DateLastRead);

                        int num_added = 0;
                        foreach (PDFDocument pdf_document in pdf_documents)
                        {
                            if (!pdf_document.DocumentExists)
                            {
                                continue;
                            }

                            if (!ddwm.ContainsPDFDocument(pdf_document))
                            {
                                ddwm.AddDocumentDisplayWork(DocumentDisplayWork.StarburstColor.Blue, "Read Recently", pdf_document);

                                if (++num_added >= ITEMS_IN_LIST)
                                {
                                    break;
                                }
                            }
                        }
                    }
                }


                // And fill the placeholders
                WPFDoEvents.InvokeInUIThread(() => UpdateLibraryStatistics_Stats_Background_GUI_AddAllPlaceHolders(ddwm.ddws));

                // Now render each document
                using (Font font = new Font("Times New Roman", 11.0f))
                {
                    using (StringFormat string_format = new StringFormat
                    {
                        Alignment = StringAlignment.Center,
                        LineAlignment = StringAlignment.Center
                    })
                    {
                        var color_matrix = new ColorMatrix();
                        color_matrix.Matrix33 = 0.9f;
                        using (var image_attributes = new ImageAttributes())
                        {
                            image_attributes.SetColorMatrix(color_matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

                            foreach (DocumentDisplayWork ddw in ddwm.ddws)
                            {
                                try
                                {
                                    using (MemoryStream ms = new MemoryStream(ddw.pdf_document.PDFRenderer.GetPageByHeightAsImage(1, PREVIEW_IMAGE_HEIGHT / PREVIEW_IMAGE_PERCENTAGE)))
                                    {
                                        Bitmap page_bitmap = (Bitmap)System.Drawing.Image.FromStream(ms);
                                        page_bitmap = page_bitmap.Clone(new RectangleF {
                                            Width = page_bitmap.Width, Height = (int)Math.Round(page_bitmap.Height * PREVIEW_IMAGE_PERCENTAGE)
                                        }, page_bitmap.PixelFormat);

                                        using (Graphics g = Graphics.FromImage(page_bitmap))
                                        {
                                            int CENTER = 60;
                                            int RADIUS = 60;

                                            {
                                                BitmapImage starburst_bi = null;
                                                switch (ddw.starburst_color)
                                                {
                                                case DocumentDisplayWork.StarburstColor.Blue:
                                                    starburst_bi = Icons.GetAppIcon(Icons.PageCornerBlue);
                                                    break;

                                                case DocumentDisplayWork.StarburstColor.Green:
                                                    starburst_bi = Icons.GetAppIcon(Icons.PageCornerGreen);
                                                    break;

                                                case DocumentDisplayWork.StarburstColor.Pink:
                                                    starburst_bi = Icons.GetAppIcon(Icons.PageCornerPink);
                                                    break;

                                                default:
                                                    starburst_bi = Icons.GetAppIcon(Icons.PageCornerOrange);
                                                    break;
                                                }

                                                Bitmap starburst_image = BitmapImageTools.ConvertBitmapSourceToBitmap(starburst_bi);
                                                g.SmoothingMode = SmoothingMode.AntiAlias;
                                                g.DrawImage(
                                                    starburst_image,
                                                    new Rectangle(CENTER - RADIUS, CENTER - RADIUS, 2 * RADIUS, 2 * RADIUS),
                                                    0,
                                                    0,
                                                    starburst_image.Width,
                                                    starburst_image.Height,
                                                    GraphicsUnit.Pixel,
                                                    image_attributes
                                                    );
                                            }

                                            using (Matrix mat = new Matrix())
                                            {
                                                mat.RotateAt(-50, new PointF(CENTER / 2, CENTER / 2));
                                                g.Transform = mat;

                                                string wrapped_caption = ddw.starburst_caption;
                                                wrapped_caption = wrapped_caption.ToLower();
                                                wrapped_caption = Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(wrapped_caption);
                                                wrapped_caption = wrapped_caption.Replace(" ", "\n");
                                                g.DrawString(wrapped_caption, font, Brushes.Black, new PointF(CENTER / 2, CENTER / 2), string_format);
                                            }
                                        }

                                        BitmapSource page_bitmap_source = BitmapImageTools.CreateBitmapSourceFromImage(page_bitmap);

                                        ddw.page_bitmap_source = page_bitmap_source;
                                    }

                                    WPFDoEvents.InvokeInUIThread(() => UpdateLibraryStatistics_Stats_Background_GUI_FillPlaceHolder(ddw));
                                }
                                catch (Exception ex)
                                {
                                    Logging.Warn(ex, "There was a problem loading a preview image for document {0}", ddw.pdf_document.Fingerprint);
                                }
                            }
                        }
                    }
                }

                if (0 == ddwm.ddws.Count)
                {
                    WPFDoEvents.InvokeAsyncInUIThread(() =>
                    {
                        ButtonCoverFlow.IsChecked = false;
                        UpdateLibraryStatistics();
                    }
                                                      );
                }
            }
        }