<commit_before>﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using Bloom.Book;
using Bloom.Collection;
using Bloom.Properties;
using Bloom.ToPalaso;
using Bloom.web;
using Bloom.WebLibraryIntegration;
using Bloom.Workspace;
using DesktopAnalytics;
using SIL.Reporting;
using L10NSharp;
using SIL.IO;

namespace Bloom.CollectionTab
{
	public partial class LibraryListView : UserControl
	{
		private const int ButtonHeight = 112;
		private const int ButtonWidth = 92;

		public delegate LibraryListView Factory();//autofac uses this

		private readonly LibraryModel _model;
		private readonly BookSelection _bookSelection;
		//private readonly HistoryAndNotesDialog.Factory _historyAndNotesDialogFactory;
		private Font _headerFont;
		private Font _editableBookFont;
		private Font _collectionBookFont;
		private bool _thumbnailRefreshPending;
		private DateTime _lastClickTime;
		private bool _primaryCollectionReloadPending;
		private bool _disposed;
		private BookCollection _downloadedBookCollection;
		private Image _dropdownImage;

		enum ButtonManagementStage
		{
			LoadPrimary, ImprovePrimary, LoadSourceCollections, ImproveAndRefresh
		}

		private ButtonManagementStage _buttonManagementStage = ButtonManagementStage.LoadPrimary;

		/// <summary>
		/// we go through these at idle time, doing slow things like actually instantiating the book to get the title in preferred language
		/// A stack would be better for updating "the thing I just changed", but we're using a queue at the moment simply because we
		/// want you'd see at the top of the screen to update before what's at the bottom or offscreen
		/// </summary>
		private readonly ConcurrentQueue<ButtonRefreshInfo> _buttonsNeedingSlowUpdate;

		private bool _alreadyReportedErrorDuringImproveAndRefreshBookButtons;

		public LibraryListView(LibraryModel model, BookSelection bookSelection, SelectedTabChangedEvent selectedTabChangedEvent, LocalizationChangedEvent localizationChangedEvent)
			//HistoryAndNotesDialog.Factory historyAndNotesDialogFactory)
		{
			_model = model;
			_bookSelection = bookSelection;
			localizationChangedEvent.Subscribe(unused=>LoadSourceCollectionButtons());
			//_historyAndNotesDialogFactory = historyAndNotesDialogFactory;
			_buttonsNeedingSlowUpdate = new ConcurrentQueue<ButtonRefreshInfo>();
			selectedTabChangedEvent.Subscribe(OnSelectedTabChanged);
			InitializeComponent();
			_primaryCollectionFlow.HorizontalScroll.Visible = false;

			_primaryCollectionFlow.Controls.Clear();
			_primaryCollectionFlow.HorizontalScroll.Visible = false;
			_sourceBooksFlow.Controls.Clear();
			_sourceBooksFlow.HorizontalScroll.Visible = false;

			if (!_model.ShowSourceCollections)
			{
				splitContainer1.Panel2Collapsed = true;
			}

			_headerFont = new Font(SystemFonts.DialogFont.FontFamily, (float)10.0, FontStyle.Bold);
			_editableBookFont = new Font(SystemFonts.DialogFont.FontFamily, (float)9.0);//, FontStyle.Bold);
			_collectionBookFont = new Font(SystemFonts.DialogFont.FontFamily, (float)9.0);

			//enhance: move to model
			bookSelection.SelectionChanged += new EventHandler(OnBookSelectionChanged);

			_settingsProtectionHelper.ManageComponent(_openFolderOnDisk);

			_showHistoryMenu.Visible = _showNotesMenu.Visible = Settings.Default.ShowSendReceive;

			if(Settings.Default.ShowExperimentalCommands)
				_settingsProtectionHelper.ManageComponent(_exportToXMLForInDesignToolStripMenuItem);//we are restricting it because it opens a folder from which the user could do damage
			_exportToXMLForInDesignToolStripMenuItem.Visible = Settings.Default.ShowExperimentalCommands;

			SetupBookDropdownIcon();
			_bookContextMenu.Closed += _bookContextMenu_Closed;
			_bookContextMenu.Opening += _bookContextMenu_Opening;
		}

		// BL-2678 Adjust the context menu item visibility based on what sort of collection we're in
		// If we're in factory-installed templates or the sample shell, don't show a menu at all
		// If we're in a book downloaded from BloomLibrary.org, only show "Open Folder on Disk" and "Delete"
		// If we're in our one editable collection, show everything
		// Otherwise (which should be bloompacks or other user-installed stuff not downloaded):
		//   only show "Open Folder on Disk"
		private void _bookContextMenu_Opening(object sender, CancelEventArgs e)
		{
			var btn = (sender as ContextMenuStrip).SourceControl as Button;
			if (btn == null)
			{
				// At least in Mono, the button selection doesn't always survive from the click to this point.
				// See https://silbloom.myjetbrains.com/youtrack/issue/BL-3424 and various internet posts like
				// http://stackoverflow.com/questions/3026380/getting-the-highest-owner-of-a-toolstripdropdownitem.
				// This might be needed only on Linux/Mono, but is safe for windows.
				btn = _clickedButton;
				_clickedButton = null;
				if (btn == null)
				{
					e.Cancel = true; // don't show the menu at all
					return;
				}
			}
			var btnInfo = btn.Tag as BookButtonInfo;
			if (btnInfo.IsEditable)
				return; // leave them all on
			if (btnInfo.HasNoContextMenu)
			{
				e.Cancel = true; // don't show the menu at all (but leave them visible for next time)
				return;
			}
			foreach (ToolStripItem menuItem in (sender as ContextMenuStrip).Items)
			{
				if (menuItem == deleteMenuItem && btnInfo.IsBLibraryBook)
					continue; // leave this one on for BloomLibrary books
				if (menuItem == _openFolderOnDisk)
					continue; // leave this one on (for both BloomLibrary and BloomPack books)
				menuItem.Visible = false;
			}
		}

		private static void _bookContextMenu_Closed(object sender, ToolStripDropDownClosedEventArgs e)
		{
			// Not sure which ones are visible at this point
			// So make them all visible so they are available in the right-click menu
			foreach (ToolStripItem menuItem in (sender as ContextMenuStrip).Items)
				menuItem.Visible = true;
		}

		private static BookInfo GetBookInfoFromButton(Button bookButton)
		{
			var bookButtonInfo = bookButton.Tag as BookButtonInfo;
			return bookButtonInfo == null ? null : bookButtonInfo.BookInfo;
		}

		private void SetupBookDropdownIcon()
		{
			// we just need the bottom part of the image for this button
			_dropdownImage = new Bitmap(10, 8, PixelFormat.Format32bppArgb);
			var src = (Bitmap)_menuTriangle.Image;
			using (var g = Graphics.FromImage(_dropdownImage))
			{
				g.DrawImage(src, new Rectangle(0, 0, 10, 8), new Rectangle(0, 7, 13, 11), GraphicsUnit.Pixel);<commit_msg>BL-4176 Fix InDesign menu visibility issue (#1440)<commit_after>﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using Bloom.Book;
using Bloom.Collection;
using Bloom.Properties;
using Bloom.ToPalaso;
using Bloom.web;
using Bloom.WebLibraryIntegration;
using Bloom.Workspace;
using DesktopAnalytics;
using SIL.Reporting;
using L10NSharp;
using SIL.IO;

namespace Bloom.CollectionTab
{
	public partial class LibraryListView : UserControl
	{
		private const int ButtonHeight = 112;
		private const int ButtonWidth = 92;

		public delegate LibraryListView Factory();//autofac uses this

		private readonly LibraryModel _model;
		private readonly BookSelection _bookSelection;
		//private readonly HistoryAndNotesDialog.Factory _historyAndNotesDialogFactory;
		private Font _headerFont;
		private Font _editableBookFont;
		private Font _collectionBookFont;
		private bool _thumbnailRefreshPending;
		private DateTime _lastClickTime;
		private bool _primaryCollectionReloadPending;
		private bool _disposed;
		private BookCollection _downloadedBookCollection;
		private Image _dropdownImage;

		enum ButtonManagementStage
		{
			LoadPrimary, ImprovePrimary, LoadSourceCollections, ImproveAndRefresh
		}

		private ButtonManagementStage _buttonManagementStage = ButtonManagementStage.LoadPrimary;

		/// <summary>
		/// we go through these at idle time, doing slow things like actually instantiating the book to get the title in preferred language
		/// A stack would be better for updating "the thing I just changed", but we're using a queue at the moment simply because we
		/// want you'd see at the top of the screen to update before what's at the bottom or offscreen
		/// </summary>
		private readonly ConcurrentQueue<ButtonRefreshInfo> _buttonsNeedingSlowUpdate;

		private bool _alreadyReportedErrorDuringImproveAndRefreshBookButtons;

		public LibraryListView(LibraryModel model, BookSelection bookSelection, SelectedTabChangedEvent selectedTabChangedEvent, LocalizationChangedEvent localizationChangedEvent)
			//HistoryAndNotesDialog.Factory historyAndNotesDialogFactory)
		{
			_model = model;
			_bookSelection = bookSelection;
			localizationChangedEvent.Subscribe(unused=>LoadSourceCollectionButtons());
			//_historyAndNotesDialogFactory = historyAndNotesDialogFactory;
			_buttonsNeedingSlowUpdate = new ConcurrentQueue<ButtonRefreshInfo>();
			selectedTabChangedEvent.Subscribe(OnSelectedTabChanged);
			InitializeComponent();
			_primaryCollectionFlow.HorizontalScroll.Visible = false;

			_primaryCollectionFlow.Controls.Clear();
			_primaryCollectionFlow.HorizontalScroll.Visible = false;
			_sourceBooksFlow.Controls.Clear();
			_sourceBooksFlow.HorizontalScroll.Visible = false;

			if (!_model.ShowSourceCollections)
			{
				splitContainer1.Panel2Collapsed = true;
			}

			_headerFont = new Font(SystemFonts.DialogFont.FontFamily, (float)10.0, FontStyle.Bold);
			_editableBookFont = new Font(SystemFonts.DialogFont.FontFamily, (float)9.0);//, FontStyle.Bold);
			_collectionBookFont = new Font(SystemFonts.DialogFont.FontFamily, (float)9.0);

			//enhance: move to model
			bookSelection.SelectionChanged += new EventHandler(OnBookSelectionChanged);

			_settingsProtectionHelper.ManageComponent(_openFolderOnDisk);

			_showHistoryMenu.Visible = _showNotesMenu.Visible = Settings.Default.ShowSendReceive;

			if(Settings.Default.ShowExperimentalCommands)
				_settingsProtectionHelper.ManageComponent(_exportToXMLForInDesignToolStripMenuItem);//we are restricting it because it opens a folder from which the user could do damage
			_exportToXMLForInDesignToolStripMenuItem.Visible = Settings.Default.ShowExperimentalCommands;

			SetupBookDropdownIcon();
			_bookContextMenu.Closed += _bookContextMenu_Closed;
			_bookContextMenu.Opening += _bookContextMenu_Opening;
		}

		// BL-2678 Adjust the context menu item visibility based on what sort of collection we're in
		// If we're in factory-installed templates or the sample shell, don't show a menu at all
		// If we're in a book downloaded from BloomLibrary.org, only show "Open Folder on Disk" and "Delete"
		// If we're in our one editable collection, show everything
		// Otherwise (which should be bloompacks or other user-installed stuff not downloaded):
		//   only show "Open Folder on Disk"
		private void _bookContextMenu_Opening(object sender, CancelEventArgs e)
		{
			var btn = (sender as ContextMenuStrip).SourceControl as Button;
			if (btn == null)
			{
				// At least in Mono, the button selection doesn't always survive from the click to this point.
				// See https://silbloom.myjetbrains.com/youtrack/issue/BL-3424 and various internet posts like
				// http://stackoverflow.com/questions/3026380/getting-the-highest-owner-of-a-toolstripdropdownitem.
				// This might be needed only on Linux/Mono, but is safe for windows.
				btn = _clickedButton;
				_clickedButton = null;
				if (btn == null)
				{
					e.Cancel = true; // don't show the menu at all
					return;
				}
			}
			var btnInfo = btn.Tag as BookButtonInfo;
			if (btnInfo.IsEditable)
				return; // leave them all on
			if (btnInfo.HasNoContextMenu)
			{
				e.Cancel = true; // don't show the menu at all (but leave them visible for next time)
				return;
			}
			foreach (ToolStripItem menuItem in (sender as ContextMenuStrip).Items)
			{
				if (menuItem == deleteMenuItem && btnInfo.IsBLibraryBook)
					continue; // leave this one on for BloomLibrary books
				if (menuItem == _openFolderOnDisk)
					continue; // leave this one on (for both BloomLibrary and BloomPack books)
				menuItem.Visible = false;
			}
		}

		private void _bookContextMenu_Closed(object sender, ToolStripDropDownClosedEventArgs e)
		{
			// Not sure which ones are visible at this point
			// So make them all visible so they are available in the right-click menu
			foreach (ToolStripItem menuItem in (sender as ContextMenuStrip).Items)
			{
				// Except that we do know that this one's visibility has already been set correctly;
				// Don't change it! (BL-4176)
				if (menuItem == _exportToXMLForInDesignToolStripMenuItem)
					menuItem.Visible = _exportToXMLForInDesignToolStripMenuItem.Visible;
				else menuItem.Visible = true;
			}
		}

		private static BookInfo GetBookInfoFromButton(Button bookButton)
		{
			var bookButtonInfo = bookButton.Tag as BookButtonInfo;
			return bookButtonInfo == null ? null : bookButtonInfo.BookInfo;
		}

		private void SetupBookDropdownIcon()
		{
			// we just need the bottom part of the image for this button
			_dropdownImage = new Bitmap(10, 8, PixelFormat.Format32bppArgb);
			var src = (Bitmap)_menuTriangle.Image;
			using (var g = Graphics.FromImage(_dropdownImage))
			{
				g.DrawImage(src, new Rectangle(0, 0, 10, 8), new Rectangle(0, 7, 13, 11), GraphicsUnit.Pixel);
{'fraction_non_alphanumeric': 0.07474114044042585, 'fraction_numerical': 0.007729327694326965, 'mean_word_length': 4.554880518428513, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 13, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '124994', 'n_tokens_mistral': 4379, 'n_tokens_neox': 3733, 'n_words': 1166}