diff options
author | Michael Vrhel <michael.vrhel@artifex.com> | 2014-09-09 16:31:31 -0700 |
---|---|---|
committer | Michael Vrhel <michael.vrhel@artifex.com> | 2014-09-09 16:39:41 -0700 |
commit | 7ea99e3a8951e265d1437a77dcfee069de0edf76 (patch) | |
tree | 8e113fea67931064e2a9338d67b26aaabab27512 /platform/windows/gsview/MainWindow.xaml.cs | |
parent | 8a9519f2183b64fe220bcb1f6acedbe6acc190cd (diff) | |
download | mupdf-7ea99e3a8951e265d1437a77dcfee069de0edf76.tar.xz |
Rename of winrt to windows due to presence on gsview in this folder.
The contents of this folder will contain both winrt and gsview projects
which are shared in a common visual studio 2013 solution.
Diffstat (limited to 'platform/windows/gsview/MainWindow.xaml.cs')
-rw-r--r-- | platform/windows/gsview/MainWindow.xaml.cs | 4906 |
1 files changed, 4906 insertions, 0 deletions
diff --git a/platform/windows/gsview/MainWindow.xaml.cs b/platform/windows/gsview/MainWindow.xaml.cs new file mode 100644 index 00000000..6e6ee855 --- /dev/null +++ b/platform/windows/gsview/MainWindow.xaml.cs @@ -0,0 +1,4906 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using System.Windows.Forms; +using System.ComponentModel; +using System.IO; +using System.Windows.Xps.Packaging; +using System.Printing; +using System.Windows.Markup; +using System.Runtime.InteropServices; +using Microsoft.Win32; /* For registry */ + +public enum AA_t +{ + HIGH = 8, + MEDHIGH = 6, + MED = 4, + LOW = 2, + NONE = 0 +} + +enum PDFType_t +{ + PDFX, + PDFA +} + +enum AppBar_t +{ + TEXT_SEARCH, + STANDARD +} + +enum NotifyType_t +{ + MESS_STATUS, + MESS_ERROR +}; + +enum RenderingStatus_t +{ + REN_AVAILABLE, + REN_THUMBS, + REN_UPDATE_THUMB_CANVAS, + REN_PAGE /* Used to ignore value when source based setting */ +}; + +public enum status_t +{ + S_ISOK, + E_FAILURE, + E_OUTOFMEM, + E_NEEDPASSWORD +}; + +public enum textout_t +{ + HTML = 0, + XML, + TEXT +} + +enum zoom_t +{ + NO_ZOOM, + ZOOM_IN, + ZOOM_OUT +} + +enum view_t +{ + VIEW_WEB, + VIEW_CONTENT, + VIEW_PAGE, + VIEW_PASSWORD, + VIEW_TEXTSEARCH +}; + +public enum Page_Content_t +{ + FULL_RESOLUTION = 0, + THUMBNAIL, + OLD_RESOLUTION, + NOTSET +}; + +/* Put all the PDF types first to make the switch statment shorter + Save_Type_t.PDF is the test */ +public enum Save_Type_t +{ + PDF13, + LINEAR_PDF, + PDFA1_RGB, + PDFA1_CMYK, + PDFA2_RGB, + PDFA2_CMYK, + PDFX3_GRAY, + PDFX3_CMYK, + PDF, + PCLXL, + XPS, + SVG, + TEXT, + HTML, + XML +} + +public enum Extract_Type_t +{ + PDF, + EPS, + PS, + SVG +} + +/* C# has no defines.... */ +static class Constants +{ + public const int SCROLL_STEPSIZE = 48; + public const int INIT_LOOK_AHEAD = 2; /* A + count on the pages to pre-render */ + public const int THUMB_PREADD = 10; + public const double MIN_SCALE = 0.5; + public const double SCALE_THUMB = 0.05; + public const int BLANK_WIDTH = 17; + public const int BLANK_HEIGHT = 22; + public const double ZOOM_STEP = 0.25; + public const int ZOOM_MAX = 4; + public const double ZOOM_MIN = 0.25; + public const int KEY_PLUS = 0xbb; + public const int KEY_MINUS = 0xbd; + public const int ZOOM_IN = 0; + public const int ZOOM_OUT = 1; + public const double SCREEN_SCALE = 1; + public const int HEADER_SIZE = 54; + public const int SEARCH_FORWARD = 1; + public const int SEARCH_BACKWARD = -1; + public const int TEXT_NOT_FOUND = -1; + public const int DEFAULT_GS_RES = 300; + public const int DISPATCH_TIME = 50; + public const int SCROLL_STEP = 10; + public const int SCROLL_EDGE_BUFFER = 90; + public const int VERT_SCROLL_STEP = 48; + public const int PAGE_MARGIN = 1; +} + +public static class DocumentTypes +{ + public const string PDF = "Portable Document Format"; + public const string PS = "PostScript"; + public const string XPS = "XPS"; + public const string EPS = "Encapsulated PostScript"; + public const string CBZ = "Comic Book Archive"; + public const string PNG = "Portable Network Graphics Image"; + public const string JPG = "Joint Photographic Experts Group Image"; + public const string UNKNOWN = "Unknown"; +} + +namespace gsview +{ + /// <summary> + /// Interaction logic for MainWindow.xaml + /// </summary> + /// + + public struct pageprogress_t + { + public Byte[] bitmap; + public BlocksText charlist; + public int pagenum; + public Point size; + public Annotate_t annot; + } + + public struct ContextMenu_t + { + public int page_num; + public Point mouse_position; + } + + public struct thumb_t + { + public int page_num; + public Byte[] bitmap; + public Point size; + } + + public struct searchResults_t + { + public String needle; + public bool done; + public int page_found; + public List<Rect> rectangles; + public int num_rects; + } + + public struct textSelectInfo_t + { + public int pagenum; + public bool first_line_full; + public bool last_line_full; + } + + public static class ScrollBarExtensions + { + public static double GetThumbCenter(this System.Windows.Controls.Primitives.ScrollBar s) + { + double thumbLength = GetThumbLength(s); + double trackLength = s.Maximum - s.Minimum; + + return thumbLength / 2 + s.Minimum + (s.Value - s.Minimum) * + (trackLength - thumbLength) / trackLength; + } + + public static void SetThumbCenter(this System.Windows.Controls.Primitives.ScrollBar s, double thumbCenter) + { + double thumbLength = GetThumbLength(s); + double trackLength = s.Maximum - s.Minimum; + + if (thumbCenter >= s.Maximum - thumbLength / 2) + { + s.Value = s.Maximum; + } + else if (thumbCenter <= s.Minimum + thumbLength / 2) + { + s.Value = s.Minimum; + } + else if (thumbLength >= trackLength) + { + s.Value = s.Minimum; + } + else + { + s.Value = (int)(s.Minimum + trackLength * + ((thumbCenter - s.Minimum - thumbLength / 2) + / (trackLength - thumbLength))); + } + } + + public static double GetThumbLength(this System.Windows.Controls.Primitives.ScrollBar s) + { + double trackLength = s.Maximum - s.Minimum; + return trackLength * s.ViewportSize / + (trackLength + s.ViewportSize); + } + + public static void SetThumbLength(this System.Windows.Controls.Primitives.ScrollBar s, double thumbLength) + { + double trackLength = s.Maximum - s.Minimum; + + if (thumbLength < 0) + { + s.ViewportSize = 0; + } + else if (thumbLength < trackLength) + { + s.ViewportSize = trackLength * thumbLength / (trackLength - thumbLength); + } + else + { + s.ViewportSize = double.MaxValue; + } + } + } + + public partial class MainWindow : Window + { + mudocument mu_doc = null; + public Pages m_docPages; + List<textSelectInfo_t> m_textSelect; + List<DocPage> m_thumbnails; + List<List<RectList>> m_page_link_list = null; + IList<RectList> m_text_list; + public List<LinesText> m_lineptrs = null; + public List<BlocksText> m_textptrs = null; + List<Boolean> m_textset = null; + private bool m_file_open; + private int m_currpage; + private int m_searchpage; + private int m_num_pages; + private bool m_init_done; + private bool m_links_on; + String m_textsearchcolor = "#4072AC25"; + String m_textselectcolor = "#402572AC"; + String m_regionselect = "#00FFFFFF"; + String m_blockcolor = "#00FFFFFF"; + //String m_regionselect = "#FFFF0000"; /* Debug */ + String m_linkcolor = "#40AC7225"; + private bool m_have_thumbs; + double m_doczoom; + ghostsharp m_ghostscript; + String m_currfile; + String m_origfile; + private gsprint m_ghostprint = null; + bool m_isXPS; + gsOutput m_gsoutput; + Convert m_convertwin; + PageExtractSave m_extractwin; + Password m_password = null; + String m_currpassword = null; + BackgroundWorker m_thumbworker = null; + BackgroundWorker m_textsearch = null; + BackgroundWorker m_linksearch = null; + BackgroundWorker m_openfile = null; + BackgroundWorker m_initrender = null; + BackgroundWorker m_copytext = null; + String m_document_type; + Info m_infowindow; + OutputIntent m_outputintents; + Selection m_selection; + String m_prevsearch = null; + bool m_clipboardset; + bool m_doscroll; + bool m_intxtselect; + bool m_textselected; + System.Windows.Threading.DispatcherTimer m_dispatcherTimer = null; + double m_lastY; + double m_maxY; + bool m_ignorescrollchange; + double m_totalpageheight; + AA_t m_AA; + bool m_regstartup; + int m_initpage; + bool m_selectall; + bool m_showannot; + bool m_ScrolledChanged; + + public MainWindow() + { + InitializeComponent(); + this.Closing += new System.ComponentModel.CancelEventHandler(Window_Closing); + m_file_open = false; + m_regstartup = true; + m_showannot = true; + + /* Allocations and set up */ + try + { + m_docPages = new Pages(); + m_thumbnails = new List<DocPage>(); + m_lineptrs = new List<LinesText>(); + m_textptrs = new List<BlocksText>(); + m_textset = new List<Boolean>(); + m_ghostscript = new ghostsharp(); + m_ghostscript.gsUpdateMain += new ghostsharp.gsCallBackMain(gsProgress); + m_gsoutput = new gsOutput(); + m_gsoutput.Activate(); + m_outputintents = new OutputIntent(); + m_outputintents.Activate(); + m_ghostscript.gsIOUpdateMain += new ghostsharp.gsIOCallBackMain(gsIO); + m_ghostscript.gsDLLProblemMain += new ghostsharp.gsDLLProblem(gsDLL); + m_convertwin = null; + m_extractwin = null; + m_selection = null; + xaml_ZoomSlider.AddHandler(MouseLeftButtonUpEvent, new MouseButtonEventHandler(ZoomReleased), true); + xaml_PageList.AddHandler(Grid.DragOverEvent, new System.Windows.DragEventHandler(Grid_DragOver), true); + xaml_PageList.AddHandler(Grid.DropEvent, new System.Windows.DragEventHandler(Grid_Drop), true); + DimSelections(); + status_t result = CleanUp(); + + string[] arguments = Environment.GetCommandLineArgs(); + if (arguments.Length > 1) + { + string filePath = arguments[1]; + ProcessFile(filePath); + } + else + { + if (m_regstartup) + InitFromRegistry(); + } + } + catch (OutOfMemoryException e) + { + Console.WriteLine("Memory allocation failed at initialization\n"); + ShowMessage(NotifyType_t.MESS_ERROR, "Out of memory: " + e.Message); + } + } + + private void Grid_DragOver(object sender, System.Windows.DragEventArgs e) + { + if (e.Data.GetDataPresent(System.Windows.DataFormats.FileDrop)) + { + e.Effects = System.Windows.DragDropEffects.All; + } + else + { + e.Effects = System.Windows.DragDropEffects.None; + } + e.Handled = false; + } + + private void Grid_Drop(object sender, System.Windows.DragEventArgs e) + { + if (e.Data.GetDataPresent(System.Windows.DataFormats.FileDrop)) + { + string[] docPath = (string[]) e.Data.GetData(System.Windows.DataFormats.FileDrop); + ProcessFile(String.Join("",docPath)); + } + } + + void CloseExtraWindows(bool shutdown) + { + if (m_selection != null) + m_selection.Close(); + if (m_convertwin != null) + m_convertwin.Close(); + if (m_extractwin != null) + m_extractwin.Close(); + if (m_infowindow != null) + m_infowindow.Close(); + if (shutdown) + { + if (m_gsoutput != null) + m_gsoutput.RealWindowClosing(); + if (m_outputintents != null) + m_outputintents.RealWindowClosing(); + } + else + { + if (m_gsoutput != null) + m_gsoutput.Hide(); + if (m_outputintents != null) + m_outputintents.Hide(); + } + } + + void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) + { + CloseExtraWindows(true); + } + + /* Stuff not enabled when source is XPS */ + void EnabletoPDF() + { + xaml_savepdf.IsEnabled = true; + xaml_linearize_pdf.IsEnabled = true; + xaml_saveas.IsEnabled = true; + xaml_Extract.IsEnabled = true; + xaml_conversions.IsEnabled = true; + xaml_extractselection.IsEnabled = true; + } + + void DisabletoPDF() + { + xaml_savepdf.IsEnabled = false; + xaml_linearize_pdf.IsEnabled = false; + xaml_saveas.IsEnabled = false; + xaml_Extract.IsEnabled = false; + xaml_conversions.IsEnabled = false; + xaml_extractselection.IsEnabled = false; + } + + private void DimSelections() + { + xaml_currPage.Text = ""; + xaml_TotalPages.Text = "/ 0"; + xaml_Zoomsize.Text = "100"; + xaml_BackPage.Opacity = 0.5; + xaml_Contents.Opacity = 0.5; + xaml_currPage.Opacity = 0.5; + xaml_currPage.IsEnabled = false; + xaml_ForwardPage.Opacity = 0.5; + xaml_Links.Opacity = 0.5; + xaml_Print.Opacity = 0.5; + xaml_SavePDF.Opacity = 0.5; + xaml_Search.Opacity = 0.5; + xaml_Thumbs.Opacity = 0.5; + xaml_TotalPages.Opacity = 0.5; + xaml_zoomIn.Opacity = 0.5; + xaml_zoomOut.Opacity = 0.5; + xaml_Zoomsize.Opacity = 0.5; + xaml_ExpandFill.Opacity = 0.5; + xaml_ContScrollFill.Opacity = 0.5; + xaml_ActualSize.Opacity = 0.5; + xaml_Zoomsize.IsEnabled = false; + xaml_ZoomSlider.Opacity = 0.5; + xaml_ZoomSlider.IsEnabled = false; + xaml_saveas.IsEnabled = false; + xaml_closefile.IsEnabled = false; + xaml_showinfo.IsEnabled = false; + xaml_extractselection.IsEnabled = false; + xaml_conversions.IsEnabled = false; + xaml_gsmessage.IsEnabled = false; + xaml_print.IsEnabled = false; + xaml_view.IsEnabled = false; + xaml_edit.IsEnabled = false; + } + + private status_t CleanUp() + { + m_init_done = false; + this.Cursor = System.Windows.Input.Cursors.Arrow; + /* Collapse this stuff since it is going to be released */ + xaml_ThumbGrid.Visibility = System.Windows.Visibility.Collapsed; + xaml_ContentGrid.Visibility = System.Windows.Visibility.Collapsed; + xaml_VerticalScroll.Visibility = System.Windows.Visibility.Collapsed; + + /* Clear out everything */ + if (m_docPages != null && m_docPages.Count > 0) + m_docPages.Clear(); + if (m_textSelect != null) + m_textSelect.Clear(); + if (m_textset != null) + m_textset.Clear(); + if (m_lineptrs != null && m_lineptrs.Count > 0) + m_lineptrs.Clear(); + if (m_thumbnails != null && m_thumbnails.Count > 0) + m_thumbnails.Clear(); + if (m_textptrs != null && m_textptrs.Count > 0) + m_textptrs.Clear(); + if (m_page_link_list != null && m_page_link_list.Count > 0) + { + m_page_link_list.Clear(); + m_page_link_list = null; + } + if (m_text_list != null && m_text_list.Count > 0) + { + m_text_list.Clear(); + m_text_list = null; + } + if (mu_doc != null) + mu_doc.CleanUp(); + try + { + mu_doc = new mudocument(); + } + catch (OutOfMemoryException e) + { + Console.WriteLine("Memory allocation failed during clean up\n"); + ShowMessage(NotifyType_t.MESS_ERROR, "Out of memory: " + e.Message); + } + mu_doc.mupdfDLLProblemMain += new mudocument.mupdfDLLProblem(muDLL); + status_t result = mu_doc.Initialize(); + mu_doc.mupdfUpdateMain += new mudocument.mupdfCallBackMain(mupdfUpdate); + + if (result != status_t.S_ISOK) + { + Console.WriteLine("Library allocation failed during clean up\n"); + ShowMessage(NotifyType_t.MESS_ERROR, "Library allocation failed!"); + return result; + } + + m_have_thumbs = false; + m_file_open = false; + m_num_pages = -1; + m_links_on = false; + m_doczoom = 1.0; + m_isXPS = false; + //xaml_CancelThumb.IsEnabled = true; + m_currpage = 0; + m_ignorescrollchange = false; + m_document_type = DocumentTypes.UNKNOWN; + EnabletoPDF(); + m_clipboardset = false; + m_doscroll = false; + m_intxtselect = false; + m_textselected = false; + m_currpassword = null; + CloseExtraWindows(false); + ResetScroll(); + m_totalpageheight = 0; + m_AA = GetAA(); + m_origfile = null; + m_initpage = 0; + xaml_Zoomsize.Text = "100"; + m_selectall = false; + return result; + } + + /* Initialize from registry */ + private void InitFromRegistry() + { + RegistryKey key = Registry.CurrentUser.CreateSubKey("Software"); + RegistryKey keyA = key.CreateSubKey("Artifex Software"); + RegistryKey keygs = keyA.CreateSubKey("GSview 6.0"); + String filepath = null; + Int32 page; + AA_t aa = AA_t.HIGH; + + try + { + filepath = (String)keygs.GetValue("File", null); + aa = (AA_t)keygs.GetValue("AA"); + page = (Int32)keygs.GetValue("Page"); + } + catch + { + return; + } + keygs.Close(); + keyA.Close(); + key.Close(); + + SetAA(aa); + m_AA = aa; + + if (filepath != null && File.Exists(filepath)) + { + m_initpage = page; + ProcessFile(filepath); + } + else + m_initpage = 0; + } + + private void SetRegistry() + { + if (m_currfile == null) + return; + + RegistryKey key = Registry.CurrentUser.CreateSubKey("Software"); + RegistryKey keyA = key.CreateSubKey("Artifex Software"); + RegistryKey keygs = keyA.CreateSubKey("GSview 6.0"); + + if (m_origfile != null && (m_document_type == DocumentTypes.PS || + m_document_type == DocumentTypes.EPS)) + { + keygs.SetValue("File", m_origfile, RegistryValueKind.String); + } + else + { + keygs.SetValue("File", m_currfile, RegistryValueKind.String); + } + keygs.SetValue("Page", m_currpage, RegistryValueKind.DWord); + Int32 aa_int = (Int32)m_AA; + keygs.SetValue("AA", aa_int, RegistryValueKind.DWord); + keygs.Close(); + keyA.Close(); + key.Close(); + } + + private void AppClosing(object sender, CancelEventArgs e) + { + if (m_init_done) + SetRegistry(); + } + + private void ShowMessage(NotifyType_t type, String Message) + { + if (type == NotifyType_t.MESS_ERROR) + { + System.Windows.Forms.MessageBox.Show(Message, "Error", + MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + else + { + System.Windows.Forms.MessageBox.Show(Message, "Notice", + MessageBoxButtons.OK); + } + } + + private void CloseCommand(object sender, ExecutedRoutedEventArgs e) + { + if (m_init_done) + CloseDoc(); + } + + private void CloseDoc() + { + CleanUp(); + } + + /* Set the page with the new raster information */ + private void UpdatePage(int page_num, Byte[] bitmap, Point ras_size, + Page_Content_t content, double zoom_in, AA_t AA) + { + DocPage doc_page = this.m_docPages[page_num]; + + doc_page.Width = (int)ras_size.X; + doc_page.Height = (int)ras_size.Y; + + doc_page.Content = content; + doc_page.Zoom = zoom_in; + + int stride = doc_page.Width * 4; + doc_page.BitMap = BitmapSource.Create(doc_page.Width, doc_page.Height, + 72, 72, PixelFormats.Pbgra32, BitmapPalettes.Halftone256, bitmap, stride); + doc_page.PageNum = page_num; + doc_page.AA = AA; + + if (content == Page_Content_t.THUMBNAIL) + { + doc_page.Width = (int)(ras_size.X / Constants.SCALE_THUMB); + doc_page.Height = (int)(ras_size.Y / Constants.SCALE_THUMB); + } + } + + private void OpenFileCommand(object sender, ExecutedRoutedEventArgs e) + { + OpenFile(sender, e); + } + + private void OpenFile(object sender, RoutedEventArgs e) + { + if (m_password != null && m_password.IsActive) + m_password.Close(); + + if (m_infowindow != null && m_infowindow.IsActive) + m_infowindow.Close(); + + /* Check if gs is currently busy. If it is then don't allow a new + * file to be opened. They can cancel gs with the cancel button if + * they want */ + if (m_ghostscript.GetStatus() != gsStatus.GS_READY) + { + ShowMessage(NotifyType_t.MESS_STATUS, "GS busy. Cancel to open new file."); + return; + } + + if (m_ghostprint != null && m_ghostprint.IsBusy()) + { + ShowMessage(NotifyType_t.MESS_STATUS, "Let printing complete"); + return; + } + + System.Windows.Forms.OpenFileDialog dlg = new System.Windows.Forms.OpenFileDialog(); + dlg.Filter = "Document Files(*.ps;*.eps;*.pdf;*.xps;*.oxps;*.cbz;*.png;*.jpg;*.jpeg)|*.ps;*.eps;*.pdf;*.xps;*.oxps;*.cbz;*.png;*.jpg;*.jpeg|All files (*.*)|*.*"; + dlg.FilterIndex = 1; + if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) + ProcessFile(dlg.FileName); + } + + private void ProcessFile(String FileName) + { + if (m_file_open) + { + CloseDoc(); + } + /* If we have a ps or eps file then launch the distiller first + * and then we will get a temp pdf file which will be opened by + * mupdf */ + string extension = System.IO.Path.GetExtension(FileName); + /* We are doing this based on the extension but like should do + * it based upon the content */ + switch (extension.ToUpper()) + { + case ".PS": + m_document_type = DocumentTypes.PS; + break; + case ".EPS": + m_document_type = DocumentTypes.EPS; + break; + case ".XPS": + case ".OXPS": + m_document_type = DocumentTypes.XPS; + break; + case ".PDF": + m_document_type = DocumentTypes.PDF; + break; + case ".CBZ": + m_document_type = DocumentTypes.CBZ; + break; + case ".PNG": + m_document_type = DocumentTypes.PNG; + break; + case ".JPG": + m_document_type = DocumentTypes.JPG; + break; + case ".JPEG": + m_document_type = DocumentTypes.JPG; + break; + default: + { + ShowMessage(NotifyType_t.MESS_STATUS, "Unknown File Type"); + return; + } + } + if (extension.ToUpper() == ".PS" || extension.ToUpper() == ".EPS") + { + xaml_DistillProgress.Value = 0; + if (m_ghostscript.DistillPS(FileName, Constants.DEFAULT_GS_RES) == gsStatus.GS_BUSY) + { + ShowMessage(NotifyType_t.MESS_STATUS, "GS currently busy"); + return; + } + xaml_DistillName.Text = "Distilling"; + xaml_CancelDistill.Visibility = System.Windows.Visibility.Visible; + xaml_DistillName.FontWeight = FontWeights.Bold; + xaml_DistillGrid.Visibility = System.Windows.Visibility.Visible; + return; + } + /* Set if this is already xps for printing */ + if (extension.ToUpper() == ".XPS" || extension.ToUpper() == ".OXPS") + m_isXPS = true; + OpenFile2(FileName); + } + + private void OpenFile2(String File) + { + m_currfile = File; + xaml_OpenProgressGrid.Visibility = System.Windows.Visibility.Visible; + xaml_openfilestatus.Text = "Opening File"; + /* The file open can take a fair amount of time. So that we can show + * an indeterminate progress bar while opening, go ahead an do this + * on a separate thread */ + OpenFileBG(); + } + + private void OpenWork(object sender, DoWorkEventArgs e) + { + BackgroundWorker worker = sender as BackgroundWorker; + + status_t code = mu_doc.OpenFile(m_currfile); + worker.ReportProgress(100, code); + } + + private void OpenProgress(object sender, ProgressChangedEventArgs e) + { + status_t result = (status_t)(e.UserState); + + if (result == status_t.S_ISOK) + { + /* Check if we need a password */ + if (mu_doc.RequiresPassword()) + { + xaml_OpenProgressGrid.Visibility = System.Windows.Visibility.Collapsed; + GetPassword(); + } + else + StartViewer(); + } + else + { + m_currfile = null; + } + } + + private void OpenFileBG() + { + try + { + m_openfile = new BackgroundWorker(); + m_openfile.WorkerReportsProgress = true; + m_openfile.WorkerSupportsCancellation = false; + m_openfile.DoWork += new DoWorkEventHandler(OpenWork); + m_openfile.ProgressChanged += new ProgressChangedEventHandler(OpenProgress); + m_openfile.RunWorkerAsync(); + } + catch (OutOfMemoryException e) + { + Console.WriteLine("Memory allocation failed during opening\n"); + ShowMessage(NotifyType_t.MESS_ERROR, "Out of memory: " + e.Message); + } + } + + private void SetPageAnnot(int page_num, Annotate_t render_result) + { + if (m_docPages[page_num].Annotate == Annotate_t.UNKNOWN || + m_docPages[page_num].Annotate == Annotate_t.COMPUTING) + { + if (render_result == Annotate_t.NO_ANNOTATE) + m_docPages[page_num].Annotate = Annotate_t.NO_ANNOTATE; + else + { + if (m_showannot) + m_docPages[page_num].Annotate = Annotate_t.ANNOTATE_VISIBLE; + else + m_docPages[page_num].Annotate = Annotate_t.ANNOTATE_HIDDEN; + } + } + else + { + if (m_docPages[page_num].Annotate != Annotate_t.NO_ANNOTATE) + { + if (m_showannot) + m_docPages[page_num].Annotate = Annotate_t.ANNOTATE_VISIBLE; + else + m_docPages[page_num].Annotate = Annotate_t.ANNOTATE_HIDDEN; + } + } + } + + private void InitialRenderWork(object sender, DoWorkEventArgs e) + { + BackgroundWorker worker = sender as BackgroundWorker; + int look_ahead = Math.Min(m_num_pages, Constants.INIT_LOOK_AHEAD); + + /* Do the first few full res pages */ + for (int k = 0; k < look_ahead; k++) + { + if (m_num_pages > k) + { + Point ras_size; + double scale_factor = 1.0; + Byte[] bitmap; + BlocksText charlist; + status_t code; + Annotate_t annot; + + if (ComputePageSize(k, scale_factor, out ras_size) == status_t.S_ISOK) + { + try + { + bitmap = new byte[(int)ras_size.X * (int)ras_size.Y * 4]; + + /* Synchronous call on our background thread */ + code = (status_t)mu_doc.RenderPage(k, bitmap, (int)ras_size.X, + (int)ras_size.Y, scale_factor, false, true, + !(m_textset[k]), out charlist, m_showannot, out annot); + } + catch (OutOfMemoryException em) + { + Console.WriteLine("Memory allocation failed init page " + k + em.Message + "\n"); + break; + } + /* create new page if we rendered ok. set ui value with + * progress call back, pass page number, charlist and bitmap */ + if (code == status_t.S_ISOK) + { + pageprogress_t page_prog = new pageprogress_t(); + page_prog.bitmap = bitmap; + page_prog.charlist = charlist; + page_prog.pagenum = k; + page_prog.size = ras_size; + page_prog.annot = annot; + worker.ReportProgress(100, page_prog); + } + } + } + } + } + + private void InitialRenderProgressChanged(object sender, ProgressChangedEventArgs e) + { + pageprogress_t result = (pageprogress_t)(e.UserState); + int k = result.pagenum; + + m_textset[k] = true; + m_textptrs[k] = result.charlist; + m_docPages[k].TextBlocks = result.charlist; + UpdatePage(k, result.bitmap, result.size, Page_Content_t.FULL_RESOLUTION, 1.0, m_AA); + m_docPages[k].NativeHeight = (int) result.size.Y; + m_docPages[k].NativeWidth = (int)result.size.X; + SetPageAnnot(k, result.annot); + } + + private void InitialRenderCompleted(object sender, RunWorkerCompletedEventArgs e) + { + m_init_done = true; + m_currpage = 0; + RenderThumbs(); + m_file_open = true; + xaml_BackPage.Opacity = 1; + xaml_Contents.Opacity = 1; + xaml_currPage.Opacity = 1; + xaml_ForwardPage.Opacity = 1; + xaml_Links.Opacity = 1; + xaml_Print.Opacity = 1; + xaml_SavePDF.Opacity = 1; + xaml_Search.Opacity = 1; + xaml_Thumbs.Opacity = 1; + xaml_TotalPages.Opacity = 1; + xaml_zoomIn.Opacity = 1; + xaml_zoomOut.Opacity = 1; + xaml_Zoomsize.Opacity = 1; + xaml_ExpandFill.Opacity = 1; + xaml_ContScrollFill.Opacity = 1; + xaml_ActualSize.Opacity = 1; + xaml_Zoomsize.IsEnabled = true; + xaml_currPage.IsEnabled = true; + xaml_TotalPages.Text = "/ " + m_num_pages.ToString(); + xaml_currPage.Text = "1"; + xaml_ZoomSlider.Opacity = 1.0; + xaml_ZoomSlider.IsEnabled = true; + xaml_closefile.IsEnabled = true; + xaml_saveas.IsEnabled = true; + xaml_showinfo.IsEnabled = true; + xaml_extractselection.IsEnabled = true; + xaml_conversions.IsEnabled = true; + xaml_gsmessage.IsEnabled = true; + xaml_print.IsEnabled = true; + xaml_view.IsEnabled = true; + xaml_edit.IsEnabled = true; + if (m_isXPS) + DisabletoPDF(); + xaml_OpenProgressGrid.Visibility = System.Windows.Visibility.Collapsed; + xaml_VerticalScroll.Visibility = System.Windows.Visibility.Visible; + xaml_VerticalScroll.Value = 0; + } + + private void InitialRenderBG() + { + int look_ahead = Math.Min(Constants.INIT_LOOK_AHEAD, m_num_pages); + m_currpage = 0; + m_thumbnails.Capacity = m_num_pages; + + for (int k = 0; k < Constants.INIT_LOOK_AHEAD; k++) + { + m_docPages.Add(InitDocPage()); + m_docPages[k].PageNum = k; + m_textptrs.Add(new BlocksText()); + m_lineptrs.Add(new LinesText()); + m_textset.Add(false); + } + var dummy = InitDocPage(); + for (int k = Constants.INIT_LOOK_AHEAD; k < m_num_pages; k++) + { + m_docPages.Add(dummy); + m_textptrs.Add(new BlocksText()); + m_lineptrs.Add(new LinesText()); + m_textset.Add(false); + } + + xaml_PageList.ItemsSource = m_docPages; + + try + { + m_initrender = new BackgroundWorker(); + m_initrender.WorkerReportsProgress = true; + m_initrender.WorkerSupportsCancellation = false; + m_initrender.DoWork += new DoWorkEventHandler(InitialRenderWork); + m_initrender.RunWorkerCompleted += new RunWorkerCompletedEventHandler(InitialRenderCompleted); + m_initrender.ProgressChanged += new ProgressChangedEventHandler(InitialRenderProgressChanged); + m_initrender.RunWorkerAsync(); + } + catch (OutOfMemoryException e) + { + Console.WriteLine("Memory allocation failed during initial render\n"); + ShowMessage(NotifyType_t.MESS_ERROR, "Out of memory: " + e.Message); + } + } + private void StartViewer() + { + m_num_pages = mu_doc.GetPageCount(); + + if (m_num_pages == 0) + { + xaml_OpenProgressGrid.Visibility = System.Windows.Visibility.Collapsed; + CleanUp(); + ShowMessage(NotifyType_t.MESS_ERROR, m_currfile + " is corrupted"); + } + else + { + xaml_openfilestatus.Text = "Initial Page Rendering"; + xaml_openfilestatus.UpdateLayout(); + InitialRenderBG(); + } + } + + private status_t ComputePageSize(int page_num, double scale_factor, + out Point render_size) + { + Point renpageSize = new Point(); + + status_t code = (status_t)mu_doc.GetPageSize(page_num, out render_size); + if (code != status_t.S_ISOK) + return code; + + renpageSize.X = (render_size.X * scale_factor); + renpageSize.Y = (render_size.Y * scale_factor); + + render_size = renpageSize; + + return status_t.S_ISOK; + } + + private DocPage InitDocPage() + { + DocPage doc_page = new DocPage(); + + doc_page.BitMap = null; + doc_page.Height = Constants.BLANK_HEIGHT; + doc_page.Width = Constants.BLANK_WIDTH; + doc_page.NativeHeight = Constants.BLANK_HEIGHT; + doc_page.NativeWidth = Constants.BLANK_WIDTH; + doc_page.Content = Page_Content_t.NOTSET; + doc_page.TextBox = null; + doc_page.LinkBox = null; + doc_page.SelHeight = 0; + doc_page.SelWidth = 0; + doc_page.SelX = 0; + doc_page.SelY = 0; + return doc_page; + } + + #region Navigation + private void OnBackPageClick(object sender, RoutedEventArgs e) + { + if (m_currpage == 0 || !m_init_done) return; + m_ignorescrollchange = true; + RenderRange(m_currpage - 1, true, zoom_t.NO_ZOOM, 0); + } + + private void OnForwardPageClick(object sender, RoutedEventArgs e) + { + if (m_currpage == m_num_pages - 1 || !m_init_done) return; + m_ignorescrollchange = true; + RenderRange(m_currpage + 1, true, zoom_t.NO_ZOOM, 0); + } + + private void PageEnterClicked(object sender, System.Windows.Input.KeyEventArgs e) + { + if (e.Key == Key.Return) + { + e.Handled = true; + var desired_page = xaml_currPage.Text; + try + { + int page = System.Convert.ToInt32(desired_page); + if (page > 0 && page < (m_num_pages + 1)) + { + m_ignorescrollchange = true; + RenderRange(page - 1, true, zoom_t.NO_ZOOM, 0); + } + } + catch (FormatException e1) + { + Console.WriteLine("String is not a sequence of digits."); + } + catch (OverflowException e2) + { + Console.WriteLine("The number cannot fit in an Int32."); + } + } + } + + private void OnKeyDownHandler(object sender, System.Windows.Input.KeyEventArgs e) + { + switch (e.Key) + { + case Key.Left: + case Key.PageUp: + if (m_currpage == 0 || !m_init_done) + return; + m_ignorescrollchange = true; + RenderRange(m_currpage - 1, true, zoom_t.NO_ZOOM, 0); + e.Handled = true; + break; + + case Key.Right: + case Key.PageDown: + if (m_currpage == m_num_pages - 1 || !m_init_done) + return; + m_ignorescrollchange = true; + RenderRange(m_currpage + 1, true, zoom_t.NO_ZOOM, 0); + e.Handled = true; + break; + + case Key.Up: + if (!m_init_done) + return; + e.Handled = true; + OffsetScroll(-Constants.VERT_SCROLL_STEP * m_doczoom); + break; + + case Key.Down: + if (!m_init_done) + return; + e.Handled = true; + OffsetScroll(Constants.VERT_SCROLL_STEP * m_doczoom); + break; + } + } + #endregion Navigation + + private void CancelLoadClick(object sender, RoutedEventArgs e) + { + /* Cancel during thumbnail loading. Deactivate the button + * and cancel the thumbnail rendering */ + if (m_thumbworker != null) + m_thumbworker.CancelAsync(); + //xaml_CancelThumb.IsEnabled = false; + } + + private void ToggleThumbs(object sender, RoutedEventArgs e) + { + if (m_have_thumbs) + { + if (xaml_ThumbGrid.Visibility == System.Windows.Visibility.Collapsed) + { + xaml_ThumbGrid.Visibility = System.Windows.Visibility.Visible; + } + else + { + xaml_ThumbGrid.Visibility = System.Windows.Visibility.Collapsed; + } + } + } + + private void ToggleContents(object sender, RoutedEventArgs e) + { + if (xaml_ContentGrid.Visibility == System.Windows.Visibility.Visible) + { + xaml_ContentGrid.Visibility = System.Windows.Visibility.Collapsed; + return; + } + + if (m_num_pages < 0) + return; + + if (xaml_ContentList.Items.IsEmpty) + { + int size_content = mu_doc.ComputeContents(); + if (size_content == 0) + return; + xaml_ContentList.ItemsSource = mu_doc.contents; + } + xaml_ContentGrid.Visibility = System.Windows.Visibility.Visible; + } + + private void ThumbSelected(object sender, MouseButtonEventArgs e) + { + var item = ((FrameworkElement)e.OriginalSource).DataContext as DocPage; + + if (item != null) + { + if (item.PageNum < 0) + return; + RenderRange(item.PageNum, true, zoom_t.NO_ZOOM, 0); + } + } + + private void ContentSelected(object sender, MouseButtonEventArgs e) + { + var item = ((FrameworkElement)e.OriginalSource).DataContext as ContentItem; + if (item != null && item.Page < m_num_pages) + { + int page = m_docPages[item.Page].PageNum; + if (page >= 0 && page < m_num_pages) + RenderRange(page, true, zoom_t.NO_ZOOM, 0); + } + } + + /* We need to avoid rendering due to size changes */ + private void ListViewScrollChanged(object sender, ScrollChangedEventArgs e) + { + /* This makes sure we dont call render range a second time due to + * page advances */ + int first_item = -1; + int second_item = -1; + //Console.WriteLine("***************************************/n"); + //Console.WriteLine("VerticalChange = " + e.VerticalChange + "/n"); + //Console.WriteLine("ExtentHeightChange = " + e.ExtentHeightChange + "/n"); + //Console.WriteLine("ExtentWidthChange = " + e.ExtentWidthChange + "/n"); + //Console.WriteLine("HorizontalChange = " + e.HorizontalChange + "/n"); + //Console.WriteLine("ViewportHeightChange = " + e.ViewportHeightChange + "/n"); + //Console.WriteLine("ViewportWidthChange = " + e.ViewportWidthChange + "/n"); + //Console.WriteLine("ExtentHeight = " + e.ExtentHeight + "/n"); + //Console.WriteLine("ViewportHeight = " + e.ViewportHeight + "/n"); + //Console.WriteLine("VerticalOffset = " + e.VerticalOffset + "/n"); + //Console.WriteLine("***************************************/n"); + if (m_ignorescrollchange == true) + { + m_ignorescrollchange = false; + return; + } + if (!m_init_done) + return; + if (e.VerticalChange == 0) + return; + if (m_num_pages == 1) + return; + + /* From current page go forward and backward checking if pages are + * visible */ + ScrollViewer viewer = FindScrollViewer(xaml_PageList); + if (viewer != null) + { + double bottom = this.ActualHeight; + /* first going forward */ + for (int kk = m_currpage + 1; kk < m_num_pages; kk++) + { + UIElement uiElement = (UIElement)xaml_PageList.ItemContainerGenerator.ContainerFromIndex(kk); + double y_top = uiElement.TranslatePoint(new System.Windows.Point(0, 0), xaml_PageList).Y; + double y_bottom = uiElement.TranslatePoint(new System.Windows.Point(0, m_docPages[kk].Height), xaml_PageList).Y; + /* Test if this and all further pages are outside window */ + if (y_top > bottom) + break; + /* Test if page is not even yet in window */ + if (y_bottom > 0) + { + if (!(m_dispatcherTimer != null && m_dispatcherTimer.IsEnabled == true)) + { + /* In this case grab the first one that we find */ + if (second_item == -1) + second_item = kk; + } + } + } + + /* and now going backward */ + for (int kk = m_currpage; kk > -1; kk--) + { + UIElement uiElement = (UIElement)xaml_PageList.ItemContainerGenerator.ContainerFromIndex(kk); + double y_top = uiElement.TranslatePoint(new System.Windows.Point(0, 0), xaml_PageList).Y; + double y_bottom = uiElement.TranslatePoint(new System.Windows.Point(0, m_docPages[kk].Height), xaml_PageList).Y; + /* Test if this and all further pages are outside window */ + if (y_bottom < 0) + break; + if (y_top < bottom) + if (!(m_dispatcherTimer != null && m_dispatcherTimer.IsEnabled == true)) + first_item = kk; + } + e.Handled = true; + if (first_item != -1) + second_item = first_item; + /* Finish */ + if (m_ScrolledChanged) + { + m_ScrolledChanged = false; + } + else + { + /* We have to update the vertical scroll position */ + double perc = (e.VerticalOffset) / (e.ExtentHeight - e.ViewportHeight); + xaml_VerticalScroll.Value = perc * xaml_VerticalScroll.Maximum; + } + if (second_item < 0) + second_item = 0; + RenderRange(second_item, false, zoom_t.NO_ZOOM, 0); + } + } + + /* ScrollIntoView will not scroll to top on its own. If item is already + * in view it just sits there */ + private void ScrollPageToTop(int k, double offset, bool from_scroller) + { + if (m_num_pages == 1) + return; + /* Get access to the scrollviewer */ + ScrollViewer viewer = FindScrollViewer(xaml_PageList); + if (viewer != null) + { + UIElement uiElement = (UIElement) xaml_PageList.ItemContainerGenerator.ContainerFromIndex(k); + double y = uiElement.TranslatePoint(new System.Windows.Point(0, offset), xaml_PageList).Y; + double curr_value = viewer.VerticalOffset; + viewer.ScrollToVerticalOffset(curr_value + y); + + if (!from_scroller) + { + double perc = (double) k / (double) ( m_num_pages - 1); + xaml_VerticalScroll.Value = perc * xaml_VerticalScroll.Maximum; + } + } + } + + /* Scroll to offset */ + private void OffsetScroll(double offset) + { + if (m_num_pages == 1) + return; + /* Get access to the scrollviewer */ + ScrollViewer viewer = FindScrollViewer(xaml_PageList); + if (viewer != null) + { + double curr_value = viewer.VerticalOffset; + AdjustScrollPercent(offset / viewer.ScrollableHeight); + viewer.ScrollToVerticalOffset(curr_value + offset); + } + } + + /* Scroll to offset */ + private void OffsetScrollPercent(double percent) + { + /* Get access to the scrollviewer */ + ScrollViewer viewer = FindScrollViewer(xaml_PageList); + if (viewer != null) + { + double curr_value = viewer.VerticalOffset; + if (curr_value < 0 || curr_value > viewer.MaxHeight) + return; + var extentheight = viewer.ExtentHeight - viewer.ViewportHeight; + + var pos = extentheight * percent; + viewer.ScrollToVerticalOffset(pos); + } + } + + /* Render +/- the look ahead from where we are if blank page is present */ + async private void RenderRange(int new_page, bool scrollto, zoom_t newzoom, double zoom_offset) + { + /* Need to figure out what pages are going to be visible */ + double bottom = this.ActualHeight; + bool done = false; + int final_page = new_page; + double count = -zoom_offset; + int offset = -1; + bool scrollbottom = false; + + if (newzoom != zoom_t.NO_ZOOM) + offset = 0; + + if (m_thumbnails.Count < m_num_pages) + final_page = final_page + 1; + else + { + while (!done && final_page >= 0 && final_page < m_num_pages) + { + count = count + m_thumbnails[final_page].NativeHeight * m_doczoom; + final_page = final_page + 1; + if (final_page == m_num_pages || count > bottom) + done = true; + } + /* We have zoomed out to a point where the offset will not stay + * in its current spot. Figure out where we need to be */ + final_page = final_page - 1; + if (newzoom == zoom_t.ZOOM_OUT && count < bottom) + { + int curr_page = new_page - 1; + while (true) + { + if (curr_page < 0) + break; + count = count + m_thumbnails[curr_page].NativeHeight * m_doczoom; + if (count > bottom) + break; + curr_page = curr_page - 1; + } + new_page = curr_page; + if (new_page < 0) + new_page = 0; + scrollbottom = true; + } + } + + for (int k = new_page + offset; k <= final_page + 1; k++) + { + if (k >= 0 && k < m_num_pages) + { + /* Check if page is already rendered */ + var doc = m_docPages[k]; + if (doc.Content != Page_Content_t.FULL_RESOLUTION || + doc.Zoom != m_doczoom || m_AA != doc.AA || + (doc.Annotate == Annotate_t.UNKNOWN && m_showannot) || + (doc.Annotate == Annotate_t.ANNOTATE_VISIBLE && !m_showannot) || + (doc.Annotate == Annotate_t.ANNOTATE_HIDDEN && m_showannot)) + { + Point ras_size; + double scale_factor = m_doczoom; + /* To avoid multiple page renderings on top of one + * another with scroll changes mark this as being + * full resolution */ + m_docPages[k].Content = Page_Content_t.FULL_RESOLUTION; + /* Avoid launching another thread just because we don't + * know the annotation condition for this page */ + m_docPages[k].Annotate = Annotate_t.COMPUTING; + if (ComputePageSize(k, scale_factor, out ras_size) == status_t.S_ISOK) + { + try + { + Byte[] bitmap = new byte[(int)ras_size.X * (int)ras_size.Y * 4]; + BlocksText charlist = null; + Annotate_t annot = Annotate_t.UNKNOWN; + m_docPages[k].NativeWidth = (int)(ras_size.X / scale_factor); + m_docPages[k].NativeHeight = (int)(ras_size.Y / scale_factor); + + Task<int> ren_task = + new Task<int>(() => mu_doc.RenderPage(k, bitmap, + (int)ras_size.X, (int)ras_size.Y, scale_factor, + false, true, !(m_textset[k]), out charlist, m_showannot, + out annot)); + ren_task.Start(); + await ren_task.ContinueWith((antecedent) => + { + status_t code = (status_t)ren_task.Result; + if (code == status_t.S_ISOK) + { + SetPageAnnot(k, annot); + if (m_docPages[k].TextBox != null) + ScaleTextBox(k); + if (m_links_on && m_page_link_list != null) + { + m_docPages[k].LinkBox = m_page_link_list[k]; + if (m_docPages[k].LinkBox != null) + ScaleLinkBox(k); + } + else + { + m_docPages[k].LinkBox = null; + } + if (!(m_textset[k]) && charlist != null) + { + m_textptrs[k] = charlist; + if (scale_factor != 1.0) + ScaleTextBlocks(k, scale_factor); + m_docPages[k].TextBlocks = m_textptrs[k]; + m_textset[k] = true; + if (m_selectall) + { + int num_blocks = m_docPages[k].TextBlocks.Count; + for (int jj = 0; jj < num_blocks; jj++) + { + m_docPages[k].TextBlocks[jj].Color = m_textselectcolor; + } + } + } + else + { + /* We had to rerender due to scale */ + if (m_textptrs[k] != null) + { + ScaleTextBlocks(k, scale_factor); + m_docPages[k].TextBlocks = m_textptrs[k]; + } + if (m_lineptrs[k] != null) + { + ScaleTextLines(k, scale_factor); + m_docPages[k].SelectedLines = m_lineptrs[k]; + } + } + /* This needs to be handled here to reduce + * flashing effects */ + if (newzoom != zoom_t.NO_ZOOM && k == new_page) + { + m_ignorescrollchange = true; + UpdatePageSizes(); + xaml_VerticalScroll.Maximum = m_totalpageheight * m_doczoom + 4 * m_num_pages; + if (!scrollbottom) + ScrollPageToTop(new_page, zoom_offset, false); + } + UpdatePage(k, bitmap, ras_size, + Page_Content_t.FULL_RESOLUTION, m_doczoom, m_AA); + if (k == new_page && scrollto && new_page != m_currpage) + { + m_doscroll = true; + ScrollPageToTop(k, 0, false); + } + } + }, TaskScheduler.FromCurrentSynchronizationContext()); + } + catch (OutOfMemoryException e) + { + Console.WriteLine("Memory allocation failed page " + k + "\n"); + ShowMessage(NotifyType_t.MESS_ERROR, "Out of memory: " + e.Message); + } + } + } + else + { + /* We did not have to render the page but we may need to + * scroll to it */ + if (k == new_page && scrollto && new_page != m_currpage) + { + m_ignorescrollchange = true; + ScrollPageToTop(k, 0, false); + } + } + } + } + /* Release old range and set new page */ + //ReleasePages(m_currpage, new_page - 1, final_page + 1); + m_currpage = new_page; + xaml_currPage.Text = (m_currpage + 1).ToString(); + } + + /* Avoids the next page jumping into view when touched by mouse. See xaml code */ + private void AvoidScrollIntoView(object sender, RequestBringIntoViewEventArgs e) + { + if (!m_doscroll) + e.Handled = true; + else + m_doscroll = false; + } + + private void ReleasePages(int old_page, int new_page, int final_page) + { + if (old_page == new_page) return; + /* To keep from having memory issue reset the page back to + the thumb if we are done rendering the thumbnails */ + for (int k = 0; k < m_num_pages; k++) + { + if (k < new_page || k > final_page) + { + if (k >= 0 && k < m_num_pages) + { + SetThumb(k); + } + } + } + } + + /* Return this page from a full res image to the thumb image */ + private void SetThumb(int page_num) + { + /* See what is there now */ + var doc_page = m_docPages[page_num]; + if (doc_page.Content == Page_Content_t.THUMBNAIL && + doc_page.Zoom == m_doczoom) return; + + if (m_thumbnails.Count > page_num) + { + doc_page.Content = Page_Content_t.THUMBNAIL; + doc_page.Zoom = m_doczoom; + + doc_page.BitMap = m_thumbnails[page_num].BitMap; + doc_page.Width = (int)(m_doczoom * doc_page.BitMap.PixelWidth / Constants.SCALE_THUMB); + doc_page.Height = (int)(m_doczoom * doc_page.BitMap.PixelHeight / Constants.SCALE_THUMB); + doc_page.PageNum = page_num; + doc_page.LinkBox = null; + doc_page.TextBox = null; + /* No need to refresh unless it just occurs during other stuff + * we just want to make sure we can release the bitmaps */ + //doc_page.PageRefresh(); + } + } + + private void gsDLL(object gsObject, String mess) + { + ShowMessage(NotifyType_t.MESS_STATUS, mess); + } + + /* Catastrophic */ + private void muDLL(object gsObject, String mess) + { + ShowMessage(NotifyType_t.MESS_ERROR, mess); + /* Disable even the ability to open a file */ + xaml_open.Opacity = 0.5; + xaml_open.IsEnabled = false; + xaml_file.Opacity = 0.5; + xaml_file.IsEnabled = false; + /* And to drag - drop or registry start up */ + xaml_PageList.RemoveHandler(Grid.DragOverEvent, new System.Windows.DragEventHandler(Grid_DragOver)); + xaml_PageList.RemoveHandler(Grid.DropEvent, new System.Windows.DragEventHandler(Grid_Drop)); + m_regstartup = false; + } + + private void gsIO(object gsObject, String mess, int len) + { + m_gsoutput.Update(mess, len); + } + + private void mupdfUpdate(object muObject, muPDFEventArgs asyncInformation) + { + if (asyncInformation.Completed) + { + xaml_MuPDFProgress.Value = 100; + xaml_MuPDFGrid.Visibility = System.Windows.Visibility.Collapsed; + if (asyncInformation.Params.result == GS_Result_t.gsFAILED) + { + ShowMessage(NotifyType_t.MESS_STATUS, "MuPDF failed to convert document"); + } + MuPDFResult(asyncInformation.Params); + } + else + { + this.xaml_MuPDFProgress.Value = asyncInformation.Progress; + } + } + + /* MuPDF Result*/ + public void MuPDFResult(ConvertParams_t gs_result) + { + if (gs_result.result == GS_Result_t.gsCANCELLED) + { + xaml_MuPDFGrid.Visibility = System.Windows.Visibility.Collapsed; + return; + } + if (gs_result.result == GS_Result_t.gsFAILED) + { + xaml_MuPDFGrid.Visibility = System.Windows.Visibility.Collapsed; + ShowMessage(NotifyType_t.MESS_STATUS, "MuPDF Failed Conversion"); + return; + } + ShowMessage(NotifyType_t.MESS_STATUS, "MuPDF Completed Conversion"); + } + + private void gsProgress(object gsObject, gsEventArgs asyncInformation) + { + if (asyncInformation.Completed) + { + xaml_DistillProgress.Value = 100; + xaml_DistillGrid.Visibility = System.Windows.Visibility.Collapsed; + if (asyncInformation.Params.result == GS_Result_t.gsFAILED) + { + switch (asyncInformation.Params.task) + { + case GS_Task_t.CREATE_XPS: + ShowMessage(NotifyType_t.MESS_STATUS, "Ghostscript failed to create XPS"); + break; + + case GS_Task_t.PS_DISTILL: + ShowMessage(NotifyType_t.MESS_STATUS, "Ghostscript failed to distill PS"); + break; + + case GS_Task_t.SAVE_RESULT: + ShowMessage(NotifyType_t.MESS_STATUS, "Ghostscript failed to convert document"); + break; + } + return; + } + GSResult(asyncInformation.Params); + } + else + { + this.xaml_DistillProgress.Value = asyncInformation.Progress; + } + } + + /* GS Result*/ + public void GSResult(gsParams_t gs_result) + { + if (gs_result.result == GS_Result_t.gsCANCELLED) + { + xaml_DistillGrid.Visibility = System.Windows.Visibility.Collapsed; + return; + } + if (gs_result.result == GS_Result_t.gsFAILED) + { + xaml_DistillGrid.Visibility = System.Windows.Visibility.Collapsed; + ShowMessage(NotifyType_t.MESS_STATUS, "GS Failed Conversion"); + return; + } + switch (gs_result.task) + { + case GS_Task_t.CREATE_XPS: + xaml_DistillGrid.Visibility = System.Windows.Visibility.Collapsed; + PrintXPS(gs_result.outputfile); + break; + + case GS_Task_t.PS_DISTILL: + xaml_DistillGrid.Visibility = System.Windows.Visibility.Collapsed; + m_origfile = gs_result.inputfile; + OpenFile2(gs_result.outputfile); + break; + + case GS_Task_t.SAVE_RESULT: + ShowMessage(NotifyType_t.MESS_STATUS, "GS Completed Conversion"); + break; + } + } + + private void PrintCommand(object sender, ExecutedRoutedEventArgs e) + { + Print(sender, e); + } + + /* Printing is achieved using xpswrite device in ghostscript and + * pushing that file through the XPS print queue */ + private void Print(object sender, RoutedEventArgs e) + { + if (!m_file_open) + return; + + /* If file is already xps then gs need not do this */ + if (!m_isXPS) + { + xaml_DistillProgress.Value = 0; + if (m_ghostscript.CreateXPS(m_currfile, Constants.DEFAULT_GS_RES, m_num_pages) == gsStatus.GS_BUSY) + { + ShowMessage(NotifyType_t.MESS_STATUS, "GS currently busy"); + return; + } + else + { + /* Right now this is not possible to cancel due to the way + * that gs is run for xpswrite from pdf */ + xaml_CancelDistill.Visibility = System.Windows.Visibility.Collapsed; + xaml_DistillName.Text = "Convert to XPS"; + xaml_DistillName.FontWeight = FontWeights.Bold; + xaml_DistillGrid.Visibility = System.Windows.Visibility.Visible; + } + } + else + PrintXPS(m_currfile); + } + + private void PrintXPS(String file) + { + gsprint ghostprint = new gsprint(); + System.Windows.Controls.PrintDialog pDialog = ghostprint.GetPrintDialog(); + + if (pDialog == null) + return; + /* We have to create the XPS document on a different thread */ + XpsDocument xpsDocument = new XpsDocument(file, FileAccess.Read); + FixedDocumentSequence fixedDocSeq = xpsDocument.GetFixedDocumentSequence(); + PrintQueue printQueue = pDialog.PrintQueue; + + m_ghostprint = ghostprint; + xaml_PrintGrid.Visibility = System.Windows.Visibility.Visible; + + xaml_PrintProgress.Value = 0; + + ghostprint.Print(printQueue, fixedDocSeq); + } + + private void PrintProgress(object printHelper, gsPrintEventArgs Information) + { + if (Information.Status != PrintStatus_t.PRINT_BUSY) + { + xaml_PrintProgress.Value = 100; + xaml_PrintGrid.Visibility = System.Windows.Visibility.Collapsed; + } + else + { + xaml_PrintProgress.Value = + 100.0 * (double)Information.Page / (double)m_num_pages; + } + } + + private void CancelMuPDFClick(object sender, RoutedEventArgs e) + { + xaml_CancelMuPDF.IsEnabled = false; + mu_doc.Cancel(); + } + + private void CancelDistillClick(object sender, RoutedEventArgs e) + { + xaml_CancelDistill.IsEnabled = false; + if (m_ghostscript != null) + m_ghostscript.Cancel(); + } + + private void CancelPrintClick(object sender, RoutedEventArgs e) + { + m_ghostprint.CancelAsync(); + } + + private void ShowGSMessage(object sender, RoutedEventArgs e) + { + m_gsoutput.Show(); + } + + private void ConvertClick(object sender, RoutedEventArgs e) + { + if (m_ghostscript.GetStatus() != gsStatus.GS_READY) + { + ShowMessage(NotifyType_t.MESS_STATUS, "GS busy"); + return; + } + + if (m_convertwin == null || !m_convertwin.IsActive) + { + m_convertwin = new Convert(m_num_pages); + m_convertwin.ConvertUpdateMain += new Convert.ConvertCallBackMain(ConvertReturn); + m_convertwin.Activate(); + m_convertwin.Show(); + } + } + + private void ConvertReturn(object sender) + { + Device device = (Device)m_convertwin.xaml_DeviceList.SelectedItem; + if (device == null) + { + ShowMessage(NotifyType_t.MESS_STATUS, "No Device Selected"); + return; + } + + if (m_ghostscript.GetStatus() != gsStatus.GS_READY && + !device.MuPDFDevice) + { + ShowMessage(NotifyType_t.MESS_STATUS, "GS busy"); + return; + } + + System.Collections.IList pages = m_convertwin.xaml_PageList.SelectedItems; + System.Collections.IList pages_selected = null; + String options = m_convertwin.xaml_options.Text; + int resolution = 72; + bool multi_page_needed = false; + int first_page = -1; + int last_page = -1; + + if (pages.Count == 0) + { + ShowMessage(NotifyType_t.MESS_STATUS, "No Pages Selected"); + return; + } + + /* Get a filename */ + System.Windows.Forms.SaveFileDialog dlg = new System.Windows.Forms.SaveFileDialog(); + dlg.Filter = "All files (*.*)|*.*"; + dlg.FilterIndex = 1; + if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) + { + if (device.MuPDFDevice) + { + /* Allow only one of these as a time */ + pages_selected = pages; + var val = m_convertwin.xaml_resolution.Text; + if (val.Length > 0) + { + bool isok = true; + int num = resolution; + try + { + num = System.Convert.ToInt32(val); + } + catch (FormatException e) + { + isok = false; + Console.WriteLine("Input string is not a sequence of digits."); + } + catch (OverflowException e) + { + isok = false; + Console.WriteLine("The number cannot fit in an Int32."); + } + if (isok && num > 0) + resolution = num; + } + + if (mu_doc.ConvertSave(device.DeviceType, dlg.FileName, + pages.Count, pages_selected, resolution) == gsStatus.GS_BUSY) + { + ShowMessage(NotifyType_t.MESS_STATUS, "MuPDF conversion busy"); + return; + } + xaml_CancelMuPDF.Visibility = System.Windows.Visibility.Visible; + xaml_MuPDFGrid.Visibility = System.Windows.Visibility.Visible; + } + else + { + if (!device.SupportsMultiPage && m_num_pages > 1) + multi_page_needed = true; + + if (pages.Count != m_num_pages) + { + /* We may need to go through page by page. Determine if + * selection of pages is continuous. This is done by + * looking at the first one in the list and the last one + * in the list and checking the length */ + SelectPage lastpage = (SelectPage)pages[pages.Count - 1]; + SelectPage firstpage = (SelectPage)pages[0]; + int temp = lastpage.Page - firstpage.Page + 1; + if (temp == pages.Count) + { + /* Pages are contiguous. Add first and last page + * as command line option */ + options = options + " -dFirstPage=" + firstpage.Page + " -dLastPage=" + lastpage.Page; + first_page = firstpage.Page; + last_page = lastpage.Page; + } + else + { + /* Pages are not continguous. We will do this page + * by page.*/ + pages_selected = pages; + multi_page_needed = true; /* need to put in separate outputs */ + } + } + xaml_DistillProgress.Value = 0; + if (m_ghostscript.Convert(m_currfile, options, + device.DeviceName, dlg.FileName, pages.Count, resolution, + multi_page_needed, pages_selected, first_page, last_page, + null, null) == gsStatus.GS_BUSY) + { + ShowMessage(NotifyType_t.MESS_STATUS, "GS busy"); + return; + } + xaml_DistillName.Text = "GS Converting Document"; + xaml_CancelDistill.Visibility = System.Windows.Visibility.Collapsed; + xaml_DistillName.FontWeight = FontWeights.Bold; + xaml_DistillGrid.Visibility = System.Windows.Visibility.Visible; + } + m_convertwin.Close(); + } + return; + } + + private void ExtractPages(object sender, RoutedEventArgs e) + { + if (!m_init_done || m_isXPS) + return; + + if (m_extractwin == null || !m_extractwin.IsActive) + { + m_extractwin = new PageExtractSave(m_num_pages); + m_extractwin.ExtractMain += new PageExtractSave.ExtractCallBackMain(ExtractReturn); + m_extractwin.Activate(); + m_extractwin.Show(); + } + } + + private void ExtractReturn(object sender) + { + if (m_extractwin.xaml_PageList.SelectedItems.Count == 0) + { + ShowMessage(NotifyType_t.MESS_STATUS, "No Pages Selected"); + return; + } + + /* Go through the actual list not the selected items list. The + * selected items list contains them in the order that the were + * selected not the order graphically shown */ + List<SelectPage> pages = new List<SelectPage>(m_extractwin.xaml_PageList.SelectedItems.Count); + + for (int kk = 0; kk < m_extractwin.xaml_PageList.Items.Count; kk++) + { + var item = (m_extractwin.xaml_PageList.ItemContainerGenerator.ContainerFromIndex(kk)) as System.Windows.Controls.ListViewItem; + if (item.IsSelected == true) + { + pages.Add((SelectPage) m_extractwin.Pages[kk]); + } + } + + /* Get a filename */ + System.Windows.Forms.SaveFileDialog dlg = new System.Windows.Forms.SaveFileDialog(); + dlg.Filter = "All files (*.pdf)|*.pdf"; + dlg.FilterIndex = 1; + if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) + { + mu_doc.PDFExtract(m_currfile, dlg.FileName, m_currpassword, m_currpassword != null, + false, pages.Count, pages); + m_extractwin.Close(); + } + return; + } + + private void GetPassword() + { + if (m_password == null) + { + m_password = new Password(); + m_password.PassUpdateMain += new Password.PassCallBackMain(PasswordReturn); + m_password.Activate(); + m_password.Show(); + } + } + + private void PasswordReturn(object sender) + { + if (mu_doc.ApplyPassword(m_password.xaml_Password.Password)) + { + m_currpassword = m_password.xaml_Password.Password; + m_password.Close(); + m_password = null; + xaml_OpenProgressGrid.Visibility = System.Windows.Visibility.Visible; + xaml_openfilestatus.Text = "Opening File"; + StartViewer(); + } + else + { + xaml_OpenProgressGrid.Visibility = System.Windows.Visibility.Collapsed; + ShowMessage(NotifyType_t.MESS_STATUS, "Password Incorrect"); + } + } + + private void ShowInfo(object sender, RoutedEventArgs e) + { + String Message; + + if (m_file_open) + { + String filename; + + if (m_origfile != null && (m_document_type == DocumentTypes.PS || + m_document_type == DocumentTypes.EPS)) + filename = m_origfile; + else + filename = m_currfile; + + Message = + " File: " + filename + "\n" + + "Document Type: " + m_document_type + "\n" + + " Pages: " + m_num_pages + "\n" + + " Current Page: " + (m_currpage + 1) + "\n"; + if (m_infowindow == null || !(m_infowindow.IsActive)) + m_infowindow = new Info(); + m_infowindow.xaml_TextInfo.Text = Message; + m_infowindow.FontFamily = new FontFamily("Courier New"); + m_infowindow.Show(); + } + } + + #region Zoom Control + + /* Find out where the current page is */ + private double ComputeOffsetZoomOut(double old_zoom) + { + double y = 0; + ScrollViewer viewer = FindScrollViewer(xaml_PageList); + if (viewer != null) + { + /* Look at the offset and where it falls relative to the top of our current page */ + UIElement uiElement = (UIElement)xaml_PageList.ItemContainerGenerator.ContainerFromIndex(m_currpage); + y = viewer.TranslatePoint(new System.Windows.Point(0, 0), uiElement).Y; + } + return y * m_doczoom / old_zoom; + } + + private double ComputeOffsetZoomIn(double old_zoom, out int new_page) + { + double y = 0; + ScrollViewer viewer = FindScrollViewer(xaml_PageList); + new_page = m_currpage; + if (viewer != null) + { + /* Look at the offset and where it falls relative to the top of our current page */ + UIElement uiElement = (UIElement)xaml_PageList.ItemContainerGenerator.ContainerFromIndex(m_currpage); + y = viewer.TranslatePoint(new System.Windows.Point(0, 0), uiElement).Y; + + /* If we are zoomed out, we can be on a page that is not on the top boundry. See if we can find one + * that is */ + if (y < 0) + { + new_page = m_currpage - 1; + while (true) + { + if (new_page < 0) + { + new_page = 0; + return 0; + } + uiElement = (UIElement)xaml_PageList.ItemContainerGenerator.ContainerFromIndex(new_page); + y = viewer.TranslatePoint(new System.Windows.Point(0, 0), uiElement).Y; + if (y >= 0) + { + return y * m_doczoom / old_zoom; + } + new_page = new_page - 1; + } + } + } + return y * m_doczoom / old_zoom; + } + + private void ZoomOut(object sender, RoutedEventArgs e) + { + if (!m_init_done || m_doczoom <= Constants.ZOOM_MIN) + return; + double old_zoom = m_doczoom; + m_doczoom = m_doczoom - Constants.ZOOM_STEP; + if (m_doczoom < Constants.ZOOM_MIN) + m_doczoom = Constants.ZOOM_MIN; + xaml_ZoomSlider.Value = m_doczoom * 100.0; + double offset = ComputeOffsetZoomOut(old_zoom); + RenderRange(m_currpage, false, zoom_t.ZOOM_OUT, offset); + } + + private void ZoomIn(object sender, RoutedEventArgs e) + { + if (!m_init_done || m_doczoom >= Constants.ZOOM_MAX) + return; + double old_zoom = m_doczoom; + m_doczoom = m_doczoom + Constants.ZOOM_STEP; + if (m_doczoom > Constants.ZOOM_MAX) + m_doczoom = Constants.ZOOM_MAX; + xaml_ZoomSlider.Value = m_doczoom * 100.0; + int newpage; + double offset = ComputeOffsetZoomIn(old_zoom, out newpage); + RenderRange(newpage, false, zoom_t.ZOOM_IN, offset); + } + + private void ActualSize(object sender, RoutedEventArgs e) + { + if (!m_init_done) + return; + double old_zoom = m_doczoom; + m_doczoom = 1.0; + xaml_ZoomSlider.Value = m_doczoom * 100.0; + if (old_zoom < 1.0) + { + int new_page; + double offset = ComputeOffsetZoomIn(old_zoom, out new_page); + RenderRange(new_page, false, zoom_t.ZOOM_IN, offset); + } + else if (old_zoom > 1.0) + { + double offset = ComputeOffsetZoomOut(old_zoom); + RenderRange(m_currpage, false, zoom_t.ZOOM_OUT, offset); + } + } + + private void ContScrollFill(object sender, RoutedEventArgs e) + { + if (!m_init_done) + return; + /* Scale our pages based upon the size of scrollviewer */ + ScrollViewer viewer = FindScrollViewer(xaml_PageList); + if (viewer == null) + return; + double width = viewer.ViewportWidth; + double page_width = m_thumbnails[m_currpage].NativeWidth; + double scale = width / page_width; + if (scale < Constants.ZOOM_MIN) + scale = Constants.ZOOM_MIN; + if (scale > Constants.ZOOM_MAX) + scale = Constants.ZOOM_MAX; + if (m_doczoom == scale) + return; + double old_zoom = m_doczoom; + m_doczoom = scale; + xaml_ZoomSlider.Value = m_doczoom * 100.0; + if (old_zoom > m_doczoom) + RenderRange(m_currpage, true, zoom_t.ZOOM_OUT, 0); + else + RenderRange(m_currpage, true, zoom_t.ZOOM_IN, 0); + } + + private void ExpandFill(object sender, RoutedEventArgs e) + { + if (!m_init_done) + return; + /* Scale our pages based upon the size of scrollviewer */ + ScrollViewer viewer = FindScrollViewer(xaml_PageList); + if (viewer == null) + return; + double height = viewer.ViewportHeight; + double width = viewer.ViewportWidth; + double page_height = m_thumbnails[m_currpage].NativeHeight; + double page_width = m_thumbnails[m_currpage].NativeWidth; + double height_scale = height / page_height; + double width_scale = width / page_width; + double scale = Math.Min(height_scale, width_scale); + if (scale < Constants.ZOOM_MIN) + scale = Constants.ZOOM_MIN; + if (scale > Constants.ZOOM_MAX) + scale = Constants.ZOOM_MAX; + if (m_doczoom == scale) + return; + double old_zoom = m_doczoom; + m_doczoom = scale; + xaml_ZoomSlider.Value = m_doczoom * 100.0; + if (old_zoom > m_doczoom) + RenderRange(m_currpage, true, zoom_t.ZOOM_OUT, 0); + else + RenderRange(m_currpage, true, zoom_t.ZOOM_IN, 0); + } + + private void ShowFooter(object sender, RoutedEventArgs e) + { + xaml_FooterControl.Visibility = System.Windows.Visibility.Visible; + } + + private void HideFooter(object sender, RoutedEventArgs e) + { + xaml_FooterControl.Visibility = System.Windows.Visibility.Collapsed; + } + + private void ZoomReleased(object sender, MouseButtonEventArgs e) + { + if (m_init_done) + { + double zoom = xaml_ZoomSlider.Value / 100.0; + if (zoom > Constants.ZOOM_MAX) + zoom = Constants.ZOOM_MAX; + if (zoom < Constants.ZOOM_MIN) + zoom = Constants.ZOOM_MIN; + double old_zoom = zoom; + m_doczoom = zoom; + if (old_zoom > m_doczoom) + { + double offset = ComputeOffsetZoomOut(old_zoom); + RenderRange(m_currpage, false, zoom_t.ZOOM_OUT, offset); + } + else + { + int new_page; + double offset = ComputeOffsetZoomIn(old_zoom, out new_page); + RenderRange(new_page, false, zoom_t.ZOOM_IN, offset); + } + } + } + + /* If the zoom is not equalto 1 then set the zoom to 1 and scoll to this page */ + private void PageDoubleClick(object sender, MouseButtonEventArgs e) + { + return; /* Disable this for now */ + if (m_doczoom != 1.0) + { + double old_zoom = m_doczoom; + m_doczoom = 1.0; + xaml_Zoomsize.Text = "100"; + var item = ((FrameworkElement)e.OriginalSource).DataContext as DocPage; + if (item != null) + { + if (old_zoom > m_doczoom) + { + double offset = ComputeOffsetZoomOut(old_zoom); + RenderRange(m_currpage, false, zoom_t.ZOOM_OUT, offset); + } + else + { + int new_page; + double offset = ComputeOffsetZoomIn(old_zoom, out new_page); + RenderRange(new_page, false, zoom_t.ZOOM_IN, offset); + } + } + } + } + + private void ZoomEnterClicked(object sender, System.Windows.Input.KeyEventArgs e) + { + if (e.Key == Key.Return) + { + e.Handled = true; + var desired_zoom = xaml_Zoomsize.Text; + try + { + double zoom = (double)System.Convert.ToInt32(desired_zoom) / 100.0; + if (zoom > Constants.ZOOM_MAX) + zoom = Constants.ZOOM_MAX; + if (zoom < Constants.ZOOM_MIN) + zoom = Constants.ZOOM_MIN; + double old_zoom = m_doczoom; + m_doczoom = zoom; + if (old_zoom > m_doczoom) + { + double offset = ComputeOffsetZoomOut(old_zoom); + RenderRange(m_currpage, false, zoom_t.ZOOM_OUT, offset); + } + else + { + int new_page; + double offset = ComputeOffsetZoomIn(old_zoom, out new_page); + RenderRange(new_page, false, zoom_t.ZOOM_IN, offset); + } + } + catch (FormatException e1) + { + Console.WriteLine("String is not a sequence of digits."); + } + catch (OverflowException e2) + { + Console.WriteLine("The number cannot fit in an Int32."); + } + } + } + + /* Rescale the pages based upon the zoom value and the native size */ + private void UpdatePageSizes() + { + SetThumbwidth(); + for (int k = 0; k > m_num_pages; k++) + { + var thumbpage = m_thumbnails[k]; + var page = m_docPages[k]; + + if (page.Zoom == m_doczoom) + continue; + int scale_zoom = (int)Math.Round((double)page.Height / (double)thumbpage.NativeHeight); + if (scale_zoom != m_doczoom) + { + page.Height = (int)Math.Round(thumbpage.NativeHeight * m_doczoom); + page.Width = (int)Math.Round(thumbpage.NativeWidth * m_doczoom); + } + } + } + #endregion Zoom Control + + #region Thumb Rendering + void SetThumbInit(int page_num, Byte[] bitmap, Point ras_size, double zoom_in) + { + /* Three jobs. Store the thumb and possibly update the full page. Also + add to collection of pages. Set up page geometry info (scale of + 100 percent ) */ + + DocPage doc_page = new DocPage(); + m_thumbnails.Add(doc_page); + + doc_page.Width = (int)ras_size.X; + + doc_page.Height = (int)ras_size.Y; + doc_page.NativeWidth = (int)(ras_size.X / Constants.SCALE_THUMB); + doc_page.NativeHeight = (int)(ras_size.Y / Constants.SCALE_THUMB); + m_totalpageheight = m_totalpageheight + doc_page.NativeHeight; + + doc_page.Content = Page_Content_t.THUMBNAIL; + doc_page.Zoom = zoom_in; + int stride = doc_page.Width * 4; + doc_page.BitMap = BitmapSource.Create(doc_page.Width, doc_page.Height, + 72, 72, PixelFormats.Pbgra32, BitmapPalettes.Halftone256, bitmap, stride); + doc_page.PageNum = page_num; + + /* Lets see if we need to set the main page */ + var doc = m_docPages[page_num]; + switch (doc.Content) + { + case Page_Content_t.FULL_RESOLUTION: + case Page_Content_t.THUMBNAIL: + return; + + case Page_Content_t.NOTSET: + doc_page = InitDocPage(); + doc_page.Content = Page_Content_t.THUMBNAIL; + doc_page.Zoom = zoom_in; + doc_page.BitMap = m_thumbnails[page_num].BitMap; + doc_page.Width = (int)(ras_size.X / Constants.SCALE_THUMB); + doc_page.Height = (int)(ras_size.Y / Constants.SCALE_THUMB); + doc_page.PageNum = page_num; + this.m_docPages[page_num] = doc_page; + break; + + case Page_Content_t.OLD_RESOLUTION: + return; + } + } + + private void ThumbsWork(object sender, DoWorkEventArgs e) + { + Point ras_size; + status_t code; + double scale_factor = Constants.SCALE_THUMB; + BackgroundWorker worker = sender as BackgroundWorker; + + Byte[] bitmap; + + for (int k = 0; k < m_num_pages; k++) + { + if (ComputePageSize(k, scale_factor, out ras_size) == status_t.S_ISOK) + { + try + { + bitmap = new byte[(int)ras_size.X * (int)ras_size.Y * 4]; + BlocksText charlist; + Annotate_t annot; + /* Synchronous call on our background thread */ + code = (status_t)mu_doc.RenderPage(k, bitmap, (int)ras_size.X, + (int)ras_size.Y, scale_factor, false, false, false, + out charlist, false, out annot); + } + catch (OutOfMemoryException em) + { + Console.WriteLine("Memory allocation failed thumb page " + k + em.Message + "\n"); + break; + } + /* Use thumb if we rendered ok */ + if (code == status_t.S_ISOK) + { + double percent = 100 * (double)(k + 1) / (double)m_num_pages; + thumb_t curr_thumb = new thumb_t(); + curr_thumb.page_num = k; + curr_thumb.bitmap = bitmap; + curr_thumb.size = ras_size; + worker.ReportProgress((int)percent, curr_thumb); + } + } + if (worker.CancellationPending == true) + { + e.Cancel = true; + break; + } + } + } + + private void ThumbsCompleted(object sender, RunWorkerCompletedEventArgs e) + { + xaml_ProgressGrid.Visibility = System.Windows.Visibility.Collapsed; + xaml_ThumbProgress.Value = 0; + xaml_ThumbList.ItemsSource = m_thumbnails; + m_have_thumbs = true; + m_thumbworker = null; + //xaml_CancelThumb.IsEnabled = true; + xaml_ThumbList.Items.Refresh(); + xaml_VerticalScroll.Minimum = 0; + xaml_VerticalScroll.Maximum = m_totalpageheight + 4 * m_num_pages; + //thumbSize = (viewportSize/(maximum–minimum+viewportSize))×trackLength + SetThumbwidth(); + //ScrollBarExtensions.SetThumbLength(xaml_VerticalScroll, 1); + } + + private void ThumbsProgressChanged(object sender, ProgressChangedEventArgs e) + { + thumb_t thumb = (thumb_t)(e.UserState); + + xaml_ThumbProgress.Value = e.ProgressPercentage; + SetThumbInit(thumb.page_num, thumb.bitmap, thumb.size, 1.0); + } + + private void RenderThumbs() + { + /* Create background task for rendering the thumbnails. Allow + this to be cancelled if we open a new doc while we are in loop + rendering. Put the UI updates in the progress changed which will + run on the main thread */ + try + { + m_thumbworker = new BackgroundWorker(); + m_thumbworker.WorkerReportsProgress = true; + m_thumbworker.WorkerSupportsCancellation = true; + m_thumbworker.DoWork += new DoWorkEventHandler(ThumbsWork); + m_thumbworker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(ThumbsCompleted); + m_thumbworker.ProgressChanged += new ProgressChangedEventHandler(ThumbsProgressChanged); + xaml_ProgressGrid.Visibility = System.Windows.Visibility.Visible; + m_thumbworker.RunWorkerAsync(); + } + catch (OutOfMemoryException e) + { + Console.WriteLine("Memory allocation failed during thumb rendering\n"); + ShowMessage(NotifyType_t.MESS_ERROR, "Out of memory: " + e.Message); + } + } + #endregion Thumb Rendering + + #region Copy Paste + /* Copy the current page as a bmp to the clipboard this is done at the + * current resolution */ + private void CopyPage(object sender, RoutedEventArgs e) + { + if (!m_init_done) + return; + var curr_page = m_docPages[m_currpage]; + System.Windows.Clipboard.SetImage(curr_page.BitMap); + m_clipboardset = true; + } + + /* Paste the page to various types supported by the windows encoder class */ + private void PastePage(object sender, RoutedEventArgs e) + { + var menu = (System.Windows.Controls.MenuItem)sender; + + String tag = (String)menu.Tag; + + if (!m_clipboardset || !System.Windows.Clipboard.ContainsImage() || + !m_init_done) + return; + var bitmap = System.Windows.Clipboard.GetImage(); + + BitmapEncoder encoder; + System.Windows.Forms.SaveFileDialog dlg = new System.Windows.Forms.SaveFileDialog(); + dlg.FilterIndex = 1; + + switch (tag) + { + case "PNG": + dlg.Filter = "PNG Files(*.png)|*.png"; + encoder = new PngBitmapEncoder(); + + break; + case "JPG": + dlg.Filter = "JPEG Files(*.jpg)|*.jpg"; + encoder = new JpegBitmapEncoder(); + break; + + case "WDP": + dlg.Filter = "HDP Files(*.wdp)|*.wdp"; + encoder = new WmpBitmapEncoder(); + break; + + case "TIF": + dlg.Filter = "TIFF Files(*.tif)|*.tif"; + encoder = new TiffBitmapEncoder(); + break; + + case "BMP": + dlg.Filter = "BMP Files(*.bmp)|*.bmp"; + encoder = new BmpBitmapEncoder(); + break; + + case "GIF": + dlg.Filter = "GIF Files(*.gif)|*.gif"; + encoder = new GifBitmapEncoder(); + break; + + default: + return; + } + + encoder.Frames.Add(BitmapFrame.Create(bitmap)); + if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) + { + using (var stream = dlg.OpenFile()) + encoder.Save(stream); + } + } + #endregion Copy Paste + + #region SaveAs + String CreatePDFXA(Save_Type_t type) + { + Byte[] Resource; + String Profile; + + switch (type) + { + case Save_Type_t.PDFA1_CMYK: + case Save_Type_t.PDFA2_CMYK: + Resource = Properties.Resources.PDFA_def; + Profile = m_outputintents.cmyk_icc; + break; + + case Save_Type_t.PDFA1_RGB: + case Save_Type_t.PDFA2_RGB: + Resource = Properties.Resources.PDFA_def; + Profile = m_outputintents.rgb_icc; + break; + + case Save_Type_t.PDFX3_CMYK: + Resource = Properties.Resources.PDFX_def; + Profile = m_outputintents.cmyk_icc; + break; + + case Save_Type_t.PDFX3_GRAY: + Resource = Properties.Resources.PDFX_def; + Profile = m_outputintents.gray_icc; + break; + + default: + return null; + } + + String Profile_new = Profile.Replace("\\", "/"); + String result = System.Text.Encoding.UTF8.GetString(Resource); + String pdfx_cust = result.Replace("ICCPROFILE", Profile_new); + var out_file = System.IO.Path.GetTempFileName(); + System.IO.File.WriteAllText(out_file, pdfx_cust); + return out_file; + } + + private void SaveFile(Save_Type_t type) + { + if (!m_file_open) + return; + + System.Windows.Forms.SaveFileDialog dlg = new System.Windows.Forms.SaveFileDialog(); + dlg.FilterIndex = 1; + + /* PDF output types */ + if (type <= Save_Type_t.PDF) + { + dlg.Filter = "PDF Files(*.pdf)|*.pdf"; + if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) + { + String options = null; + bool use_gs = true; + String init_file = CreatePDFXA(type); + + switch (type) + { + case Save_Type_t.PDF: + /* All done. No need to use gs or mupdf */ + System.IO.File.Copy(m_currfile, dlg.FileName, true); + use_gs = false; + break; + case Save_Type_t.LINEAR_PDF: + mu_doc.PDFExtract(m_currfile, dlg.FileName, m_currpassword, + m_currpassword != null, true, -1, null); + use_gs = false; + break; + case Save_Type_t.PDF13: + options = "-dCompatibilityLevel=1.3"; + break; + case Save_Type_t.PDFA1_CMYK: + options = "-dPDFA=1 -dNOOUTERSAVE -dPDFACompatibilityPolicy=1 -sProcessColorModel=DeviceCMYK -dColorConversionStrategy=/CMYK -sOutputICCProfile=" + m_outputintents.cmyk_icc; + break; + case Save_Type_t.PDFA1_RGB: + options = "-dPDFA=1 -dNOOUTERSAVE -dPDFACompatibilityPolicy=1 -sProcessColorModel=DeviceRGB -dColorConversionStrategy=/RGB -sOutputICCProfile=" + m_outputintents.rgb_icc; + break; + case Save_Type_t.PDFA2_CMYK: + options = "-dPDFA=2 -dNOOUTERSAVE -dPDFACompatibilityPolicy=1 -sProcessColorModel=DeviceCMYK -dColorConversionStrategy=/CMYK -sOutputICCProfile=" + m_outputintents.cmyk_icc; + break; + case Save_Type_t.PDFA2_RGB: + options = "-dPDFA=2 -dNOOUTERSAVE -dPDFACompatibilityPolicy=1 -sProcessColorModel=DeviceRGB -dColorConversionStrategy=/RGB -sOutputICCProfile=" + m_outputintents.rgb_icc; + break; + case Save_Type_t.PDFX3_CMYK: + options = "-dPDFX -dNOOUTERSAVE -dPDFACompatibilityPolicy=1 -sProcessColorModel=DeviceCMYK -dColorConversionStrategy=/CMYK -sOutputICCProfile=" + m_outputintents.cmyk_icc; + break; + case Save_Type_t.PDFX3_GRAY: + options = "-dPDFX -dNOOUTERSAVE -dPDFACompatibilityPolicy=1 -sProcessColorModel=DeviceGray -dColorConversionStrategy=/Gray -sOutputICCProfile=" + m_outputintents.cmyk_icc; + break; + + } + if (use_gs) + { + xaml_DistillProgress.Value = 0; + if (m_ghostscript.Convert(m_currfile, options, + Enum.GetName(typeof(gsDevice_t), gsDevice_t.pdfwrite), + dlg.FileName, m_num_pages, 300, false, null, -1, -1, + init_file, null) == gsStatus.GS_BUSY) + { + ShowMessage(NotifyType_t.MESS_STATUS, "GS busy"); + return; + } + xaml_DistillName.Text = "Creating PDF"; + xaml_CancelDistill.Visibility = System.Windows.Visibility.Collapsed; + xaml_DistillName.FontWeight = FontWeights.Bold; + xaml_DistillGrid.Visibility = System.Windows.Visibility.Visible; + } + } + } + else + { + /* Non PDF output */ + gsDevice_t Device = gsDevice_t.xpswrite; + bool use_mupdf = true; + String Message = ""; + textout_t textout = textout_t.HTML; + switch (type) + { + case Save_Type_t.HTML: + dlg.Filter = "HTML (*.html)|*.html"; + Message = "HTML content written"; + break; + case Save_Type_t.XML: + dlg.Filter = "XML (*.xml)|*.xml"; + Message = "XML content written"; + textout = textout_t.XML; + break; + case Save_Type_t.TEXT: + dlg.Filter = "Text (*.txt)|*.txt"; + Message = "Text content written"; + textout = textout_t.TEXT; + break; + case Save_Type_t.PCLXL: + use_mupdf = false; + dlg.Filter = "PCL-XL (*.bin)|*.bin"; + Device = gsDevice_t.pxlcolor; + break; + case Save_Type_t.XPS: + use_mupdf = false; + dlg.Filter = "XPS Files(*.xps)|*.xps"; + break; + } + if (!use_mupdf) + { + if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) + { + if (m_ghostscript.Convert(m_currfile, "", + Enum.GetName(typeof(gsDevice_t), Device), + dlg.FileName, 1, 300, false, null, -1, -1, + null, null) == gsStatus.GS_BUSY) + { + ShowMessage(NotifyType_t.MESS_STATUS, "GS busy"); + return; + } + } + } + else + { + if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) + { + /* Write out first non null page then append the rest */ + int curr_page = 0; + bool done = false; + + while (!done) + { + String output = null; + output = mu_doc.GetText(curr_page, textout); + if (output == null) + { + curr_page = curr_page + 1; + if (curr_page == m_num_pages) + { + ShowMessage(NotifyType_t.MESS_STATUS, "No text found in file"); + return; + } + } + else + { + System.IO.File.WriteAllText(dlg.FileName, output); + done = true; + } + } + curr_page = curr_page + 1; + + if (curr_page == m_num_pages) + { + ShowMessage(NotifyType_t.MESS_STATUS, Message); + return; + } + done = false; + while (!done) + { + String output = null; + output = mu_doc.GetText(curr_page, textout); + if (output != null) + { + System.IO.File.AppendAllText(dlg.FileName, output); + } + curr_page = curr_page + 1; + if (curr_page == m_num_pages) + { + ShowMessage(NotifyType_t.MESS_STATUS, Message); + return; + } + } + } + } + } + } + + private void SaveSVG(object sender, RoutedEventArgs e) + { + SaveFile(Save_Type_t.SVG); + } + + private void SavePDF(object sender, RoutedEventArgs e) + { + SaveFile(Save_Type_t.PDF); + } + + private void SaveText(object sender, RoutedEventArgs e) + { + SaveFile(Save_Type_t.TEXT); + } + + private void SaveXML(object sender, RoutedEventArgs e) + { + SaveFile(Save_Type_t.XML); + } + + private void SaveHTML(object sender, RoutedEventArgs e) + { + SaveFile(Save_Type_t.HTML); + } + + private void Linearize(object sender, RoutedEventArgs e) + { + SaveFile(Save_Type_t.LINEAR_PDF); + } + + private void SavePDF13(object sender, RoutedEventArgs e) + { + SaveFile(Save_Type_t.PDF13); + } + + private void SavePDFX3_Gray(object sender, RoutedEventArgs e) + { + if (m_outputintents.gray_icc == null) + { + ShowMessage(NotifyType_t.MESS_STATUS, "Set Gray Output Intent ICC Profile"); + return; + } + SaveFile(Save_Type_t.PDFX3_GRAY); + } + + private void SavePDFX3_CMYK(object sender, RoutedEventArgs e) + { + if (m_outputintents.cmyk_icc == null) + { + ShowMessage(NotifyType_t.MESS_STATUS, "Set CMYK Output Intent ICC Profile"); + return; + } + SaveFile(Save_Type_t.PDFX3_CMYK); + } + + private void SavePDFA1_RGB(object sender, RoutedEventArgs e) + { + if (m_outputintents.rgb_icc == null) + { + ShowMessage(NotifyType_t.MESS_STATUS, "Set RGB Output Intent ICC Profile"); + return; + } + SaveFile(Save_Type_t.PDFA1_RGB); + } + + private void SavePDFA1_CMYK(object sender, RoutedEventArgs e) + { + if (m_outputintents.cmyk_icc == null) + { + ShowMessage(NotifyType_t.MESS_STATUS, "Set CMYK Output Intent ICC Profile"); + return; + } + SaveFile(Save_Type_t.PDFA1_CMYK); + } + + private void SavePDFA2_RGB(object sender, RoutedEventArgs e) + { + if (m_outputintents.rgb_icc == null) + { + ShowMessage(NotifyType_t.MESS_STATUS, "Set RGB Output Intent ICC Profile"); + return; + } + SaveFile(Save_Type_t.PDFA2_RGB); + } + + private void SavePDFA2_CMYK(object sender, RoutedEventArgs e) + { + if (m_outputintents.cmyk_icc == null) + { + ShowMessage(NotifyType_t.MESS_STATUS, "Set CMYK Output Intent ICC Profile"); + return; + } + SaveFile(Save_Type_t.PDFA2_CMYK); + } + + private void SavePCLXL(object sender, RoutedEventArgs e) + { + SaveFile(Save_Type_t.PCLXL); + } + private void SaveXPS(object sender, RoutedEventArgs e) + { + SaveFile(Save_Type_t.XPS); + } + #endregion SaveAs + + #region Extract + private void Extract(Extract_Type_t type) + { + if (m_selection != null || !m_init_done) + return; + + m_selection = new Selection(m_currpage + 1, m_doczoom, type); + m_selection.UpdateMain += new Selection.CallBackMain(SelectionMade); + m_selection.Show(); + m_selection.xaml_Image.Source = m_docPages[m_currpage].BitMap; + m_selection.xaml_Image.Height = m_docPages[m_currpage].Height; + m_selection.xaml_Image.Width = m_docPages[m_currpage].Width; + } + + async private void SelectionZoom(int page_num, double zoom) + { + Point ras_size; + if (ComputePageSize(page_num, zoom, out ras_size) == status_t.S_ISOK) + { + try + { + Byte[] bitmap = new byte[(int)ras_size.X * (int)ras_size.Y * 4]; + BlocksText charlist; + Annotate_t annot; + + Task<int> ren_task = + new Task<int>(() => mu_doc.RenderPage(page_num, bitmap, + (int)ras_size.X, (int)ras_size.Y, zoom, false, true, + false, out charlist, true, out annot)); + ren_task.Start(); + await ren_task.ContinueWith((antecedent) => + { + status_t code = (status_t)ren_task.Result; + if (code == status_t.S_ISOK) + { + if (m_selection != null) + { + int stride = (int)ras_size.X * 4; + m_selection.xaml_Image.Source = BitmapSource.Create((int)ras_size.X, (int)ras_size.Y, 72, 72, PixelFormats.Pbgra32, BitmapPalettes.Halftone256, bitmap, stride); + m_selection.xaml_Image.Height = (int)ras_size.Y; + m_selection.xaml_Image.Width = (int)ras_size.X; + m_selection.UpdateRect(); + m_selection.m_curr_state = SelectStatus_t.OK; + } + } + }, TaskScheduler.FromCurrentSynchronizationContext()); + } + catch (OutOfMemoryException e) + { + Console.WriteLine("Memory allocation failed page " + page_num + "\n"); + ShowMessage(NotifyType_t.MESS_ERROR, "Out of memory: " + e.Message); + } + } + } + + private void SelectionMade(object gsObject, SelectEventArgs results) + { + switch (results.State) + { + case SelectStatus_t.CANCEL: + case SelectStatus_t.CLOSE: + m_selection = null; + return; + case SelectStatus_t.SELECT: + /* Get the information we need */ + double zoom = results.ZoomFactor; + Point start = results.TopLeft; + Point size = results.Size; + int page = results.PageNum; + gsDevice_t Device = gsDevice_t.pdfwrite; + + start.X = start.X / zoom; + start.Y = start.Y / zoom; + size.X = size.X / zoom; + size.Y = size.Y / zoom; + + /* Do the actual extraction */ + String options; + System.Windows.Forms.SaveFileDialog dlg = new System.Windows.Forms.SaveFileDialog(); + dlg.FilterIndex = 1; + + /* Get us set up to do a fixed size */ + options = "-dFirstPage=" + page + " -dLastPage=" + page + + " -dDEVICEWIDTHPOINTS=" + size.X + " -dDEVICEHEIGHTPOINTS=" + + size.Y + " -dFIXEDMEDIA"; + + /* Set up the translation */ + String init_string = "<</Install {-" + start.X + " -" + + start.Y + " translate (testing) == flush}>> setpagedevice"; + + switch (results.Type) + { + case Extract_Type_t.PDF: + dlg.Filter = "PDF Files(*.pdf)|*.pdf"; + break; + case Extract_Type_t.EPS: + dlg.Filter = "EPS Files(*.eps)|*.eps"; + Device = gsDevice_t.eps2write; + break; + case Extract_Type_t.PS: + dlg.Filter = "PostScript Files(*.ps)|*.ps"; + Device = gsDevice_t.ps2write; + break; + case Extract_Type_t.SVG: + dlg.Filter = "SVG Files(*.svg)|*.svg"; + break; + } + if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) + { + if (m_ghostscript.Convert(m_currfile, options, + Enum.GetName(typeof(gsDevice_t), Device), + dlg.FileName, 1, 300, false, null, page, page, + null, init_string) == gsStatus.GS_BUSY) + { + ShowMessage(NotifyType_t.MESS_STATUS, "GS busy"); + return; + } + } + m_selection.Close(); + break; + case SelectStatus_t.ZOOMIN: + /* Render new page at this resolution and hand it off */ + SelectionZoom(results.PageNum - 1, results.ZoomFactor); + break; + case SelectStatus_t.ZOOMOUT: + /* Render new page at this resolution and hand it off */ + SelectionZoom(results.PageNum - 1, results.ZoomFactor); + break; + } + } + + private void ExtractPDF(object sender, RoutedEventArgs e) + { + Extract(Extract_Type_t.PDF); + } + private void ExtractEPS(object sender, RoutedEventArgs e) + { + Extract(Extract_Type_t.EPS); + } + private void ExtractPS(object sender, RoutedEventArgs e) + { + Extract(Extract_Type_t.PS); + } + private void OutputIntents(object sender, RoutedEventArgs e) + { + m_outputintents.Show(); + } + #endregion Extract + + #region Search + /* Search related code */ + private void Search(object sender, RoutedEventArgs e) + { + if (!m_init_done || (m_textsearch != null && m_textsearch.IsBusy)) + return; + + m_textsearch = null; /* Start out fresh */ + if (xaml_SearchControl.Visibility == System.Windows.Visibility.Collapsed) + xaml_SearchControl.Visibility = System.Windows.Visibility.Visible; + else + { + xaml_SearchControl.Visibility = System.Windows.Visibility.Collapsed; + xaml_SearchGrid.Visibility = System.Windows.Visibility.Collapsed; + ClearTextSearch(); + } + } + + private void OnSearchBackClick(object sender, RoutedEventArgs e) + { + String textToFind = xaml_SearchText.Text; + TextSearchSetUp(-1, textToFind); + } + + private void OnSearchForwardClick(object sender, RoutedEventArgs e) + { + String textToFind = xaml_SearchText.Text; + TextSearchSetUp(1, textToFind); + } + + /* The thread that is actually doing the search work */ + void SearchWork(object sender, DoWorkEventArgs e) + { + BackgroundWorker worker = sender as BackgroundWorker; + List<object> genericlist = e.Argument as List<object>; + int direction = (int)genericlist[0]; + String needle = (String)genericlist[1]; + /* To make sure we get the next page or current page during search */ + int in_search = (int)genericlist[2]; + m_searchpage = m_currpage + direction * in_search; + searchResults_t results = new searchResults_t(); + + /* Break if we find something, get to the end (or start of doc) + * or if we have a cancel occur */ + while (true) + { + int box_count = mu_doc.TextSearchPage(m_searchpage, needle); + int percent; + + if (direction == 1) + percent = (int)(100.0 * ((double)m_searchpage + 1) / (double)m_num_pages); + else + percent = 100 - (int)(100.0 * ((double)m_searchpage) / (double)m_num_pages); + + if (box_count > 0) + { + /* This page has something lets go ahead and extract and + * signal to the UI thread and end this thread */ + results.done = false; + results.num_rects = box_count; + results.page_found = m_searchpage; + results.rectangles = new List<Rect>(); + + for (int kk = 0; kk < box_count; kk++) + { + Point top_left; + Size size; + mu_doc.GetTextSearchItem(kk, out top_left, out size); + var rect = new Rect(top_left, size); + results.rectangles.Add(rect); + } + /* Reset global smart pointer once we have everything */ + mu_doc.ReleaseTextSearch(); + worker.ReportProgress(percent, results); + break; + } + else + { + /* This page has nothing. Lets go ahead and just update + * the progress bar */ + worker.ReportProgress(percent, null); + if (percent >= 100) + { + results.done = true; + results.needle = needle; + break; + } + m_searchpage = m_searchpage + direction; + } + if (worker.CancellationPending == true) + { + e.Cancel = true; + break; + } + } + e.Result = results; + } + + private void SearchProgressChanged(object sender, ProgressChangedEventArgs e) + { + if (e.UserState == null) + { + /* Nothing found */ + xaml_SearchProgress.Value = e.ProgressPercentage; + } + else + { + m_text_list = new List<RectList>(); + /* found something go to page and show results */ + searchResults_t results = (searchResults_t)e.UserState; + xaml_SearchProgress.Value = e.ProgressPercentage; + m_currpage = results.page_found; + /* Add in the rectangles */ + for (int kk = 0; kk < results.num_rects; kk++) + { + var rect_item = new RectList(); + rect_item.Scale = m_doczoom; + rect_item.Color = m_textsearchcolor; + rect_item.Height = results.rectangles[kk].Height * m_doczoom; + rect_item.Width = results.rectangles[kk].Width * m_doczoom; + rect_item.X = results.rectangles[kk].X * m_doczoom; + rect_item.Y = results.rectangles[kk].Y * m_doczoom; + rect_item.Index = kk.ToString(); + m_text_list.Add(rect_item); + } + m_docPages[results.page_found].TextBox = m_text_list; + m_doscroll = true; + xaml_PageList.ScrollIntoView(m_docPages[results.page_found]); + } + } + + private void SearchCompleted(object sender, RunWorkerCompletedEventArgs e) + { + if (e.Cancelled == true) + { + xaml_SearchGrid.Visibility = System.Windows.Visibility.Collapsed; + m_textsearch = null; + } + else + { + searchResults_t results = (searchResults_t)e.Result; + if (results.done == true) + { + xaml_SearchGrid.Visibility = System.Windows.Visibility.Collapsed; + m_textsearch = null; + ShowMessage(NotifyType_t.MESS_STATUS, "End of document search for \"" + results.needle + "\""); + } + } + } + + private void CancelSearchClick(object sender, RoutedEventArgs e) + { + if (m_textsearch != null && m_textsearch.IsBusy) + m_textsearch.CancelAsync(); + xaml_SearchGrid.Visibility = System.Windows.Visibility.Collapsed; + m_textsearch = null; + ClearTextSearch(); + } + + private void ClearTextSearch() + { + for (int kk = 0; kk < m_num_pages; kk++) + { + var temp = m_docPages[kk].TextBox; + if (temp != null) + { + m_docPages[kk].TextBox = null; + } + } + } + + private void ScaleTextBox(int pagenum) + { + var temp = m_docPages[pagenum].TextBox; + for (int kk = 0; kk < temp.Count; kk++) + { + var rect_item = temp[kk]; + double factor = m_doczoom / temp[kk].Scale; + + temp[kk].Height = temp[kk].Height * factor; + temp[kk].Width = temp[kk].Width * factor; + temp[kk].X = temp[kk].X * factor; + temp[kk].Y = temp[kk].Y * factor; + + temp[kk].Scale = m_doczoom; + temp[kk].PageRefresh(); + } + m_docPages[pagenum].TextBox = temp; + } + + private void TextSearchSetUp(int direction, String needle) + { + /* Create background task for performing text search. */ + try + { + int in_text_search = 0; + + if (m_textsearch != null && m_textsearch.IsBusy) + return; + + if (m_textsearch != null) + { + in_text_search = 1; + m_textsearch = null; + } + if (m_prevsearch != null && needle != m_prevsearch) + { + in_text_search = 0; + ClearTextSearch(); + } + + if (m_textsearch == null) + { + m_prevsearch = needle; + m_textsearch = new BackgroundWorker(); + m_textsearch.WorkerReportsProgress = true; + m_textsearch.WorkerSupportsCancellation = true; + var arguments = new List<object>(); + arguments.Add(direction); + arguments.Add(needle); + arguments.Add(in_text_search); + m_textsearch.DoWork += new DoWorkEventHandler(SearchWork); + m_textsearch.RunWorkerCompleted += new RunWorkerCompletedEventHandler(SearchCompleted); + m_textsearch.ProgressChanged += new ProgressChangedEventHandler(SearchProgressChanged); + xaml_SearchGrid.Visibility = System.Windows.Visibility.Visible; + m_textsearch.RunWorkerAsync(arguments); + } + } + catch (OutOfMemoryException e) + { + Console.WriteLine("Memory allocation failed during text search\n"); + ShowMessage(NotifyType_t.MESS_ERROR, "Out of memory: " + e.Message); + } + } + #endregion Search + + #region Link + private void LinksToggle(object sender, RoutedEventArgs e) + { + if (!m_init_done) + return; + + m_links_on = !m_links_on; + + if (m_page_link_list == null) + { + if (m_linksearch != null && m_linksearch.IsBusy) + return; + + m_page_link_list = new List<List<RectList>>(); + m_linksearch = new BackgroundWorker(); + m_linksearch.WorkerReportsProgress = false; + m_linksearch.WorkerSupportsCancellation = true; + m_linksearch.DoWork += new DoWorkEventHandler(LinkWork); + m_linksearch.RunWorkerCompleted += new RunWorkerCompletedEventHandler(LinkCompleted); + m_linksearch.RunWorkerAsync(); + } + else + { + if (m_links_on) + LinksOn(); + else + LinksOff(); + } + } + + private void LinkWork(object sender, DoWorkEventArgs e) + { + BackgroundWorker worker = sender as BackgroundWorker; + + for (int k = 0; k < m_num_pages; k++) + { + int box_count = mu_doc.GetLinksPage(k); + List<RectList> links = new List<RectList>(); + if (box_count > 0) + { + for (int j = 0; j < box_count; j++) + { + Point top_left; + Size size; + String uri; + int type; + int topage; + + mu_doc.GetLinkItem(j, out top_left, out size, out uri, + out topage, out type); + var rectlist = new RectList(); + rectlist.Height = size.Height * m_doczoom; + rectlist.Width = size.Width * m_doczoom; + rectlist.X = top_left.X * m_doczoom; + rectlist.Y = top_left.Y * m_doczoom; + rectlist.Color = m_linkcolor; + rectlist.Index = k.ToString() + "." + j.ToString(); + rectlist.PageNum = topage; + rectlist.Scale = m_doczoom; + if (uri != null) + rectlist.Urilink = new Uri(uri); + rectlist.Type = (Link_t)type; + links.Add(rectlist); + } + } + mu_doc.ReleaseLink(); + m_page_link_list.Add(links); + + if (worker.CancellationPending == true) + { + e.Cancel = true; + break; + } + } + } + + private void LinkCompleted(object sender, RunWorkerCompletedEventArgs e) + { + LinksOn(); + } + + private void ScaleLinkBox(int pagenum) + { + var temp = m_docPages[pagenum].LinkBox; + for (int kk = 0; kk < temp.Count; kk++) + { + var rect_item = temp[kk]; + double factor = m_doczoom / temp[kk].Scale; + + temp[kk].Height = temp[kk].Height * factor; + temp[kk].Width = temp[kk].Width * factor; + temp[kk].X = temp[kk].X * factor; + temp[kk].Y = temp[kk].Y * factor; + + temp[kk].Scale = m_doczoom; + temp[kk].PageRefresh(); + } + m_docPages[pagenum].LinkBox = temp; + } + /* Merge these */ + private void ScaleTextLines(int pagenum, double scale_factor) + { + var temp = m_lineptrs[pagenum]; + for (int kk = 0; kk < temp.Count; kk++) + { + var rect_item = temp[kk]; + double factor = scale_factor / temp[kk].Scale; + + temp[kk].Height = temp[kk].Height * factor; + temp[kk].Width = temp[kk].Width * factor; + temp[kk].X = temp[kk].X * factor; + temp[kk].Y = temp[kk].Y * factor; + + temp[kk].Scale = scale_factor; + } + m_lineptrs[pagenum] = temp; + } + + private void ScaleTextBlocks(int pagenum, double scale_factor) + { + var temp = m_textptrs[pagenum]; + for (int kk = 0; kk < temp.Count; kk++) + { + var rect_item = temp[kk]; + double factor = scale_factor / temp[kk].Scale; + + temp[kk].Height = temp[kk].Height * factor; + temp[kk].Width = temp[kk].Width * factor; + temp[kk].X = temp[kk].X * factor; + temp[kk].Y = temp[kk].Y * factor; + + temp[kk].Scale = scale_factor; + } + m_textptrs[pagenum] = temp; + } + + private int GetVisibleRange() + { + /* Need to figure out what pages are going to be visible */ + double bottom = this.ActualHeight; + bool done = false; + int final_page = m_currpage; + double count = 0; + + while (!done) + { + count = count + m_thumbnails[final_page].NativeHeight * m_doczoom; + final_page = final_page + 1; + if (final_page == m_num_pages || count > bottom) + done = true; + } + return final_page; + } + + /* Only visible pages */ + private void LinksOff() + { + int final_page = GetVisibleRange(); + for (int kk = m_currpage - 1; kk <= final_page + 1; kk++) + { + var temp = m_docPages[kk].LinkBox; + if (temp != null) + { + m_docPages[kk].LinkBox = null; + } + } + } + + /* Only visible pages */ + private void LinksOn() + { + int final_page = GetVisibleRange(); + for (int kk = m_currpage - 1; kk <= final_page + 1; kk++) + { + if (!(kk < 0 || kk > m_num_pages - 1)) + { + var temp = m_docPages[kk].LinkBox; + if (temp == null) + { + m_docPages[kk].LinkBox = m_page_link_list[kk]; + } + } + } + } + + private void LinkClick(object sender, MouseButtonEventArgs e) + { + var item = (Rectangle)sender; + + if (item == null) + return; + + String tag = (String)item.Tag; + int page = 0; + int index = 0; + + if (tag == null || tag.Length < 3 || !(tag.Contains('.'))) + return; + + String[] parts = tag.Split('.'); + try + { + page = System.Convert.ToInt32(parts[0]); + index = System.Convert.ToInt32(parts[1]); + + } + catch (FormatException e1) + { + Console.WriteLine("String is not a sequence of digits."); + } + catch (OverflowException e2) + { + Console.WriteLine("The number cannot fit in an Int32."); + } + + if (index >= 0 && index < m_num_pages && page >= 0 && page < m_num_pages) + { + var link_list = m_page_link_list[page]; + var link = link_list[index]; + + if (link.Type == Link_t.LINK_GOTO) + { + if (m_currpage != link.PageNum && link.PageNum >= 0 && + link.PageNum < m_num_pages) + RenderRange(link.PageNum, true, zoom_t.NO_ZOOM, 0); + } + else if (link.Type == Link_t.LINK_URI) + System.Diagnostics.Process.Start(link.Urilink.AbsoluteUri); + } + } + #endregion Link + + #region TextSelection + + /* Change cursor if we are over text block */ + private void ExitTextBlock(object sender, System.Windows.Input.MouseEventArgs e) + { + this.Cursor = System.Windows.Input.Cursors.Arrow; + } + + private void EnterTextBlock(object sender, System.Windows.Input.MouseEventArgs e) + { + this.Cursor = System.Windows.Input.Cursors.IBeam; + } + + private void ClearSelections() + { + for (int kk = 0; kk < m_textSelect.Count; kk++) + { + m_lineptrs[m_textSelect[kk].pagenum].Clear(); + if (m_docPages[m_textSelect[kk].pagenum].SelectedLines != null) + m_docPages[m_textSelect[kk].pagenum].SelectedLines.Clear(); + } + m_textSelect.Clear(); + m_textselected = false; + m_selectall = false; + SetSelectAll(m_blockcolor); + } + + private void InitTextSelection(DocPage page) + { + if (m_textSelect != null) + ClearSelections(); + else + m_textSelect = new List<textSelectInfo_t>(); + + m_intxtselect = true; + + textSelectInfo_t selinfo = new textSelectInfo_t(); + selinfo.pagenum = page.PageNum; + selinfo.first_line_full = false; + selinfo.last_line_full = false; + m_textSelect.Add(selinfo); + } + + private void PageMouseDown(object sender, MouseButtonEventArgs e) + { + if (this.Cursor != System.Windows.Input.Cursors.IBeam) + return; + + var page = ((FrameworkElement)e.Source).DataContext as DocPage; + Canvas can = ((FrameworkElement)e.Source).Parent as Canvas; + if (page == null || can == null) + return; + + InitTextSelection(page); + var posit = e.GetPosition(can); + + page.SelX = posit.X; + page.SelY = posit.Y; + page.SelAnchorX = posit.X; + page.SelAnchorY = posit.Y; + page.SelColor = m_regionselect; + + /* Create new holder for lines highlighted */ + m_lineptrs[page.PageNum] = new LinesText(); + } + + private void PageMouseMove(object sender, System.Windows.Input.MouseEventArgs e) + { + if (e.LeftButton == MouseButtonState.Released || m_intxtselect == false) + return; + + var page = ((FrameworkElement)e.Source).DataContext as DocPage; + Canvas can = ((FrameworkElement)e.Source).Parent as Canvas; + if (page == null || can == null) + return; + if (page.PageNum < 0) + return; + /* Store the location of our most recent page in case we exit window */ + var pos = e.GetPosition(can); + m_lastY = pos.Y; + m_maxY = can.Height; + /* Don't allow the listview to maintain control of the mouse, we need + * to detect if we leave the window */ + /* Make sure page is rendered */ + if (page.Content != Page_Content_t.FULL_RESOLUTION || + page.Zoom != m_doczoom) + { + RenderRange(page.PageNum, false, zoom_t.NO_ZOOM, 0); + } + + UpdateSelection(pos, page); + } + + /* Resize selection rect */ + private void UpdateSelection(System.Windows.Point pos, DocPage page) + { + bool new_page = true; + TextLine start_line, end_line; + double x = 0, y, w = 0, h; + bool found_first = false; + bool above_anchor = true; + bool first_line_full = false; + bool last_line_full = false; + + for (int kk = 0; kk < m_textSelect.Count; kk++) + if (m_textSelect[kk].pagenum == page.PageNum) + new_page = false; + + /* See if we have gone back to a previous page */ + if (!new_page && page.PageNum != m_textSelect[m_textSelect.Count - 1].pagenum) + { + DocPage curr_page = m_docPages[m_textSelect[m_textSelect.Count - 1].pagenum]; + curr_page.SelHeight = 0; + curr_page.SelWidth = 0; + m_textSelect.RemoveAt(m_textSelect.Count - 1); + m_lineptrs[curr_page.PageNum].Clear(); + curr_page.SelectedLines.Clear(); + } + if (new_page) + { + /* New page */ + page.SelX = pos.X; + page.SelY = pos.Y; + page.SelAnchorX = m_docPages[m_textSelect[m_textSelect.Count - 1].pagenum].SelAnchorX; + if (m_textSelect[m_textSelect.Count - 1].pagenum > page.PageNum) + { + page.SelAnchorY = page.Height; + } + else + { + page.SelAnchorY = 0; + } + page.SelColor = m_regionselect; + textSelectInfo_t info = new textSelectInfo_t(); + info.pagenum = page.PageNum; + info.first_line_full = false; + info.last_line_full = false; + m_textSelect.Add(info); + /* Create new holder for lines highlighted */ + m_lineptrs[page.PageNum] = new LinesText(); + } + + if (page.TextBlocks == null || page.TextBlocks.Count == 0) + return; + + /* Width changes translate across the pages */ + for (int jj = 0; jj < m_textSelect.Count; jj++) + { + DocPage curr_page = m_docPages[m_textSelect[jj].pagenum]; + x = Math.Min(pos.X, curr_page.SelAnchorX); + w = Math.Max(pos.X, curr_page.SelAnchorX) - x; + curr_page.SelX = x; + curr_page.SelWidth = w; + } + /* Height is just the current page */ + y = Math.Min(pos.Y, page.SelAnchorY); + h = Math.Max(pos.Y, page.SelAnchorY) - y; + + /* Determine if we are going up or down */ + if (pos.Y > page.SelAnchorY) + above_anchor = false; + page.SelY = y; + page.SelHeight = h; + + /* Clear out what we currently have */ + m_lineptrs[page.PageNum].Clear(); + + /* Stuff already selected above us */ + if (m_textSelect.Count > 1) + found_first = true; + /* Moving backwards through pages */ + if (m_textSelect.Count > 1 && m_textSelect[m_textSelect.Count - 2].pagenum > page.PageNum) + found_first = false; + + for (int jj = 0; jj < page.TextBlocks.Count; jj++) + { + /* Text blocks are already scaled. Lines are not */ + var intersect_blk = page.TextBlocks[jj].CheckIntersection(x, y, w, h); + var lines = page.TextBlocks[jj].TextLines; + + if (intersect_blk == Intersection_t.FULL) + { + /* Just add all the lines for this block */ + for (int kk = 0; kk < lines.Count; kk++) + m_lineptrs[page.PageNum].Add(lines[kk]); + if (jj == 0) + { + first_line_full = true; + found_first = true; + } + if (jj == page.TextBlocks.Count - 1) + last_line_full = true; + } + else if (intersect_blk != Intersection_t.NONE) + { + /* Now go through the lines */ + for (int kk = 0; kk < lines.Count; kk++) + { + double scale = m_doczoom / lines[kk].Scale; + //var intersect_line = lines[kk].CheckIntersection(x * scale, y * scale, w * scale, h * scale); + var intersect_line = lines[kk].CheckIntersection(x / scale , y / scale , w / scale , h / scale); + if (intersect_line == Intersection_t.FULL) + { + m_lineptrs[page.PageNum].Add(lines[kk]); + found_first = true; + if (jj == 0 && kk == 0) + first_line_full = true; + if (jj == page.TextBlocks.Count - 1 && + kk == lines.Count - 1) + last_line_full = true; + + } + else if (intersect_line == Intersection_t.PARTIAL) + { + double val; + var lett = lines[kk].TextCharacters; + + /* Now go through the width. */ + if (found_first) + { + if (above_anchor) + val = page.SelAnchorX; + else + val = pos.X; + + /* our second partial line */ + if (val > lines[kk].X * scale + lines[kk].Width * scale) + m_lineptrs[page.PageNum].Add(lines[kk]); + else + { + /* Use either anchor point or mouse pos */ + end_line = new TextLine(); + end_line.TextCharacters = new List<TextCharacter>(); + end_line.Height = 0; + end_line.Scale = m_doczoom; + for (int mm = 0; mm < lett.Count; mm++) + { + double letscale = m_doczoom / lett[mm].Scale; + if (lett[mm].X * letscale < val) + { + /* Can set to special color for debug */ + end_line.Color = m_textselectcolor; + /* special color for debug */ + //end_line.Color = "#4000FF00"; + end_line.Height = lines[kk].Height * scale; + end_line.Width = lett[mm].X * letscale + lett[mm].Width * letscale - lines[kk].X * scale; + end_line.Y = lines[kk].Y * scale; + end_line.X = lines[kk].X * scale; + end_line.TextCharacters.Add(lett[mm]); + } + else + break; + } + if (end_line.Height != 0) + m_lineptrs[page.PageNum].Add(end_line); + } + } + else + { + if (!above_anchor) + val = page.SelAnchorX; + else + val = pos.X; + + /* our first partial line */ + found_first = true; + if (val < lines[kk].X * scale) + m_lineptrs[page.PageNum].Add(lines[kk]); + else + { + start_line = new TextLine(); + start_line.TextCharacters = new List<TextCharacter>(); + start_line.Height = 0; + start_line.Scale = m_doczoom; + /* Use either anchor point or mouse pos */ + bool highlight_done = false; + for (int mm = 0; mm < lett.Count; mm++) + { + double letscale = m_doczoom / lett[mm].Scale; + if (lett[mm].X * letscale + lett[mm].Width * letscale >= val) + { + /* In this case, we are done with the + * highlight section as it only + * depends upon the first character + * we encounter and the line end. + * But we must continue to add in + * the selected characters */ + if (!highlight_done) + { + start_line.Color = m_textselectcolor; + /* special color for debug */ + /* start_line.Color = "#40FF0000"; */ + start_line.Height = lines[kk].Height * scale; + start_line.Width = lines[kk].X * scale + lines[kk].Width * scale - lett[mm].X * letscale; + start_line.X = lett[mm].X * letscale; + start_line.Y = lines[kk].Y * scale; + highlight_done = true; + } + start_line.TextCharacters.Add(lett[mm]); + } + } + if (start_line.Height > 0) + m_lineptrs[page.PageNum].Add(start_line); + } + } + } + } + } + } + var txtsel = m_textSelect[m_textSelect.Count - 1]; + txtsel.first_line_full = first_line_full; + txtsel.last_line_full = last_line_full; + m_textSelect[m_textSelect.Count - 1] = txtsel; + + /* Adjust for scale before assigning */ + var temp = m_lineptrs[page.PageNum]; + for (int kk = 0; kk < temp.Count; kk++) + { + var rect_item = temp[kk]; + double factor = m_doczoom / rect_item.Scale; + + temp[kk].Height = temp[kk].Height * factor; + temp[kk].Width = temp[kk].Width * factor; + temp[kk].X = temp[kk].X * factor; + temp[kk].Y = temp[kk].Y * factor; + + temp[kk].Scale = m_doczoom; + } + page.SelectedLines = m_lineptrs[page.PageNum]; + } + + /* A fix for handling column cases TODO FIXME */ + private void UpdateSelectionCol(System.Windows.Point pos, DocPage page) + { + bool new_page = true; + TextLine start_line, end_line; + double x = 0, y, w = 0, h; + bool found_first = false; + bool above_anchor = true; + bool first_line_full = false; + bool last_line_full = false; + + for (int kk = 0; kk < m_textSelect.Count; kk++) + if (m_textSelect[kk].pagenum == page.PageNum) + new_page = false; + + /* See if we have gone back to a previous page */ + if (!new_page && page.PageNum != m_textSelect[m_textSelect.Count - 1].pagenum) + { + DocPage curr_page = m_docPages[m_textSelect[m_textSelect.Count - 1].pagenum]; + curr_page.SelHeight = 0; + curr_page.SelWidth = 0; + m_textSelect.RemoveAt(m_textSelect.Count - 1); + m_lineptrs[curr_page.PageNum].Clear(); + curr_page.SelectedLines.Clear(); + } + if (new_page) + { + /* New page */ + page.SelX = pos.X; + page.SelY = pos.Y; + page.SelAnchorX = m_docPages[m_textSelect[m_textSelect.Count - 1].pagenum].SelAnchorX; + if (m_textSelect[m_textSelect.Count - 1].pagenum > page.PageNum) + { + page.SelAnchorY = page.Height; + } + else + { + page.SelAnchorY = 0; + } + page.SelColor = m_regionselect; + textSelectInfo_t info = new textSelectInfo_t(); + info.pagenum = page.PageNum; + info.first_line_full = false; + info.last_line_full = false; + m_textSelect.Add(info); + /* Create new holder for lines highlighted */ + m_lineptrs[page.PageNum] = new LinesText(); + } + + if (page.TextBlocks == null || page.TextBlocks.Count == 0) + return; + + /* Width changes translate across the pages */ + for (int jj = 0; jj < m_textSelect.Count; jj++) + { + DocPage curr_page = m_docPages[m_textSelect[jj].pagenum]; + x = Math.Min(pos.X, curr_page.SelAnchorX); + w = Math.Max(pos.X, curr_page.SelAnchorX) - x; + curr_page.SelX = x; + curr_page.SelWidth = w; + } + /* Height is just the current page */ + y = Math.Min(pos.Y, page.SelAnchorY); + h = Math.Max(pos.Y, page.SelAnchorY) - y; + + /* Determine if we are going up or down */ + if (pos.Y > page.SelAnchorY) + above_anchor = false; + page.SelY = y; + page.SelHeight = h; + + /* Clear out what we currently have */ + m_lineptrs[page.PageNum].Clear(); + + /* Stuff already selected above us */ + if (m_textSelect.Count > 1) + found_first = true; + /* Moving backwards through pages */ + if (m_textSelect.Count > 1 && m_textSelect[m_textSelect.Count - 2].pagenum > page.PageNum) + found_first = false; + + /* To properly handle the multiple columns we have to find the last + * line and make sure that all blocks between our first and last + * line are included. To do this we do an initial step through the + * blocks looking at our intersections */ + int first_block = -1; + int last_block = -1; + for (int jj = 0; jj < page.TextBlocks.Count; jj++ ) + { + var intersect_blk = page.TextBlocks[jj].CheckIntersection(x, y, w, h); + if (intersect_blk == Intersection_t.NONE && first_block != -1) + { + last_block = jj; /* NB: this is just past last block */ + break; + } + else if (intersect_blk != Intersection_t.NONE && first_block == -1) + first_block = jj; /* NB: this is the first block */ + } + if (first_block == -1) + return; + if (last_block == -1) + { + /* Only 1 block */ + last_block = first_block + 1; + } + + for (int jj = first_block; jj < last_block; jj++) + { + /* Text blocks are already scaled. Lines are not */ + var intersect_blk = page.TextBlocks[jj].CheckIntersection(x, y, w, h); + var lines = page.TextBlocks[jj].TextLines; + + if (jj == first_block || jj == last_block - 1) + { + /* Partial cases */ + if (intersect_blk == Intersection_t.FULL) + { + for (int kk = 0; kk < lines.Count; kk++) + m_lineptrs[page.PageNum].Add(lines[kk]); + if (jj == first_block) + { + first_line_full = true; + found_first = true; + } + if (jj == last_block - 1) + { + last_line_full = true; + } + } + else if (intersect_blk == Intersection_t.PARTIAL) + { + for (int kk = 0; kk < lines.Count; kk++) + { + double scale = m_doczoom / lines[kk].Scale; + var intersect_line = lines[kk].CheckIntersection(x * scale, y * scale, w * scale, h * scale); + if (intersect_line == Intersection_t.FULL) + { + m_lineptrs[page.PageNum].Add(lines[kk]); + found_first = true; + if (jj == 0 && kk == 0) + first_line_full = true; + if (jj == page.TextBlocks.Count - 1 && + kk == lines.Count - 1) + last_line_full = true; + + } + else if (intersect_line == Intersection_t.PARTIAL) + { + double val; + var lett = lines[kk].TextCharacters; + + /* Now go through the width. */ + if (found_first) + { + if (above_anchor) + val = page.SelAnchorX; + else + val = pos.X; + + /* our second partial line */ + if (val > lines[kk].X * scale + lines[kk].Width * scale) + m_lineptrs[page.PageNum].Add(lines[kk]); + else + { + /* Use either anchor point or mouse pos */ + end_line = new TextLine(); + end_line.TextCharacters = new List<TextCharacter>(); + end_line.Height = 0; + end_line.Scale = m_doczoom; + for (int mm = 0; mm < lett.Count; mm++) + { + double letscale = m_doczoom / lett[mm].Scale; + if (lett[mm].X * letscale < val) + { + /* Can set to special color for debug */ + end_line.Color = m_textselectcolor; + /* special color for debug */ + //end_line.Color = "#4000FF00"; + end_line.Height = lines[kk].Height * scale; + end_line.Width = lett[mm].X * letscale + lett[mm].Width * letscale - lines[kk].X * scale; + end_line.Y = lines[kk].Y * scale; + end_line.X = lines[kk].X * scale; + end_line.TextCharacters.Add(lett[mm]); + } + else + break; + } + if (end_line.Height != 0) + m_lineptrs[page.PageNum].Add(end_line); + } + } + else + { + if (!above_anchor) + val = page.SelAnchorX; + else + val = pos.X; + + /* our first partial line */ + found_first = true; + if (val < lines[kk].X * scale) + m_lineptrs[page.PageNum].Add(lines[kk]); + else + { + start_line = new TextLine(); + start_line.TextCharacters = new List<TextCharacter>(); + start_line.Height = 0; + start_line.Scale = m_doczoom; + /* Use either anchor point or mouse pos */ + for (int mm = 0; mm < lett.Count; mm++) + { + double letscale = m_doczoom / lett[mm].Scale; + if (lett[mm].X * letscale + lett[mm].Width * letscale >= val) + { + start_line.Color = m_textselectcolor; + /* special color for debug */ + //start_line.Color = "#40FF0000"; + start_line.Height = lines[kk].Height * scale; + start_line.Width = lines[kk].X * scale + lines[kk].Width * scale - lett[mm].X * letscale; + start_line.X = lett[mm].X * letscale; + start_line.Y = lines[kk].Y * scale; + start_line.TextCharacters.Add(lett[mm]); + break; + } + } + if (start_line.Height > 0) + m_lineptrs[page.PageNum].Add(start_line); + } + } + } + } + } + } + else + { + /* Add all the lines for the blocks between the first and last */ + for (int kk = 0; kk < lines.Count; kk++) + m_lineptrs[page.PageNum].Add(lines[kk]); + } + } + + var txtsel = m_textSelect[m_textSelect.Count - 1]; + txtsel.first_line_full = first_line_full; + txtsel.last_line_full = last_line_full; + m_textSelect[m_textSelect.Count - 1] = txtsel; + + /* Adjust for scale before assigning */ + var temp = m_lineptrs[page.PageNum]; + for (int kk = 0; kk < temp.Count; kk++) + { + var rect_item = temp[kk]; + double factor = m_doczoom / rect_item.Scale; + + temp[kk].Height = temp[kk].Height * factor; + temp[kk].Width = temp[kk].Width * factor; + temp[kk].X = temp[kk].X * factor; + temp[kk].Y = temp[kk].Y * factor; + + temp[kk].Scale = m_doczoom; + } + page.SelectedLines = m_lineptrs[page.PageNum]; + } + + private void CheckIfSelected() + { + m_textselected = false; + + if (m_selectall) + { + SetSelectAll(m_blockcolor); + m_selectall = false; + } + /* Check if anything was selected */ + for (int kk = 0; kk < m_lineptrs.Count; kk++) + { + if (m_lineptrs[kk].Count > 0) + { + m_textselected = true; + break; + } + } + } + + /* Rect should be removed */ + private void PageLeftClickUp(object sender, MouseButtonEventArgs e) + { + m_intxtselect = false; + CheckIfSelected(); + } + + private void StepScroll(int stepsize) + { + ScrollViewer viewer = FindScrollViewer(xaml_PageList); + if (viewer != null) + { + var scrollpos = viewer.VerticalOffset; + viewer.ScrollToVerticalOffset(scrollpos + stepsize); + } + } + + private void ResetScroll() + { + ScrollViewer viewer = FindScrollViewer(xaml_PageList); + if (viewer != null) + viewer.ScrollToVerticalOffset(0); + } + + /* Recursive call to find the scroll viewer */ + private ScrollViewer FindScrollViewer(DependencyObject d) + { + if (d is ScrollViewer) + return d as ScrollViewer; + + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(d); i++) + { + var sw = FindScrollViewer(VisualTreeHelper.GetChild(d, i)); + if (sw != null) return sw; + } + return null; + } + + /* Only worry about cases where we are moving and left button is down */ + private void ListPreviewMouseMove(object sender, System.Windows.Input.MouseEventArgs e) + { + var relPoint = e.GetPosition(xaml_PageList); + var absPoint = this.PointToScreen(relPoint); + /* Console.Write("abs Y position = " + absPoint.Y + "\n"); + Console.Write("rel Y position = " + relPoint.Y + "\n"); + Console.Write("Height is = " + (this.Top + this.Height) + "\n"); */ + + if (xaml_PageList.IsMouseCaptured == true) + { + if (!m_intxtselect) + { + xaml_PageList.ReleaseMouseCapture(); + e.Handled = true; + return; + } + + if (relPoint.Y < Constants.SCROLL_EDGE_BUFFER || + absPoint.Y > (this.Top + this.Height - Constants.SCROLL_EDGE_BUFFER)) + { + if (m_dispatcherTimer == null) + { + m_dispatcherTimer = new System.Windows.Threading.DispatcherTimer(); + m_dispatcherTimer.Tick += new EventHandler(dispatcherTimerTick); + m_dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, Constants.DISPATCH_TIME); + } + if (m_dispatcherTimer.IsEnabled == false) + m_dispatcherTimer.Start(); + e.Handled = true; + } + + /* This is not desirable, but the scrollviewer behaves badly + * when it has captured the mouse and we move beyond the + * range. So we wont allow it */ + if (relPoint.Y < 0 || + absPoint.Y > (this.Top + this.Height) - Constants.SCROLL_EDGE_BUFFER / 2.0) + { + xaml_PageList.ReleaseMouseCapture(); + e.Handled = true; + if (m_dispatcherTimer != null && m_dispatcherTimer.IsEnabled == true) + m_dispatcherTimer.Stop(); + return; + } + } + } + + private void ListPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + if (m_dispatcherTimer != null && m_dispatcherTimer.IsEnabled) + { + m_dispatcherTimer.Stop(); + } + } + + private void ListMouseLeave(object sender, System.Windows.Input.MouseEventArgs e) + { + if (m_dispatcherTimer != null && m_dispatcherTimer.IsEnabled) + { + m_dispatcherTimer.Stop(); + } + if (xaml_PageList.IsMouseCaptured == true) + xaml_PageList.ReleaseMouseCapture(); + } + + /* Get mouse position, update selection accordingly */ + private void dispatcherTimerTick(object sender, EventArgs e) + { + var position = this.PointToScreen(Mouse.GetPosition(xaml_PageList)); + /* Console.Write("Y position = " + position.Y + "\n"); + Console.Write("Top position = " + this.Top + "\n"); + Console.Write("Bottom position = " + (this.Top + this.Height) + "\n"); */ + DocPage page; + int page_num; + + if (!xaml_PageList.IsMouseCaptured) + { + //Console.Write("Lost capture\n"); + return; + } + /*else + { + Console.Write("Have capture\n"); + } */ + /* Get our most recent page */ + var pageinfo = m_textSelect[m_textSelect.Count - 1]; + page_num = pageinfo.pagenum; + + /* Scrolling up */ + if (position.Y > this.Top + this.Height - Constants.SCROLL_EDGE_BUFFER) + { + /* See if we have the last line for this page */ + if (pageinfo.last_line_full) + { + page_num = page_num + 1; + m_lastY = 0; + if (page_num >= m_num_pages) + return; + } + page = m_docPages[page_num]; + StepScroll(Constants.SCROLL_STEP); + /* Set position for proper selection update */ + m_lastY = m_lastY + Constants.SCROLL_STEP; + if (m_lastY > m_maxY) + m_lastY = m_maxY; + position.Y = m_lastY; + UpdateSelection(position, page); + } + else if (position.Y < this.Top + Constants.SCROLL_EDGE_BUFFER) + { + /* See if we have the first line for this page */ + if (pageinfo.first_line_full) + { + if (page_num <= 0) + return; + page_num = page_num - 1; + m_lastY = m_docPages[page_num].Height; + } + page = m_docPages[page_num]; + StepScroll(-Constants.SCROLL_STEP); + /* Set position for proper selection update */ + m_lastY = m_lastY - Constants.SCROLL_STEP; + if (m_lastY < 0) + m_lastY = 0; + position.Y = m_lastY; + UpdateSelection(position, page); + } + } + + private void ListPreviewLeftButtonUp(object sender, MouseButtonEventArgs e) + { + if (m_dispatcherTimer != null && m_dispatcherTimer.IsEnabled) + { + m_dispatcherTimer.Stop(); + } + } + + private void ShowContextMenu(object sender, MouseButtonEventArgs e) + { + if (this.Cursor != System.Windows.Input.Cursors.IBeam) + return; + + var contextmenu = new System.Windows.Controls.ContextMenu(); + Canvas can = ((FrameworkElement)e.Source).Parent as Canvas; + var page = ((FrameworkElement)e.Source).DataContext as DocPage; + if (can == null || page == null) + return; + + var posit = e.GetPosition(can); + ContextMenu_t info = new ContextMenu_t(); + info.mouse_position = posit; + info.page_num = page.PageNum; + can.ContextMenu = contextmenu; + + if (m_textselected || m_selectall) + { + var m1 = new System.Windows.Controls.MenuItem(); + m1.Header = "Copy"; + + /* amazing what I have to do here to get the icon out of the + * resources into something that wpf can use */ + var iconres = Properties.Resources.copy; + var bitmap = iconres.ToBitmap(); + using (MemoryStream memory = new MemoryStream()) + { + bitmap.Save(memory, System.Drawing.Imaging.ImageFormat.Png); + memory.Position = 0; + BitmapImage bitmapImage = new BitmapImage(); + bitmapImage.BeginInit(); + bitmapImage.StreamSource = memory; + bitmapImage.CacheOption = BitmapCacheOption.OnLoad; + bitmapImage.EndInit(); + Image iconImage = new Image(); + iconImage.Source = bitmapImage; + m1.Icon = iconImage; + m1.Click += cntxMenuCopy; + contextmenu.Items.Add(m1); + } + + var m6 = new System.Windows.Controls.MenuItem(); + m6.Header = "Deselect All"; + m6.Click += cntxMenuDeselectAll; + contextmenu.Items.Add(m6); + + /* Below to be enabled when we add annotations */ + /* + var ma1 = new System.Windows.Controls.MenuItem(); + ma1.Header = "Highlight"; + ma1.Click += cntxMenuHighlight; + contextmenu.Items.Add(ma1); + + var ma2 = new System.Windows.Controls.MenuItem(); + ma2.Header = "Underline"; + ma2.Click += cntxMenuUnderline; + contextmenu.Items.Add(ma2); + + var ma3 = new System.Windows.Controls.MenuItem(); + ma3.Header = "Strikeout"; + ma3.Click += cntxMenuStrike; + contextmenu.Items.Add(ma3);*/ + + } + var m2 = new System.Windows.Controls.MenuItem(); + m2.Header = "Select Line"; + m2.Click += cntxMenuSelectLine; + m2.Tag = info; + contextmenu.Items.Add(m2); + + var m3 = new System.Windows.Controls.MenuItem(); + m3.Header = "Select Block"; + m3.Click += cntxMenuSelectBlock; + m3.Tag = info; + contextmenu.Items.Add(m3); + + var m4 = new System.Windows.Controls.MenuItem(); + m4.Header = "Select Page"; + m4.Click += cntxMenuSelectPage; + m4.Tag = info; + contextmenu.Items.Add(m4); + + var m5 = new System.Windows.Controls.MenuItem(); + m5.Header = "Select All"; + m5.Click += cntxMenuSelectAll; + contextmenu.Items.Add(m5); + } + + private void CopyTextDone(object sender, RunWorkerCompletedEventArgs e) + { + String result = (String) e.Result; + xaml_CopyTextProgress.Visibility = System.Windows.Visibility.Collapsed; + xaml_CopyTextProgress.Value = 0; + + try + { + System.Windows.Clipboard.SetText(result); + } + catch + { + return; + } + } + + private void CopyTextWork(object sender, DoWorkEventArgs e) + { + String output = null; + String fullstring = null; + BackgroundWorker worker = sender as BackgroundWorker; + + for (int k = 0; k < m_num_pages; k++) + { + output = mu_doc.GetText(k, textout_t.TEXT); + if (output != null) + fullstring = fullstring + output; + + double percent = 100 * (double)(k + 1) / (double)m_num_pages; + worker.ReportProgress((int)percent, output); + + if (worker.CancellationPending == true) + { + e.Cancel = true; + break; + } + } + e.Result = fullstring; + } + + private void CopyTextProgress(object sender, ProgressChangedEventArgs e) + { + String output = (String)(e.UserState); + xaml_CopyTextProgress.Value = e.ProgressPercentage; + } + + private void cntxMenuCopy(object sender, RoutedEventArgs e) + { + if (m_selectall) + { + /* Start a thread to go through and copy the pages to the + * clipboard */ + m_copytext = new BackgroundWorker(); + m_copytext.WorkerReportsProgress = true; + m_copytext.WorkerSupportsCancellation = true; + m_copytext.DoWork += new DoWorkEventHandler(CopyTextWork); + m_copytext.RunWorkerCompleted += new RunWorkerCompletedEventHandler(CopyTextDone); + m_copytext.ProgressChanged += new ProgressChangedEventHandler(CopyTextProgress); + xaml_CopyTextProgress.Visibility = System.Windows.Visibility.Visible; + m_copytext.RunWorkerAsync(); + return; + } + + /* Go through and get each line of text */ + String result = null; + + for (int kk = 0; kk < m_textSelect.Count; kk++) + { + var lines = m_lineptrs[m_textSelect[kk].pagenum]; + for (int jj = 0; jj < lines.Count; jj++) + { + var text = lines[jj].TextCharacters; + for (int mm = 0; mm < text.Count; mm++) + { + result += text[mm].character; + } + result += "\r\n"; + } + } + System.Windows.Clipboard.SetText(result); + } + + private void cntxMenuSelectLine(object sender, RoutedEventArgs e) + { + var mi = sender as System.Windows.Controls.MenuItem; + ContextMenu_t info = (ContextMenu_t)mi.Tag; + var page = m_docPages[info.page_num]; + + InitTextSelection(page); + + page.SelX = 0; + page.SelY = info.mouse_position.Y - 1; + page.SelAnchorX = 0; + page.SelAnchorY = info.mouse_position.Y - 1; + page.SelColor = m_regionselect; + + /* Create new holder for lines highlighted */ + m_lineptrs[page.PageNum] = new LinesText(); + + Point pos = new Point(); + pos.X = page.Width; + pos.Y += info.mouse_position.Y + 1; + + UpdateSelection(pos, page); + CheckIfSelected(); + } + + /* This one requires its own special handling TODO FIXME */ + private void cntxMenuSelectBlock(object sender, RoutedEventArgs e) + { + var mi = sender as System.Windows.Controls.MenuItem; + ContextMenu_t info = (ContextMenu_t)mi.Tag; + var page = m_docPages[info.page_num]; + bool found = false; + int jj; + + InitTextSelection(page); + + /* Find the block that we are in */ + for (jj = 0; jj < page.TextBlocks.Count; jj++) + { + var intersect_blk = page.TextBlocks[jj].CheckIntersection(info.mouse_position.X, info.mouse_position.Y, 1, 1); + if (intersect_blk != Intersection_t.NONE) + { + found = true; + break; + } + } + if (found) + { + page.SelX = page.TextBlocks[jj].X; + page.SelY = page.TextBlocks[jj].Y; + page.SelAnchorX = page.TextBlocks[jj].X; + page.SelAnchorY = page.TextBlocks[jj].Y; + page.SelColor = m_regionselect; + + /* Create new holder for lines highlighted */ + m_lineptrs[page.PageNum] = new LinesText(); + + Point pos = new Point(); + pos.X = page.TextBlocks[jj].X + page.TextBlocks[jj].Width; + pos.Y = page.TextBlocks[jj].Y + page.TextBlocks[jj].Height; + + UpdateSelection(pos, page); + CheckIfSelected(); + } + else + m_textselected = false; + } + + private void SelectFullPage(int page_num) + { + var page = m_docPages[page_num]; + + InitTextSelection(page); + + page.SelX = 0; + page.SelY = 0; + page.SelAnchorX = 0; + page.SelAnchorY = 0; + page.SelColor = m_regionselect; + + /* Create new holder for lines highlighted */ + m_lineptrs[page.PageNum] = new LinesText(); + + Point pos = new Point(); + pos.X = page.Width; + pos.Y = page.Height; + + UpdateSelection(pos, page); + } + + private void cntxMenuSelectPage(object sender, RoutedEventArgs e) + { + var mi = sender as System.Windows.Controls.MenuItem; + ContextMenu_t info = (ContextMenu_t)mi.Tag; + + SelectFullPage(info.page_num); + CheckIfSelected(); + } + + private void cntxMenuSelectAll(object sender, RoutedEventArgs e) + { + var mi = sender as System.Windows.Controls.MenuItem; + if (m_textSelect != null) + ClearSelections(); + else + m_textSelect = new List<textSelectInfo_t>(); + + m_selectall = true; + SetSelectAll(m_textselectcolor); + } + + private void SetSelectAll(String color) + { + if (!m_init_done) + return; + + for (int kk = 0; kk < m_num_pages; kk++) + { + if (m_docPages[kk] != null && m_docPages[kk].TextBlocks != null) + { + int num_blocks = m_docPages[kk].TextBlocks.Count; + for (int jj = 0; jj < num_blocks; jj++) + m_docPages[kk].TextBlocks[jj].Color = color; + } + } + } + + private void cntxMenuDeselectAll(object sender, RoutedEventArgs e) + { + ClearSelections(); + } + + private void SelectAllCommand(object sender, ExecutedRoutedEventArgs e) + { + if (m_init_done) + cntxMenuSelectAll(sender, e); + } + + private void CopyCommand(object sender, ExecutedRoutedEventArgs e) + { + if (m_init_done) + cntxMenuCopy(sender, e); + } + + private void CancelCopyText(object sender, RoutedEventArgs e) + { + if (m_copytext != null && m_copytext.IsBusy) + m_copytext.CancelAsync(); + } + + /* To add with annotation support */ + /* + private void cntxMenuHighlight(object sender, RoutedEventArgs e) + { + + } + + private void cntxMenuUnderline(object sender, RoutedEventArgs e) + { + + } + + private void cntxMenuStrike(object sender, RoutedEventArgs e) + { + + } + */ + #endregion TextSelection + + private void OnAboutClick(object sender, RoutedEventArgs e) + { + String muversion; + About about = new About(this); + var desc_static = about.Description; + String desc; + + /* Get our gs and mupdf version numbers to add to the description */ + mu_doc.GetVersion(out muversion); + if (muversion == null) + desc = desc_static + "\nMuPDF DLL: Not Found"; + else + { + if (mu_doc.is64bit) + { + desc = desc_static + "\nUsing MuPDF Version " + muversion + " 64 bit\n"; + } + else + { + desc = desc_static + "\nUsing MuPDF Version " + muversion + " 32 bit\n"; + } + } + String gs_vers = m_ghostscript.GetVersion(); + if (gs_vers == null) + desc = desc + "\nGhostscript DLL: Not Found"; + else + if (mu_doc.is64bit) + { + desc = desc + "\nGhostscript DLL: " + gs_vers + " 64 bit\n"; + } + else + { + desc = desc + "\nGhostscript DLL: " + gs_vers + " 64 bit\n"; + } + about.description.Text = desc; + about.ShowDialog(); + } + + private void HelpCommand(object sender, ExecutedRoutedEventArgs e) + { + OnHelpClick(sender, e); + } + + private void OnHelpClick(object sender, RoutedEventArgs e) + { + + } + + private void CloseFile(object sender, RoutedEventArgs e) + { + CleanUp(); + DimSelections(); + } + + private double GetTotalHeightZoom() + { + return m_totalpageheight * m_doczoom + (m_num_pages - 1) * Constants.PAGE_MARGIN; + } + + private double GetTotalHeightNoZoom() + { + return m_totalpageheight + (m_num_pages - 1) * Constants.PAGE_MARGIN; + } + + private double GetViewPortSize() + { + ScrollViewer viewer = FindScrollViewer(xaml_PageList); + return viewer.ViewportHeight; + } + + private void SetThumbwidth() + { + double percent = GetViewPortSize() / GetTotalHeightZoom(); + double range = xaml_VerticalScroll.Maximum - xaml_VerticalScroll.Minimum; + xaml_VerticalScroll.SetThumbLength(percent * range); + } + + private void AdjustScrollPercent(double percent) + { + double curr_value = xaml_VerticalScroll.Value; + double range = xaml_VerticalScroll.Maximum; + double step = range * percent; + + xaml_VerticalScroll.Value = curr_value + step; + } + + /* Due to the scroll bar on the scroll viewer being wonky on its updating during zooming + * we have to do this ourselves */ + private void VerticalScroll(object sender, System.Windows.Controls.Primitives.ScrollEventArgs e) + { + var mi = sender as System.Windows.Controls.Primitives.ScrollBar; + ScrollViewer viewer = FindScrollViewer(xaml_PageList); + if (viewer == null || mi == null) + return; + + m_ScrolledChanged = true; + + if (e.ScrollEventType == System.Windows.Controls.Primitives.ScrollEventType.ThumbTrack) + { + OffsetScrollPercent(mi.Value / mi.Maximum); + e.Handled = true; + } + else if (e.ScrollEventType == System.Windows.Controls.Primitives.ScrollEventType.First) + { + mi.Value = 0; + viewer.ScrollToTop(); + } + else if (e.ScrollEventType == System.Windows.Controls.Primitives.ScrollEventType.Last) + { + mi.Value = mi.Maximum; + viewer.ScrollToBottom(); + } + else if (e.ScrollEventType == System.Windows.Controls.Primitives.ScrollEventType.SmallDecrement) + { + OffsetScroll(-Constants.VERT_SCROLL_STEP * m_doczoom); + } + else if (e.ScrollEventType == System.Windows.Controls.Primitives.ScrollEventType.SmallIncrement) + { + OffsetScroll(Constants.VERT_SCROLL_STEP * m_doczoom); + } + else if (e.ScrollEventType == System.Windows.Controls.Primitives.ScrollEventType.LargeDecrement) + { + if (m_currpage == 0) + { + mi.Value = 0; + viewer.ScrollToTop(); + } + else + OnBackPageClick(null, null); + } + else if (e.ScrollEventType == System.Windows.Controls.Primitives.ScrollEventType.LargeIncrement) + { + if (m_currpage == m_num_pages - 1) + { + mi.Value = mi.Maximum; + viewer.ScrollToBottom(); + } + else + OnForwardPageClick(null, null); + } + else if (e.ScrollEventType == System.Windows.Controls.Primitives.ScrollEventType.ThumbPosition) + { + OffsetScrollPercent(e.NewValue / mi.Maximum); + } + } + + private void OnAAChecked(object sender, RoutedEventArgs e) + { + var control = sender as System.Windows.Controls.Control; + string Name = control.Name; + + /* It would be nice to uncheck all and then recheck the one + * that we want to avoid the repeated code below, but that puts + * us in a infinite recursion with the call from the xaml Checked + * call */ + + switch (Name) + { + case "xaml_AA_High": + m_AA = AA_t.HIGH; + if (xaml_AA_MedHigh != null) + xaml_AA_MedHigh.IsChecked = false; + if (xaml_AA_Med != null) + xaml_AA_Med.IsChecked = false; + if (xaml_AA_Low != null) + xaml_AA_Low.IsChecked = false; + if (xaml_AA_None != null) + xaml_AA_None.IsChecked = false; + break; + case "xaml_AA_MedHigh": + m_AA = AA_t.MEDHIGH; + if (xaml_AA_High != null) + xaml_AA_High.IsChecked = false; + if (xaml_AA_Med != null) + xaml_AA_Med.IsChecked = false; + if (xaml_AA_Low != null) + xaml_AA_Low.IsChecked = false; + if (xaml_AA_None != null) + xaml_AA_None.IsChecked = false; + break; + case "xaml_AA_Med": + m_AA = AA_t.MED; + if (xaml_AA_High != null) + xaml_AA_High.IsChecked = false; + if (xaml_AA_MedHigh != null) + xaml_AA_MedHigh.IsChecked = false; + if (xaml_AA_Low != null) + xaml_AA_Low.IsChecked = false; + if (xaml_AA_None != null) + xaml_AA_None.IsChecked = false; + break; + case "xaml_AA_Low": + m_AA = AA_t.LOW; + if (xaml_AA_High != null) + xaml_AA_High.IsChecked = false; + if (xaml_AA_MedHigh != null) + xaml_AA_MedHigh.IsChecked = false; + if (xaml_AA_Med != null) + xaml_AA_Med.IsChecked = false; + if (xaml_AA_None != null) + xaml_AA_None.IsChecked = false; + break; + case "xaml_AA_None": + m_AA = AA_t.NONE; + if (xaml_AA_High != null) + xaml_AA_High.IsChecked = false; + if (xaml_AA_MedHigh != null) + xaml_AA_MedHigh.IsChecked = false; + if (xaml_AA_Med != null) + xaml_AA_Med.IsChecked = false; + if (xaml_AA_Low != null) + xaml_AA_Low.IsChecked = false; + break; + } + if (mu_doc != null) + mu_doc.SetAA(m_AA); + if (m_init_done) + RenderRange(m_currpage, false, zoom_t.NO_ZOOM, 0); + } + + private AA_t GetAA() + { + if (xaml_AA_High.IsChecked) + return AA_t.HIGH; + else if (xaml_AA_MedHigh.IsChecked) + return AA_t.MEDHIGH; + else if (xaml_AA_Med.IsChecked) + return AA_t.MED; + else if (xaml_AA_Low.IsChecked) + return AA_t.LOW; + else + return AA_t.NONE; + } + + private void SetAA(AA_t aa) + { + xaml_AA_High.IsChecked = false; + xaml_AA_MedHigh.IsChecked = false; + xaml_AA_Med.IsChecked = false; + xaml_AA_Low.IsChecked = false; + xaml_AA_None.IsChecked = false; + + switch (aa) + { + case AA_t.HIGH: + xaml_AA_High.IsChecked = true; + break; + case AA_t.MEDHIGH: + xaml_AA_MedHigh.IsChecked = true; + break; + case AA_t.MED: + xaml_AA_High.IsChecked = true; + break; + case AA_t.LOW: + xaml_AA_High.IsChecked = true; + break; + case AA_t.NONE: + xaml_AA_High.IsChecked = true; + break; + } + } + + private void AnnotationOn(object sender, RoutedEventArgs e) + { + if (!m_init_done) + return; + m_showannot = true; + RenderRange(m_currpage, false, zoom_t.NO_ZOOM, 0); + } + + private void AnnotationOff(object sender, RoutedEventArgs e) + { + if (!m_init_done) + return; + m_showannot = false; + RenderRange(m_currpage, false, zoom_t.NO_ZOOM, 0); + } + } +}
\ No newline at end of file |